Files
ladill-events/resources/views/qr/account/settings.blade.php
T
isaaccladandCursor 1bcbdbfdb1
Deploy Ladill Events / deploy (push) Successful in 51s
Make Events payment routing plan-aware.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-21 19:47:10 +00:00

330 lines
24 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<x-user-layout>
<x-slot name="title">Settings</x-slot>
@php
$ed = $eventDefaults;
$badgeFieldLabels = old('event_defaults.badge_fields', $ed['badge_fields'] ?? ['Company', 'Role']);
@endphp
<div class="mx-auto max-w-2xl">
<h1 class="text-xl font-semibold tracking-tight text-slate-900">Settings</h1>
<p class="mt-0.5 text-sm text-slate-500">Notifications, defaults for new events, and QR preferences.</p>
@if (session('success'))
<div class="mt-4 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800">{{ session('success') }}</div>
@endif
<form method="POST" action="{{ route('account.settings.update') }}" enctype="multipart/form-data" class="mt-6 space-y-4">
@csrf
@method('PUT')
<div class="rounded-2xl border border-slate-200 bg-white p-5">
<h2 class="text-sm font-semibold text-slate-900">Notifications</h2>
<p class="mt-1 text-xs text-slate-500">Choose what we email you about your events and account.</p>
<div class="mt-4">
<label for="notify_email" class="block text-[11px] font-medium text-slate-500">Notifications email</label>
<input type="email" id="notify_email" name="notify_email"
value="{{ old('notify_email', $settings->notify_email ?? $account->email) }}"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
@error('notify_email') <p class="mt-1 text-xs text-rose-600">{{ $message }}</p> @enderror
</div>
<label class="mt-4 flex items-center justify-between gap-4">
<span>
<span class="block text-sm font-medium text-slate-800">New registrations</span>
<span class="block text-xs text-slate-400">Email when someone registers or buys a ticket.</span>
</span>
<input type="checkbox" name="notify_registrations" value="1"
@checked(old('notify_registrations', $settings->notify_registrations ?? true))
class="h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500">
</label>
<label class="mt-4 flex items-center justify-between gap-4">
<span>
<span class="block text-sm font-medium text-slate-800">Payouts & settlements</span>
<span class="block text-xs text-slate-400">Email when ticket revenue is ready to withdraw.</span>
</span>
<input type="checkbox" name="notify_payouts" value="1"
@checked(old('notify_payouts', $settings->notify_payouts ?? true))
class="h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500">
</label>
<label class="mt-4 flex items-center justify-between gap-4">
<span>
<span class="block text-sm font-medium text-slate-800">Low QR balance</span>
<span class="block text-xs text-slate-400">Email when your wallet is too low to publish a new event QR.</span>
</span>
<input type="checkbox" name="low_balance_alerts" value="1"
@checked(old('low_balance_alerts', $settings->low_balance_alerts ?? true))
class="h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500">
</label>
<label class="mt-4 flex items-center justify-between gap-4">
<span>
<span class="block text-sm font-medium text-slate-800">Ladill Events updates</span>
<span class="block text-xs text-slate-400">Occasional emails about new features and improvements.</span>
</span>
<input type="checkbox" name="product_updates" value="1"
@checked(old('product_updates', $settings->product_updates ?? true))
class="h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500">
</label>
</div>
<div class="rounded-2xl border border-slate-200 bg-white p-5">
<h2 class="text-sm font-semibold text-slate-900">Company branding</h2>
<p class="mt-1 text-xs text-slate-500">Your logo appears in customer emails (registration confirmations, join links, and programme shares).</p>
@if (\App\Support\AccountBranding::hasCustomLogo($settings))
<div class="mt-4">
<img src="{{ \App\Support\AccountBranding::logoUrl($settings) }}" alt="Company logo" class="h-12 w-auto max-w-[200px] rounded-lg border border-slate-100 bg-slate-50 object-contain p-2">
</div>
<label class="mt-3 flex items-center gap-2 text-sm text-slate-600">
<input type="checkbox" name="remove_logo" value="1" class="rounded border-slate-300 text-rose-600 focus:ring-rose-500">
Remove current logo
</label>
@endif
<div class="mt-4">
<label for="logo" class="block text-[11px] font-medium text-slate-500">{{ \App\Support\AccountBranding::hasCustomLogo($settings) ? 'Replace logo' : 'Upload logo' }}</label>
<input type="file" id="logo" name="logo" accept="image/png,image/jpeg,image/webp,image/svg+xml"
class="mt-1 block w-full text-sm text-slate-600 file:mr-3 file:rounded-lg file:border-0 file:bg-indigo-50 file:px-3 file:py-2 file:text-sm file:font-semibold file:text-indigo-700 hover:file:bg-indigo-100">
@error('logo') <p class="mt-1 text-xs text-rose-600">{{ $message }}</p> @enderror
</div>
</div>
<div class="rounded-2xl border border-slate-200 bg-white p-5">
<h2 class="text-sm font-semibold text-slate-900">New event defaults</h2>
<p class="mt-1 text-xs text-slate-500">Pre-fill the create flow so every new event starts with your usual setup.</p>
<div class="mt-4 grid gap-4 sm:grid-cols-2">
<div>
<label for="default_currency" class="block text-[11px] font-medium text-slate-500">Currency</label>
<select id="default_currency" name="event_defaults[currency]"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
@foreach (['GHS' => 'GHS (Ghanaian Cedi)', 'USD' => 'USD (US Dollar)', 'NGN' => 'NGN (Nigerian Naira)', 'KES' => 'KES (Kenyan Shilling)'] as $code => $label)
<option value="{{ $code }}" @selected(old('event_defaults.currency', $ed['currency']) === $code)>{{ $label }}</option>
@endforeach
</select>
</div>
<div>
<label for="default_mode" class="block text-[11px] font-medium text-slate-500">Collection type</label>
<select id="default_mode" name="event_defaults[mode]"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
<option value="ticketing" @selected(old('event_defaults.mode', $ed['mode']) === 'ticketing')>Ticketed event</option>
<option value="contributions" @selected(old('event_defaults.mode', $ed['mode']) === 'contributions')>Contributions / gifts</option>
<option value="free" @selected(old('event_defaults.mode', $ed['mode']) === 'free')>Free registration</option>
</select>
</div>
</div>
<div class="mt-4 grid gap-4 sm:grid-cols-2">
<div>
<label for="default_badge_size" class="block text-[11px] font-medium text-slate-500">Badge size</label>
<select id="default_badge_size" name="event_defaults[badge_size]"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
@foreach (['4x3' => '4 × 3 in (landscape)', '4x6' => '4 × 6 in (lanyard)', 'cr80' => 'CR80 card'] as $size => $label)
<option value="{{ $size }}" @selected(old('event_defaults.badge_size', $ed['badge_size']) === $size)>{{ $label }}</option>
@endforeach
</select>
</div>
<div>
<label for="default_brand_color" class="block text-[11px] font-medium text-slate-500">Brand color</label>
<input type="color" id="default_brand_color" name="event_defaults[brand_color]"
value="{{ old('event_defaults.brand_color', $ed['brand_color']) }}"
class="mt-1 h-10 w-full cursor-pointer rounded-lg border border-slate-200 bg-white p-1">
</div>
</div>
<div class="mt-4">
<label for="default_organizer" class="block text-[11px] font-medium text-slate-500">Default organizer name</label>
<input type="text" id="default_organizer" name="event_defaults[organizer]" maxlength="120"
value="{{ old('event_defaults.organizer', $ed['organizer']) }}"
placeholder="e.g. CAPBuSS Events"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
</div>
<div class="mt-4" x-data="{ fields: @js(array_values($badgeFieldLabels)) }">
<label class="block text-[11px] font-medium text-slate-500">Default badge fields</label>
<p class="mt-0.5 text-[11px] text-slate-400">Extra attendee fields shown on badges (e.g. Company, Role).</p>
<div class="mt-2 space-y-2">
<template x-for="(field, i) in fields" :key="i">
<div class="flex items-center gap-2">
<input type="text" :name="'event_defaults[badge_fields]['+i+']'" x-model="fields[i]" maxlength="40"
class="flex-1 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
<button type="button" x-show="fields.length > 1" @click="fields.splice(i, 1)"
class="rounded-lg border border-slate-200 px-2 py-1 text-xs text-slate-500 hover:bg-slate-50">Remove</button>
</div>
</template>
</div>
<button type="button" @click="fields.push('')"
class="mt-2 text-xs font-semibold text-indigo-600 hover:text-indigo-800">+ Add field</button>
</div>
<label class="mt-4 flex items-center justify-between gap-4 rounded-xl border border-slate-100 bg-slate-50/80 px-4 py-3">
<span>
<span class="block text-sm font-medium text-slate-800">Registration open by default</span>
<span class="block text-xs text-slate-400">New events accept sign-ups unless you turn this off.</span>
</span>
<input type="checkbox" name="event_defaults[registration_open]" value="1"
@checked(old('event_defaults.registration_open', $ed['registration_open']))
class="h-5 w-5 rounded border-slate-300 text-indigo-600 focus:ring-indigo-500">
</label>
</div>
<details class="group rounded-2xl border border-slate-200 bg-white">
<summary class="cursor-pointer list-none p-5 marker:content-none">
<div class="flex items-center justify-between gap-3">
<div>
<h2 class="text-sm font-semibold text-slate-900">QR code defaults</h2>
<p class="mt-1 text-xs text-slate-500">Style applied when you design event QR codes.</p>
</div>
<svg class="h-5 w-5 shrink-0 text-slate-400 transition group-open:rotate-180" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5"/></svg>
</div>
</summary>
<div class="space-y-4 border-t border-slate-100 px-5 pb-5 pt-4">
<div class="grid gap-4 sm:grid-cols-2">
<div>
<label for="foreground" class="block text-[11px] font-medium text-slate-500">Foreground</label>
<input type="color" id="foreground" name="default_style[foreground]"
value="{{ old('default_style.foreground', $style['foreground']) }}"
class="mt-1 h-10 w-full cursor-pointer rounded-lg border border-slate-200 bg-white p-1">
</div>
<div>
<label for="background" class="block text-[11px] font-medium text-slate-500">Background</label>
<input type="color" id="background" name="default_style[background]"
value="{{ old('default_style.background', $style['background']) }}"
class="mt-1 h-10 w-full cursor-pointer rounded-lg border border-slate-200 bg-white p-1">
</div>
</div>
<div class="grid gap-4 sm:grid-cols-2">
<div>
<label for="module_style" class="block text-[11px] font-medium text-slate-500">Module style</label>
<select id="module_style" name="default_style[module_style]"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
@foreach ($moduleStyles as $key => $meta)
<option value="{{ $key }}" @selected(old('default_style.module_style', $style['module_style']) === $key)>{{ $meta['label'] }}</option>
@endforeach
</select>
</div>
<div>
<label for="error_correction" class="block text-[11px] font-medium text-slate-500">Error correction</label>
<select id="error_correction" name="default_style[error_correction]"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
@foreach (['L' => 'Low', 'M' => 'Medium', 'Q' => 'Quartile', 'H' => 'High'] as $key => $label)
<option value="{{ $key }}" @selected(old('default_style.error_correction', $style['error_correction']) === $key)>{{ $label }} ({{ $key }})</option>
@endforeach
</select>
</div>
</div>
<div class="grid gap-4 sm:grid-cols-2">
<div>
<label for="finder_outer" class="block text-[11px] font-medium text-slate-500">Corner outer</label>
<select id="finder_outer" name="default_style[finder_outer]"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
@foreach ($cornerOuterStyles as $key => $meta)
<option value="{{ $key }}" @selected(old('default_style.finder_outer', $style['finder_outer']) === $key)>{{ $meta['label'] }}</option>
@endforeach
</select>
</div>
<div>
<label for="finder_inner" class="block text-[11px] font-medium text-slate-500">Corner inner</label>
<select id="finder_inner" name="default_style[finder_inner]"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
@foreach ($cornerInnerStyles as $key => $meta)
<option value="{{ $key }}" @selected(old('default_style.finder_inner', $style['finder_inner']) === $key)>{{ $meta['label'] }}</option>
@endforeach
</select>
</div>
</div>
<div class="grid gap-4 sm:grid-cols-2">
<div>
<label for="frame_style" class="block text-[11px] font-medium text-slate-500">Frame</label>
<select id="frame_style" name="default_style[frame_style]"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
@foreach ($frameStyles as $key => $meta)
<option value="{{ $key }}" @selected(old('default_style.frame_style', $style['frame_style']) === $key)>{{ $meta['label'] }}</option>
@endforeach
</select>
</div>
<div>
<label for="frame_color" class="block text-[11px] font-medium text-slate-500">Frame color</label>
<input type="color" id="frame_color" name="default_style[frame_color]"
value="{{ old('default_style.frame_color', $style['frame_color']) }}"
class="mt-1 h-10 w-full cursor-pointer rounded-lg border border-slate-200 bg-white p-1">
</div>
</div>
<div>
<label for="frame_text" class="block text-[11px] font-medium text-slate-500">Frame label</label>
<input type="text" id="frame_text" name="default_style[frame_text]" maxlength="100"
value="{{ old('default_style.frame_text', $style['frame_text']) }}"
placeholder="SCAN ME"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
</div>
</div>
</details>
<div class="rounded-2xl border border-slate-200 bg-white p-5 space-y-4">
<div>
<h2 class="text-base font-semibold text-slate-900">Online payments</h2>
<p class="mt-1 text-sm text-slate-500">Ladill Pay is the recommended default and needs no API keys. Pro and Business may optionally select an owner gateway.</p>
</div>
<p class="rounded-lg bg-emerald-50 px-3 py-2 text-sm text-emerald-800">Ladill Pay is active on all plans and remains the automatic fallback.</p>
@if ($canUsePaymentGateway ?? false)
<select name="gateway_provider" class="w-full rounded-lg border-slate-200 text-sm">
@php $selectedGateway = old('gateway_provider', $gateway?->is_active ? $gateway?->provider : ''); @endphp
<option value="">Ladill Pay (recommended)</option>
@foreach (['paystack' => 'Paystack', 'flutterwave' => 'Flutterwave', 'hubtel' => 'Hubtel'] as $value => $label)
<option value="{{ $value }}" @selected($selectedGateway === $value)>{{ $label }}</option>
@endforeach
</select>
<div class="grid gap-3 sm:grid-cols-2">
<input name="gateway_public_key" value="" placeholder="{{ $gateway?->public_key ? 'Public key saved — leave blank to keep' : 'Public key / merchant account' }}" class="rounded-lg border-slate-200 text-sm">
<input type="password" name="gateway_secret_key" value="" placeholder="{{ $gateway?->secret_key ? 'Secret saved — leave blank to keep' : 'Secret / API key' }}" autocomplete="new-password" class="rounded-lg border-slate-200 text-sm">
</div>
<input type="password" name="gateway_webhook_secret" value="" placeholder="Webhook secret (optional)" autocomplete="new-password" class="w-full rounded-lg border-slate-200 text-sm">
<label class="flex items-center gap-2 text-sm text-slate-700">
<input type="hidden" name="gateway_is_active" value="0">
<input type="checkbox" name="gateway_is_active" value="1" @checked(old('gateway_is_active', $gateway?->is_active ?? false)) class="rounded border-slate-300 text-indigo-600">
Use my gateway instead of Ladill Pay
</label>
<p class="text-xs text-slate-500">Incomplete or invalid credentials automatically fall back to Ladill Pay.</p>
@else
<p class="rounded-lg bg-indigo-50 px-3 py-2 text-sm text-indigo-800">Free uses Ladill Pay only. Upgrade to Pro to optionally connect your own gateway.</p>
@endif
</div>
<button type="submit" class="btn-primary">
Save settings
</button>
</form>
<div class="mt-4 rounded-2xl border border-slate-200 bg-white p-5">
<h2 class="text-sm font-semibold text-slate-900">Messaging</h2>
<p class="mt-1 text-xs text-slate-500">
Attendee and speaker email/SMS use suite messaging by default no Bird or SMS API keys required.
Set a Ladill mailbox (From address) and optional SMS sender ID under Account Messaging.
Plan allowances cover included sends; Pro overage bills your wallet.
</p>
<div class="mt-3 flex flex-wrap gap-x-4 gap-y-2 text-sm font-semibold">
<a href="{{ $messagingSettingsUrl ?? '#' }}" class="text-indigo-600 hover:text-indigo-800" target="_blank" rel="noopener">
Account messaging settings
</a>
<a href="{{ route('account.integrations') }}" class="text-slate-500 hover:text-slate-700">
Advanced: optional product API keys
</a>
</div>
</div>
<p class="mt-6 text-xs text-slate-400">
Profile, password, and security are managed on
<a href="{{ ladill_account_url('account-settings') }}" class="font-medium text-indigo-600 hover:text-indigo-800">account.ladill.com</a>.
</p>
</div>
</x-user-layout>