Replace native confirm() dialogs with styled confirm modals.
Deploy Ladill QR Plus / deploy (push) Successful in 27s
Deploy Ladill QR Plus / deploy (push) Successful in 27s
Add shared confirm-dialog component, Alpine ladillConfirm store, and swap browser confirms for consistent bottom-sheet modals across user, admin, and hosting flows. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+7
-1
@@ -205,7 +205,13 @@ switch_current_release() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log "Switching current release"
|
log "Switching current release"
|
||||||
switch_current_release
|
if ! switch_current_release; then
|
||||||
|
echo "Failed to point $CURRENT_LINK at $NEW_RELEASE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
LIVE_REV="$(cat "$CURRENT_LINK/REVISION" 2>/dev/null || echo unknown)"
|
||||||
|
log "Live release: $STAMP (revision $LIVE_REV)"
|
||||||
|
|
||||||
log "Optimizing Laravel"
|
log "Optimizing Laravel"
|
||||||
if [ -L "$CURRENT_LINK" ] && [ -f "$CURRENT_LINK/artisan" ]; then
|
if [ -L "$CURRENT_LINK" ] && [ -f "$CURRENT_LINK/artisan" ]; then
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import './bootstrap';
|
import './bootstrap';
|
||||||
|
|
||||||
|
import { registerLadillConfirmStore, registerLadillModalHelpers } from './ladill-modals';
|
||||||
|
|
||||||
|
registerLadillModalHelpers();
|
||||||
|
|
||||||
|
|
||||||
import Alpine from 'alpinejs';
|
import Alpine from 'alpinejs';
|
||||||
import collapse from '@alpinejs/collapse';
|
import collapse from '@alpinejs/collapse';
|
||||||
import QRCodeStyling from 'qr-code-styling';
|
import QRCodeStyling from 'qr-code-styling';
|
||||||
@@ -191,4 +196,6 @@ Alpine.data('topbarSearch', (config = {}) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
window.Alpine = Alpine;
|
window.Alpine = Alpine;
|
||||||
|
registerLadillConfirmStore(Alpine);
|
||||||
|
|
||||||
Alpine.start();
|
Alpine.start();
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* Lightweight modal dispatch helpers (optional — balanceGate in layout is primary).
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function openLadillModal(name) {
|
||||||
|
if (!name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.dispatchEvent(new CustomEvent('open-modal', { detail: name, bubbles: true }));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeLadillModal(name) {
|
||||||
|
if (!name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.dispatchEvent(new CustomEvent('close-modal', { detail: name, bubbles: true }));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ladillNeedsTopup(balance, price) {
|
||||||
|
const normalizedBalance = Number.parseFloat(balance);
|
||||||
|
const normalizedPrice = Number.parseFloat(price);
|
||||||
|
|
||||||
|
if (!Number.isFinite(normalizedBalance) || !Number.isFinite(normalizedPrice)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedBalance <= 0 || normalizedBalance < normalizedPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerLadillConfirmStore(Alpine) {
|
||||||
|
Alpine.store('ladillConfirm', {
|
||||||
|
open: false,
|
||||||
|
title: '',
|
||||||
|
message: '',
|
||||||
|
confirmLabel: 'Confirm',
|
||||||
|
cancelLabel: 'Cancel',
|
||||||
|
variant: 'danger',
|
||||||
|
_resolve: null,
|
||||||
|
|
||||||
|
ask(options = {}) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.title = options.title || 'Are you sure?';
|
||||||
|
this.message = options.message || '';
|
||||||
|
this.confirmLabel = options.confirmLabel || 'Confirm';
|
||||||
|
this.cancelLabel = options.cancelLabel || 'Cancel';
|
||||||
|
this.variant = options.variant || 'danger';
|
||||||
|
this._resolve = resolve;
|
||||||
|
this.open = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
answer(confirmed) {
|
||||||
|
if (this._resolve) {
|
||||||
|
this._resolve(confirmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.open = false;
|
||||||
|
this._resolve = null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
window.ladillConfirm = (options = {}) => Alpine.store('ladillConfirm').ask(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerLadillModalHelpers() {
|
||||||
|
window.openLadillModal = openLadillModal;
|
||||||
|
window.closeLadillModal = closeLadillModal;
|
||||||
|
window.ladillNeedsTopup = ladillNeedsTopup;
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
@props([
|
||||||
|
'name',
|
||||||
|
'title',
|
||||||
|
'message' => null,
|
||||||
|
'action',
|
||||||
|
'method' => 'POST',
|
||||||
|
'confirmLabel' => 'Confirm',
|
||||||
|
'cancelLabel' => 'Cancel',
|
||||||
|
'variant' => 'danger',
|
||||||
|
])
|
||||||
|
|
||||||
|
@php
|
||||||
|
$confirmBtnClass = $variant === 'danger'
|
||||||
|
? 'bg-red-600 hover:bg-red-700'
|
||||||
|
: 'bg-violet-600 hover:bg-violet-700';
|
||||||
|
$iconWrapClass = $variant === 'danger'
|
||||||
|
? 'bg-red-100 text-red-600'
|
||||||
|
: 'bg-violet-100 text-violet-600';
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
@if(isset($trigger))
|
||||||
|
<span @click.stop="$dispatch('open-modal', {{ Js::from($name) }})" class="inline-flex">
|
||||||
|
{{ $trigger }}
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<x-modal :name="$name" maxWidth="md">
|
||||||
|
<div class="px-5 pb-6 pt-2 sm:px-6 sm:pb-6 sm:pt-4">
|
||||||
|
<div class="flex flex-col items-center text-center sm:items-start sm:text-left">
|
||||||
|
<div @class(['flex h-12 w-12 items-center justify-center rounded-full', $iconWrapClass])>
|
||||||
|
@if($variant === 'danger')
|
||||||
|
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"/>
|
||||||
|
</svg>
|
||||||
|
@else
|
||||||
|
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z"/>
|
||||||
|
</svg>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<h2 class="mt-4 text-lg font-semibold text-slate-900">{{ $title }}</h2>
|
||||||
|
@if($message)
|
||||||
|
<p class="mt-2 text-sm leading-relaxed text-slate-500">{{ $message }}</p>
|
||||||
|
@endif
|
||||||
|
@isset($details)
|
||||||
|
<div class="mt-3 w-full">{{ $details }}</div>
|
||||||
|
@endisset
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" action="{{ $action }}" class="mt-6 flex flex-col-reverse gap-2.5 sm:flex-row sm:justify-end">
|
||||||
|
@csrf
|
||||||
|
@if(strtoupper($method) !== 'POST')
|
||||||
|
@method($method)
|
||||||
|
@endif
|
||||||
|
@isset($fields)
|
||||||
|
{{ $fields }}
|
||||||
|
@endisset
|
||||||
|
<button type="button"
|
||||||
|
@click="$dispatch('close-modal', {{ Js::from($name) }})"
|
||||||
|
class="rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm font-semibold text-slate-700 transition hover:bg-slate-50">
|
||||||
|
{{ $cancelLabel }}
|
||||||
|
</button>
|
||||||
|
<button type="submit"
|
||||||
|
@class(['rounded-xl px-4 py-2.5 text-sm font-semibold text-white transition', $confirmBtnClass])>
|
||||||
|
{{ $confirmLabel }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</x-modal>
|
||||||
@@ -46,10 +46,18 @@
|
|||||||
{{ $token->last_used_at ? 'last used '.$token->last_used_at->diffForHumans() : 'never used' }}
|
{{ $token->last_used_at ? 'last used '.$token->last_used_at->diffForHumans() : 'never used' }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<form method="POST" action="{{ route('account.developers.destroy', $token->id) }}" onsubmit="return confirm('Revoke {{ $token->name }}?')">
|
<x-confirm-dialog
|
||||||
@csrf @method('DELETE')
|
:name="'revoke-token-'.$token->id"
|
||||||
<button class="text-xs font-medium text-rose-600 hover:underline">Revoke</button>
|
title="Revoke API token?"
|
||||||
</form>
|
:message="'Revoke '.$token->name.'? Apps using this token will stop working.'"
|
||||||
|
:action="route('account.developers.destroy', $token->id)"
|
||||||
|
method="DELETE"
|
||||||
|
confirm-label="Revoke"
|
||||||
|
>
|
||||||
|
<x-slot:trigger>
|
||||||
|
<button type="button" class="text-xs font-medium text-rose-600 hover:underline">Revoke</button>
|
||||||
|
</x-slot:trigger>
|
||||||
|
</x-confirm-dialog>
|
||||||
</div>
|
</div>
|
||||||
@empty
|
@empty
|
||||||
<p class="px-5 py-8 text-center text-sm text-slate-400">No tokens yet.</p>
|
<p class="px-5 py-8 text-center text-sm text-slate-400">No tokens yet.</p>
|
||||||
|
|||||||
@@ -22,13 +22,22 @@
|
|||||||
<div class="mt-4 rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2.5 text-sm text-emerald-800">
|
<div class="mt-4 rounded-lg border border-emerald-200 bg-emerald-50 px-3 py-2.5 text-sm text-emerald-800">
|
||||||
Linked mailbox: <span class="font-semibold">{{ $linkStatus['linked_mailbox'] }}</span>
|
Linked mailbox: <span class="font-semibold">{{ $linkStatus['linked_mailbox'] }}</span>
|
||||||
</div>
|
</div>
|
||||||
<form method="POST" action="{{ route('account.settings.mailbox-unlink') }}" class="mt-3"
|
<x-confirm-dialog
|
||||||
onsubmit="return confirm('Unlink this mailbox from your Ladill account? Ladill Mail will no longer open automatically with Ladill sign-in.')">
|
name="unlink-mailbox"
|
||||||
@csrf @method('DELETE')
|
title="Unlink mailbox?"
|
||||||
<button type="submit" class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-semibold text-slate-700 transition hover:border-slate-300 hover:bg-slate-50">
|
message="Unlink this mailbox from your Ladill account? Ladill Mail will no longer open automatically with Ladill sign-in."
|
||||||
Unlink mailbox
|
:action="route('account.settings.mailbox-unlink')"
|
||||||
</button>
|
method="DELETE"
|
||||||
</form>
|
confirm-label="Unlink"
|
||||||
|
variant="primary"
|
||||||
|
class="mt-3"
|
||||||
|
>
|
||||||
|
<x-slot:trigger>
|
||||||
|
<button type="button" class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-semibold text-slate-700 transition hover:border-slate-300 hover:bg-slate-50">
|
||||||
|
Unlink mailbox
|
||||||
|
</button>
|
||||||
|
</x-slot:trigger>
|
||||||
|
</x-confirm-dialog>
|
||||||
@elseif(($linkStatus['stage'] ?? '') === 'needs_domain')
|
@elseif(($linkStatus['stage'] ?? '') === 'needs_domain')
|
||||||
<p class="mt-3 text-sm text-amber-800">Add and verify an email domain first.</p>
|
<p class="mt-3 text-sm text-amber-800">Add and verify an email domain first.</p>
|
||||||
<a href="{{ route('email.domains.index') }}" class="mt-3 inline-flex items-center gap-1 text-sm font-semibold text-indigo-700 hover:text-indigo-800">
|
<a href="{{ route('email.domains.index') }}" class="mt-3 inline-flex items-center gap-1 text-sm font-semibold text-indigo-700 hover:text-indigo-800">
|
||||||
|
|||||||
@@ -64,10 +64,18 @@
|
|||||||
<option value="admin" @selected($member->role === 'admin')>Admin</option>
|
<option value="admin" @selected($member->role === 'admin')>Admin</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
<form method="POST" action="{{ route('account.team.destroy', $member) }}" onsubmit="return confirm('Remove {{ $member->email }}?')">
|
<x-confirm-dialog
|
||||||
@csrf @method('DELETE')
|
:name="'remove-member-'.$member->id"
|
||||||
<button class="text-xs font-medium text-rose-600 hover:underline">Remove</button>
|
title="Remove team member?"
|
||||||
</form>
|
:message="'Remove '.$member->email.' from this team?'"
|
||||||
|
:action="route('account.team.destroy', $member)"
|
||||||
|
method="DELETE"
|
||||||
|
confirm-label="Remove"
|
||||||
|
>
|
||||||
|
<x-slot:trigger>
|
||||||
|
<button type="button" class="text-xs font-medium text-rose-600 hover:underline">Remove</button>
|
||||||
|
</x-slot:trigger>
|
||||||
|
</x-confirm-dialog>
|
||||||
@else
|
@else
|
||||||
<span class="rounded-full bg-slate-100 px-2.5 py-1 text-[11px] font-medium capitalize text-slate-600">{{ $member->role }}</span>
|
<span class="rounded-full bg-slate-100 px-2.5 py-1 text-[11px] font-medium capitalize text-slate-600">{{ $member->role }}</span>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@@ -54,9 +54,18 @@
|
|||||||
</div>
|
</div>
|
||||||
@endunless
|
@endunless
|
||||||
|
|
||||||
<form method="POST" action="{{ route('email.domains.destroy', $domain['id']) }}" class="mt-4" onsubmit="return confirm('Remove {{ $domain['domain'] }}?')">
|
<x-confirm-dialog
|
||||||
@csrf @method('DELETE')
|
:name="'remove-domain-'.$domain['id']"
|
||||||
<button class="text-xs font-medium text-rose-600 hover:underline">Remove domain</button>
|
title="Remove domain?"
|
||||||
</form>
|
:message="'Remove '.$domain['domain'].'?'"
|
||||||
|
:action="route('email.domains.destroy', $domain['id'])"
|
||||||
|
method="DELETE"
|
||||||
|
confirm-label="Remove domain"
|
||||||
|
class="mt-4"
|
||||||
|
>
|
||||||
|
<x-slot:trigger>
|
||||||
|
<button type="button" class="text-xs font-medium text-rose-600 hover:underline">Remove domain</button>
|
||||||
|
</x-slot:trigger>
|
||||||
|
</x-confirm-dialog>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
@@ -74,10 +74,19 @@
|
|||||||
<div class="mt-4 rounded-2xl border border-rose-200 bg-white p-5">
|
<div class="mt-4 rounded-2xl border border-rose-200 bg-white p-5">
|
||||||
<h2 class="text-sm font-semibold text-rose-700">Delete mailbox</h2>
|
<h2 class="text-sm font-semibold text-rose-700">Delete mailbox</h2>
|
||||||
<p class="mt-0.5 text-xs text-slate-400">This permanently removes the mailbox and its email.</p>
|
<p class="mt-0.5 text-xs text-slate-400">This permanently removes the mailbox and its email.</p>
|
||||||
<form method="POST" action="{{ route('email.mailboxes.destroy', $mailbox['id']) }}" class="mt-3" onsubmit="return confirm('Delete {{ $mailbox['address'] }}? This cannot be undone.')">
|
<x-confirm-dialog
|
||||||
@csrf @method('DELETE')
|
:name="'delete-mailbox-'.$mailbox['id']"
|
||||||
<button class="rounded-lg bg-rose-600 px-4 py-2 text-sm font-semibold text-white hover:bg-rose-700">Delete mailbox</button>
|
title="Delete mailbox?"
|
||||||
</form>
|
:message="'Delete '.$mailbox['address'].'? This cannot be undone.'"
|
||||||
|
:action="route('email.mailboxes.destroy', $mailbox['id'])"
|
||||||
|
method="DELETE"
|
||||||
|
confirm-label="Delete mailbox"
|
||||||
|
class="mt-3"
|
||||||
|
>
|
||||||
|
<x-slot:trigger>
|
||||||
|
<button type="button" class="rounded-lg bg-rose-600 px-4 py-2 text-sm font-semibold text-white hover:bg-rose-700">Delete mailbox</button>
|
||||||
|
</x-slot:trigger>
|
||||||
|
</x-confirm-dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
@@ -55,5 +55,6 @@
|
|||||||
])
|
])
|
||||||
@include('partials.afia')
|
@include('partials.afia')
|
||||||
@endauth
|
@endauth
|
||||||
|
@include('partials.confirm-prompt')
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -270,5 +270,6 @@ document.addEventListener('keydown', (e) => {
|
|||||||
</script>
|
</script>
|
||||||
@include('partials.afia')
|
@include('partials.afia')
|
||||||
@include('partials.sso-keepalive')
|
@include('partials.sso-keepalive')
|
||||||
|
@include('partials.confirm-prompt')
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<div
|
||||||
|
x-cloak
|
||||||
|
x-show="$store.ladillConfirm.open"
|
||||||
|
x-transition:enter="transition-opacity ease-out duration-200"
|
||||||
|
x-transition:enter-start="opacity-0"
|
||||||
|
x-transition:enter-end="opacity-100"
|
||||||
|
x-transition:leave="transition-opacity ease-in duration-150"
|
||||||
|
x-transition:leave-start="opacity-100"
|
||||||
|
x-transition:leave-end="opacity-0"
|
||||||
|
class="fixed inset-0 z-[60] flex items-end sm:items-center sm:justify-center"
|
||||||
|
style="background: rgba(0,0,0,0.45); backdrop-filter: blur(3px);"
|
||||||
|
@keydown.escape.window="$store.ladillConfirm.answer(false)"
|
||||||
|
>
|
||||||
|
<div class="absolute inset-0" @click="$store.ladillConfirm.answer(false)"></div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
x-show="$store.ladillConfirm.open"
|
||||||
|
class="relative z-10 w-full max-h-[90vh] overflow-y-auto rounded-t-3xl bg-white shadow-2xl sm:mb-6 sm:max-h-[85vh] sm:max-w-md sm:rounded-2xl sm:border sm:border-gray-200"
|
||||||
|
x-transition:enter="ease-out duration-300"
|
||||||
|
x-transition:enter-start="translate-y-full sm:translate-y-0 sm:opacity-0 sm:scale-95"
|
||||||
|
x-transition:enter-end="translate-y-0 sm:opacity-100 sm:scale-100"
|
||||||
|
x-transition:leave="ease-in duration-200"
|
||||||
|
x-transition:leave-start="translate-y-0 sm:opacity-100 sm:scale-100"
|
||||||
|
x-transition:leave-end="translate-y-full sm:translate-y-0 sm:opacity-0 sm:scale-95"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<div class="flex justify-center pb-1 pt-3 sm:hidden">
|
||||||
|
<div class="h-1 w-10 rounded-full bg-slate-200"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="px-5 pb-6 pt-2 sm:px-6 sm:pb-6 sm:pt-4">
|
||||||
|
<div class="flex flex-col items-center text-center sm:items-start sm:text-left">
|
||||||
|
<div class="flex h-12 w-12 items-center justify-center rounded-full"
|
||||||
|
:class="$store.ladillConfirm.variant === 'primary' ? 'bg-violet-100 text-violet-600' : 'bg-red-100 text-red-600'">
|
||||||
|
<template x-if="$store.ladillConfirm.variant === 'primary'">
|
||||||
|
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z"/>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
<template x-if="$store.ladillConfirm.variant !== 'primary'">
|
||||||
|
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"/>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<h2 class="mt-4 text-lg font-semibold text-slate-900" x-text="$store.ladillConfirm.title"></h2>
|
||||||
|
<p x-show="$store.ladillConfirm.message" class="mt-2 whitespace-pre-line text-sm leading-relaxed text-slate-500" x-text="$store.ladillConfirm.message"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6 flex flex-col-reverse gap-2.5 sm:flex-row sm:justify-end">
|
||||||
|
<button type="button"
|
||||||
|
@click="$store.ladillConfirm.answer(false)"
|
||||||
|
class="rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm font-semibold text-slate-700 transition hover:bg-slate-50"
|
||||||
|
x-text="$store.ladillConfirm.cancelLabel">
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
@click="$store.ladillConfirm.answer(true)"
|
||||||
|
class="rounded-xl px-4 py-2.5 text-sm font-semibold text-white transition"
|
||||||
|
:class="$store.ladillConfirm.variant === 'primary' ? 'bg-violet-600 hover:bg-violet-700' : 'bg-red-600 hover:bg-red-700'"
|
||||||
|
x-text="$store.ladillConfirm.confirmLabel">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -43,7 +43,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<form method="POST" action="{{ route('user.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="async ($event) => {
|
||||||
|
if (busy) return;
|
||||||
|
if (! await $store.ladillConfirm.ask({
|
||||||
|
title: 'Send programme?',
|
||||||
|
message: 'Send the programme outline to all confirmed attendees by email and SMS?',
|
||||||
|
confirmLabel: 'Send',
|
||||||
|
variant: 'primary',
|
||||||
|
})) { $event.preventDefault(); return; }
|
||||||
|
busy = true;
|
||||||
|
}"
|
||||||
class="shrink-0">
|
class="shrink-0">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" :disabled="busy"
|
<button type="submit" :disabled="busy"
|
||||||
|
|||||||
@@ -43,10 +43,18 @@
|
|||||||
{{ $token->last_used_at ? 'last used '.$token->last_used_at->diffForHumans() : 'never used' }}
|
{{ $token->last_used_at ? 'last used '.$token->last_used_at->diffForHumans() : 'never used' }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<form method="POST" action="{{ route('account.developers.destroy', $token->id) }}" onsubmit="return confirm('Revoke {{ $token->name }}?')">
|
<x-confirm-dialog
|
||||||
@csrf @method('DELETE')
|
:name="'revoke-token-'.$token->id"
|
||||||
<button class="text-xs font-medium text-rose-600 hover:underline">Revoke</button>
|
title="Revoke API token?"
|
||||||
</form>
|
:message="'Revoke '.$token->name.'? Apps using this token will stop working.'"
|
||||||
|
:action="route('account.developers.destroy', $token->id)"
|
||||||
|
method="DELETE"
|
||||||
|
confirm-label="Revoke"
|
||||||
|
>
|
||||||
|
<x-slot:trigger>
|
||||||
|
<button type="button" class="text-xs font-medium text-rose-600 hover:underline">Revoke</button>
|
||||||
|
</x-slot:trigger>
|
||||||
|
</x-confirm-dialog>
|
||||||
</div>
|
</div>
|
||||||
@empty
|
@empty
|
||||||
<p class="px-5 py-8 text-center text-sm text-slate-400">No tokens yet.</p>
|
<p class="px-5 py-8 text-center text-sm text-slate-400">No tokens yet.</p>
|
||||||
|
|||||||
@@ -66,10 +66,18 @@
|
|||||||
<option value="admin" @selected($member->role === 'admin')>Admin</option>
|
<option value="admin" @selected($member->role === 'admin')>Admin</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
<form method="POST" action="{{ route('account.team.destroy', $member) }}" onsubmit="return confirm('Remove {{ $member->email }}?')">
|
<x-confirm-dialog
|
||||||
@csrf @method('DELETE')
|
:name="'remove-member-'.$member->id"
|
||||||
<button class="text-xs font-medium text-rose-600 hover:underline">Remove</button>
|
title="Remove team member?"
|
||||||
</form>
|
:message="'Remove '.$member->email.' from this team?'"
|
||||||
|
:action="route('account.team.destroy', $member)"
|
||||||
|
method="DELETE"
|
||||||
|
confirm-label="Remove"
|
||||||
|
>
|
||||||
|
<x-slot:trigger>
|
||||||
|
<button type="button" class="text-xs font-medium text-rose-600 hover:underline">Remove</button>
|
||||||
|
</x-slot:trigger>
|
||||||
|
</x-confirm-dialog>
|
||||||
@else
|
@else
|
||||||
<span class="rounded-full bg-slate-100 px-2.5 py-1 text-[11px] font-medium capitalize text-slate-600">{{ $member->role }}</span>
|
<span class="rounded-full bg-slate-100 px-2.5 py-1 text-[11px] font-medium capitalize text-slate-600">{{ $member->role }}</span>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
Reference in New Issue
Block a user