Prefill business QR creation from CRM contact links.
Deploy Ladill QR Plus / deploy (push) Successful in 51s
Deploy Ladill QR Plus / deploy (push) Successful in 51s
Decode CRM prefill tokens so contact name, phone, email, and address carry into QR Plus. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -73,6 +73,12 @@ class QrCodeController extends Controller
|
||||
$wallet = $this->manager->walletFor($account);
|
||||
$qrSettings = $account->getOrCreateQrSetting();
|
||||
|
||||
$prefill = \App\Support\CrmPrefillCodec::decode($request->query('prefill'));
|
||||
$defaultType = $qrSettings->resolvedDefaultType();
|
||||
if (($prefill['kind'] ?? null) === 'qr_business' && ! empty($prefill['type'])) {
|
||||
$defaultType = (string) $prefill['type'];
|
||||
}
|
||||
|
||||
return view('qr-codes.create', [
|
||||
'wallet' => $wallet,
|
||||
'types' => QrTypeCatalog::all(),
|
||||
@@ -84,8 +90,9 @@ class QrCodeController extends Controller
|
||||
'minTopup' => QrWallet::minTopupGhs(),
|
||||
'ladillWalletBalance' => $this->platformBilling->balanceMinor($account->public_id) / 100,
|
||||
'topupUrl' => 'https://'.config('app.account_domain').'/wallet',
|
||||
'defaultType' => $qrSettings->resolvedDefaultType(),
|
||||
'defaultType' => $defaultType,
|
||||
'accountDefaultStyle' => $qrSettings->resolvedDefaultStyle(),
|
||||
'prefill' => ($prefill['kind'] ?? null) === 'qr_business' ? $prefill : null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
final class CrmPrefillCodec
|
||||
{
|
||||
/** @return array<string, mixed>|null */
|
||||
public static function decode(?string $token): ?array
|
||||
{
|
||||
if (! is_string($token) || $token === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$padded = $token.str_repeat('=', (4 - strlen($token) % 4) % 4);
|
||||
$json = base64_decode(strtr($padded, '-_', '+/'), true);
|
||||
|
||||
if ($json === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (\JsonException) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return is_array($data) ? $data : null;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
$defaultStyle = \App\Support\Qr\QrStyleDefaults::merge(old('style') ?: ($accountDefaultStyle ?? null));
|
||||
@endphp
|
||||
|
||||
@php $prefill = $prefill ?? []; @endphp
|
||||
<div class="mx-auto max-w-6xl space-y-6"
|
||||
x-data="qrCustomizer({
|
||||
previewUrl: @js(route('user.qr-codes.style-preview')),
|
||||
@@ -14,9 +15,15 @@
|
||||
balance: @js((float) $wallet->spendableBalance()),
|
||||
price: @js((float) $pricePerQr),
|
||||
topupUrl: @js($topupUrl),
|
||||
type: @js(old('type', $defaultType ?? 'url')),
|
||||
type: @js(old('type', $prefill['type'] ?? $defaultType ?? 'url')),
|
||||
})">
|
||||
|
||||
@if(!empty($prefill))
|
||||
<div class="rounded-xl border border-indigo-200 bg-indigo-50 px-4 py-3 text-sm text-indigo-900">
|
||||
Prefilled from Ladill CRM. Review the business details, then create your QR code.
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(session('error'))
|
||||
<div class="rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">{{ session('error') }}</div>
|
||||
@endif
|
||||
@@ -65,7 +72,7 @@
|
||||
<div class="space-y-4 p-5">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600">Label</label>
|
||||
<input type="text" name="label" value="{{ old('label') }}" required maxlength="120"
|
||||
<input type="text" name="label" value="{{ old('label', $prefill['label'] ?? '') }}" required maxlength="120"
|
||||
class="mt-1.5 w-full rounded-xl border border-slate-200 bg-white px-3.5 py-2.5 text-sm placeholder:text-slate-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400/30"
|
||||
placeholder="e.g. Shop flyer, WiFi guest, Menu">
|
||||
</div>
|
||||
@@ -149,7 +156,7 @@
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
@include('qr-codes.partials.type-fields-create')
|
||||
@include('qr-codes.partials.type-fields-create', ['prefill' => $prefill ?? []])
|
||||
</div>
|
||||
|
||||
<p class="rounded-xl bg-slate-50 px-3.5 py-2.5 text-xs leading-5 text-slate-400">
|
||||
|
||||
@@ -121,19 +121,19 @@
|
||||
{{-- Business --}}
|
||||
<div x-show="type === 'business'" x-cloak class="space-y-4">
|
||||
<div class="grid gap-3">
|
||||
<input type="text" name="name" value="{{ old('name') }}" placeholder="Business name *"
|
||||
<input type="text" name="name" value="{{ old('name', $prefill['name'] ?? '') }}" placeholder="Business name *"
|
||||
class="rounded-xl border border-slate-200 px-3.5 py-2.5 text-sm placeholder:text-slate-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400/30">
|
||||
<input type="text" name="tagline" value="{{ old('tagline') }}" placeholder="Tagline or brief description"
|
||||
class="rounded-xl border border-slate-200 px-3.5 py-2.5 text-sm placeholder:text-slate-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400/30">
|
||||
<div class="grid gap-3 sm:grid-cols-2">
|
||||
<input type="text" name="phone" value="{{ old('phone') }}" placeholder="Phone"
|
||||
<input type="text" name="phone" value="{{ old('phone', $prefill['phone'] ?? '') }}" placeholder="Phone"
|
||||
class="rounded-xl border border-slate-200 px-3.5 py-2.5 text-sm placeholder:text-slate-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400/30">
|
||||
<input type="email" name="email" value="{{ old('email') }}" placeholder="Email"
|
||||
<input type="email" name="email" value="{{ old('email', $prefill['email'] ?? '') }}" placeholder="Email"
|
||||
class="rounded-xl border border-slate-200 px-3.5 py-2.5 text-sm placeholder:text-slate-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400/30">
|
||||
</div>
|
||||
<input type="url" name="website" value="{{ old('website') }}" placeholder="Website URL"
|
||||
class="rounded-xl border border-slate-200 px-3.5 py-2.5 text-sm placeholder:text-slate-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400/30">
|
||||
<input type="text" name="address" value="{{ old('address') }}" placeholder="Address"
|
||||
<input type="text" name="address" value="{{ old('address', $prefill['address'] ?? '') }}" placeholder="Address"
|
||||
class="rounded-xl border border-slate-200 px-3.5 py-2.5 text-sm placeholder:text-slate-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400/30">
|
||||
<textarea name="hours" rows="2" placeholder="Opening hours (e.g. Mon–Fri 8am–6pm)"
|
||||
class="rounded-xl border border-slate-200 px-3.5 py-2.5 text-sm placeholder:text-slate-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400/30">{{ old('hours') }}</textarea>
|
||||
|
||||
Reference in New Issue
Block a user