98 lines
3.1 KiB
TypeScript
98 lines
3.1 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import AdminGuard from '@/components/admin-guard';
|
|
import { guestsApi, type Guest } from '@/lib/api';
|
|
|
|
export default function AdminGuestsPage() {
|
|
return (
|
|
<AdminGuard>
|
|
<GuestsManager />
|
|
</AdminGuard>
|
|
);
|
|
}
|
|
|
|
function GuestsManager() {
|
|
const [guests, setGuests] = useState<Guest[]>([]);
|
|
const [name, setName] = useState('');
|
|
const [busy, setBusy] = useState(false);
|
|
const [err, setErr] = useState('');
|
|
|
|
const load = async () => setGuests(await guestsApi.list());
|
|
useEffect(() => { load(); }, []);
|
|
|
|
const linkFor = (g: Guest) => {
|
|
const base = typeof window === 'undefined' ? '' : window.location.origin;
|
|
return `${base}/?usr=${g.id}`;
|
|
};
|
|
|
|
const onCreate = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setErr('');
|
|
if (!name.trim()) return;
|
|
setBusy(true);
|
|
try {
|
|
await guestsApi.create(name.trim());
|
|
setName('');
|
|
await load();
|
|
} catch (e: any) {
|
|
setErr(e.message || 'Erro ao criar');
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
};
|
|
|
|
const onRename = async (g: Guest) => {
|
|
const next = prompt('Novo nome', g.name);
|
|
if (!next || next.trim() === g.name) return;
|
|
await guestsApi.rename(g.id, next.trim());
|
|
await load();
|
|
};
|
|
|
|
const onDelete = async (g: Guest) => {
|
|
if (!confirm(`Excluir o convidado ${g.name}? As reservas dele(a) ficarão sem dono.`)) return;
|
|
await guestsApi.delete(g.id);
|
|
await load();
|
|
};
|
|
|
|
const onCopy = async (g: Guest) => {
|
|
await navigator.clipboard.writeText(linkFor(g));
|
|
};
|
|
|
|
return (
|
|
<div className="max-w-3xl mx-auto p-6 space-y-6">
|
|
<h1 className="text-2xl font-bold">Convidados</h1>
|
|
|
|
<form onSubmit={onCreate} className="flex gap-2">
|
|
<input
|
|
value={name}
|
|
onChange={(e) => setName(e.target.value)}
|
|
placeholder="Nome do convidado"
|
|
className="flex-1 border rounded px-3 py-2"
|
|
/>
|
|
<button disabled={busy} className="bg-indigo-600 text-white rounded px-4 py-2 disabled:opacity-50">
|
|
{busy ? 'Criando…' : 'Criar link'}
|
|
</button>
|
|
</form>
|
|
{err && <div className="text-red-600 text-sm">{err}</div>}
|
|
|
|
<ul className="divide-y border rounded">
|
|
{guests.map((g) => (
|
|
<li key={g.id} className="p-3 flex items-center justify-between gap-3">
|
|
<div className="flex-1 min-w-0">
|
|
<div className="font-medium truncate">{g.name}</div>
|
|
<div className="text-xs text-gray-500 truncate">{linkFor(g)}</div>
|
|
</div>
|
|
<div className="flex gap-2 shrink-0">
|
|
<button onClick={() => onCopy(g)} className="text-sm border rounded px-2 py-1">Copiar link</button>
|
|
<button onClick={() => onRename(g)} className="text-sm border rounded px-2 py-1">Renomear</button>
|
|
<button onClick={() => onDelete(g)} className="text-sm border rounded px-2 py-1 text-red-600">Excluir</button>
|
|
</div>
|
|
</li>
|
|
))}
|
|
{guests.length === 0 && <li className="p-3 text-gray-500 text-sm">Nenhum convidado ainda</li>}
|
|
</ul>
|
|
</div>
|
|
);
|
|
}
|