Deploy Ladill Woo Manager / deploy (push) Successful in 38s
Standardize customer-facing Ladill Pay checkout shells across products, open them on all viewports, and escape iframe callbacks back to the product flow.
125 lines
5.7 KiB
PHP
125 lines
5.7 KiB
PHP
@props([
|
|
'id',
|
|
'title' => 'Add credits',
|
|
'description' => '',
|
|
'topupAction',
|
|
'minTopup' => 5,
|
|
'suggestedAmount' => 10,
|
|
'ladillWalletBalance' => 0,
|
|
'serviceBalance' => null,
|
|
'serviceBalanceLabel' => 'Current balance',
|
|
'openOnLoad' => false,
|
|
'returnUrl' => null,
|
|
])
|
|
|
|
@php
|
|
// Single-wallet (siloing step 2): there is one Ladill wallet, so "pay from
|
|
// wallet into service credits" is a meaningless round-trip — top up the one
|
|
// wallet directly (Paystack). Transfer option removed.
|
|
$canPayFromWallet = false;
|
|
@endphp
|
|
|
|
<x-modal :name="$id" :show="$openOnLoad" maxWidth="md">
|
|
<div class="flex min-h-full flex-col sm:min-h-0">
|
|
<div class="border-b border-slate-100 px-5 py-4 pr-12 sm:px-6 sm:pr-14">
|
|
<h2 class="text-lg font-semibold text-slate-900">{{ $title }}</h2>
|
|
@if($description)
|
|
<p class="mt-1 text-sm text-slate-500">{{ $description }}</p>
|
|
@endif
|
|
</div>
|
|
|
|
<form action="{{ $topupAction }}" method="POST" class="flex flex-1 flex-col p-5 sm:p-6"
|
|
x-data="{
|
|
method: 'paystack',
|
|
showSheet: false,
|
|
checkoutUrl: '',
|
|
loading: false,
|
|
errorMsg: '',
|
|
async submitTopup(event) {
|
|
if (this.method !== 'paystack') return;
|
|
|
|
event.preventDefault();
|
|
this.loading = true;
|
|
this.errorMsg = '';
|
|
|
|
try {
|
|
const res = await fetch(event.target.action, {
|
|
method: 'POST',
|
|
headers: { 'Accept': 'application/json' },
|
|
body: new FormData(event.target),
|
|
});
|
|
const data = await res.json();
|
|
if (!res.ok || data.error || !data.checkout_url) {
|
|
this.errorMsg = data.error || 'Unable to start payment. Please try again.';
|
|
this.loading = false;
|
|
return;
|
|
}
|
|
|
|
this.checkoutUrl = data.checkout_url;
|
|
this.showSheet = true;
|
|
this.loading = false;
|
|
} catch (error) {
|
|
this.errorMsg = 'Network error. Please try again.';
|
|
this.loading = false;
|
|
}
|
|
},
|
|
}"
|
|
@submit="submitTopup($event)">
|
|
@csrf
|
|
@if($returnUrl)
|
|
<input type="hidden" name="return_url" value="{{ $returnUrl }}">
|
|
@endif
|
|
|
|
@if($serviceBalance !== null)
|
|
<div class="mb-4 rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-center">
|
|
<p class="text-xl font-bold text-slate-900">GHS {{ number_format((float) $serviceBalance, 2) }}</p>
|
|
<p class="text-xs text-slate-500">{{ $serviceBalanceLabel }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
<div x-show="errorMsg" x-cloak class="mb-4 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700" x-text="errorMsg"></div>
|
|
|
|
<div>
|
|
<label class="text-sm font-medium text-slate-700">Amount (GHS)</label>
|
|
<input type="number" name="amount" min="{{ $minTopup }}" max="5000" step="0.01"
|
|
value="{{ $suggestedAmount }}"
|
|
class="mt-1.5 block w-full rounded-xl border border-slate-200 px-3 py-2.5 text-sm focus:border-indigo-400 focus:ring-1 focus:ring-indigo-400"
|
|
required>
|
|
<p class="mt-1.5 text-xs text-slate-500">Minimum GHS {{ number_format($minTopup, 2) }}</p>
|
|
</div>
|
|
|
|
<input type="hidden" name="payment_method" value="paystack" @if($canPayFromWallet) x-model="method" @endif>
|
|
|
|
@if($canPayFromWallet)
|
|
<div class="mt-4">
|
|
<p class="mb-2 text-xs font-medium text-slate-600">Payment method</p>
|
|
<div class="flex rounded-xl border border-slate-200 bg-white p-0.5 text-sm">
|
|
<button type="button" @click="method = 'paystack'"
|
|
:class="method === 'paystack' ? 'bg-indigo-600 text-white' : 'text-slate-600'"
|
|
class="flex-1 rounded-lg py-2 font-medium transition">Paystack</button>
|
|
<button type="button" @click="method = 'wallet'"
|
|
:class="method === 'wallet' ? 'bg-indigo-600 text-white' : 'text-slate-600'"
|
|
class="flex-1 rounded-lg py-2 font-medium transition">Wallet (GHS {{ number_format($ladillWalletBalance, 2) }})</button>
|
|
</div>
|
|
</div>
|
|
@else
|
|
<p class="mt-4 text-xs text-slate-500">Pay with Paystack.</p>
|
|
@endif
|
|
|
|
<div class="mt-6 flex flex-col gap-2 sm:mt-auto sm:flex-row sm:justify-end">
|
|
<button type="button" @click="$dispatch('close-modal', '{{ $id }}')"
|
|
data-close-modal="{{ $id }}"
|
|
class="hidden rounded-xl border border-slate-200 px-4 py-2.5 text-sm font-medium text-slate-700 hover:bg-slate-50 sm:inline-flex">
|
|
Cancel
|
|
</button>
|
|
<button type="submit" :disabled="loading"
|
|
class="btn-primary w-full sm:w-auto">
|
|
<span x-text="loading ? 'Processing…' : 'Add credits'">Add credits</span>
|
|
</button>
|
|
</div>
|
|
|
|
@include('partials.paystack-sheet')
|
|
</form>
|
|
</div>
|
|
</x-modal>
|