'use client'; import { useCallback, useEffect, useState } from 'react'; import { organizationApi, type OrganizationInvitationHistoryItemDto, } from '@/lib/api/organization'; import { canShareOrganizationInviteLink, readOrganizationInviteLinks, type StoredOrganizationInviteLink, writeOrganizationInviteLinks, } from '@/components/invitations/organizationInviteLinks'; export function useOrganizationInviteLinkCopy(organizationId: string | undefined) { const [pendingInviteLinks, setPendingInviteLinks] = useState< Record >({}); const [copiedId, setCopiedId] = useState(null); const [copyingInvitationId, setCopyingInvitationId] = useState(null); useEffect(() => { if (!organizationId) return; setPendingInviteLinks(readOrganizationInviteLinks(organizationId)); }, [organizationId]); const storeInviteLink = useCallback( (invitationId: string, ownerEmail: string, invitationUrl: string) => { if (!organizationId) return; setPendingInviteLinks((prev) => { const next = { ...prev, [invitationId]: { invitationId, ownerEmail: ownerEmail.trim().toLowerCase(), invitationUrl, }, }; writeOrganizationInviteLinks(organizationId, next); return next; }); }, [organizationId], ); const pruneAcceptedLinks = useCallback( (items: OrganizationInvitationHistoryItemDto[]) => { if (!organizationId) return; const acceptedIds = new Set( items.filter((item) => item.acceptedAt || item.status === 'ACTIVE').map((item) => item.id), ); setPendingInviteLinks((prev) => { let changed = false; const next = { ...prev }; for (const id of Object.keys(next)) { if (acceptedIds.has(id)) { delete next[id]; changed = true; } } if (changed) { writeOrganizationInviteLinks(organizationId, next); } return changed ? next : prev; }); }, [organizationId], ); const copyInvitationLink = useCallback( async ( invitation: OrganizationInvitationHistoryItemDto, options?: { onRegenerated?: () => void | Promise }, ): Promise => { if (!canShareOrganizationInviteLink(invitation)) return null; setCopyingInvitationId(invitation.id); try { let invitationUrl = pendingInviteLinks[invitation.id]?.invitationUrl; if (!invitationUrl || invitation.status === 'EXPIRED') { const res = await organizationApi.getInvitationLink(invitation.id); invitationUrl = res.data.invitationUrl; storeInviteLink(invitation.id, invitation.ownerEmail, invitationUrl); await options?.onRegenerated?.(); } await navigator.clipboard.writeText(invitationUrl); setCopiedId(invitation.id); setTimeout(() => setCopiedId(null), 1500); return invitationUrl; } finally { setCopyingInvitationId(null); } }, [pendingInviteLinks, storeInviteLink], ); return { pendingInviteLinks, copiedId, copyingInvitationId, storeInviteLink, copyInvitationLink, pruneAcceptedLinks, }; }