Polish Give UX: always-on online giving, correct mobile branding, clearer payouts.
Deploy Ladill Give / deploy (push) Successful in 31s

Remove the redundant accepts-payment toggle, fix the mobile header title, and update payout copy to reflect Ladill Pay and the 9% donation fee.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-06-09 09:30:39 +00:00
co-authored by Cursor
parent 3eb41fe08e
commit 8edafc5966
11 changed files with 12 additions and 53 deletions
@@ -65,7 +65,6 @@ class GivingPageController extends Controller
'brand_color' => ['nullable', 'string', 'max:20'], 'brand_color' => ['nullable', 'string', 'max:20'],
'collection_types' => ['nullable', 'array', 'min:1'], 'collection_types' => ['nullable', 'array', 'min:1'],
'collection_types.*' => ['string', 'max:80'], 'collection_types.*' => ['string', 'max:80'],
'accepts_payment' => ['nullable', 'boolean'],
'church_logo' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:4096'], 'church_logo' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:4096'],
'church_cover' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:8192'], 'church_cover' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:8192'],
]); ]);
@@ -73,7 +72,7 @@ class GivingPageController extends Controller
$data = array_merge($request->all(), [ $data = array_merge($request->all(), [
'type' => QrCode::TYPE_CHURCH, 'type' => QrCode::TYPE_CHURCH,
'currency' => 'GHS', 'currency' => 'GHS',
'accepts_payment' => $request->boolean('accepts_payment'), 'accepts_payment' => true,
'church_logo' => $request->file('church_logo'), 'church_logo' => $request->file('church_logo'),
'church_cover' => $request->file('church_cover'), 'church_cover' => $request->file('church_cover'),
]); ]);
@@ -115,14 +114,13 @@ class GivingPageController extends Controller
'brand_color' => ['nullable', 'string', 'max:20'], 'brand_color' => ['nullable', 'string', 'max:20'],
'collection_types' => ['nullable', 'array', 'min:1'], 'collection_types' => ['nullable', 'array', 'min:1'],
'collection_types.*' => ['string', 'max:80'], 'collection_types.*' => ['string', 'max:80'],
'accepts_payment' => ['nullable', 'boolean'],
'is_active' => ['sometimes', 'boolean'], 'is_active' => ['sometimes', 'boolean'],
'church_logo' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:4096'], 'church_logo' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:4096'],
'church_cover' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:8192'], 'church_cover' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:8192'],
]); ]);
$data = array_merge($request->all(), [ $data = array_merge($request->all(), [
'accepts_payment' => $request->boolean('accepts_payment', (bool) ($givingPage->content()['accepts_payment'] ?? false)), 'accepts_payment' => true,
'is_active' => $request->boolean('is_active', $givingPage->is_active), 'is_active' => $request->boolean('is_active', $givingPage->is_active),
'church_logo' => $request->file('church_logo'), 'church_logo' => $request->file('church_logo'),
'church_cover' => $request->file('church_cover'), 'church_cover' => $request->file('church_cover'),
@@ -27,10 +27,6 @@ class DonationController extends Controller
return response()->json(['error' => 'This giving page does not accept donations.'], 422); return response()->json(['error' => 'This giving page does not accept donations.'], 422);
} }
if (empty($qrCode->content()['accepts_payment'])) {
return response()->json(['error' => 'Online giving is not enabled for this page.'], 422);
}
$validated = $request->validate([ $validated = $request->validate([
'customer_name' => ['required', 'string', 'max:120'], 'customer_name' => ['required', 'string', 'max:120'],
'customer_email' => ['required', 'email', 'max:200'], 'customer_email' => ['required', 'email', 'max:200'],
@@ -30,10 +30,6 @@ class GiveDonationService
throw new RuntimeException('This QR is not a giving page.'); throw new RuntimeException('This QR is not a giving page.');
} }
if (empty($qrCode->content()['accepts_payment'])) {
throw new RuntimeException('Online giving is not enabled for this page.');
}
$items = $data['items'] ?? []; $items = $data['items'] ?? [];
if (empty($items)) { if (empty($items)) {
throw new RuntimeException('Enter an amount to give.'); throw new RuntimeException('Enter an amount to give.');
+1 -1
View File
@@ -188,7 +188,7 @@ class QrPayloadValidator
'logo_path' => $input['logo_path'] ?? null, 'logo_path' => $input['logo_path'] ?? null,
'cover_path' => $input['cover_path'] ?? null, 'cover_path' => $input['cover_path'] ?? null,
'org_type' => $orgType, 'org_type' => $orgType,
'accepts_payment' => filter_var($input['accepts_payment'] ?? false, FILTER_VALIDATE_BOOL), 'accepts_payment' => true,
'currency' => 'GHS', 'currency' => 'GHS',
'collection_types' => $collectionTypes, 'collection_types' => $collectionTypes,
], ],
+1 -1
View File
@@ -1,5 +1,5 @@
<?php <?php
return [ return [
'app_name' => 'Mini', 'app_name' => 'Give',
]; ];
@@ -75,13 +75,6 @@
<label class="block text-xs font-medium text-slate-500">Brand color</label> <label class="block text-xs font-medium text-slate-500">Brand color</label>
<input type="color" name="brand_color" value="{{ old('brand_color', '#1a3a5c') }}" class="mt-1 h-10 w-full rounded-xl border border-slate-200"> <input type="color" name="brand_color" value="{{ old('brand_color', '#1a3a5c') }}" class="mt-1 h-10 w-full rounded-xl border border-slate-200">
</div> </div>
<label class="flex cursor-pointer items-center justify-between rounded-xl border border-slate-200 px-4 py-3">
<div>
<p class="text-sm font-semibold text-slate-900">Accept online giving</p>
<p class="text-xs text-slate-500">Supporters can give online (9% platform fee).</p>
</div>
<input type="checkbox" name="accepts_payment" value="1" @checked(old('accepts_payment', true)) class="h-5 w-5 rounded text-indigo-600">
</label>
<div> <div>
<p class="mb-2 text-xs font-semibold text-slate-600">Giving categories</p> <p class="mb-2 text-xs font-semibold text-slate-600">Giving categories</p>
<template x-for="t in types" :key="t"> <template x-for="t in types" :key="t">
@@ -47,10 +47,6 @@
<input type="text" name="phone" value="{{ old('phone', $c['phone'] ?? '') }}" placeholder="Phone" class="rounded-xl border-slate-200 text-sm"> <input type="text" name="phone" value="{{ old('phone', $c['phone'] ?? '') }}" placeholder="Phone" class="rounded-xl border-slate-200 text-sm">
<input type="email" name="email" value="{{ old('email', $c['email'] ?? '') }}" placeholder="Email" class="rounded-xl border-slate-200 text-sm"> <input type="email" name="email" value="{{ old('email', $c['email'] ?? '') }}" placeholder="Email" class="rounded-xl border-slate-200 text-sm">
</div> </div>
<label class="flex items-center gap-2 text-sm text-slate-700">
<input type="checkbox" name="accepts_payment" value="1" @checked(old('accepts_payment', $c['accepts_payment'] ?? false)) class="rounded border-slate-300 text-indigo-600">
Accept online giving
</label>
<label class="flex items-center gap-2 text-sm text-slate-700"> <label class="flex items-center gap-2 text-sm text-slate-700">
<input type="checkbox" name="is_active" value="1" @checked($qrCode->is_active) class="rounded border-slate-300 text-indigo-600"> <input type="checkbox" name="is_active" value="1" @checked($qrCode->is_active) class="rounded border-slate-300 text-indigo-600">
Page is active Page is active
+3 -3
View File
@@ -4,7 +4,7 @@
<div class="space-y-6"> <div class="space-y-6">
<div> <div>
<h1 class="text-xl font-semibold text-slate-900">Payouts</h1> <h1 class="text-xl font-semibold text-slate-900">Payouts</h1>
<p class="mt-1 text-sm text-slate-500">Takings settle into your Ladill wallet (5% fee), then withdraw to bank or MoMo.</p> <p class="mt-1 text-sm text-slate-500">Donations settle into your Ladill wallet (9% fee), then withdraw to bank or MoMo.</p>
</div> </div>
<div class="grid gap-4 sm:grid-cols-2"> <div class="grid gap-4 sm:grid-cols-2">
<div class="rounded-2xl border border-slate-200 bg-white p-5"> <div class="rounded-2xl border border-slate-200 bg-white p-5">
@@ -16,8 +16,8 @@
<p class="mt-1.5 text-2xl font-semibold text-slate-900">{{ $fmt($balanceMinor) }}</p> <p class="mt-1.5 text-2xl font-semibold text-slate-900">{{ $fmt($balanceMinor) }}</p>
</div> </div>
</div> </div>
<div class="rounded-2xl border border-amber-100 bg-amber-50/60 px-6 py-4 text-sm text-amber-800"> <div class="rounded-2xl border border-slate-200 bg-slate-50 px-6 py-4 text-sm text-slate-600">
Withdraw to bank or MoMo from your Ladill account wallet. Ladill Pay integration will add in-app withdrawal history here. Donations are collected through Ladill Pay and credited to your Ladill wallet. Withdraw to bank or MoMo from your account wallet payout and withdrawal history is there.
</div> </div>
<a href="{{ $accountWalletUrl }}" class="btn-primary"> <a href="{{ $accountWalletUrl }}" class="btn-primary">
Open wallet & withdraw Open wallet & withdraw
+1 -1
View File
@@ -316,7 +316,7 @@
$churchLogoUrl = $churchHasLogo ? route('qr.public.church.logo', $qrCode->short_code) : null; $churchLogoUrl = $churchHasLogo ? route('qr.public.church.logo', $qrCode->short_code) : null;
$churchCoverUrl = $churchHasCover ? route('qr.public.church.cover', $qrCode->short_code) : null; $churchCoverUrl = $churchHasCover ? route('qr.public.church.cover', $qrCode->short_code) : null;
$churchInitials = strtoupper(substr($churchName, 0, 2)); $churchInitials = strtoupper(substr($churchName, 0, 2));
$churchAcceptsPay = !empty($content['accepts_payment']); $churchAcceptsPay = true;
$churchCurrency = $content['currency'] ?? 'GHS'; $churchCurrency = $content['currency'] ?? 'GHS';
$churchTypes = $content['collection_types'] ?? ['offering', 'tithe', 'donation', 'harvest']; $churchTypes = $content['collection_types'] ?? ['offering', 'tithe', 'donation', 'harvest'];
// Normalise legacy lowercase slugs → display strings // Normalise legacy lowercase slugs → display strings
@@ -326,20 +326,10 @@
</div> </div>
</div> </div>
{{-- Online Giving --}} <input type="hidden" name="accepts_payment" value="1">
<div> <div>
<p class="mb-2 text-xs font-semibold text-slate-600">Online Giving</p>
<label class="flex cursor-pointer items-center justify-between rounded-xl border border-slate-200 bg-white px-4 py-3 shadow-sm">
<div>
<p class="text-sm font-semibold text-slate-900">Accept online giving</p>
<p class="mt-0.5 text-xs text-slate-500">Supporters can give and pay online via Paystack.</p>
</div>
<input type="checkbox" name="accepts_payment" value="1" @checked(old('accepts_payment'))
class="ml-4 h-5 w-5 shrink-0 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500">
</label>
{{-- Collection type manager --}} {{-- Collection type manager --}}
<div class="mt-3"> <div>
<p class="mb-2 text-[11px] font-medium text-slate-500">Collection types <span class="text-slate-400">(shown as giving options)</span></p> <p class="mb-2 text-[11px] font-medium text-slate-500">Collection types <span class="text-slate-400">(shown as giving options)</span></p>
{{-- Current types as removable tags --}} {{-- Current types as removable tags --}}
@@ -336,19 +336,9 @@
</div> </div>
</div> </div>
{{-- Online Giving --}} <input type="hidden" name="accepts_payment" value="1">
<div> <div>
<p class="mb-2 text-xs font-semibold text-slate-600">Online Giving</p> <div>
<label class="flex cursor-pointer items-center justify-between rounded-xl border border-slate-200 bg-white px-4 py-3 shadow-sm">
<div>
<p class="text-sm font-semibold text-slate-900">Accept online giving</p>
<p class="mt-0.5 text-xs text-slate-500">Supporters can give and pay online via Paystack.</p>
</div>
<input type="checkbox" name="accepts_payment" value="1" @checked(!empty($c['accepts_payment']))
class="ml-4 h-5 w-5 shrink-0 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500">
</label>
<div class="mt-3">
<p class="mb-2 text-[11px] font-medium text-slate-500">Collection types</p> <p class="mb-2 text-[11px] font-medium text-slate-500">Collection types</p>
<div class="flex flex-wrap gap-2 mb-2"> <div class="flex flex-wrap gap-2 mb-2">
<template x-for="(t, i) in types" :key="t"> <template x-for="(t, i) in types" :key="t">