import { useState } from 'react'; import { Users, Check, Loader2, Globe, EyeOff } from 'lucide-react'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useCollectiveMembers } from '@/hooks/useCollectiveMembers'; import { useConfirmMembership } from '@/hooks/useMembershipAttestation'; import { useToast } from '@/hooks/useToast'; import { useTranslation } from '@/contexts/language'; import { cn } from '@/lib/utils'; import { MEMBER_VISIBILITY_DESCRIPTIONS, type MemberVisibility, } from '@/lib/types'; import { MEMBER_VISIBILITY_DESC_KEYS } from '@/lib/labelKeys'; interface ConfirmMembershipCardProps { kind: number; founderPubkey: string; identifier: string; collectiveName: string; claimedMembers: string[]; accentBg?: string; } /** Two-option visibility picker used both when confirming and when editing. */ export function VisibilityPicker({ value, onChange, accentBg = 'bg-indigo-600', }: { value: MemberVisibility; onChange: (v: MemberVisibility) => void; accentBg?: string; }) { const { t } = useTranslation(); const options: { key: MemberVisibility; label: string; icon: React.ComponentType<{ className?: string }> }[] = [ { key: 'public', label: t('socialUi.confirmMembership.public'), icon: Globe }, { key: 'crew', label: t('socialUi.confirmMembership.crewOnly'), icon: EyeOff }, ]; return (
{options.map(({ key, label, icon: Icon }) => { const active = value === key; return ( ); })}

{MEMBER_VISIBILITY_DESC_KEYS[value] ? t(MEMBER_VISIBILITY_DESC_KEYS[value]) : MEMBER_VISIBILITY_DESCRIPTIONS[value]}

); } /** * Shown to a logged-in user who has been LISTED as a member of a collective but * has not yet confirmed. Lets them pick their visibility and publishes a NIP-32 * attestation on click. Hidden for everyone else (non-members, already-confirmed * members, the founder). */ export function ConfirmMembershipCard({ kind, founderPubkey, identifier, collectiveName, claimedMembers, accentBg = 'bg-indigo-600 hover:bg-indigo-700', }: ConfirmMembershipCardProps) { const { t } = useTranslation(); const { user } = useCurrentUser(); const { toast } = useToast(); const { mutateAsync: confirm, isPending } = useConfirmMembership(); const [visibility, setVisibility] = useState('public'); const { data: members } = useCollectiveMembers({ kind, founderPubkey, identifier, claimedMembers, enabled: claimedMembers.length > 0, }); if (!user) return null; const me = user.pubkey.toLowerCase(); // Only relevant if I'm actually listed as a member and I'm not the founder. if (me === founderPubkey.toLowerCase()) return null; if (!claimedMembers.includes(me)) return null; const myStatus = members?.find((m) => m.pubkey === me)?.status; if (myStatus === 'confirmed') return null; const handleConfirm = async () => { try { await confirm({ kind, founderPubkey, identifier, collectiveName, visibility }); toast({ title: t('socialUi.confirmMembership.confirmedTitle'), description: visibility === 'crew' ? t('socialUi.confirmMembership.confirmedCrew', { name: collectiveName }) : t('socialUi.confirmMembership.confirmedPublic', { name: collectiveName }), }); } catch (error) { toast({ title: t('socialUi.confirmMembership.failed'), description: error instanceof Error ? error.message : t('common.tryAgain'), variant: 'destructive', }); } }; return (

{t('socialUi.confirmMembership.addedTo', { name: collectiveName })}

{t('socialUi.confirmMembership.addedDesc')}

{t('socialUi.confirmMembership.yourVisibility')}

); }