diff --git a/src/app/api/invites/[id]/route.ts b/src/app/api/invites/[id]/route.ts new file mode 100644 index 0000000..a533ffa --- /dev/null +++ b/src/app/api/invites/[id]/route.ts @@ -0,0 +1,26 @@ +import { NextResponse } from "next/server"; +import { sql } from "@/db"; +import { requireFamily } from "@/lib/auth"; + +// DELETE — cancel/revoke a pending invite (only the family that sent it can delete it) +export async function DELETE( + _req: Request, + { params }: { params: Promise<{ id: string }> } +) { + const auth = await requireFamily(); + if (!auth.success) return NextResponse.json({ error: auth.error }, { status: auth.status }); + + const { id } = await params; + + try { + const result = await sql.unsafe( + `DELETE FROM family_invites WHERE id = $1 AND family_id = $2`, + [id, auth.session!.familyId] + ); + // result.count === 0 means the invite didn't belong to this family or didn't exist + return NextResponse.json({ success: true }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: String(error) }, { status: 500 }); + } +} diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx index b7c62a6..22ee315 100644 --- a/src/app/settings/page.tsx +++ b/src/app/settings/page.tsx @@ -123,6 +123,15 @@ export default function SettingsPage() { } }; + const deleteInvite = async (inviteId: string) => { + try { + await fetch(`/api/invites/${inviteId}`, { method: "DELETE" }); + setInvites(prev => prev.filter(i => i.id !== inviteId)); + } catch (err) { + console.error("Failed to delete invite:", err); + } + }; + const sendInvite = async () => { if (!inviteEmail || !familyId) return; setInviteLoading(true); @@ -273,9 +282,18 @@ export default function SettingsPage() {