--- import AppLayout from '../../layouts/AppLayout.astro'; import { getAllInvites, getAllUsersPublic, revokeInvite, createInvite, updateUserRole, deactivateUser, } from '../../lib/db'; import { generateInviteToken, inviteExpiresAt } from '../../lib/auth'; import { fmtDate } from '../../lib/markdown'; import type { Role } from '../../lib/db'; const user = Astro.locals.user; // Guard: fenja only if (user.role !== 'fenja') { return Astro.redirect('/'); } const tab = Astro.url.searchParams.get('tab') ?? 'invitations'; let newInviteToken: string | null = null; let formError: string | null = null; let actionMsg: string | null = null; if (Astro.request.method === 'POST') { const data = await Astro.request.formData(); const action = String(data.get('action') ?? ''); if (action === 'create_invite') { const name = String(data.get('name') ?? '').trim(); const email = String(data.get('email') ?? '').trim().toLowerCase(); const organisation = String(data.get('organisation') ?? '').trim(); const role = String(data.get('role') ?? '') as Role; if (!name || !email || !organisation || !['pilot','cab','fenja'].includes(role)) { formError = 'All fields are required.'; } else { const { token, tokenHash } = generateInviteToken(); createInvite({ token_hash: tokenHash, email, name, organisation, role, expires_at: inviteExpiresAt(), created_by_user_id: user.id, }); newInviteToken = `${Astro.url.origin}/invite/${token}`; } } else if (action === 'revoke_invite') { const id = Number(data.get('invite_id')); if (id) revokeInvite(id); return Astro.redirect('/admin?tab=invitations&msg=revoked'); } else if (action === 'change_role') { const userId = Number(data.get('user_id')); const newRole = String(data.get('role')) as Role; if (userId && ['pilot','cab','fenja'].includes(newRole)) { updateUserRole(userId, newRole); } return Astro.redirect('/admin?tab=participants&msg=updated'); } else if (action === 'deactivate_user') { const userId = Number(data.get('user_id')); if (userId && userId !== user.id) deactivateUser(userId); return Astro.redirect('/admin?tab=participants&msg=deactivated'); } } const invites = getAllInvites(); const users = getAllUsersPublic(); actionMsg = Astro.url.searchParams.get('msg'); ---
{actionMsg && (

{actionMsg === 'revoked' ? 'Invite revoked.' : actionMsg === 'updated' ? 'Role updated.' : actionMsg === 'deactivated' ? 'User deactivated.' : ''}

)} {tab === 'invitations' && (
{/* New invite form */}

Generate invite link

{formError && ( )} {newInviteToken && (

Copy this link and send it personally. It expires in 14 days and is single-use.

)}
{/* Invite table */}

Outstanding invites

{invites.filter((i) => !i.used_at).length === 0 ? (

No outstanding invites.

) : ( {invites.filter((i) => !i.used_at).map((invite) => ( ))}
Name Email Organisation Role Expires Action
{invite.name} {invite.email} {invite.organisation} {invite.role} {fmtDate(invite.expires_at)}
)}
)} {tab === 'participants' && (

All participants

{users.map((u) => ( ))}
Name Email Organisation Role Last seen Actions
{u.name} {u.email} {u.organisation} {u.id !== user.id ? (
) : ( {u.role} )}
{u.last_seen_at ? fmtDate(u.last_seen_at) : 'Never'} {u.id !== user.id && (
)}
)}