diff --git a/TODO.md b/TODO.md index 3757832..bc58527 100644 --- a/TODO.md +++ b/TODO.md @@ -29,10 +29,10 @@ - [x] Login Customer - [x] Login Customer Gmail - [x] Customer Edit Profile -- [ ] Register Refferal -- [ ] Customer Deposit Manual -- [ ] Customer Deposit Payment Gateway +- [x] Customer Deposit Manual +- [x] Customer Deposit Payment Gateway - [ ] Customer Purchase Voucher +- [ ] Register Refferal - [ ] Customer Share Buyed Voucher, via WA dll - [ ] Customer View Coin History - [ ] Verified Akun diff --git a/app/Http/Controllers/Customer/DepositController.php b/app/Http/Controllers/Customer/DepositController.php new file mode 100644 index 0000000..d59969f --- /dev/null +++ b/app/Http/Controllers/Customer/DepositController.php @@ -0,0 +1,155 @@ +id()) + ->orderBy('updated_at', 'desc') + ->orderBy('is_valid', 'desc'); + + return inertia('Home/Deposit/Index', [ + 'histories' => $histories->paginate(20) + ]); + } + + public function create() + { + return inertia('Home/Deposit/Topup', [ + 'payments' => GeneralService::getEnablePayment(), + ]); + } + + public function store(Request $request) + { + $request->validate([ + 'amount' => 'required|numeric|min:10000', + 'payment' => [ + 'required', + Rule::in([Setting::PAYMENT_MANUAL, Setting::PAYMENT_MIDTRANS]) + ] + ]); + + DB::beginTransaction(); + $deposit = DepositHistory::make([ + 'customer_id' => auth()->id(), + 'debit' => $request->amount, + 'description' => 'Top Up #' . Str::random(5), + 'payment_channel' => $request->payment, + ]); + + if ($request->payment == Setting::PAYMENT_MANUAL) { + $deposit->is_valid = DepositHistory::STATUS_WAIT_UPLOAD; + $deposit->save(); + } + + if ($request->payment == Setting::PAYMENT_MIDTRANS) { + $deposit->is_valid = DepositHistory::STATUS_WAIT_PAYMENT; + $deposit->save(); + + $token = (new MidtransService($deposit, Setting::getByKey('MIDTRANS_SERVER_KEY')))->getSnapToken(); + + $deposit->update(['payment_token' => $token]); + } + + DB::commit(); + + return redirect()->route('customer.deposit.show', ['deposit' => $deposit->id, 'direct' => 'true']); + } + + public function show(Request $request, DepositHistory $deposit) + { + return inertia('Home/Deposit/Detail', [ + 'deposit' => $deposit, + 'accounts' => Account::get(), + 'midtrans_client_key' => Setting::getByKey('MIDTRANS_CLIENT_KEY'), + 'is_production' => app()->isProduction(), + 'direct' => $request->direct + ]); + } + + public function update(Request $request, DepositHistory $deposit) + { + $request->validate([ + 'account_id' => 'required|exists:accounts,id', + 'image' => 'required|image', + ]); + + $file = $request->file('image'); + $file->store('uploads', 'public'); + $deposit->update([ + 'image_prove' => $file->hashName('uploads'), + 'account_id' => $request->account_id, + 'is_valid' => DepositHistory::STATUS_WAIT_APPROVE + ]); + + session()->flash('message', ['type' => 'success', 'message' => 'Upload berhasil, silahkan tunggu untuk approve']);; + } + + public function midtrans_payment(Request $request, DepositHistory $deposit) + { + DB::beginTransaction(); + $transaction_status = $request->result['transaction_status']; + if ($transaction_status == 'settlement' || $transaction_status == 'capture') { + $is_valid = DepositHistory::STATUS_VALID; + $deposit->update_customer_balance(); + } elseif ($transaction_status == 'pending') { + $is_valid = DepositHistory::STATUS_WAIT_PAYMENT; + } else { + $is_valid = DepositHistory::STATUS_INVALID; + } + $deposit->update([ + 'is_valid' => $is_valid, + 'payment_response' => json_encode($request->result), + 'payment_type' => $request->result['payment_type'], + ]); + + DB::commit(); + + return redirect()->route('customer.deposit.show', ['deposit' => $deposit->id]); + } + + public function mindtrans_notification(Request $request) + { + DB::beginTransaction(); + $deposit = DepositHistory::where('id', $request->order_id)->first(); + + if ($deposit != null && $deposit->is_valid != DepositHistory::STATUS_VALID) { + $deposit->fill([ + 'payment_response' => json_encode($request->all()), + 'payment_type' => $request->result['payment_type'], + ]); + + if ($request->transaction_status == 'settlement' || $request->transaction_status == 'capture') { + $deposit->fill(['payment_status' => DepositHistory::STATUS_VALID]); + $deposit->update_customer_balance(); + } elseif ($request->transaction_status == 'pending') { + $deposit->fill(['payment_status' => DepositHistory::STATUS_WAIT_PAYMENT]); + } else { + $deposit->fill(['payment_status' => DepositHistory::STATUS_INVALID]); + } + + $deposit->save(); + } + + DB::commit(); + + return response()->json([ + 'status' => 'ok', + 'order' => $deposit, + ]); + } +} diff --git a/app/Models/Customer.php b/app/Models/Customer.php index e7927bd..f60b84e 100644 --- a/app/Models/Customer.php +++ b/app/Models/Customer.php @@ -27,6 +27,7 @@ class Customer extends Authenticatable 'google_id', 'deposit_balance', 'coin_balance', + 'paylater_balance', 'identity_verified', 'identity_image', 'customer_level_id', diff --git a/app/Models/DepositHistory.php b/app/Models/DepositHistory.php index f40e192..43bbdb7 100644 --- a/app/Models/DepositHistory.php +++ b/app/Models/DepositHistory.php @@ -2,13 +2,22 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Casts\Attribute; +use Illuminate\Support\Carbon; + class DepositHistory extends Model { - const VALID = 0; + const STATUS_VALID = 0; + + const STATUS_WAIT_UPLOAD = 1; + + const STATUS_WAIT_APPROVE = 2; + + const STATUS_WAIT_PAYMENT = 3; - const WAIT = 1; + const STATUS_INVALID = 4; - const INVALID = 2; + const STATUS_REJECT = 5; protected $fillable = [ 'debit', @@ -19,10 +28,75 @@ class DepositHistory extends Model 'related_id', 'is_valid', 'image_prove', + 'account_id', 'payment_token', 'payment_status', 'payment_response', 'payment_channel', 'payment_type', ]; + + protected $appends = [ + 'status', + 'format_human_created_at', + 'format_created_at', + 'amount', + 'image_prove_url' + ]; + + public function status(): Attribute + { + return Attribute::make(get: function () { + return [ + self::STATUS_VALID => ['text' => 'Success', 'color' => 'bg-green-600'], + self::STATUS_WAIT_UPLOAD => ['text' => 'Upload bukti transfer', 'color' => 'bg-red-600'], + self::STATUS_WAIT_APPROVE => ['text' => 'Menunggu Approve', 'color' => 'bg-green-600'], + self::STATUS_WAIT_PAYMENT => ['text' => 'Menunggu Pembayaran', 'color' => 'bg-green-600'], + self::STATUS_INVALID => ['text' => 'Error', 'color' => 'bg-red-600'], + self::STATUS_REJECT => ['text' => 'Reject', 'color' => 'bg-red-600'], + ][$this->is_valid]; + }); + } + + public function formatHumanCreatedAt(): Attribute + { + return Attribute::make(get: function () { + return Carbon::parse($this->created_at)->locale('id')->format('d F Y'); + }); + } + + public function formatCreatedAt(): Attribute + { + return Attribute::make(get: function () { + return Carbon::parse($this->created_at)->locale('id')->format('d M Y H:i:s'); + }); + } + + public function amount(): Attribute + { + return Attribute::make(get: function () { + if ($this->credit == 0) { + return $this->debit; + } + return $this->credit; + }); + } + + public function imageProveUrl(): Attribute + { + return Attribute::make(get: function () { + return $this->image_prove == null ? '' : asset($this->image_prove); + }); + } + + public function customer() + { + return $this->belongsTo(Customer::class); + } + + public function update_customer_balance() + { + $customer = Customer::find($this->customer_id); + $customer->update(['deposit_balance' => $customer->deposit_balance + $this->debit]); + } } diff --git a/app/Models/PaylaterHistory.php b/app/Models/PaylaterHistory.php new file mode 100644 index 0000000..9853922 --- /dev/null +++ b/app/Models/PaylaterHistory.php @@ -0,0 +1,13 @@ +value('value'); + } } diff --git a/app/Services/GeneralService.php b/app/Services/GeneralService.php index 2c1e63c..b8be990 100644 --- a/app/Services/GeneralService.php +++ b/app/Services/GeneralService.php @@ -2,6 +2,8 @@ namespace App\Services; +use App\Models\Setting; + class GeneralService { public static function script_parser($script) @@ -50,4 +52,20 @@ class GeneralService return $item; } + + public static function getEnablePayment() + { + $payment = [ + ['name' => Setting::PAYMENT_MANUAL, 'logo' => null, 'display_name' => 'Transfer Manual'] + ]; + + $midtrans_enable = Setting::getByKey('MIDTRANS_ENABLED'); + if ($midtrans_enable == 1) { + $payment[] = ['name' => Setting::PAYMENT_MIDTRANS, 'logo' => Setting::getByKey('MIDTRANS_LOGO')]; + } + + // Paylater + + return $payment; + } } diff --git a/app/Services/MidtransService.php b/app/Services/MidtransService.php index 1c904f6..cd583d8 100644 --- a/app/Services/MidtransService.php +++ b/app/Services/MidtransService.php @@ -2,55 +2,46 @@ namespace App\Services; +use App\Models\DepositHistory; use Midtrans\Config; use Midtrans\Snap; class MidtransService { - protected $order; + protected $deposit; - public function __construct($order, $serverKey) + public function __construct(DepositHistory $deposit, $serverKey) { Config::$serverKey = $serverKey; Config::$isProduction = app()->isProduction(); Config::$isSanitized = true; Config::$is3ds = true; - $this->order = $order; + $this->deposit = $deposit; } public function getSnapToken() { - $items = $this->order->items->map(function ($item) { - return [ - 'id' => $item->id, - 'price' => $item->amount, - 'quantity' => $item->quantity, - 'name' => $item->item->order_detail, - ]; - }); - - if ($this->order->total_discount > 0) { - $items->add([ - 'id' => 'Discount', - 'price' => -$this->order->total_discount, - 'quantity' => 1, - 'name' => 'DISCOUNT', - ]); - } - $params = [ 'transaction_details' => [ - 'order_id' => $this->order->order_code, - 'gross_amount' => $this->order->total_amount, + 'order_id' => $this->deposit->id, + 'gross_amount' => $this->deposit->debit, ], - 'item_details' => $items->toArray(), + 'item_details' => [[ + 'id' => $this->deposit->id, + 'price' => $this->deposit->debit, + 'quantity' => 1, + 'name' => $this->deposit->description, + ]], 'customer_details' => [ - 'name' => $this->order->customer->name, - 'email' => $this->order->customer->email, - 'phone' => $this->order->customer->phone, - 'address' => $this->order->customer->address, + 'name' => $this->deposit->customer->fullname, + 'email' => $this->deposit->customer->email, + 'phone' => $this->deposit->customer->phone, + 'address' => $this->deposit->customer->address, ], + 'callbacks' => [ + 'finish' => route('customer.deposit.show', ['deposit' => $this->deposit->id]) + ] ]; $snapToken = Snap::getSnapToken($params); diff --git a/database/migrations/2023_05_24_130552_create_customers_table.php b/database/migrations/2023_05_24_130552_create_customers_table.php index 83027f5..c783247 100644 --- a/database/migrations/2023_05_24_130552_create_customers_table.php +++ b/database/migrations/2023_05_24_130552_create_customers_table.php @@ -26,6 +26,7 @@ return new class extends Migration $table->string('google_id')->nullable(); $table->decimal('deposit_balance', 20, 2)->default(0); $table->decimal('coin_balance', 20, 2)->default(0); + $table->decimal('paylater_balance', 20, 2)->default(0); $table->smallInteger('identity_verified')->nullable(); $table->string('identity_image')->nullable(); $table->ulid('customer_level_id')->nullable(); diff --git a/database/migrations/2023_05_24_130646_create_deposit_histories_table.php b/database/migrations/2023_05_24_130646_create_deposit_histories_table.php index 96c8846..2deb771 100644 --- a/database/migrations/2023_05_24_130646_create_deposit_histories_table.php +++ b/database/migrations/2023_05_24_130646_create_deposit_histories_table.php @@ -18,14 +18,15 @@ return new class extends Migration $table->decimal('credit', 20, 2)->default(0); $table->text('description')->nullable(); $table->ulid('customer_id')->nullable(); + $table->ulid('account_id')->nullable(); $table->string('related_type')->nullable(); $table->string('related_id')->nullable(); $table->smallInteger('is_valid')->default(0); $table->string('image_prove')->nullable(); + $table->string('payment_channel')->nullable(); $table->string('payment_token')->nullable(); $table->string('payment_status')->nullable(); $table->string('payment_response')->nullable(); - $table->string('payment_channel')->nullable(); $table->string('payment_type')->nullable(); $table->timestamps(); diff --git a/database/migrations/2023_06_03_033734_create_paylater_histories_table.php b/database/migrations/2023_06_03_033734_create_paylater_histories_table.php new file mode 100644 index 0000000..b56049b --- /dev/null +++ b/database/migrations/2023_06_03_033734_create_paylater_histories_table.php @@ -0,0 +1,37 @@ +ulid('id')->primary(); + + $table->decimal('debit', 20, 2)->default(0); + $table->decimal('credit', 20, 2)->default(0); + $table->text('description')->nullable(); + $table->ulid('customer_id')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + $table->ulid('created_by')->nullable(); + $table->ulid('updated_by')->nullable(); + $table->ulid('deleted_by')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('paylater_histories'); + } +}; diff --git a/public/uploads/NJl0MsrOekJjqc2eTqTntDarwqGDmfWTRPvatfqj.png b/public/uploads/NJl0MsrOekJjqc2eTqTntDarwqGDmfWTRPvatfqj.png new file mode 100644 index 0000000..b6f830c Binary files /dev/null and b/public/uploads/NJl0MsrOekJjqc2eTqTntDarwqGDmfWTRPvatfqj.png differ diff --git a/public/uploads/O28lqSXxDFqVCmtJ3xYgZgMpCTblUNFbhnGFUaky.png b/public/uploads/O28lqSXxDFqVCmtJ3xYgZgMpCTblUNFbhnGFUaky.png new file mode 100644 index 0000000..893a840 Binary files /dev/null and b/public/uploads/O28lqSXxDFqVCmtJ3xYgZgMpCTblUNFbhnGFUaky.png differ diff --git a/public/uploads/Ro0dn8ddZ3YD83BPGRmpwDBi8MDgseSk3Vrz9rXA.png b/public/uploads/Ro0dn8ddZ3YD83BPGRmpwDBi8MDgseSk3Vrz9rXA.png new file mode 100644 index 0000000..b6f830c Binary files /dev/null and b/public/uploads/Ro0dn8ddZ3YD83BPGRmpwDBi8MDgseSk3Vrz9rXA.png differ diff --git a/public/uploads/TOvqXsbQBjbJTIM6he1ylcPLK5VM38BXWBLSSaLE.png b/public/uploads/TOvqXsbQBjbJTIM6he1ylcPLK5VM38BXWBLSSaLE.png new file mode 100644 index 0000000..b6f830c Binary files /dev/null and b/public/uploads/TOvqXsbQBjbJTIM6he1ylcPLK5VM38BXWBLSSaLE.png differ diff --git a/public/uploads/Tb00StkRPTn9EOhn1osSFQAZNKJpbRjCFYH22Qul.png b/public/uploads/Tb00StkRPTn9EOhn1osSFQAZNKJpbRjCFYH22Qul.png new file mode 100644 index 0000000..485ae9e Binary files /dev/null and b/public/uploads/Tb00StkRPTn9EOhn1osSFQAZNKJpbRjCFYH22Qul.png differ diff --git a/public/uploads/xBp4LHXEpYZMFVMefQWomjZtXzZF6eSI3PitI9xH.png b/public/uploads/xBp4LHXEpYZMFVMefQWomjZtXzZF6eSI3PitI9xH.png new file mode 100644 index 0000000..485ae9e Binary files /dev/null and b/public/uploads/xBp4LHXEpYZMFVMefQWomjZtXzZF6eSI3PitI9xH.png differ diff --git a/resources/js/Layouts/Partials/routes.js b/resources/js/Layouts/Partials/routes.js index 2fb4418..9c46eae 100644 --- a/resources/js/Layouts/Partials/routes.js +++ b/resources/js/Layouts/Partials/routes.js @@ -24,38 +24,7 @@ export default [ active: 'dashboard', permission: 'view-dashboard', }, - { - name: 'Customer', - show: true, - icon: HiUserCircle, - route: route('customer.index'), - active: 'customer.*', - permission: 'view-customer', - }, - { - name: 'Customer Level', - show: true, - icon: HiUserCircle, - route: route('customer-level.index'), - active: 'customer-level.*', - permission: 'view-customer-level', - }, - { - name: 'Bank Akun', - show: true, - icon: HiBanknotes, - route: route('account.index'), - active: 'account.*', - permission: 'view-account', - }, - { - name: 'Setting', - show: true, - icon: HiCog, - route: route('setting.index'), - active: 'setting.*', - permission: 'view-setting', - }, + { name: 'Lokasi', show: true, @@ -95,6 +64,30 @@ export default [ }, ], }, + + { + name: 'Customer', + show: true, + icon: HiUser, + items: [ + { + name: 'Customer', + show: true, + icon: HiUserCircle, + route: route('customer.index'), + active: 'customer.*', + permission: 'view-customer', + }, + { + name: 'Level', + show: true, + icon: HiUserCircle, + route: route('customer-level.index'), + active: 'customer-level.*', + permission: 'view-customer-level', + }, + ], + }, { name: 'User', show: true, @@ -118,4 +111,20 @@ export default [ }, ], }, + { + name: 'Bank Akun', + show: true, + icon: HiBanknotes, + route: route('account.index'), + active: 'account.*', + permission: 'view-account', + }, + { + name: 'Setting', + show: true, + icon: HiCog, + route: route('setting.index'), + active: 'setting.*', + permission: 'view-setting', + }, ] diff --git a/resources/js/Pages/Home/Deposit/Detail.jsx b/resources/js/Pages/Home/Deposit/Detail.jsx new file mode 100644 index 0000000..427a450 --- /dev/null +++ b/resources/js/Pages/Home/Deposit/Detail.jsx @@ -0,0 +1,257 @@ +import React, { useState, useEffect } from 'react' +import { Head, router, useForm, usePage } from '@inertiajs/react' +import { HiChevronLeft } from 'react-icons/hi2' + +import CustomerLayout from '@/Layouts/CustomerLayout' +import { formatIDR } from '@/utils' +import FormFile from '@/Components/FormFile' +import { isEmpty } from 'lodash' +import Alert from '@/Components/Alert' + +const PayButton = () => { + const { + props: { deposit, midtrans_client_key, is_production, direct, flash }, + } = usePage() + + const [loading, setLoading] = useState(false) + + const handleResult = (result) => { + fetch(route('api.midtrans.payment', deposit), { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ result }), + }).finally(() => { + router.get(route(route().current(), deposit)) + }) + } + + const onClickPay = () => { + if (loading) { + return + } + setLoading(true) + window.snap.pay(deposit.payment_token, { + // Optional + onSuccess: function (result) { + console.log(result) + handleResult(result) + setLoading(false) + }, + // Optional + onPending: function (result) { + console.log(result) + handleResult(result) + setLoading(false) + }, + // Optional + onError: function (result) { + console.log(result) + handleResult(result) + setLoading(false) + }, + onClose: function () { + setLoading(false) + }, + }) + } + + useEffect(() => { + //change this to the script source you want to load, for example this is snap.js sandbox env + let midtransScriptUrl = 'https://app.sandbox.midtrans.com/snap/snap.js' + if (is_production) { + midtransScriptUrl = 'https://app.midtrans.com/snap/snap.js' + } + //change this according to your client-key + let scriptTag = document.createElement('script') + scriptTag.src = midtransScriptUrl + // optional if you want to set script attribute + // for example snap.js have data-client-key attribute + scriptTag.setAttribute('data-client-key', midtrans_client_key) + + document.body.appendChild(scriptTag) + + if (direct === 'true') { + setTimeout(() => { + onClickPay() + }, 1000) + } + + return () => { + document.body.removeChild(scriptTag) + } + }, []) + + return ( +
+ + {flash.message.message} + +
+ Bayar +
+
+ ) +} + +const FormUpload = () => { + const { + props: { accounts, deposit, flash }, + } = usePage() + + const [account, setAccount] = useState(null) + const { data, setData, errors, processing, post } = useForm({ + account_id: '', + image: null, + image_url: deposit.image_prove_url, + }) + + const handleSelectAccount = (id) => { + if (id === '') { + setData('account_id', '') + setAccount(null) + } + const account = accounts.find((acc) => acc.id === id) + setData('account_id', account.id) + setAccount(account) + } + + const handleSubmit = () => { + if (processing) { + return + } + post(route('customer.deposit.update', deposit)) + } + + return ( +
+
+ + + {flash.message.message} + + +
Bank
+ +
+ {data.account_id !== '' && ( + <> +
+
+
Silahkan transfer nominal di atas ke
+
+ Bank :{' '} + + {account.bank_name} + +
+
+ Atas Nama :{' '} + + {account.holder_name} + +
+
+ Nomor Rekening :{' '} + + {account.account_number} + +
+
+
+ + setData('image', e.target.files[0])} + error={errors.image} + preview={ + isEmpty(data.image_url) == false && ( + bukti transfer + ) + } + /> + +
handleSubmit()} + > + Upload +
+ + )} +
+ ) +} + +const ActionSection = ({ deposit }) => { + return ( +
+ {deposit.payment_channel === 'MIDTRANS' ? ( + + ) : ( + + )} +
+ ) +} + +export default function Detail({ deposit }) { + return ( + + +
+
{ + router.get(route('customer.deposit.index')) + }} + > + +
+ + {/* detail */} +
+
+
+ {deposit.description} +
+
+ Rp {formatIDR(deposit.amount)} +
+
+ {deposit.format_created_at} +
+
+
+
+ {deposit.status.text} +
+
+
+ + {/* action */} + {deposit.is_valid !== 0 && } +
+
+ ) +} diff --git a/resources/js/Pages/Home/Deposit/Index.jsx b/resources/js/Pages/Home/Deposit/Index.jsx new file mode 100644 index 0000000..dd0e735 --- /dev/null +++ b/resources/js/Pages/Home/Deposit/Index.jsx @@ -0,0 +1,104 @@ +import React, { useState } from 'react' +import { Head, router } from '@inertiajs/react' +import CustomerLayout from '@/Layouts/CustomerLayout' +import { formatIDR } from '@/utils' + +export default function Index({ + auth: { user }, + histories: { data, next_page_url }, +}) { + const [deposites, setDeposites] = useState(data) + + const handleNextPage = () => { + router.get( + next_page_url, + {}, + { + replace: true, + preserveState: true, + only: ['histories'], + onSuccess: (res) => { + setDeposites(deposites.concat(res.props.histories.data)) + }, + } + ) + } + + return ( + + +
+
+
{user.fullname}
+
+
+
+
+ Saldo +
+
+ Rp {user.display_deposit} +
+
+
+
+ router.get(route('customer.deposit.topup')) + } + > + Top Up +
+
+
+
+
+ {deposites.map((history) => ( +
+ router.get( + route( + 'customer.deposit.show', + history.id + ) + ) + } + > +
+
+ {history.format_human_created_at} +
+
+ {history.description} +
+
+
+
+ {formatIDR(history.amount)} +
+ {+history.is_valid !== 0 && ( +
+ {history.status.text} +
+ )} +
+
+ ))} + {next_page_url !== null && ( +
+ Load more +
+ )} +
+
+
+
+ ) +} diff --git a/resources/js/Pages/Home/Deposit/Topup.jsx b/resources/js/Pages/Home/Deposit/Topup.jsx new file mode 100644 index 0000000..597414c --- /dev/null +++ b/resources/js/Pages/Home/Deposit/Topup.jsx @@ -0,0 +1,118 @@ +import React from 'react' +import { Head, router, useForm } from '@inertiajs/react' +import { HiChevronLeft } from 'react-icons/hi2' + +import CustomerLayout from '@/Layouts/CustomerLayout' +import FormInput from '@/Components/FormInput' +import Alert from '@/Components/Alert' +import { formatIDR } from '@/utils' + +export default function Topup({ payments }) { + const { data, setData, post, processing, errors, reset, clearErrors } = + useForm({ + amount: '', + payment: '', + }) + + const amounts = [20000, 50000, 100000, 200000, 300000, 500000] + + const isActiveAmount = (amount) => { + return `px-3 py-3 border shadow-sm rounded ${ + +amount === +data.amount ? 'bg-blue-700 text-white' : '' + }` + } + + const setAmount = (amount) => { + setData('amount', amount) + } + + const isActivePayment = (payment) => { + return `p-2 border shadow rounded flex flex-row items-center space-x-5 h-14 ${ + payment === data.payment ? 'bg-blue-600 text-white' : '' + }` + } + + const handleSubmit = () => { + if (processing) { + return + } + post(route('customer.deposit.topup')) + } + + return ( + + +
+
{ + router.get(route('customer.deposit.index')) + }} + > + +
+
+
Pilih Nominal
+
+ {amounts.map((amount) => ( +
setAmount(amount)} + > + {formatIDR(amount)} +
+ ))} +
+
+
+
+
ATAU
+
+
+
+ setData('amount', e.target.value)} + error={errors.amount} + /> +
+
+
Metode Pembayaran
+ {errors.payment && ( + Pilih metode pembayaran + )} +
+
+ {payments.map((payment) => ( +
setData('payment', payment.name)} + > + + {payment.logo === null ? ( +

{payment.display_name}

+ ) : ( + + )} +
+ ))} +
+
+
+
+
+ Bayar +
+
+ + ) +} diff --git a/resources/js/Pages/Home/Index/BalanceBanner.jsx b/resources/js/Pages/Home/Index/BalanceBanner.jsx new file mode 100644 index 0000000..2cc9cd5 --- /dev/null +++ b/resources/js/Pages/Home/Index/BalanceBanner.jsx @@ -0,0 +1,34 @@ +import { router } from '@inertiajs/react' +import { HiOutlineCash } from 'react-icons/hi' + +export default function BalanceBanner({ user }) { + return ( +
router.get(route('customer.deposit.index'))} + > +
+
+
+ +
Saldo
+
+
Rp {user.display_deposit}
+
+
Coin {user.display_coin}
+
+
+
+
+ {/* */} +
Rewards
+
+
{user.level.name} Member
+
+
Limit 100.000
+
+
+
+
+ ) +} diff --git a/resources/js/Pages/Home/Index/Index.jsx b/resources/js/Pages/Home/Index/Index.jsx index bc301cb..41b0160 100644 --- a/resources/js/Pages/Home/Index/Index.jsx +++ b/resources/js/Pages/Home/Index/Index.jsx @@ -91,7 +91,7 @@ export default function Index(props) { return ( -
+
{user !== null ? : } {/* banner */} diff --git a/resources/js/Pages/Home/Index/UserBanner.jsx b/resources/js/Pages/Home/Index/UserBanner.jsx index 7d00114..306981e 100644 --- a/resources/js/Pages/Home/Index/UserBanner.jsx +++ b/resources/js/Pages/Home/Index/UserBanner.jsx @@ -1,5 +1,6 @@ import React from 'react' import { HiOutlineCash, HiOutlineBell } from 'react-icons/hi' +import BalanceBanner from './BalanceBanner' export default function UserBanner({ user }) { return ( @@ -25,34 +26,7 @@ export default function UserBanner({ user }) {
{/* saldo */} -
-
-
-
- -
Saldo
-
-
- Rp {user.display_deposit} -
-
-
Coin {user.display_coin}
-
-
-
-
- {/* */} -
Rewards
-
-
- {user.level.name} Member -
-
-
Limit 100.000
-
-
-
-
+
) } diff --git a/resources/js/Pages/Home/Profile/Index.jsx b/resources/js/Pages/Home/Profile/Index.jsx index fbab70d..fc74979 100644 --- a/resources/js/Pages/Home/Profile/Index.jsx +++ b/resources/js/Pages/Home/Profile/Index.jsx @@ -10,6 +10,7 @@ import { import { HiOutlineBell, HiOutlineCash } from 'react-icons/hi' import { useModalState } from '@/hooks' import ModalConfirm from '@/Components/ModalConfirm' +import BalanceBanner from '../Index/BalanceBanner' export default function Index({ auth: { user } }) { const confirmModal = useModalState() @@ -59,43 +60,26 @@ export default function Index({ auth: { user } }) { {/* saldo */} -
-
-
-
- -
Saldo
-
-
- Rp {user.display_deposit} -
-
-
Coin {user.display_coin}
-
-
-
-
-
Rewards
-
-
- {user.level.name} Member -
-
-
Limit 100.000
-
-
-
-
+
Upgrade Member
-
+
+ router.get(route('customer.deposit.index')) + } + >
Deposit Saldo
+
+
Coin
+ +
Transaksi
diff --git a/routes/api.php b/routes/api.php index 5055fe0..99854bf 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,6 +2,7 @@ use App\Http\Controllers\Api\RoleController; use App\Http\Controllers\Api\LocationController; +use App\Http\Controllers\Customer\DepositController; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; @@ -25,4 +26,5 @@ Route::get('/roles', [RoleController::class, 'index'])->name('api.role.index'); Route::get('/locations', [LocationController::class, 'index'])->name('api.location.index'); // midtrans -Route::post('mindtrans/notification', fn () => 'Ok!')->name('api.midtrans.notification'); +Route::post('mindtrans/notification', [DepositController::class, 'mindtrans_notification'])->name('api.midtrans.notification'); +Route::post('mindtrans/{deposit}/payment', [DepositController::class, 'midtrans_payment'])->name('api.midtrans.payment'); diff --git a/routes/web.php b/routes/web.php index a5feafe..34679fb 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,6 +1,7 @@ name('customer.logout'); + + // deposite + Route::get('deposit', [DepositController::class, 'index'])->name('customer.deposit.index'); + Route::get('deposit/topup', [DepositController::class, 'create'])->name('customer.deposit.topup'); + Route::post('deposit/topup', [DepositController::class, 'store']); + Route::get('deposit/trx/{deposit}', [DepositController::class, 'show'])->name('customer.deposit.show'); + Route::post('deposit/trx/{deposit}', [DepositController::class, 'update'])->name('customer.deposit.update'); }); + Route::middleware('guest:customer')->group(function () { // login Route::get('/login', [AuthController::class, 'login'])->name('customer.login');