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.