From 25f837bc7984b7ec15f823bcf9b29336bf204961 Mon Sep 17 00:00:00 2001 From: Aji Kamaludin Date: Fri, 23 Jun 2023 05:21:56 +0700 Subject: [PATCH] customer level and customer filter --- TODO.md | 8 +- .../Api/CustomerLevelController.php | 15 + .../Controllers/Customer/AuthController.php | 18 +- app/Http/Controllers/CustomerController.php | 34 ++- .../Controllers/CustomerLevelController.php | 18 +- app/Http/Controllers/SettingController.php | 40 ++- app/Models/Customer.php | 14 +- app/Models/CustomerLevel.php | 13 + ...24_130630_create_customer_levels_table.php | 3 +- database/seeders/InstallationSeed.php | 37 ++- database/seeders/PermissionSeeder.php | 2 + public/sample/basic.png | Bin 0 -> 2475 bytes public/sample/gold.png | Bin 0 -> 2220 bytes public/sample/platinum.png | Bin 0 -> 2544 bytes public/sample/silver.png | Bin 0 -> 2471 bytes .../ThSortComponent.jsx | 0 .../Customer/Index/Partials/BalanceBanner.jsx | 2 +- resources/js/Layouts/Partials/routes.js | 36 ++- resources/js/Pages/Customer/Index.jsx | 202 ++++++++++++-- resources/js/Pages/CustomerLevel/Form.jsx | 121 ++++++++ .../js/Pages/CustomerLevel/FormModal.jsx | 104 ------- resources/js/Pages/CustomerLevel/Index.jsx | 61 ++-- .../js/Pages/CustomerLevel/SelectionInput.jsx | 263 ++++++++++++++++++ resources/js/Pages/Role/Index.jsx | 2 +- resources/js/Pages/Voucher/Index.jsx | 2 +- routes/admin.php | 5 +- routes/api.php | 2 + 27 files changed, 794 insertions(+), 208 deletions(-) create mode 100644 app/Http/Controllers/Api/CustomerLevelController.php create mode 100644 public/sample/basic.png create mode 100644 public/sample/gold.png create mode 100644 public/sample/platinum.png create mode 100644 public/sample/silver.png rename resources/js/{Pages/Voucher => Components}/ThSortComponent.jsx (100%) create mode 100644 resources/js/Pages/CustomerLevel/Form.jsx delete mode 100644 resources/js/Pages/CustomerLevel/FormModal.jsx create mode 100644 resources/js/Pages/CustomerLevel/SelectionInput.jsx 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 0000000000000000000000000000000000000000..2077443eb1206061b67b5d7fac9b19ea5e10db89 GIT binary patch literal 2475 zcmV;c2~_rpP)a9i7racq|TEJ?MoGs;=0Fn#z z;}#drxy~__3fS!-hxTAahq!1Ui-qBQIJPNSviKo#C-YXKBUAKhX1Tlb-g18cVOro4 zT>kmqf9AcJU4V>?jEszo3>ygO0j6%$pA{|~lUwjOIB*c8{6B!Z2%GMuxyQvSq?l9- zJawb;suJ?Fdird@%g#ZwIWza@UgrsuwvpMjK-DuJgy ztrQ{W%z_jzLpVypai(V<&ixfqLMjBFT9Jofq@hx=oB|1lpnFOxZ68lV+Ga1X@3X?4 zjY!yb*!weEfkXLhSQz^=JAr+lb=`L$31RPtr9ZO~I0l~$%c4r#lU&j^3xR)stA1K~ zFl|}bc3Ai`X@Pfqb{2vQ6*gH_{yaz7pGgXA(PzU#)}KiUe9vd4oCcnd^Jg*w6ZKhR zs!b1;*Xrk7*_?U*=|TxCV_o2FpY>Ea7DY$_AFozn%ai!DB)~iS_ooVTU=eEqGxXVg zS*Qp8qMLTSC$irzg)5LVK5q5`XQe1<@w zA{IW|+=AQHhQ=$!oFkiOlM*@+fz#%*?O^nNyjC?iB(by|tH6mi1T1oGqYmr!CWN5m zNbi>_nlC|2#3FE7eYO)17+4t*r$0w3FrkJ(V(gk0b&qgV+CC6z*)uYM)9$mK_@c6< z9y$XnBO>+Zt_AKDpKS*RR?By4;K_)hcQ1>|pC`Lb+o1*SC7+KjwNL{qBf9nH zPy%mPp`44ol#X|U_2#QbiB!hZx$B85C;tDb#akv>)nl-Lr@gbxp?A#W#hiM zvB149E>4Rg8#SAtW+lRNE=*i58_iCP1l}$+iXt$j;0PGc3;0GZ+|UCDRycCDNHIU? z&YB#ceWp9zpUdhgyZJ4OdTQ8(qxr8+_qG!2{Y?-4Q}wjpN59@2FZGI7xb(e()}}fA z2zLEx5Ib>S8g}4!hjRCciyU?Z{PcheFORrd?}O1xL0qJ70JLW=`T~pGkANA6)!CgI z3KsC#paU-s?Jx3;s@2qdA5yr-bYH74u=J>|Yh23^m!9fJd_TU9!#ISi>3*fe@upcn532UamQ6A~eH0*8s-d&jCMZcV2!dMOR8 z!jd|HpBwD%lv>e`Dg)+l!=UhH~n$_wOh+ zivGcR1C}Zc_7+p zhqoIxD>{}ooA75MBUEe+&U`{&T!htr{Z6o3lQq9)ze==Jp;L<7 z4|W1CTV9O5p)v@U=tWYy`7AE(HhGoU*a`ez-|O1&kWiB47#uq7}RWYR7? zuS9%hd1J4*JD^Z+e^&8VjNo(a&p~X9Xb`Lf#`LPQeCIg?;x{wd?eWmu)yXn!oS;ADHSbG5^#- zE$vte+yW~~ST-DSh2JM$j&S!Hj*{{Hv9YkBT7>xHp|nItS77ZCihKeA&hV7k`Wu)T4)O_Wb>bpK>`tn!1XFvy%&APS2U%keP2Uuf&IID z7`$;tY^?ml;C{nK^I#Rlc(;!dWY|JF())qQ0Y(C26w8J;i6d&rNE#`n_bbzzR2o;Z z7QS6rgr;{KvPe!06;NgHydN(-T{s7Zgep~{$SPGF&pbJHq#7~5iTx<&Gf_fu%_f;Z{3R-zd<>WU_22`DhtZRMZO8HeG9J~{F5i+`AMWy4{!bWU6 zkuOU)d8Irp!8uK>tVtd8SpnW3u->41<4GN2S$BeITUCgsK{&sFjQv2LJy)xEuSF?r zi&z&HW&RvUWIh{2A}hx-f8Il+J{v@$O9Ok|pX2h`AQE5u*`xj(tIq~uZECKE_QlNT6{K$)C#I7)LR=yoH+ paaN@CK1@?8&dA8f$jHc`#h3VKPXmwobYTDh002ovPDHLkV1g1XiKPGl literal 0 HcmV?d00001 diff --git a/public/sample/gold.png b/public/sample/gold.png new file mode 100644 index 0000000000000000000000000000000000000000..f11e5e9ade2f231ae3f26a8c980529521fa598ed GIT binary patch literal 2220 zcmV;d2vhfoP)zrcx-#*F)|ES3zW~LRJ1Q$T+8Mq8tvgmNJ6(ZGSFOqd z7sis9_<}f95+ES9l^2Vpb3M5-pOPQH8_czb^-*cXGxj;!t zNl8gbi3uo{dWufa3C5**g6BWQ#t)VC8z$4XQ5DR_bx zf|b}|pm7w9U|Rik7`>xJ2je~r+u{XBIU7`{YO@gAj`(~QD>zlorbTc*ixV8>Y#7cL zBKAQ<=Cc^VIpl20Uj%CY985|XwnYdI>op~|QH4vf4C2MNf zp5>g+ECoBv*|f0DXI6q+a<&SIFwEx)m=Nb|SQjgopeVU}r5>Kee7J}aFu-{QM>$(j z!!dXqke<0V2W+iTHLs|nI~Tl(SvbU*V1YTiJ$IIY^)Da%SuDD$L_5jn!Ue}Ut5%>I zn1)YK)!sN2f9=cyHc<=4mGA;7RB%}TbjJBYMPB^#6>$5U$unn_=((aq7b4iZoNb4y zma^BB0*CEf1sB>7aLMZDz{W4ICXA~1NbnYxkQ2EG_BLlb(dop>p4{>|Q^9N+0!5;y zMOi?@_8Z7_*)uc2-sfy5ZY}}0zDA~GoX zqGP?Nni$r7ar|SC>b7=kn66d!hb+xedZaN&A z+X-;U^rjPDO)++1BX|Uopz3|X@Hmj%q$<9}sCr|J zqms?0yUa1IUQM?T1Fbi^nHFV&pMq_wH|aIeiPd+IjGuyStGCMoC zd<;A$Z`$7p`GRQ+)ys-lO zeMWr<)RgM(3b?^jFr6q-m&c`46DX(Yv3DYt`)3un#_Q~xUk1~VD?x5Ml+`aT0M8hA z@(O{UVCvCIliSJ*Cs>_<^Ab#A+Z*!|**66)@DiMMuM{^JO|5tdZpdEP=Lj#s|6TP% zGR>Qr!0#l>W|t#ZXkN?&euCG}$*$rnbF3CT_z9+Ez{?9VCDS6u@8vvrdnk*gNhY}$ zroaup-6TnpnaU;1yGdu^rkg~oLN6~C(=|#1H5`^-MbVgcllb?8=>YyX9%nN*^zX(P z84Z6rkUvj?6`VhKEy&r?L5m0VkH7+&2K_Y2UM?YP%g*Il9tV~Bz6_iDoshRDi$g)4ykm8hXZov#=)MaXicEWvAPk^iX)tCvJ# zX{RG~fLghPctm(!{e0hHSV3|b?R`!{))0Mt!LD6+sRn#M`mkILiK4w!)VQbXd`)3? ziD(l1_hhwWvPX-m>%tNHVU#W!qyM%cDFz(v!D`2!Jz4GO1Kg?NNGw$&J zAdey1@m7kG7K~k(3l1S?Ba;8*Ao!l!d(oG)5SriD&{%MEmyd><`_PxP5Tb5#zhS#+ z(iWzhH#IJCL#Rg5cWho@B{-_$0CWwBtgVH9K-1I@Y;RI&z0lFTLE?B>$psRsDQW}n zt7E?aOH!?5MUw9+$z>+z4OQ*DI@YfRZ{rM7V7$=L^*30I?x%Me67Q?T7ZSUq{yc7T zLe+_$1#7}@Fs0sYrgW7FG4GM^P?o+7U)e!JpB3gXxVY zO~_m@5e?e|N^}L5o%FthhGV*o`>`y=YH|^*Df2mz%yKq~Tm@^&d~PG-oK2z-!J59$ z=bUmji9!VveVWg?=4=v$3)b{WJ{OX+NjMX%@iw0e%-JNI3)Xm(&kk}n2{wWW;rZ+= zXOmzhSQCjJ#G;U4+j-6=!BVh>eLhpp2B@j-8r!ZKYr&dkKF@#)%yKpf5rPRu`8=<3 z_PFiN3Rj2`tZ|snl(RLCIh%wy!J5MInYJbcsB+HPB*Y5Vj7lJhz_}O~Na|8tZ%(p0i1KDVR{zJglmDT77%Ct7uPhHVJP9x1vtO u#?%*j=tf3eJKP?npDS?IcTS9Uj`h8Wll$c8~T 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 literal 0 HcmV?d00001 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'))} >
-
+
Saldo
diff --git a/resources/js/Layouts/Partials/routes.js b/resources/js/Layouts/Partials/routes.js index 1f58a94..d0e342b 100644 --- a/resources/js/Layouts/Partials/routes.js +++ b/resources/js/Layouts/Partials/routes.js @@ -8,11 +8,13 @@ import { HiOutlineCash, HiOutlineTable, HiCash, + HiArrowCircleUp, } from 'react-icons/hi' import { HiArchiveBox, HiBanknotes, HiCheckBadge, + HiCog8Tooth, HiCreditCard, HiCurrencyDollar, HiMap, @@ -111,15 +113,7 @@ export default [ icon: HiUser, items: [ { - name: 'Verifikasi', - show: true, - icon: HiCheckBadge, - route: route('customer-verification.index'), - active: 'customer-verification.*', - permission: 'view-customer-verification', - }, - { - name: 'Customer', + name: 'List', show: true, icon: HiUserCircle, route: route('customer.index'), @@ -127,13 +121,29 @@ export default [ permission: 'view-customer', }, { - name: 'Level', + name: 'Atur Level', show: true, - icon: HiUserCircle, + icon: HiArrowCircleUp, route: route('customer-level.index'), active: 'customer-level.*', permission: 'view-customer-level', }, + { + name: 'Atur Affilate', + show: true, + icon: HiCog8Tooth, + route: route('setting.affilate'), + active: 'setting.affilate', + permission: 'view-setting-affilate', + }, + { + name: 'Verifikasi', + show: true, + icon: HiCheckBadge, + route: route('customer-verification.index'), + active: 'customer-verification.*', + permission: 'view-customer-verification', + }, ], }, { @@ -175,10 +185,10 @@ export default [ { name: 'Payment Gateway', show: true, - icon: HiOutlineTable, + icon: HiCog8Tooth, route: route('setting.payment'), active: 'setting.payment', - permission: 'view-setting', + permission: 'view-setting-payment-gateway', }, { name: 'Cash / Setor Tunai', diff --git a/resources/js/Pages/Customer/Index.jsx b/resources/js/Pages/Customer/Index.jsx index e95477c..337e9ec 100644 --- a/resources/js/Pages/Customer/Index.jsx +++ b/resources/js/Pages/Customer/Index.jsx @@ -6,20 +6,33 @@ import { Button, Dropdown } from 'flowbite-react' import { HiPencil, HiTrash } from 'react-icons/hi' import { useModalState } from '@/hooks' +import { formatIDR, hasPermission } from '@/utils' import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' import Pagination from '@/Components/Pagination' import ModalConfirm from '@/Components/ModalConfirm' import SearchInput from '@/Components/SearchInput' -import { hasPermission } from '@/utils' +import LocationSelectionInput from '../Location/SelectionInput' +import LevelSelectionInput from '../CustomerLevel/SelectionInput' +import ThSort from '@/Components/ThSortComponent' export default function Customer(props) { const { query: { links, data }, + stats, auth, + _search, + _sortBy, + _sortOrder, } = props - const [search, setSearch] = useState('') - const preValue = usePrevious(search) + const [location, setLocation] = useState(null) + const [level, setLevel] = useState(null) + const [search, setSearch] = useState({ + q: _search, + sortBy: _sortBy, + sortOrder: _sortOrder, + }) + const preValue = usePrevious(`${search}${location}${level}`) const confirmModal = useModalState() @@ -34,19 +47,42 @@ export default function Customer(props) { } } - const params = { q: search } + const handleSearchChange = (e) => { + setSearch({ + ...search, + q: e.target.value, + }) + } + + const sort = (key, sort = null) => { + if (sort !== null) { + setSearch({ + ...search, + sortBy: key, + sortRule: sort, + }) + return + } + setSearch({ + ...search, + sortBy: key, + sortRule: search.sortRule == 'asc' ? 'desc' : 'asc', + }) + } + + const params = { q: search, location_id: location, level_id: level } useEffect(() => { if (preValue) { router.get( route(route().current()), - { q: search }, + { ...search, location_id: location, level_id: level }, { replace: true, preserveState: true, } ) } - }, [search]) + }, [search, location, level]) const canCreate = hasPermission(auth, 'create-customer') const canUpdate = hasPermission(auth, 'update-customer') @@ -56,8 +92,36 @@ export default function Customer(props) { -
-
+
+
+
+
+
Basic
+
+ {formatIDR(stats.basic_count)} Orang +
+
+
+
Silver
+
+ {formatIDR(stats.silver_count)} Orang +
+
+
+
Gold
+
+ {formatIDR(stats.gold_count)} Orang +
+
+
+
+ Platinum +
+
+ {formatIDR(stats.platinum_count)} Orang +
+
+
{canCreate && ( @@ -65,14 +129,36 @@ export default function Customer(props) { )} -
- setSearch(e.target.value)} - value={search} - /> +
+
+ +
+
+
+ + setLevel(id) + } + placeholder={'filter level'} + /> +
+
+ + setLocation(id) + } + placeholder={'filter lokasi'} + /> +
+
-
+
@@ -89,17 +175,31 @@ export default function Customer(props) { > Level + + Deposit + + + Poin + + + + + + + - - - @@ -119,7 +93,6 @@ export default function Info(props) { - ) } diff --git a/resources/js/Pages/CustomerLevel/SelectionInput.jsx b/resources/js/Pages/CustomerLevel/SelectionInput.jsx new file mode 100644 index 0000000..bddbc6b --- /dev/null +++ b/resources/js/Pages/CustomerLevel/SelectionInput.jsx @@ -0,0 +1,263 @@ +import React, { useRef, useEffect, useState } from 'react' +import { useDebounce } from '@/hooks' +import { usePage } from '@inertiajs/react' +import axios from 'axios' +import { HiChevronDown, HiChevronUp, HiX } from 'react-icons/hi' +import { Spinner } from 'flowbite-react' + +export default function SelectionInput(props) { + const ref = useRef() + const { + props: { auth }, + } = usePage() + + const { + label = '', + itemSelected = null, + onItemSelected = () => {}, + disabled = false, + placeholder = '', + error = '', + all = 0, + } = props + + const [showItems, setShowItem] = useState([]) + + const [isSelected, setIsSelected] = useState(true) + const [selected, setSelected] = useState(null) + + const [query, setQuery] = useState('') + const q = useDebounce(query, 300) + + const [isOpen, setIsOpen] = useState(false) + const [loading, setLoading] = useState(false) + + const toggle = () => { + setQuery('') + setIsOpen(!isOpen) + } + + const onInputMouseDown = () => { + setIsSelected(false) + setQuery('') + setIsOpen(!isOpen) + } + + const handleSelectItem = (item) => { + setIsSelected(true) + onItemSelected(item.id) + setSelected(item.name) + setIsOpen(false) + } + + const removeItem = () => { + setIsSelected(false) + setSelected('') + onItemSelected(null) + } + + const filterItems = (value) => { + setIsSelected(false) + setQuery(value) + } + + useEffect(() => { + if (isOpen === true) { + const checkIfClickedOutside = (e) => { + if (isOpen && ref.current && !ref.current.contains(e.target)) { + setIsOpen(false) + if (selected !== null) { + setIsSelected(true) + } + } + } + document.addEventListener('mousedown', checkIfClickedOutside) + return () => { + document.removeEventListener('mousedown', checkIfClickedOutside) + } + } + }, [isOpen]) + + const fetch = (q = '') => { + setLoading(true) + axios + .get(route('api.customer-level.index', { q: q, all: all }), { + headers: { + 'Content-Type': 'application/json', + // 'Authorization': 'Bearer ' + auth.user.jwt_token + }, + }) + .then((response) => { + setShowItem(response.data) + }) + .catch((err) => { + alert(err) + }) + .finally(() => setLoading(false)) + } + + // every select item open + useEffect(() => { + if (isOpen) { + fetch(q) + } + }, [q, isOpen]) + + // once page load + useEffect(() => { + fetch() + }, []) + + useEffect(() => { + if (disabled) { + setSelected('') + } + }, [disabled]) + + useEffect(() => { + if (itemSelected !== null) { + const item = showItems.find((item) => item.id === itemSelected) + if (item) { + setSelected(item.name) + setIsSelected(true) + } + return + } + setIsSelected(false) + }, [itemSelected, loading]) + + useEffect(() => { + if (isSelected && selected === '') { + setSelected('') + setIsSelected(false) + } + }, [isSelected]) + + return ( +
+
+
+
+ {label !== '' && ( + + )} +
+
+ + filterItems(e.target.value) + } + disabled={disabled} + /> + {isSelected && ( +
{} : removeItem + } + > + +
+ )} +
{} : toggle}> + +
+
+ {error && ( +

+ {error} +

+ )} +
+ {isOpen && ( +
+
+ {loading ? ( +
+
+
+
+ + Loading... +
+
+
+
+ ) : ( + <> + {showItems.map((item, index) => ( +
+ handleSelectItem(item) + } + > +
+
+
+ + {item.name} + +
+
+
+
+ ))} + {showItems.length <= 0 && ( +
+
+
+
+ + No Items + Found + +
+
+
+
+ )} + + )} +
+
+ )} +
+
+
+
+ ) +} diff --git a/resources/js/Pages/Role/Index.jsx b/resources/js/Pages/Role/Index.jsx index e664580..dfffe16 100644 --- a/resources/js/Pages/Role/Index.jsx +++ b/resources/js/Pages/Role/Index.jsx @@ -116,7 +116,7 @@ export default function Product(props) { key={ user.id } - className="px-2 py-1 bg-blue-600 text-white border rounded-full border-b-blue-900" + className="px-2 py-1 bg-blue-600 text-white border rounded-full border-blue-900" onClick={() => router.visit( route( diff --git a/resources/js/Pages/Voucher/Index.jsx b/resources/js/Pages/Voucher/Index.jsx index c6efcb7..b749f3f 100644 --- a/resources/js/Pages/Voucher/Index.jsx +++ b/resources/js/Pages/Voucher/Index.jsx @@ -11,7 +11,7 @@ import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' import Pagination from '@/Components/Pagination' import ModalConfirm from '@/Components/ModalConfirm' import SearchInput from '@/Components/SearchInput' -import ThSort from './ThSortComponent' +import ThSort from '@/Components/ThSortComponent' import ModalFilter from './ModalFilter' import ModalDelete from './ModalDelete' diff --git a/routes/admin.php b/routes/admin.php index 06b5f94..b1497a0 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -101,7 +101,8 @@ Route::middleware(['http_secure_aware', 'inertia.admin']) // customer level Route::get('/customer-levels', [CustomerLevelController::class, 'index'])->name('customer-level.index'); - Route::put('/customer-levels/{customerLevel}', [CustomerLevelController::class, 'update'])->name('customer-level.update'); + Route::get('/customer-levels/{customerLevel}', [CustomerLevelController::class, 'edit'])->name('customer-level.edit'); + Route::post('/customer-levels/{customerLevel}', [CustomerLevelController::class, 'update'])->name('customer-level.update'); // verification Route::get('/customers-verifications', [VerificationController::class, 'index'])->name('customer-verification.index'); @@ -133,6 +134,8 @@ Route::middleware(['http_secure_aware', 'inertia.admin']) // setting Route::get('/payment-gateway', [SettingController::class, 'payment'])->name('setting.payment'); Route::post('/payment-gateway', [SettingController::class, 'updatePayment']); + Route::get('/affilate', [SettingController::class, 'affilate'])->name('setting.affilate'); + Route::post('/affilate', [SettingController::class, 'updateAffilate']); Route::get('/settings', [SettingController::class, 'index'])->name('setting.index'); Route::post('/settings', [SettingController::class, 'update'])->name('setting.update'); diff --git a/routes/api.php b/routes/api.php index 9f01be6..e73cc4d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,6 +1,7 @@ name('api.role.index'); Route::get('/locations', [LocationController::class, 'index'])->name('api.location.index'); Route::get('/location-profiles', [LocationProfileController::class, 'index'])->name('api.location-profile.index'); Route::get('/customers', [CustomerController::class, 'index'])->name('api.customer.index'); +Route::get('/customer-levels', [CustomerLevelController::class, 'index'])->name('api.customer-level.index'); Route::get('/notifications/{notif?}', [NotificationController::class, 'update'])->name('api.notification.update'); // midtrans
- 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 ( + + + +
+
+
+
Atur Level
+ + setData('logo', e.target.files[0])} + error={errors.logo} + preview={ + isEmpty(data.logo_url) === false && ( + preview + ) + } + /> +
+ Loading...
}> + { + setData( + 'description', + editor.getContent() + ) + }} + /> + +
+ +
+ +
+
+
+ +
+ ) +} 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 ( - - - - - -
- - -
-
- ) -} diff --git a/resources/js/Pages/CustomerLevel/Index.jsx b/resources/js/Pages/CustomerLevel/Index.jsx index cf73821..a30518d 100644 --- a/resources/js/Pages/CustomerLevel/Index.jsx +++ b/resources/js/Pages/CustomerLevel/Index.jsx @@ -1,13 +1,11 @@ import React from 'react' -import { Head } from '@inertiajs/react' -import { Dropdown } from 'flowbite-react' +import { Head, Link } from '@inertiajs/react' import { HiPencil } from 'react-icons/hi' import { useModalState } from '@/hooks' +import { formatIDR, hasPermission } from '@/utils' import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' import Pagination from '@/Components/Pagination' -import FormModal from './FormModal' -import { formatIDR, hasPermission } from '@/utils' export default function Info(props) { const { @@ -17,11 +15,6 @@ export default function Info(props) { const formModal = useModalState() - const toggleFormModal = (customerlevel = null) => { - formModal.setData(customerlevel) - formModal.toggle() - } - const canUpdate = hasPermission(auth, 'update-customer-level') return ( @@ -41,25 +34,13 @@ export default function Info(props) { scope="col" className="py-3 px-6" > - Name - -
- Description + Logo - Minimal Deposit - - Maximal Deposit + Name - {level.name} - - - {level.description} + logo alt - {formatIDR( - level.min_amount - )} - - {formatIDR( - level.max_amount - )} + {level.name} + {canUpdate && ( -
- toggleFormModal( - level - ) - } + href={route( + 'customer-level.edit', + level.id + )} >
Ubah
-
+ )}