import { useState, type ReactNode } from 'react'; import { useNavigate } from 'react-router-dom'; import { Trash2, Loader2, AlertTriangle } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { AlertDialog, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog'; import { useDeleteEntity } from '@/hooks/useDeleteEntity'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useToast } from '@/hooks/useToast'; import { cn } from '@/lib/utils'; import type { NostrEvent } from '@nostrify/nostrify'; interface DeleteEntityDialogProps { /** The addressable event to delete (crew, Lab profile, spot, …). */ event: NostrEvent; /** Human label for the thing being deleted, e.g. "crew" or "coach profile". */ entityLabel: string; /** The name/title shown in the confirmation copy. */ entityName: string; /** Where to send the user after a successful delete (e.g. "/crews"). */ redirectTo?: string; /** Verb shown on the trigger button (default "Delete"). */ triggerText?: string; /** Optional custom trigger. If omitted a default outline button is rendered. */ trigger?: ReactNode; /** Extra classes for the default trigger button. */ className?: string; } /** * Reusable "delete / dissolve" control for any addressable event the current * user owns. Publishes a NIP-09 deletion request (see useDeleteEntity) after an * explicit confirmation, and is only rendered for the owner. */ export function DeleteEntityDialog({ event, entityLabel, entityName, redirectTo, triggerText = 'Delete', trigger, className, }: DeleteEntityDialogProps) { const { user } = useCurrentUser(); const { mutateAsync: deleteEntity, isPending } = useDeleteEntity(); const { toast } = useToast(); const navigate = useNavigate(); const [open, setOpen] = useState(false); // Only the owner can delete their own event. if (!user || user.pubkey !== event.pubkey) return null; const handleDelete = async () => { try { await deleteEntity({ event, reason: `Deleted ${entityLabel} "${entityName}"` }); toast({ title: 'Deletion requested', description: `Your ${entityLabel} has been removed. Relays that honor deletions will stop serving it.`, }); setOpen(false); if (redirectTo) navigate(redirectTo); } catch (error) { toast({ title: 'Delete failed', description: error instanceof Error ? error.message : 'Something went wrong', variant: 'destructive', }); } }; return ( <> {trigger ? ( setOpen(true)}>{trigger} ) : ( setOpen(true)} className={cn( 'gap-1.5 border-red-500/40 text-red-400 hover:bg-red-500/10 hover:text-red-300', className, )} > {triggerText} )} Delete "{entityName}"? This asks relays to remove your {entityLabel}. This can’t be undone from here — you’d have to create a new one. Nostr is decentralized, so deletion is best-effort: relays that honor NIP-09 will drop it, but a relay that doesn’t may keep a copy. setOpen(false)} disabled={isPending}> Cancel {isPending ? ( <> Deleting… > ) : ( <> {triggerText} > )} > ); }
This asks relays to remove your {entityLabel}. This can’t be undone from here — you’d have to create a new one.
Nostr is decentralized, so deletion is best-effort: relays that honor NIP-09 will drop it, but a relay that doesn’t may keep a copy.