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 { cn } from '@/lib/utils'; import { MEMBER_VISIBILITY_DESCRIPTIONS, type MemberVisibility, } from '@/lib/types'; 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 options: { key: MemberVisibility; label: string; icon: React.ComponentType<{ className?: string }> }[] = [ { key: 'public', label: 'Public', icon: Globe }, { key: 'crew', label: 'Crew only', icon: EyeOff }, ]; return (
{options.map(({ key, label, icon: Icon }) => { const active = value === key; return ( ); })}

{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 { 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: 'Membership confirmed!', description: visibility === 'crew' ? `You're verified in ${collectiveName} — visible to crew-mates only.` : `You now show as a verified member of ${collectiveName}.`, }); } catch (error) { toast({ title: 'Failed to confirm', description: error instanceof Error ? error.message : 'Please try again.', variant: 'destructive', }); } }; return (

You've been added to {collectiveName}

Confirm your membership so it shows as verified on your profile and theirs.

Your visibility

); }