import { useState } from 'react'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useNostrLogin } from '@nostrify/react/login'; import { useSendDirectMessage } from '@/hooks/useDirectMessages'; import { useToast } from '@/hooks/useToast'; import { hasNip44 as checkNip44 } from '@/lib/signerCapabilities'; import { UserPlus, Loader2, Lock } from 'lucide-react'; interface CrewRequestToJoinProps { crewName: string; founderPubkey: string; /** Delegated admins — they also receive the request so growth isn't founder-only. */ admins?: string[]; } /** * Lets a skater request to join a crew via an encrypted NIP-17 DM to the * founder and admins. This removes the founder-push-only bottleneck: anyone can * knock, and any admin can then add them from the crew editor. * * Privacy: the request is a gift-wrapped DM (kinds 14/13/1059) — only the * recipients can read it. No public "join" event leaks the social graph. */ export function CrewRequestToJoin({ crewName, founderPubkey, admins = [] }: CrewRequestToJoinProps) { const { user } = useCurrentUser(); const { logins } = useNostrLogin(); const { mutateAsync: sendMessage, isPending } = useSendDirectMessage(); const { toast } = useToast(); const [open, setOpen] = useState(false); const [note, setNote] = useState(''); if (!user) return null; const recipients = Array.from(new Set([founderPubkey, ...admins])).filter( (pk) => pk !== user.pubkey, ); // Don't show for people already in the leadership. if (recipients.length === 0) return null; const canDM = checkNip44(user, logins); const handleSend = async () => { if (!canDM) { toast({ title: 'Encryption unavailable', description: 'Your signer does not support NIP-44 encryption. Please upgrade your extension.', variant: 'destructive', }); return; } try { const body = `🛹 Request to join ${crewName}` + (note.trim() ? `\n\n${note.trim()}` : '\n\nWould love to roll with the crew.'); await sendMessage({ recipients, content: body, subject: `${crewName} — join request`, }); toast({ title: 'Request sent!', description: `The ${crewName} crew leadership got your encrypted message.`, }); setOpen(false); setNote(''); } catch (err) { toast({ title: 'Could not send request', description: err instanceof Error ? err.message : 'Please try again.', variant: 'destructive', }); } }; return ( Join {crewName} Sends a private, encrypted message to the crew's founder & admins.