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 { useSendJoinRequest } from '@/hooks/useCrewInvites'; import { useToast } from '@/hooks/useToast'; import { useTranslation } from '@/contexts/language'; import { UserPlus, Loader2, Bell } from 'lucide-react'; import type { SkateCrew } from '@/lib/types'; interface CrewRequestToJoinProps { crew: SkateCrew; } /** * Lets a skater request to join a crew by publishing a structured, notifiable * join-request (kind 31969) addressed to the founder + admins. Their clients * surface it in the notification bell with a one-click "Add to crew" (founder), * so requests aren't lost in a DM inbox. Nothing sensitive is published — just * an optional note. */ export function CrewRequestToJoin({ crew }: CrewRequestToJoinProps) { const { t } = useTranslation(); const { user } = useCurrentUser(); const { mutateAsync: sendJoinRequest, isPending } = useSendJoinRequest(); const { toast } = useToast(); const [open, setOpen] = useState(false); const [note, setNote] = useState(''); if (!user) return null; const recipients = Array.from(new Set([crew.pubkey, ...crew.admins])).filter( (pk) => pk !== user.pubkey, ); // Don't show for people already in the leadership. if (recipients.length === 0) return null; const handleSend = async () => { try { await sendJoinRequest({ crew, note }); toast({ title: t('socialUi.requestToJoin.sentTitle'), description: t('socialUi.requestToJoin.sentDesc', { crew: crew.name }), }); setOpen(false); setNote(''); } catch (err) { toast({ title: t('socialUi.requestToJoin.couldNotSend'), description: err instanceof Error ? err.message : t('common.tryAgain'), variant: 'destructive', }); } }; return ( {t('socialUi.requestToJoin.title', { crew: crew.name })} {t('socialUi.requestToJoin.description')}