invitation-row.tsx41 lines · main
1'use client';
2
3import { useTransition } from 'react';
4
5interface Invitation {
6 id: string;
7 email: string;
8 role: string;
9 expiresAt: string;
10}
11
12interface Props {
13 invitation: Invitation;
14 onRevoke: (invitationId: string) => Promise<void>;
15}
16
17export function InvitationRow({ invitation, onRevoke }: Props) {
18 const [pending, startTransition] = useTransition();
19
20 return (
21 <li className="flex items-center justify-between rounded-md border border-[var(--color-border-subtle)] bg-[var(--color-surface)] px-4 py-2">
22 <div>
23 <p className="font-mono text-sm">
24 {invitation.email}{' '}
25 <span className="text-[var(--color-text-subtle)]">· pending · {invitation.role}</span>
26 </p>
27 <p className="mt-0.5 font-mono text-xs text-[var(--color-text-subtle)]">
28 expires {new Date(invitation.expiresAt).toISOString().slice(0, 10)}
29 </p>
30 </div>
31 <button
32 type="button"
33 disabled={pending}
34 onClick={() => startTransition(() => onRevoke(invitation.id))}
35 className="rounded-md border border-[var(--color-border)] px-3 py-1.5 font-mono text-xs text-[var(--color-text-muted)] hover:border-red-400 hover:text-red-400 disabled:opacity-50"
36 >
37 {pending ? 'revoking...' : 'revoke'}
38 </button>
39 </li>
40 );
41}