Fix QR codes views to use user.qr-codes route names.
Deploy Ladill QR Plus / deploy (push) Successful in 56s

Removes missing topup route/modal and sends low-balance users to the platform wallet.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-06-07 06:02:33 +00:00
co-authored by Cursor
parent 6f4c68d274
commit bcd1cf5d28
9 changed files with 73 additions and 79 deletions
+13 -1
View File
@@ -20,8 +20,10 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View; use Illuminate\View\View;
use RuntimeException; use RuntimeException;
use Throwable;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpFoundation\StreamedResponse;
@@ -45,12 +47,22 @@ class QrCodeController extends Controller
->latest() ->latest()
->get(); ->get();
$ladillWalletBalance = 0.0;
try {
$ladillWalletBalance = $this->platformBilling->balanceMinor($user->public_id) / 100;
} catch (Throwable $e) {
Log::warning('QR Plus index could not load Ladill wallet balance', [
'user' => $user->public_id,
'error' => $e->getMessage(),
]);
}
return view('qr-codes.index', [ return view('qr-codes.index', [
'wallet' => $wallet, 'wallet' => $wallet,
'qrCodes' => $qrCodes, 'qrCodes' => $qrCodes,
'pricePerQr' => QrWallet::pricePerQr(), 'pricePerQr' => QrWallet::pricePerQr(),
'minTopup' => QrWallet::minTopupGhs(), 'minTopup' => QrWallet::minTopupGhs(),
'ladillWalletBalance' => $this->platformBilling->balanceMinor($user->public_id) / 100, 'ladillWalletBalance' => $ladillWalletBalance,
'topupUrl' => 'https://'.config('app.account_domain').'/wallet', 'topupUrl' => 'https://'.config('app.account_domain').'/wallet',
]); ]);
} }
+6
View File
@@ -352,6 +352,7 @@ document.addEventListener('alpine:init', () => {
balance: Number(config.balance ?? 0), balance: Number(config.balance ?? 0),
price: Number(config.price ?? 0), price: Number(config.price ?? 0),
modalId: config.modalId ?? null, modalId: config.modalId ?? null,
topupUrl: config.topupUrl ?? null,
href: config.href ?? null, href: config.href ?? null,
requiresPayment: Object.prototype.hasOwnProperty.call(config, 'requiresPayment') requiresPayment: Object.prototype.hasOwnProperty.call(config, 'requiresPayment')
? config.requiresPayment !== false ? config.requiresPayment !== false
@@ -367,6 +368,11 @@ document.addEventListener('alpine:init', () => {
return this.needsTopupFor(this.requiresPayment); return this.needsTopupFor(this.requiresPayment);
}, },
openTopup() { openTopup() {
if (this.topupUrl) {
window.location.href = this.topupUrl;
return;
}
if (! this.modalId) { if (! this.modalId) {
return; return;
} }
+7 -7
View File
@@ -7,8 +7,8 @@
selected: [], selected: [],
toggle(id) { const i = this.selected.indexOf(id); i === -1 ? this.selected.push(id) : this.selected.splice(i, 1); }, toggle(id) { const i = this.selected.indexOf(id); i === -1 ? this.selected.push(id) : this.selected.splice(i, 1); },
get qs() { return this.selected.map(id => 'ids[]=' + id).join('&'); }, get qs() { return this.selected.map(id => 'ids[]=' + id).join('&'); },
printSelected() { window.open(@js(route('qr-codes.badges', $qrCode)) + '?auto=1&' + this.qs, '_blank'); }, printSelected() { window.open(@js(route('user.qr-codes.badges', $qrCode)) + '?auto=1&' + this.qs, '_blank'); },
zplSelected() { window.location = @js(route('qr-codes.badges.zpl', $qrCode)) + '?' + this.qs; } zplSelected() { window.location = @js(route('user.qr-codes.badges.zpl', $qrCode)) + '?' + this.qs; }
}"> }">
{{-- Flash --}} {{-- Flash --}}
@@ -22,7 +22,7 @@
{{-- Header --}} {{-- Header --}}
<div> <div>
<a href="{{ route('qr-codes.show', $qrCode) }}" class="inline-flex items-center gap-1 text-sm text-slate-500 hover:text-slate-700"> <a href="{{ route('user.qr-codes.show', $qrCode) }}" class="inline-flex items-center gap-1 text-sm text-slate-500 hover:text-slate-700">
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/></svg> <svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/></svg>
{{ $qrCode->label }} {{ $qrCode->label }}
</a> </a>
@@ -41,7 +41,7 @@
<p class="text-xs text-slate-500">Email &amp; text the <span class="font-medium text-slate-600">{{ $programme->label }}</span> programme link to all confirmed attendees.</p> <p class="text-xs text-slate-500">Email &amp; text the <span class="font-medium text-slate-600">{{ $programme->label }}</span> programme link to all confirmed attendees.</p>
</div> </div>
</div> </div>
<form method="POST" action="{{ route('qr-codes.attendees.share-programme', $qrCode) }}" <form method="POST" action="{{ route('user.qr-codes.attendees.share-programme', $qrCode) }}"
x-data="{ busy: false }" x-data="{ busy: false }"
@submit="if (!confirm('Send the programme outline to all confirmed attendees by email and SMS?')) { $event.preventDefault(); return; } busy = true;" @submit="if (!confirm('Send the programme outline to all confirmed attendees by email and SMS?')) { $event.preventDefault(); return; } busy = true;"
class="shrink-0"> class="shrink-0">
@@ -90,9 +90,9 @@
class="rounded-xl bg-indigo-600 px-3.5 py-2 text-xs font-semibold text-white hover:bg-indigo-700 transition">Print selected</button> class="rounded-xl bg-indigo-600 px-3.5 py-2 text-xs font-semibold text-white hover:bg-indigo-700 transition">Print selected</button>
<button type="button" x-show="selected.length" x-cloak @click="zplSelected()" <button type="button" x-show="selected.length" x-cloak @click="zplSelected()"
class="rounded-xl border border-slate-200 px-3.5 py-2 text-xs font-semibold text-slate-600 hover:bg-slate-50 transition">ZPL selected</button> class="rounded-xl border border-slate-200 px-3.5 py-2 text-xs font-semibold text-slate-600 hover:bg-slate-50 transition">ZPL selected</button>
<a href="{{ route('qr-codes.badges', $qrCode) }}?auto=1" target="_blank" <a href="{{ route('user.qr-codes.badges', $qrCode) }}?auto=1" target="_blank"
class="rounded-xl bg-slate-900 px-3.5 py-2 text-xs font-semibold text-white hover:bg-slate-800 transition">Print all badges</a> class="rounded-xl bg-slate-900 px-3.5 py-2 text-xs font-semibold text-white hover:bg-slate-800 transition">Print all badges</a>
<a href="{{ route('qr-codes.badges.zpl', $qrCode) }}" <a href="{{ route('user.qr-codes.badges.zpl', $qrCode) }}"
class="rounded-xl border border-slate-200 px-3.5 py-2 text-xs font-semibold text-slate-600 hover:bg-slate-50 transition">Download ZPL</a> class="rounded-xl border border-slate-200 px-3.5 py-2 text-xs font-semibold text-slate-600 hover:bg-slate-50 transition">Download ZPL</a>
</div> </div>
@endunless @endunless
@@ -144,7 +144,7 @@
</td> </td>
@unless($isContribution) @unless($isContribution)
<td class="px-4 py-3 text-right"> <td class="px-4 py-3 text-right">
<form method="POST" action="{{ route('qr-codes.attendees.check-in', [$qrCode, $reg]) }}"> <form method="POST" action="{{ route('user.qr-codes.attendees.check-in', [$qrCode, $reg]) }}">
@csrf @method('PATCH') @csrf @method('PATCH')
<button type="submit" class="rounded-lg border px-2.5 py-1 text-xs font-semibold transition {{ $reg->checked_in_at ? 'border-emerald-200 bg-emerald-50 text-emerald-700' : 'border-slate-200 text-slate-500 hover:bg-slate-50' }}"> <button type="submit" class="rounded-lg border px-2.5 py-1 text-xs font-semibold transition {{ $reg->checked_in_at ? 'border-emerald-200 bg-emerald-50 text-emerald-700' : 'border-slate-200 text-slate-500 hover:bg-slate-50' }}">
{{ $reg->checked_in_at ? '✓ In' : 'Check in' }} {{ $reg->checked_in_at ? '✓ In' : 'Check in' }}
+6 -22
View File
@@ -2,20 +2,18 @@
<x-slot name="title">Create QR Code</x-slot> <x-slot name="title">Create QR Code</x-slot>
@php @php
$modalId = 'service-topup-qr';
$openTopup = session('open_topup_modal') === 'qr';
$defaultStyle = \App\Support\Qr\QrStyleDefaults::merge(old('style')); $defaultStyle = \App\Support\Qr\QrStyleDefaults::merge(old('style'));
@endphp @endphp
<div class="mx-auto max-w-6xl space-y-6" <div class="mx-auto max-w-6xl space-y-6"
x-data="qrCustomizer({ x-data="qrCustomizer({
previewUrl: @js(route('qr-codes.style-preview')), previewUrl: @js(route('user.qr-codes.style-preview')),
csrf: @js(csrf_token()), csrf: @js(csrf_token()),
shortCode: 'preview', shortCode: 'preview',
style: @js($defaultStyle), style: @js($defaultStyle),
balance: @js((float) $wallet->spendableBalance()), balance: @js((float) $wallet->spendableBalance()),
price: @js((float) $pricePerQr), price: @js((float) $pricePerQr),
topupModalId: @js($modalId), topupUrl: @js($topupUrl),
type: @js(old('type', 'url')), type: @js(old('type', 'url')),
})"> })">
@@ -25,7 +23,7 @@
{{-- Mobile page header --}} {{-- Mobile page header --}}
<div class="flex items-center gap-3 py-1 lg:hidden"> <div class="flex items-center gap-3 py-1 lg:hidden">
<a href="{{ route('qr-codes.index') }}" <a href="{{ route('user.qr-codes.index') }}"
class="flex h-9 w-9 items-center justify-center rounded-xl border border-slate-200 bg-white shadow-sm text-slate-500 hover:text-slate-900 transition"> class="flex h-9 w-9 items-center justify-center rounded-xl border border-slate-200 bg-white shadow-sm text-slate-500 hover:text-slate-900 transition">
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
@@ -36,7 +34,7 @@
{{-- Desktop page header --}} {{-- Desktop page header --}}
<div class="hidden lg:block"> <div class="hidden lg:block">
<a href="{{ route('qr-codes.index') }}" class="inline-flex items-center gap-1 text-sm text-slate-500 hover:text-slate-700"> <a href="{{ route('user.qr-codes.index') }}" class="inline-flex items-center gap-1 text-sm text-slate-500 hover:text-slate-700">
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/></svg> <svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/></svg>
QR Codes QR Codes
</a> </a>
@@ -44,7 +42,7 @@
<p class="mt-1 text-sm text-slate-500">Customize your code, then create.</p> <p class="mt-1 text-sm text-slate-500">Customize your code, then create.</p>
</div> </div>
<form x-ref="createForm" action="{{ route('qr-codes.store') }}" method="POST" enctype="multipart/form-data" <form x-ref="createForm" action="{{ route('user.qr-codes.store') }}" method="POST" enctype="multipart/form-data"
class="grid grid-cols-1 gap-8 lg:grid-cols-[380px_1fr]" class="grid grid-cols-1 gap-8 lg:grid-cols-[380px_1fr]"
@submit="submitOrTopup($event)"> @submit="submitOrTopup($event)">
@csrf @csrf
@@ -77,7 +75,7 @@
slug: @js(old('custom_short_code', '')), slug: @js(old('custom_short_code', '')),
status: '', status: '',
timer: null, timer: null,
checkUrl: @js(route('qr-codes.check-slug')), checkUrl: @js(route('user.qr-codes.check-slug')),
baseUrl: @js(\App\Models\QrCode::publicBaseUrl() . '/q'), baseUrl: @js(\App\Models\QrCode::publicBaseUrl() . '/q'),
check() { check() {
clearTimeout(this.timer); clearTimeout(this.timer);
@@ -250,18 +248,4 @@
</div> </div>
</div> </div>
<x-user.service-topup-modal
:id="$modalId"
title="Add QR credits"
description="Top up your QR balance to create codes."
:topup-action="route('qr-codes.topup')"
:min-topup="$minTopup"
:suggested-amount="max($minTopup, $pricePerQr)"
:ladill-wallet-balance="$ladillWalletBalance"
:service-balance="$wallet->spendableBalance()"
service-balance-label="QR balance"
:return-url="url()->current()"
:open-on-load="$openTopup"
/>
</x-user-layout> </x-user-layout>
+3 -22
View File
@@ -1,17 +1,12 @@
<x-user-layout> <x-user-layout>
<x-slot name="title">QR Codes</x-slot> <x-slot name="title">QR Codes</x-slot>
@php
$modalId = 'service-topup-qr';
$openTopup = session('open_topup_modal') === 'qr';
@endphp
<div class="space-y-6" <div class="space-y-6"
x-data="balanceGate({ x-data="balanceGate({
balance: @js((float) $wallet->spendableBalance()), balance: @js((float) $wallet->spendableBalance()),
price: @js((float) $pricePerQr), price: @js((float) $pricePerQr),
modalId: @js($modalId), topupUrl: @js($topupUrl),
href: @js(route('qr-codes.create')), href: @js(route('user.qr-codes.create')),
})"> })">
@foreach(['success', 'error'] as $flash) @foreach(['success', 'error'] as $flash)
@if(session($flash)) @if(session($flash))
@@ -70,7 +65,7 @@
@else @else
<div class="divide-y divide-slate-100"> <div class="divide-y divide-slate-100">
@foreach($qrCodes as $code) @foreach($qrCodes as $code)
<a href="{{ route('qr-codes.show', $code) }}" class="flex items-center gap-4 px-6 py-4 transition hover:bg-slate-50"> <a href="{{ route('user.qr-codes.show', $code) }}" class="flex items-center gap-4 px-6 py-4 transition hover:bg-slate-50">
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg {{ $code->is_active ? 'bg-violet-100 text-violet-600' : 'bg-slate-100 text-slate-400' }}"> <div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg {{ $code->is_active ? 'bg-violet-100 text-violet-600' : 'bg-slate-100 text-slate-400' }}">
<x-icons.qr-code class="h-5 w-5" /> <x-icons.qr-code class="h-5 w-5" />
</div> </div>
@@ -88,18 +83,4 @@
@endif @endif
</div> </div>
</div> </div>
<x-user.service-topup-modal
:id="$modalId"
title="Add QR credits"
description="Top up your QR balance to create codes."
:topup-action="route('qr-codes.topup')"
:min-topup="$minTopup"
:suggested-amount="max($minTopup, $pricePerQr)"
:ladill-wallet-balance="$ladillWalletBalance"
:service-balance="$wallet->spendableBalance()"
service-balance-label="QR balance"
:return-url="route('qr-codes.index')"
:open-on-load="$openTopup"
/>
</x-user-layout> </x-user-layout>
@@ -16,6 +16,7 @@
balance: config.balance ?? null, balance: config.balance ?? null,
price: config.price ?? null, price: config.price ?? null,
topupModalId: config.topupModalId ?? null, topupModalId: config.topupModalId ?? null,
topupUrl: config.topupUrl ?? null,
canonicalSyncUrl: config.canonicalSyncUrl ?? null, canonicalSyncUrl: config.canonicalSyncUrl ?? null,
csrf: config.csrf ?? null, csrf: config.csrf ?? null,
_canonicalSynced: false, _canonicalSynced: false,
@@ -225,28 +226,36 @@
Object.assign(this, presets[preset] || presets.square); Object.assign(this, presets[preset] || presets.square);
this.schedulePreview(); this.schedulePreview();
}, },
checkBalance(event) { redirectTopup() {
if (this.balance === null || this.price === null || !this.topupModalId) { if (this.topupUrl) {
return; window.location.href = this.topupUrl;
return true;
} }
if (this.balance <= 0 || this.balance < this.price) {
event?.preventDefault();
window.dispatchEvent(new CustomEvent('open-modal', {
detail: this.topupModalId,
bubbles: true,
}));
}
},
submitOrTopup(event) {
if (this.balance <= 0 || this.balance < this.price) {
event?.preventDefault();
if (this.topupModalId) { if (this.topupModalId) {
window.dispatchEvent(new CustomEvent('open-modal', { window.dispatchEvent(new CustomEvent('open-modal', {
detail: this.topupModalId, detail: this.topupModalId,
bubbles: true, bubbles: true,
})); }));
return true;
} }
return false;
},
checkBalance(event) {
if (this.balance === null || this.price === null) {
return;
}
if (this.balance <= 0 || this.balance < this.price) {
event?.preventDefault();
this.redirectTopup();
}
},
submitOrTopup(event) {
if (this.balance <= 0 || this.balance < this.price) {
event?.preventDefault();
this.redirectTopup();
return; return;
} }
@@ -101,7 +101,7 @@
<p class="mb-3 text-[10px] font-semibold uppercase tracking-[0.1em] text-slate-400">Download &amp; Share</p> <p class="mb-3 text-[10px] font-semibold uppercase tracking-[0.1em] text-slate-400">Download &amp; Share</p>
<div class="grid grid-cols-4 gap-2"> <div class="grid grid-cols-4 gap-2">
<a href="{{ route('qr-codes.download', [$qrCode, 'png']) }}" <a href="{{ route('user.qr-codes.download', [$qrCode, 'png']) }}"
class="group flex flex-col items-center gap-1.5 rounded-xl border border-slate-200 bg-white py-3.5 text-center transition hover:border-indigo-300 hover:bg-indigo-50"> class="group flex flex-col items-center gap-1.5 rounded-xl border border-slate-200 bg-white py-3.5 text-center transition hover:border-indigo-300 hover:bg-indigo-50">
<svg class="h-4 w-4 text-slate-400 transition group-hover:text-indigo-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <svg class="h-4 w-4 text-slate-400 transition group-hover:text-indigo-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12M12 16.5V3"/> <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12M12 16.5V3"/>
@@ -109,7 +109,7 @@
<span class="text-xs font-semibold text-slate-600 transition group-hover:text-indigo-700">PNG</span> <span class="text-xs font-semibold text-slate-600 transition group-hover:text-indigo-700">PNG</span>
</a> </a>
<a href="{{ route('qr-codes.download', [$qrCode, 'svg']) }}" <a href="{{ route('user.qr-codes.download', [$qrCode, 'svg']) }}"
class="group flex flex-col items-center gap-1.5 rounded-xl border border-slate-200 bg-white py-3.5 text-center transition hover:border-violet-300 hover:bg-violet-50"> class="group flex flex-col items-center gap-1.5 rounded-xl border border-slate-200 bg-white py-3.5 text-center transition hover:border-violet-300 hover:bg-violet-50">
<svg class="h-4 w-4 text-slate-400 transition group-hover:text-violet-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <svg class="h-4 w-4 text-slate-400 transition group-hover:text-violet-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M7.5 21 3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5"/> <path stroke-linecap="round" stroke-linejoin="round" d="M7.5 21 3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5"/>
@@ -117,7 +117,7 @@
<span class="text-xs font-semibold text-slate-600 transition group-hover:text-violet-700">SVG</span> <span class="text-xs font-semibold text-slate-600 transition group-hover:text-violet-700">SVG</span>
</a> </a>
<a href="{{ route('qr-codes.download', [$qrCode, 'pdf']) }}" <a href="{{ route('user.qr-codes.download', [$qrCode, 'pdf']) }}"
class="group flex flex-col items-center gap-1.5 rounded-xl border border-slate-200 bg-white py-3.5 text-center transition hover:border-rose-300 hover:bg-rose-50"> class="group flex flex-col items-center gap-1.5 rounded-xl border border-slate-200 bg-white py-3.5 text-center transition hover:border-rose-300 hover:bg-rose-50">
<svg class="h-4 w-4 text-slate-400 transition group-hover:text-rose-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <svg class="h-4 w-4 text-slate-400 transition group-hover:text-rose-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"/> <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"/>
@@ -596,11 +596,13 @@
@endif @endif
</div> </div>
<a href="{{ route('qr-codes.attendees', $qrCode) }}" @if (Route::has('user.qr-codes.attendees'))
<a href="{{ route('user.qr-codes.attendees', $qrCode) }}"
class="flex items-center justify-center gap-2 rounded-xl border border-indigo-200 bg-indigo-50 px-4 py-3 text-sm font-semibold text-indigo-700 hover:bg-indigo-100 transition"> class="flex items-center justify-center gap-2 rounded-xl border border-indigo-200 bg-indigo-50 px-4 py-3 text-sm font-semibold text-indigo-700 hover:bg-indigo-100 transition">
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z"/></svg> <svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z"/></svg>
Manage attendees &amp; print badges Manage attendees &amp; print badges
</a> </a>
@endif
</div> </div>
@elseif($qrCode->type === \App\Models\QrCode::TYPE_ITINERARY) @elseif($qrCode->type === \App\Models\QrCode::TYPE_ITINERARY)
+8 -8
View File
@@ -7,9 +7,9 @@
<div class="mx-auto max-w-6xl space-y-6" <div class="mx-auto max-w-6xl space-y-6"
x-data="qrCustomizer({ x-data="qrCustomizer({
previewUrl: @js(route('qr-codes.style-preview')), previewUrl: @js(route('user.qr-codes.style-preview')),
csrf: @js(csrf_token()), csrf: @js(csrf_token()),
canonicalSyncUrl: @js(route('qr-codes.canonical-image', $qrCode)), canonicalSyncUrl: @js(route('user.qr-codes.canonical-image', $qrCode)),
shortCode: @js($qrCode->short_code), shortCode: @js($qrCode->short_code),
qrData: @js($qrCode->encodedPayload()), qrData: @js($qrCode->encodedPayload()),
initialPreview: @js($previewDataUri), initialPreview: @js($previewDataUri),
@@ -29,7 +29,7 @@
{{-- Mobile page header --}} {{-- Mobile page header --}}
<div class="flex items-center gap-3 py-1 lg:hidden"> <div class="flex items-center gap-3 py-1 lg:hidden">
<a href="{{ route('qr-codes.index') }}" <a href="{{ route('user.qr-codes.index') }}"
class="flex h-9 w-9 items-center justify-center rounded-xl border border-slate-200 bg-white shadow-sm text-slate-500 hover:text-slate-900 transition"> class="flex h-9 w-9 items-center justify-center rounded-xl border border-slate-200 bg-white shadow-sm text-slate-500 hover:text-slate-900 transition">
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
@@ -40,7 +40,7 @@
{{-- Desktop page header --}} {{-- Desktop page header --}}
<div class="hidden lg:block"> <div class="hidden lg:block">
<a href="{{ route('qr-codes.index') }}" class="inline-flex items-center gap-1 text-sm text-slate-500 hover:text-slate-700"> <a href="{{ route('user.qr-codes.index') }}" class="inline-flex items-center gap-1 text-sm text-slate-500 hover:text-slate-700">
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/></svg> <svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/></svg>
QR Codes QR Codes
</a> </a>
@@ -55,7 +55,7 @@
</div> </div>
{{-- Main 2-column layout --}} {{-- Main 2-column layout --}}
<form x-ref="updateForm" action="{{ route('qr-codes.update', $qrCode) }}" method="POST" enctype="multipart/form-data" <form x-ref="updateForm" action="{{ route('user.qr-codes.update', $qrCode) }}" method="POST" enctype="multipart/form-data"
class="grid grid-cols-1 gap-8 lg:grid-cols-[380px_1fr]"> class="grid grid-cols-1 gap-8 lg:grid-cols-[380px_1fr]">
@csrf @csrf
@method('PATCH') @method('PATCH')
@@ -193,15 +193,15 @@
$mobileShareEnc = urlencode($mobileShareUrl); $mobileShareEnc = urlencode($mobileShareUrl);
@endphp @endphp
<div class="grid grid-cols-4 gap-2 px-6 pb-6"> <div class="grid grid-cols-4 gap-2 px-6 pb-6">
<a href="{{ route('qr-codes.download', [$qrCode, 'png']) }}" <a href="{{ route('user.qr-codes.download', [$qrCode, 'png']) }}"
class="flex flex-col items-center gap-1 rounded-xl border border-white/20 bg-white/10 py-3 text-center text-white transition hover:bg-white/20"> class="flex flex-col items-center gap-1 rounded-xl border border-white/20 bg-white/10 py-3 text-center text-white transition hover:bg-white/20">
<span class="text-xs font-semibold">PNG</span> <span class="text-xs font-semibold">PNG</span>
</a> </a>
<a href="{{ route('qr-codes.download', [$qrCode, 'svg']) }}" <a href="{{ route('user.qr-codes.download', [$qrCode, 'svg']) }}"
class="flex flex-col items-center gap-1 rounded-xl border border-white/20 bg-white/10 py-3 text-center text-white transition hover:bg-white/20"> class="flex flex-col items-center gap-1 rounded-xl border border-white/20 bg-white/10 py-3 text-center text-white transition hover:bg-white/20">
<span class="text-xs font-semibold">SVG</span> <span class="text-xs font-semibold">SVG</span>
</a> </a>
<a href="{{ route('qr-codes.download', [$qrCode, 'pdf']) }}" <a href="{{ route('user.qr-codes.download', [$qrCode, 'pdf']) }}"
class="flex flex-col items-center gap-1 rounded-xl border border-white/20 bg-white/10 py-3 text-center text-white transition hover:bg-white/20"> class="flex flex-col items-center gap-1 rounded-xl border border-white/20 bg-white/10 py-3 text-center text-white transition hover:bg-white/20">
<span class="text-xs font-semibold">PDF</span> <span class="text-xs font-semibold">PDF</span>
</a> </a>