import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useNostr } from '@nostrify/react'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { MEMBERSHIP_LABEL_NAMESPACE, MEMBERSHIP_LABEL_VALUE, type MemberVisibility, } from '@/lib/types'; interface AttestParams { /** Kind of the collective profile being joined. */ kind: number; /** Founder pubkey (author of the collective profile). */ founderPubkey: string; /** d-tag identifier of the collective profile. */ identifier: string; /** Collective display name (stored in content for readability). */ collectiveName?: string; /** Relay hint for the referenced collective. */ relayHint?: string; /** Opt-in visibility choice — defaults to 'public' if omitted. */ visibility?: MemberVisibility; } /** * Publish a NIP-32 membership attestation (kind 1985) confirming that the * logged-in user is a member of the given collective. Signed with the user's * OWN key, so the confirmation cannot be forged by the collective. */ export function useConfirmMembership() { const { nostr } = useNostr(); const { user } = useCurrentUser(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ kind, founderPubkey, identifier, collectiveName, relayHint, visibility = 'public', }: AttestParams) => { if (!user) throw new Error('You must be logged in to confirm membership'); const address = `${kind}:${founderPubkey}:${identifier}`; const aTag = relayHint ? ['a', address, relayHint] : ['a', address]; const tags: string[][] = [ ['L', MEMBERSHIP_LABEL_NAMESPACE], ['l', MEMBERSHIP_LABEL_VALUE, MEMBERSHIP_LABEL_NAMESPACE], aTag, ['p', founderPubkey], ['visibility', visibility], ['alt', `Skate collective membership confirmation for ${collectiveName ?? address}`], ]; const event = await user.signer.signEvent({ kind: 1985, content: collectiveName ? `I'm a member of ${collectiveName}` : 'Confirmed collective membership', tags, created_at: Math.floor(Date.now() / 1000), }); await nostr.event(event, { signal: AbortSignal.timeout(15000) }); return event; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['collective-members'] }); }, }); }