diff --git a/TODO.md b/TODO.md index ccb4872..1b4ed9f 100644 --- a/TODO.md +++ b/TODO.md @@ -15,13 +15,13 @@ # Back Office -- [ ] tambah biaya admin di deposit manual transfer +- [x] tambah biaya admin di deposit manual transfer - [x] info di ubah jadi html - [ ] tambahan detail customer untuk detail mitra wbb - [ ] detail customer level untuk tampilan screen level customer di depan - [ ] rombak fitur affiliasi -- [ ] tambah detail di user admin -- [ ] tambah logo bank -- [ ] tambah setor tunai +- [x] tambah detail di user admin +- [x] tambah logo bank +- [x] tambah setor tunai - [ ] pengaturan share dapat menggunakan html - [ ] menu mitrawbb diff --git a/app/Http/Controllers/Api/CustomerLevelController.php b/app/Http/Controllers/Api/CustomerLevelController.php new file mode 100644 index 0000000..eb8e136 --- /dev/null +++ b/app/Http/Controllers/Api/CustomerLevelController.php @@ -0,0 +1,15 @@ +with('message', ['type' => 'error', 'message' => 'Akun belum aktif, Silahkan klik link verifikasi di email anda']); } - if ($user->status == Customer::STATUS_SUSPEND) { - return redirect()->route('customer.login') - ->with('message', ['type' => 'error', 'message' => 'Akun anda telah disuspend, silahkan hubungi penyedia layanan']); - } + // Akun Suspend + // if ($user->status == Customer::STATUS_SUSPEND) { + // return redirect()->route('customer.login') + // ->with('message', ['type' => 'error', 'message' => 'Akun anda telah disuspend, silahkan hubungi penyedia layanan']); + // } $isAuth = Auth::guard('customer')->login($user); if ($isAuth) { @@ -111,10 +112,11 @@ class AuthController extends Controller $customer->update(['google_oauth_response' => json_encode($user)]); } - if ($customer->status == Customer::STATUS_SUSPEND) { - return redirect()->route('customer.login') - ->with('message', ['type' => 'error', 'message' => 'Akun anda telah disuspend, silahkan hubungi penyedia layanan']); - } + // Akun Suspend + // if ($customer->status == Customer::STATUS_SUSPEND) { + // return redirect()->route('customer.login') + // ->with('message', ['type' => 'error', 'message' => 'Akun anda telah disuspend, silahkan hubungi penyedia layanan']); + // } Auth::guard('customer')->loginUsingId($customer->id); diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 8c066df..fc8bf0a 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -11,17 +11,41 @@ class CustomerController extends Controller { public function index(Request $request) { - $query = Customer::query()->with(['level'])->orderBy('updated_at', 'desc'); + $stats = [ + 'basic_count' => Customer::whereHas('level', fn ($q) => $q->where('key', CustomerLevel::BASIC))->count(), + 'silver_count' => Customer::whereHas('level', fn ($q) => $q->where('key', CustomerLevel::SILVER))->count(), + 'gold_count' => Customer::whereHas('level', fn ($q) => $q->where('key', CustomerLevel::GOLD))->count(), + 'platinum_count' => Customer::whereHas('level', fn ($q) => $q->where('key', CustomerLevel::PLATINUM))->count(), + ]; + + $query = Customer::query()->with(['level', 'paylater', 'locationFavorites']); if ($request->q != '') { - $query->where('name', 'like', "%$request->q%") - ->orWhere('fullname', 'like', "%$request->q%") - ->orWhere('email', 'like', "%$request->q%") - ->orWhere('phone', 'like', "%$request->q%"); + $query->where(function ($query) use ($request) { + $query->where('name', 'like', "%$request->q%") + ->orWhere('fullname', 'like', "%$request->q%") + ->orWhere('email', 'like', "%$request->q%") + ->orWhere('phone', 'like', "%$request->q%"); + }); + } + + if ($request->location_id != '') { + $query->whereHas('locationFavorites', fn ($q) => $q->where('id', $request->location_id)); + } + + if ($request->level_id != '') { + $query->where('customer_level_id', $request->level_id); + } + + if ($request->sortBy != '' && $request->sortRule != '') { + $query->orderBy($request->sortBy, $request->sortRule); + } else { + $query->orderBy('updated_at', 'desc'); } return inertia('Customer/Index', [ 'query' => $query->paginate(), + 'stats' => $stats, ]); } diff --git a/app/Http/Controllers/CustomerLevelController.php b/app/Http/Controllers/CustomerLevelController.php index 1bc80fc..fae6741 100644 --- a/app/Http/Controllers/CustomerLevelController.php +++ b/app/Http/Controllers/CustomerLevelController.php @@ -16,6 +16,13 @@ class CustomerLevelController extends Controller ]); } + public function edit(CustomerLevel $customerLevel) + { + return inertia('CustomerLevel/Form', [ + 'customer_level' => $customerLevel + ]); + } + public function update(Request $request, CustomerLevel $customerLevel) { $request->validate([ @@ -23,15 +30,24 @@ class CustomerLevelController extends Controller 'description' => 'nullable|string', 'min_amount' => 'required|numeric|min:0', 'max_amount' => 'required|numeric|min:0', + 'logo' => 'nullable|image', ]); + if ($request->hasFile('logo')) { + $file = $request->file('logo'); + $file->store('uploads', 'public'); + $customerLevel->logo = $file->hashName('uploads'); + } + $customerLevel->update([ 'name' => $request->name, 'description' => $request->description, 'min_amount' => $request->min_amount, 'max_amount' => $request->max_amount, + 'logo' => $customerLevel->logo, ]); - session()->flash('message', ['type' => 'success', 'message' => 'Item has beed updated']); + return redirect()->route('customer-level.index') + ->with('message', ['type' => 'success', 'message' => 'Item has beed updated']); } } diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php index b5d42c3..0830d6f 100644 --- a/app/Http/Controllers/SettingController.php +++ b/app/Http/Controllers/SettingController.php @@ -61,7 +61,6 @@ class SettingController extends Controller ]); } - public function updatePayment(Request $request) { $request->validate([ @@ -90,4 +89,43 @@ class SettingController extends Controller session()->flash('message', ['type' => 'success', 'message' => 'Setting has beed saved']); } + + public function affilate() + { + $setting = Setting::all(); + + return inertia('Setting/Payment', [ + 'setting' => $setting, + 'midtrans_notification_url' => route('api.midtrans.notification'), + ]); + } + + public function updateAffilate(Request $request) + { + $request->validate([ + 'MIDTRANS_SERVER_KEY' => 'required|string', + 'MIDTRANS_CLIENT_KEY' => 'required|string', + 'MIDTRANS_MERCHANT_ID' => 'required|string', + 'MIDTRANS_ADMIN_FEE' => 'required|numeric', + 'MIDTRANS_ENABLED' => 'required|in:0,1', + 'midtrans_logo_file' => 'nullable|image', + ]); + + DB::beginTransaction(); + foreach ($request->except(['midtrans_logo_file']) as $key => $value) { + Setting::where('key', $key)->update(['value' => $value]); + } + + if ($request->hasFile('midtrans_logo_file')) { + $file = $request->file('midtrans_logo_file'); + $file->store('uploads', 'public'); + Setting::where('key', 'MIDTRANS_LOGO')->update(['value' => $file->hashName('uploads')]); + } + + Cache::flush(); + + DB::commit(); + + session()->flash('message', ['type' => 'success', 'message' => 'Setting has beed saved']); + } } diff --git a/app/Models/Customer.php b/app/Models/Customer.php index 93e5f89..a6e1b90 100644 --- a/app/Models/Customer.php +++ b/app/Models/Customer.php @@ -65,6 +65,7 @@ class Customer extends Authenticatable 'display_deposit', 'display_poin', 'display_phone', + 'paylater_remain', 'paylater_limit', 'is_allow_paylater', 'verification_status', @@ -160,7 +161,7 @@ class Customer extends Authenticatable }); } - public function paylaterLimit(): Attribute + public function paylaterRemain(): Attribute { return Attribute::make(get: function () { if ($this->is_allow_paylater) { @@ -171,6 +172,17 @@ class Customer extends Authenticatable }); } + public function paylaterLimit(): Attribute + { + return Attribute::make(get: function () { + if ($this->is_allow_paylater) { + return $this->paylater->limit; + } + + return ''; + }); + } + public function isAllowPaylater(): Attribute { return Attribute::make(get: function () { diff --git a/app/Models/CustomerLevel.php b/app/Models/CustomerLevel.php index a80f937..8e7a732 100644 --- a/app/Models/CustomerLevel.php +++ b/app/Models/CustomerLevel.php @@ -2,6 +2,8 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Casts\Attribute; + class CustomerLevel extends Model { const BASIC = 'basic'; @@ -25,11 +27,22 @@ class CustomerLevel extends Model 'name', 'description', 'key', + 'logo', 'min_amount', 'max_amount', 'max_loan', ]; + protected $appends = [ + 'logo_url', + ]; + + protected function logoUrl(): Attribute + { + return Attribute::make(get: function () { + return asset($this->logo); + }); + } public static function getByKey($key) { return CustomerLevel::where('key', $key)->first(); diff --git a/database/migrations/2023_05_24_130630_create_customer_levels_table.php b/database/migrations/2023_05_24_130630_create_customer_levels_table.php index 63e531b..97b3173 100644 --- a/database/migrations/2023_05_24_130630_create_customer_levels_table.php +++ b/database/migrations/2023_05_24_130630_create_customer_levels_table.php @@ -15,7 +15,8 @@ return new class extends Migration $table->ulid('id')->primary(); $table->string('name')->nullable(); - $table->string('description')->nullable(); + $table->string('logo')->nullable(); + $table->text('description')->nullable(); $table->string('key')->nullable(); $table->decimal('min_amount', 20, 2)->default(0); $table->decimal('max_amount', 20, 2)->default(0); diff --git a/database/seeders/InstallationSeed.php b/database/seeders/InstallationSeed.php index e6850d6..aec83af 100644 --- a/database/seeders/InstallationSeed.php +++ b/database/seeders/InstallationSeed.php @@ -51,10 +51,39 @@ class InstallationSeed extends Seeder public function customer_levels() { $levels = [ - ['name' => 'Basic', 'key' => 'basic', 'description' => '-', 'min_amount' => '100000', 'max_amount' => '500000'], - ['name' => 'Silver', 'key' => 'silver', 'description' => '-', 'min_amount' => '100000', 'max_amount' => '1000000'], - ['name' => 'Gold', 'key' => 'gold', 'description' => '-', 'min_amount' => '100000', 'max_amount' => '2000000'], - ['name' => 'Platinum', 'key' => 'platinum', 'description' => '-', 'min_amount' => '100000', 'max_amount' => '3000000'], + [ + 'name' => 'Basic', + 'key' => 'basic', + 'logo' => 'sample/basic.png', + 'description' => '-', + 'min_amount' => + '100000', + 'max_amount' => '500000' + ], + [ + 'name' => 'Silver', + 'key' => 'silver', + 'logo' => 'sample/silver.png', + 'description' => '-', + 'min_amount' => '100000', + 'max_amount' => '1000000' + ], + [ + 'name' => 'Gold', + 'key' => 'gold', + 'logo' => 'sample/gold.png', + 'description' => '-', + 'min_amount' => '100000', + 'max_amount' => '2000000' + ], + [ + 'name' => 'Platinum', + 'key' => 'platinum', + 'logo' => 'sample/platinum.png', + 'description' => '-', + 'min_amount' => '100000', + 'max_amount' => '3000000' + ], ]; foreach ($levels as $level) { diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index 965d250..f68faba 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -58,6 +58,8 @@ class PermissionSeeder extends Seeder ['id' => Str::ulid(), 'label' => 'View Customer Verification', 'name' => 'view-customer-verification'], ['id' => Str::ulid(), 'label' => 'View Setting', 'name' => 'view-setting'], + ['id' => Str::ulid(), 'label' => 'View Setting Payment Gatewat', 'name' => 'view-setting-payment-gateway'], + ['id' => Str::ulid(), 'label' => 'View Setting Affilate', 'name' => 'view-setting-affilate'], ['id' => Str::ulid(), 'label' => 'View Deposit', 'name' => 'view-deposit'], ['id' => Str::ulid(), 'label' => 'Update Deposit', 'name' => 'update-deposit'], diff --git a/public/sample/basic.png b/public/sample/basic.png new file mode 100644 index 0000000..2077443 Binary files /dev/null and b/public/sample/basic.png differ diff --git a/public/sample/gold.png b/public/sample/gold.png new file mode 100644 index 0000000..f11e5e9 Binary files /dev/null and b/public/sample/gold.png differ diff --git a/public/sample/platinum.png b/public/sample/platinum.png new file mode 100644 index 0000000..d5b6d2a Binary files /dev/null and b/public/sample/platinum.png differ diff --git a/public/sample/silver.png b/public/sample/silver.png new file mode 100644 index 0000000..f591051 Binary files /dev/null and b/public/sample/silver.png differ diff --git a/resources/js/Pages/Voucher/ThSortComponent.jsx b/resources/js/Components/ThSortComponent.jsx similarity index 100% rename from resources/js/Pages/Voucher/ThSortComponent.jsx rename to resources/js/Components/ThSortComponent.jsx diff --git a/resources/js/Customer/Index/Partials/BalanceBanner.jsx b/resources/js/Customer/Index/Partials/BalanceBanner.jsx index f8e38e6..e26ffac 100644 --- a/resources/js/Customer/Index/Partials/BalanceBanner.jsx +++ b/resources/js/Customer/Index/Partials/BalanceBanner.jsx @@ -10,7 +10,7 @@ export default function BalanceBanner({ user }) { onClick={() => router.get(route('customer.deposit.index'))} >
- Deposit + Sisa Saldo Hutang | - poin + Limit Hutang | Referral Code | ++ Lokasi + | ++ Whatsapp + | - {customer.name} + + {customer.name} + | {customer.display_poin} | ++ {formatIDR( + customer.paylater_remain + )} + | ++ {formatIDR( + customer.paylater_limit + )} + | {customer.referral_code} | +
+ {customer.location_favorites.map(
+ (location) => (
+
+ {location.name}
+
+ )
+ )}
+ |
+ + {customer.phone !== + null && ( + + +62{customer.phone} + + )} + | import('@/Components/TinyMCE'))
+
+export default function Form(props) {
+ const { customer_level } = props
+
+ const { data, setData, post, processing, errors } = useForm({
+ name: '',
+ description: '',
+ min_amount: 0,
+ max_amount: 0,
+ logo: null,
+ logo_url: '',
+ })
+
+ const handleOnChange = (event) => {
+ setData(
+ event.target.name,
+ event.target.type === 'checkbox'
+ ? event.target.checked
+ ? 1
+ : 0
+ : event.target.value
+ )
+ }
+ const handleSubmit = () => {
+ post(route('customer-level.update', customer_level.id))
+ }
+
+ useEffect(() => {
+ if (isEmpty(customer_level) === false) {
+ setData({
+ name: customer_level.name,
+ description: customer_level.description,
+ min_amount: customer_level.min_amount,
+ max_amount: customer_level.max_amount,
+ logo_url: customer_level.logo_url,
+ })
+ }
+ }, [customer_level])
+
+ return (
+
+
+
+
+ )
+}
diff --git a/resources/js/Pages/CustomerLevel/FormModal.jsx b/resources/js/Pages/CustomerLevel/FormModal.jsx
deleted file mode 100644
index 3bcfe88..0000000
--- a/resources/js/Pages/CustomerLevel/FormModal.jsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import React, { useEffect } from 'react'
-import Modal from '@/Components/Modal'
-import { useForm } from '@inertiajs/react'
-import Button from '@/Components/Button'
-import FormInput from '@/Components/FormInput'
-import RoleSelectionInput from '../Role/SelectionInput'
-
-import { isEmpty } from 'lodash'
-
-export default function FormModal(props) {
- const { modalState } = props
- const { data, setData, post, put, processing, errors, reset, clearErrors } =
- useForm({
- name: '',
- description: '',
- min_amount: 0,
- max_amount: 0,
- })
-
- const handleOnChange = (event) => {
- setData(
- event.target.name,
- event.target.type === 'checkbox'
- ? event.target.checked
- ? 1
- : 0
- : event.target.value
- )
- }
-
- const handleReset = () => {
- modalState.setData(null)
- reset()
- clearErrors()
- }
-
- const handleClose = () => {
- handleReset()
- modalState.toggle()
- }
-
- const handleSubmit = () => {
- const customerLevel = modalState.data
- put(route('customer-level.update', customerLevel.id), {
- onSuccess: () => handleClose(),
- })
- }
-
- useEffect(() => {
- const customerLevel = modalState.data
- if (isEmpty(customerLevel) === false) {
- setData({
- name: customerLevel.name,
- description: customerLevel.description,
- min_amount: customerLevel.min_amount,
- max_amount: customerLevel.max_amount,
- })
- return
- }
- }, [modalState])
-
- return (
-
+
+
+
+
+ Atur Level
+
+ }>
+
+
+
+
-
-
-
- | - Description + Logo | - Minimal Deposit - | -- Maximal Deposit + Name | - {level.name} - - | - {level.description} + | - {formatIDR( - level.min_amount - )} - | -- {formatIDR( - level.max_amount - )} + {level.name} | -+ |
{canUpdate && (
-
- toggleFormModal(
- level
- )
- }
+ href={route(
+ 'customer-level.edit',
+ level.id
+ )}
>
+
)}
Ubah
- |
@@ -119,7 +93,6 @@ export default function Info(props) {
-
---|