Files
ladill-events/resources/views/qr/account/integrations.blade.php
T
isaacclad a5ebd1e414
Deploy Ladill Events / deploy (push) Successful in 48s
fix(events): point Messaging settings at suite defaults, not API keys
Mirror Care: suite platform keys count as ready for attendee email/SMS;
Account Messaging is primary, product Bird/SMS keys are advanced.
SmsService now prefers channel=suite before customer API keys.
2026-07-16 11:36:43 +00:00

145 lines
9.3 KiB
PHP

<x-user-layout>
<x-slot name="title">Integrations</x-slot>
<div class="mx-auto max-w-2xl">
<h1 class="text-xl font-semibold tracking-tight text-slate-900">Messaging (advanced)</h1>
<p class="mt-0.5 text-sm text-slate-500">
<strong class="font-semibold text-slate-800">Attendee email and SMS work by default</strong> via suite messaging
set a Ladill mailbox and optional sender ID under
<a href="{{ $messagingSettingsUrl ?? (function_exists('ladill_account_url') ? ladill_account_url('/account/settings/messaging') : (config('smtp.messaging_settings_url') ?? '#')) }}"
class="font-medium text-indigo-600 hover:text-indigo-800" target="_blank" rel="noopener">Account Messaging</a>.
Product
<a href="https://sms.ladill.com" target="_blank" rel="noopener" class="font-medium text-indigo-600 hover:text-indigo-800">SMS</a>
and
<a href="https://bird.ladill.com" target="_blank" rel="noopener" class="font-medium text-indigo-600 hover:text-indigo-800">Bird</a>
API keys below are optional (power users / custom keys).
</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
@if (session('error'))
<div class="mt-4 rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-800">{{ session('error') }}</div>
@endif
<div class="mt-6 space-y-4">
<div class="rounded-2xl border border-slate-200 bg-white p-5">
<h2 class="text-sm font-semibold text-slate-900">SMS</h2>
<p class="mt-1 text-xs text-slate-500">API key and approved sender ID.</p>
@if ($credential->hasValidSms())
<div class="mt-4 rounded-xl border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-800">
Connected · key {{ $credential->sms_api_key_prefix }} · sender <strong>{{ $credential->sms_sender_id }}</strong>
@if ($credential->sms_validated_at)
· validated {{ $credential->sms_validated_at->diffForHumans() }}
@endif
</div>
@elseif ($credential->sms_status === \App\Models\MessagingCredential::STATUS_INVALID)
<div class="mt-4 rounded-xl border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-800">
{{ $credential->sms_last_error ?: 'SMS credentials are invalid.' }}
</div>
@endif
<form method="POST" action="{{ route('account.integrations.sms.save') }}" class="mt-4 space-y-4">
@csrf
<div>
<label class="block text-[11px] font-medium text-slate-500">SMS API key</label>
<input type="password" name="sms_api_key" autocomplete="off" required
placeholder="lsk_sms_live_…"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 font-mono text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
</div>
<div>
<label class="block text-[11px] font-medium text-slate-500">Sender ID</label>
<input type="text" name="sms_sender_id" maxlength="11" required
value="{{ old('sms_sender_id', $credential->sms_sender_id) }}"
placeholder="Approved sender ID"
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">
<p class="mt-1 text-[11px] text-slate-400">Must match an approved sender ID on your SMS service (or the platform default).</p>
</div>
<button type="submit" class="btn-primary">Validate &amp; save</button>
</form>
@if ($credential->sms_api_key_encrypted || $credential->hasValidSms())
<div class="mt-3">
<x-confirm-dialog
name="disconnect-sms"
title="Disconnect SMS?"
message="Outbound SMS will stop until credentials are connected again."
:action="route('account.integrations.sms.disconnect')"
confirm-label="Disconnect"
>
<x-slot:trigger>
<button type="button" class="text-sm text-rose-700 hover:underline">Disconnect</button>
</x-slot:trigger>
</x-confirm-dialog>
</div>
@endif
</div>
<div class="rounded-2xl border border-slate-200 bg-white p-5">
<h2 class="text-sm font-semibold text-slate-900">Email</h2>
<p class="mt-1 text-xs text-slate-500">API key and from address on a verified domain.</p>
@if ($credential->hasValidBird())
<div class="mt-4 rounded-xl border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm text-emerald-800">
Connected · key {{ $credential->bird_api_key_prefix }} · from
<strong>{{ $credential->bird_from_name ? $credential->bird_from_name.' <'.$credential->bird_from_email.'>' : $credential->bird_from_email }}</strong>
@if ($credential->bird_validated_at)
· validated {{ $credential->bird_validated_at->diffForHumans() }}
@endif
</div>
@elseif ($credential->bird_status === \App\Models\MessagingCredential::STATUS_INVALID)
<div class="mt-4 rounded-xl border border-rose-200 bg-rose-50 px-3 py-2 text-sm text-rose-800">
{{ $credential->bird_last_error ?: 'Bird credentials are invalid.' }}
</div>
@endif
<form method="POST" action="{{ route('account.integrations.bird.save') }}" class="mt-4 space-y-4">
@csrf
<div>
<label class="block text-[11px] font-medium text-slate-500">Bird API key</label>
<input type="password" name="bird_api_key" autocomplete="off" required
placeholder="lsk_live_…"
class="mt-1 w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 font-mono text-sm focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
</div>
<div>
<label class="block text-[11px] font-medium text-slate-500">From email</label>
<input type="email" name="bird_from_email" required
value="{{ old('bird_from_email', $credential->bird_from_email) }}"
placeholder="events@yourdomain.com"
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>
<label class="block text-[11px] font-medium text-slate-500">From name</label>
<input type="text" name="bird_from_name" maxlength="100"
value="{{ old('bird_from_name', $credential->bird_from_name ?: $account->name) }}"
placeholder="{{ $account->name }}"
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>
<button type="submit" class="btn-primary">Validate &amp; save</button>
</form>
@if ($credential->bird_api_key_encrypted || $credential->hasValidBird())
<div class="mt-3">
<x-confirm-dialog
name="disconnect-bird"
title="Disconnect email?"
message="Outbound email will stop until credentials are connected again."
:action="route('account.integrations.bird.disconnect')"
confirm-label="Disconnect"
>
<x-slot:trigger>
<button type="button" class="text-sm text-rose-700 hover:underline">Disconnect</button>
</x-slot:trigger>
</x-confirm-dialog>
</div>
@endif
</div>
</div>
<p class="mt-6 text-xs text-slate-400">
<a href="{{ route('account.settings') }}" class="font-medium text-indigo-600 hover:text-indigo-800"> Back to settings</a>
</p>
</div>
</x-user-layout>