@fluid-app/portal-sdk 0.1.353 → 0.1.354
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AppDownloadScreen-CVr7r37B.mjs → AppDownloadScreen-3xiLZXHs.mjs} +2 -2
- package/dist/{AppDownloadScreen-CVr7r37B.mjs.map → AppDownloadScreen-3xiLZXHs.mjs.map} +1 -1
- package/dist/{AppDownloadScreen-DKQedbR1.cjs → AppDownloadScreen-Cxf6aa_H.cjs} +2 -2
- package/dist/{AppDownloadScreen-DKQedbR1.cjs.map → AppDownloadScreen-Cxf6aa_H.cjs.map} +1 -1
- package/dist/{ContactsScreen-oEtuUDs9.mjs → ContactsScreen-Co6JOwmr.mjs} +2 -2
- package/dist/{ContactsScreen-oEtuUDs9.mjs.map → ContactsScreen-Co6JOwmr.mjs.map} +1 -1
- package/dist/{ContactsScreen-0GD35BwW.cjs → ContactsScreen-CxfuYNmW.cjs} +1 -1
- package/dist/{ContactsScreen-BeMCXI7V.cjs → ContactsScreen-zvC1DF-w.cjs} +2 -2
- package/dist/{ContactsScreen-BeMCXI7V.cjs.map → ContactsScreen-zvC1DF-w.cjs.map} +1 -1
- package/dist/{MessagingScreen-DbVQ4_ps.mjs → MessagingScreen-B9OT4qwk.mjs} +1 -1
- package/dist/{MessagingScreen-DuAr-qMo.cjs → MessagingScreen-BCgBxVnz.cjs} +1 -1
- package/dist/{MessagingScreen-BDNX2gKP.cjs → MessagingScreen-Bf8MMgAx.cjs} +3 -3
- package/dist/{MessagingScreen-BDNX2gKP.cjs.map → MessagingScreen-Bf8MMgAx.cjs.map} +1 -1
- package/dist/{MessagingScreen-DydTQrhU.mjs → MessagingScreen-eydvu4x5.mjs} +3 -3
- package/dist/{MessagingScreen-DydTQrhU.mjs.map → MessagingScreen-eydvu4x5.mjs.map} +1 -1
- package/dist/{ProfileScreen-_xC3sqcu.mjs → ProfileScreen-BQuAEttF.mjs} +3 -3
- package/dist/{ProfileScreen-_xC3sqcu.mjs.map → ProfileScreen-BQuAEttF.mjs.map} +1 -1
- package/dist/{ProfileScreen-nf0o_HaC.cjs → ProfileScreen-D4xeQu_7.cjs} +1 -1
- package/dist/{ProfileScreen-fmsFpDyt.mjs → ProfileScreen-DKUVVKVq.mjs} +1 -1
- package/dist/{ProfileScreen-1en0o4qK.cjs → ProfileScreen-Dpp_4vHN.cjs} +3 -3
- package/dist/{ProfileScreen-1en0o4qK.cjs.map → ProfileScreen-Dpp_4vHN.cjs.map} +1 -1
- package/dist/{ShareablesScreen-DyL3kfMR.cjs → ShareablesScreen-BXGNgdty.cjs} +1 -1
- package/dist/{ShareablesScreen-DqaJepbb.cjs → ShareablesScreen-C7QRWLbK.cjs} +3 -3
- package/dist/{ShareablesScreen-DqaJepbb.cjs.map → ShareablesScreen-C7QRWLbK.cjs.map} +1 -1
- package/dist/{ShareablesScreen-V7xKu8Sp.mjs → ShareablesScreen-CaVbAkb1.mjs} +1 -1
- package/dist/{ShareablesScreen-Dqu25t_S.mjs → ShareablesScreen-NPWkQkoM.mjs} +3 -3
- package/dist/{ShareablesScreen-Dqu25t_S.mjs.map → ShareablesScreen-NPWkQkoM.mjs.map} +1 -1
- package/dist/{ShopScreen-BmeAPT3j.cjs → ShopScreen-BoP_TsJj.cjs} +1 -1
- package/dist/{ShopScreen-CGfZuk_c.mjs → ShopScreen-CGKfBSQY.mjs} +2 -2
- package/dist/{ShopScreen-CGfZuk_c.mjs.map → ShopScreen-CGKfBSQY.mjs.map} +1 -1
- package/dist/{ShopScreen-DKAuzZE9.mjs → ShopScreen-DUaCcc4I.mjs} +1 -1
- package/dist/{ShopScreen-BxAB0csG.cjs → ShopScreen-PqulelLK.cjs} +2 -2
- package/dist/{ShopScreen-BxAB0csG.cjs.map → ShopScreen-PqulelLK.cjs.map} +1 -1
- package/dist/{SubscriptionsScreen-BI7DHPkC.cjs → SubscriptionsScreen-Bfrpj0eM.cjs} +1 -1
- package/dist/{SubscriptionsScreen-CAURjxCJ.cjs → SubscriptionsScreen-Bp8u_j0h.cjs} +4 -4
- package/dist/{SubscriptionsScreen-CAURjxCJ.cjs.map → SubscriptionsScreen-Bp8u_j0h.cjs.map} +1 -1
- package/dist/{SubscriptionsScreen-CxBwXn5k.mjs → SubscriptionsScreen-CrJ5kXmu.mjs} +4 -4
- package/dist/{SubscriptionsScreen-CxBwXn5k.mjs.map → SubscriptionsScreen-CrJ5kXmu.mjs.map} +1 -1
- package/dist/{SubscriptionsScreen-DFe-bS7k.mjs → SubscriptionsScreen-D0JnspgC.mjs} +1 -1
- package/dist/index.cjs +34 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +35 -25
- package/dist/index.mjs.map +1 -1
- package/dist/{query-keys-qP4SU2jn.cjs → query-keys-cklBTHJ-.cjs} +1 -1
- package/dist/{query-keys-DXle2tm8.mjs.map → query-keys-cklBTHJ-.cjs.map} +1 -1
- package/dist/{query-keys-DXle2tm8.mjs → query-keys-xJy_fapN.mjs} +1 -1
- package/dist/{query-keys-qP4SU2jn.cjs.map → query-keys-xJy_fapN.mjs.map} +1 -1
- package/dist/{use-account-Ifgh2X8L.cjs → use-account-3GYuE8w3.cjs} +2 -2
- package/dist/{use-account-Ifgh2X8L.cjs.map → use-account-3GYuE8w3.cjs.map} +1 -1
- package/dist/{use-account-CdPNHkp2.mjs → use-account-DEj6E1PK.mjs} +2 -2
- package/dist/{use-account-CdPNHkp2.mjs.map → use-account-DEj6E1PK.mjs.map} +1 -1
- package/dist/{use-store-CoNdSDN_.mjs → use-store-CfKYYLnj.mjs} +1 -1
- package/dist/{use-store-CoNdSDN_.mjs.map → use-store-CfKYYLnj.mjs.map} +1 -1
- package/dist/{use-store-DIPvYypj.cjs → use-store-US-JJQ_j.cjs} +1 -1
- package/dist/{use-store-DIPvYypj.cjs.map → use-store-US-JJQ_j.cjs.map} +1 -1
- package/package.json +17 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContactsScreen-oEtuUDs9.mjs","names":["ContextMenuPrimitive.Root","ContextMenuPrimitive.Trigger","ContextMenuPrimitive.Portal","ContextMenuPrimitive.Content","ContextMenuPrimitive.Item","ContextMenuPrimitive.Label","ContextMenuPrimitive.Separator","ContextMenuPrimitive.Sub","ContextMenuPrimitive.SubTrigger","ContextMenuPrimitive.SubContent","formatDueDate","r","e","t","n","z","X","o","a","l","EmojiPickerPrimitive","HexColorPicker","HexColorInput"],"sources":["../../../contacts/ui/src/portal/hooks/groups/invalidate-contact-caches.ts","../../../contacts/ui/src/screens/ContactCreateScreen.tsx","../../../contacts/ui/src/portal/hooks/groups/use-bulk-delete-contacts.ts","../../../contacts/ui/src/portal/hooks/groups/use-groups.ts","../../../contacts/ui/src/portal/components/contacts/rep-layout/utils.ts","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactsSidebarRow.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContextMenu.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactsSidebar.tsx","../../../contacts/ui/src/shared/components/contacts/contactDetailsForm.tsx","../../../contacts/ui/src/shared/hooks/useContactDetail.ts","../../../contacts/ui/src/shared/hooks/useUpdateContactMutation.ts","../../../contacts/ui/src/shared/hooks/useDeleteContactMutation.ts","../../../contacts/ui/src/shared/schemas/contactFormSchema.ts","../../../contacts/ui/src/shared/hooks/useContactDetailPage.ts","../../../contacts/ui/src/portal/hooks/contacts/use-contact-tasks.ts","../../../contacts/ui/src/portal/hooks/notes/use-contact-notes.ts","../../../contacts/ui/src/portal/hooks/groups/use-create-group.ts","../../../contacts/ui/src/portal/hooks/groups/use-update-contact-tags.ts","../../../contacts/ui/src/shared/components/contacts/statusBadge.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/InlineGroupsEditor.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactDetailHero.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactInfoRow.tsx","../../../contacts/ui/src/portal/hooks/contacts/use-toggle-task-completion.ts","../../../contacts/ui/src/portal/hooks/contacts/use-delete-contact-task.ts","../../../contacts/ui/src/portal/hooks/contacts/use-update-contact-task.ts","../../../contacts/ui/src/portal/utils/format-date.ts","../../../contacts/ui/src/portal/components/editor/note-task-editor.tsx","../../../contacts/ui/src/portal/components/editor/note-task-modal.tsx","../../../contacts/ui/src/portal/components/tasks/task-list.tsx","../../../contacts/ui/src/portal/components/tasks/inline-task-composer.tsx","../../../contacts/ui/src/portal/hooks/notes/use-delete-contact-note.ts","../../../contacts/ui/src/portal/hooks/notes/use-update-contact-note.ts","../../../contacts/ui/src/portal/hooks/notes/use-create-contact-note.ts","../../../contacts/ui/src/portal/components/notes/inline-note-composer.tsx","../../../contacts/ui/src/portal/components/notes/notes-list.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactDetailTabs.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactDetailPane.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactsEmptyState.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/RepContactsLayout.tsx","../../../../node_modules/.pnpm/react-colorful@5.6.1_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/react-colorful/dist/index.mjs","../../../contacts/ui/src/portal/hooks/groups/use-delete-group.ts","../../../contacts/ui/src/portal/hooks/groups/use-update-group.ts","../../../contacts/ui/src/portal/components/contacts/rep-layout/GroupsManagePage.tsx","../../../contacts/ui/src/shared/hooks/useCreateContactMutation.ts","../src/screens/ContactsScreen.tsx"],"sourcesContent":["import type { QueryClient } from \"@tanstack/react-query\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function invalidateContactCaches(queryClient: QueryClient) {\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(\"contacts\"),\n });\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(\"sdk-contacts\"),\n });\n queryClient.invalidateQueries({\n queryKey: [\"portal-contacts\"],\n });\n}\n","\"use client\";\n\nimport React, { type ReactNode } from \"react\";\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n Button,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ScreenHeaderActions,\n ScreenHeaderBreadcrumbs,\n} from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\n\nexport interface ContactCreateScreenProps {\n onNavigateToList: () => void;\n onSubmit: () => void;\n isPending: boolean;\n children: ReactNode;\n}\n\nexport function ContactCreateScreen({\n onNavigateToList,\n onSubmit,\n isPending,\n children,\n}: ContactCreateScreenProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n\n return (\n <>\n <ScreenHeaderActions>\n <Button\n variant=\"outline\"\n onClick={onNavigateToList}\n disabled={isPending}\n >\n {t(\"cancel\")}\n </Button>\n <Button onClick={onSubmit} disabled={isPending}>\n {isPending ? t(\"adding\") : t(\"add_contact\")}\n </Button>\n </ScreenHeaderActions>\n <ScreenHeaderBreadcrumbs>\n <Breadcrumb>\n <BreadcrumbList className=\"text-lg\">\n <BreadcrumbItem>\n <BreadcrumbLink\n href=\"#\"\n onClick={(e) => {\n e.preventDefault();\n onNavigateToList();\n }}\n >\n {t(\"breadcrumb\")}\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage className=\"font-semibold\">\n {t(\"breadcrumb_new\")}\n </BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n </ScreenHeaderBreadcrumbs>\n {children}\n </>\n );\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"./invalidate-contact-caches\";\n\nexport function useBulkDeleteContacts() {\n const api = useContactsCrud();\n const queryClient = useQueryClient();\n const { t } = useContactsTranslation();\n\n return useMutation({\n mutationFn: (ids: number[]) => api.bulkDeleteContacts(ids),\n onSuccess: (_data, ids) => {\n invalidateContactCaches(queryClient);\n const count = ids.length;\n fluidToast({\n title:\n count === 1\n ? t(\"contacts_deleted_one\", { count })\n : t(\"contacts_deleted_other\", { count }),\n type: \"success\",\n });\n },\n onError: (_error, ids) => {\n const count = ids.length;\n fluidToast({\n title:\n count === 1\n ? t(\"contacts_delete_failed_one\")\n : t(\"contacts_delete_failed_other\"),\n description: parseApiErrors(_error),\n type: \"error\",\n });\n },\n });\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useGroupsApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useGroups() {\n const api = useGroupsApi();\n\n return useQuery({\n queryKey: contactsKeys.groups(),\n queryFn: () => api!.listGroups(),\n enabled: !!api,\n select: (data) => data.groups,\n });\n}\n","import type { Contact } from \"@fluid-app/contacts-core/types\";\n\nexport function getDisplayName(contact: Contact): string {\n if (contact.full_name && contact.full_name.trim().length > 0) {\n return contact.full_name;\n }\n const parts = [contact.first_name, contact.last_name].filter(Boolean);\n if (parts.length > 0) return parts.join(\" \");\n if (contact.email) return contact.email;\n return \"Contact\";\n}\n\nexport function getInitials(name: string): string {\n const parts = name.trim().split(/\\s+/);\n const first = parts[0]?.[0] ?? \"\";\n const last = parts.length > 1 ? (parts[parts.length - 1]?.[0] ?? \"\") : \"\";\n return (first + last).toUpperCase() || \"?\";\n}\n\n/** Lowercase relative label derived from `contact.updated_at`.\n * Returns null if the timestamp is missing or unparseable. Lowercase on\n * purpose so callers can compose phrases like \"Last updated 3 days ago\"\n * without an awkward \"Last updated Today\". */\nexport function getRelativeUpdated(contact: Contact): string | null {\n const updated =\n typeof contact.updated_at === \"string\" ? contact.updated_at : null;\n if (!updated) return null;\n const date = new Date(updated);\n if (Number.isNaN(date.getTime())) return null;\n\n const diffMs = Date.now() - date.getTime();\n const day = 1000 * 60 * 60 * 24;\n const diffDays = Math.floor(diffMs / day);\n\n if (diffDays <= 0) return \"today\";\n if (diffDays === 1) return \"yesterday\";\n if (diffDays < 7) return `${diffDays} days ago`;\n if (diffDays < 30) {\n const weeks = Math.floor(diffDays / 7);\n return weeks === 1 ? \"1 week ago\" : `${weeks} weeks ago`;\n }\n if (diffDays < 365) {\n const months = Math.floor(diffDays / 30);\n return months === 1 ? \"1 month ago\" : `${months} months ago`;\n }\n const years = Math.floor(diffDays / 365);\n return years === 1 ? \"1 year ago\" : `${years} years ago`;\n}\n","\"use client\";\n\nimport React, { useCallback, useEffect, useRef } from \"react\";\nimport { Check, ChevronRight, Trash2 } from \"lucide-react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { getDisplayName, getInitials } from \"./utils\";\n\nconst SWIPE_THRESHOLD = 40;\nconst REVEAL_WIDTH = 80;\n\nexport interface ContactsSidebarRowProps {\n contact: Contact;\n isSelected: boolean;\n isChecked?: boolean;\n highlight?: boolean;\n revealed?: boolean;\n onRevealChange?: (contactId: string, open: boolean) => void;\n onDismissRevealed?: () => void;\n onSelect: (id: string) => void;\n onShiftSelect?: (id: string) => void;\n onContextMenu?: (e: React.MouseEvent, contact: Contact) => void;\n onDelete?: (contact: Contact) => void;\n}\n\nexport function ContactsSidebarRow({\n contact,\n isSelected,\n isChecked,\n highlight,\n revealed = false,\n onRevealChange,\n onDismissRevealed,\n onSelect,\n onShiftSelect,\n onContextMenu,\n onDelete,\n}: ContactsSidebarRowProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const name = getDisplayName(contact);\n const id = String(contact.id);\n const secondary = contact.email ?? contact.status?.trim() ?? null;\n\n const cardRef = useRef<HTMLDivElement>(null);\n const offsetRef = useRef(0);\n const animateCloseRef = useRef(false);\n const startXRef = useRef(0);\n const startYRef = useRef(0);\n const activeRef = useRef(false);\n const lockedRef = useRef(false);\n const horizontalRef = useRef(false);\n const didSwipeRef = useRef(false);\n const autoHideRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const mouseDragAbortRef = useRef<AbortController | null>(null);\n\n // Abort any in-flight mouse-drag listeners if the component unmounts.\n useEffect(() => {\n return () => {\n mouseDragAbortRef.current?.abort();\n };\n }, []);\n\n // Direct DOM manipulation for zero-lag transforms\n const setOffset = useCallback(\n (value: number, animate: \"open\" | \"close\" | false) => {\n offsetRef.current = value;\n const el = cardRef.current;\n if (!el) return;\n if (animate === \"open\") {\n el.style.transition =\n \"transform 0.15s cubic-bezier(0.25, 0.1, 0.25, 1)\";\n } else if (animate === \"close\") {\n el.style.transition =\n \"transform 0.35s cubic-bezier(0.25, 0.1, 0.25, 1)\";\n } else {\n el.style.transition = \"none\";\n }\n el.style.transform = `translateX(${value}px)`;\n },\n [],\n );\n\n // Sync with external revealed state\n useEffect(() => {\n if (revealed) {\n setOffset(-REVEAL_WIDTH, false);\n autoHideRef.current = setTimeout(() => {\n animateCloseRef.current = true;\n onRevealChange?.(id, false);\n }, 2000);\n } else if (!activeRef.current) {\n animateCloseRef.current = false;\n setOffset(0, \"close\");\n }\n return () => {\n if (autoHideRef.current) clearTimeout(autoHideRef.current);\n };\n }, [revealed, setOffset, onRevealChange, id]);\n\n const onStart = useCallback(\n (x: number, y: number) => {\n if (!onDelete) return;\n startXRef.current = x;\n startYRef.current = y;\n activeRef.current = true;\n lockedRef.current = false;\n horizontalRef.current = false;\n didSwipeRef.current = false;\n if (autoHideRef.current) clearTimeout(autoHideRef.current);\n // Dismiss other revealed rows immediately\n if (!revealed) onDismissRevealed?.();\n },\n [onDelete, revealed, onDismissRevealed],\n );\n\n const onMove = useCallback(\n (x: number, y: number) => {\n if (!activeRef.current) return;\n const dx = x - startXRef.current;\n const dy = y - startYRef.current;\n\n if (!lockedRef.current) {\n if (Math.abs(dx) < 4 && Math.abs(dy) < 4) return;\n lockedRef.current = true;\n horizontalRef.current = Math.abs(dx) > Math.abs(dy);\n if (!horizontalRef.current) return;\n }\n if (!horizontalRef.current) return;\n\n didSwipeRef.current = true;\n const base = revealed ? -REVEAL_WIDTH : 0;\n const offset = Math.max(-REVEAL_WIDTH, Math.min(0, base + dx));\n setOffset(offset, false);\n },\n [revealed, setOffset],\n );\n\n const onEnd = useCallback(() => {\n if (!activeRef.current) return;\n activeRef.current = false;\n\n if (!didSwipeRef.current) return;\n\n const offset = offsetRef.current;\n if (offset < -SWIPE_THRESHOLD) {\n setOffset(-REVEAL_WIDTH, \"open\");\n onRevealChange?.(id, true);\n } else {\n setOffset(0, \"close\");\n onRevealChange?.(id, false);\n }\n }, [setOffset, onRevealChange, id]);\n\n // Touch\n const handleTouchStart = useCallback(\n (e: React.TouchEvent) => {\n const t = e.touches[0];\n if (t) onStart(t.clientX, t.clientY);\n },\n [onStart],\n );\n const handleTouchMove = useCallback(\n (e: React.TouchEvent) => {\n const t = e.touches[0];\n if (t) onMove(t.clientX, t.clientY);\n },\n [onMove],\n );\n\n // Mouse drag\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (e.button !== 0) return;\n onStart(e.clientX, e.clientY);\n mouseDragAbortRef.current?.abort();\n const controller = new AbortController();\n mouseDragAbortRef.current = controller;\n const { signal } = controller;\n window.addEventListener(\n \"mousemove\",\n (me) => onMove(me.clientX, me.clientY),\n { signal },\n );\n window.addEventListener(\n \"mouseup\",\n () => {\n onEnd();\n controller.abort();\n if (mouseDragAbortRef.current === controller) {\n mouseDragAbortRef.current = null;\n }\n },\n { signal },\n );\n },\n [onStart, onMove, onEnd],\n );\n\n // Trackpad two-finger swipe\n const wheelAccum = useRef(0);\n const wheelTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const handleWheel = useCallback(\n (e: React.WheelEvent) => {\n if (!onDelete) return;\n if (Math.abs(e.deltaX) <= Math.abs(e.deltaY)) return;\n\n // On first wheel event of a gesture, dismiss others\n if (!wheelTimer.current && !revealed) {\n onDismissRevealed?.();\n }\n\n wheelAccum.current += e.deltaX;\n const base = revealed ? -REVEAL_WIDTH : 0;\n const offset = Math.max(\n -REVEAL_WIDTH,\n Math.min(0, base - wheelAccum.current),\n );\n setOffset(offset, false);\n\n if (wheelTimer.current) clearTimeout(wheelTimer.current);\n wheelTimer.current = setTimeout(() => {\n const final = offsetRef.current;\n if (final < -SWIPE_THRESHOLD) {\n setOffset(-REVEAL_WIDTH, \"open\");\n onRevealChange?.(id, true);\n } else {\n setOffset(0, \"close\");\n onRevealChange?.(id, false);\n }\n wheelAccum.current = 0;\n wheelTimer.current = null;\n }, 80);\n },\n [onDelete, revealed, onDismissRevealed, setOffset, onRevealChange, id],\n );\n\n useEffect(() => {\n return () => {\n if (wheelTimer.current) clearTimeout(wheelTimer.current);\n };\n }, []);\n\n const handleActivate = useCallback(\n (shiftKey: boolean) => {\n if (didSwipeRef.current) {\n didSwipeRef.current = false;\n return;\n }\n if (revealed) {\n animateCloseRef.current = true;\n onRevealChange?.(id, false);\n return;\n }\n if (shiftKey && onShiftSelect) {\n onShiftSelect(id);\n return;\n }\n onSelect(id);\n },\n [revealed, onRevealChange, onSelect, onShiftSelect, id],\n );\n\n const handleClick = useCallback(\n (e: React.MouseEvent) => handleActivate(e.shiftKey),\n [handleActivate],\n );\n\n const handleContextMenu = useCallback(\n (e: React.MouseEvent) => {\n if (onContextMenu) {\n e.preventDefault();\n onContextMenu(e, contact);\n }\n },\n [onContextMenu, contact],\n );\n\n const handleDelete = useCallback(() => {\n onRevealChange?.(id, false);\n onDelete?.(contact);\n }, [onDelete, onRevealChange, contact, id]);\n\n return (\n <div className=\"relative overflow-hidden rounded-xl\">\n {onDelete && !isChecked && (\n <div\n className=\"bg-destructive text-destructive-foreground absolute inset-y-0 right-0 flex w-[88px] cursor-pointer flex-col items-center justify-center gap-1 pl-2\"\n onPointerDown={(e) => {\n e.stopPropagation();\n e.preventDefault();\n handleDelete();\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleDelete();\n }\n }}\n role=\"button\"\n tabIndex={0}\n aria-label={t(\"delete_contact_aria\", { name })}\n >\n <Trash2 className=\"size-5\" />\n <span className=\"text-xs font-medium\">{t(\"delete\")}</span>\n </div>\n )}\n\n <div\n ref={cardRef}\n onClick={handleClick}\n onContextMenu={handleContextMenu}\n onTouchStart={onDelete ? handleTouchStart : undefined}\n onTouchMove={onDelete ? handleTouchMove : undefined}\n onTouchEnd={onDelete ? onEnd : undefined}\n onMouseDown={onDelete ? handleMouseDown : undefined}\n onWheel={onDelete ? handleWheel : undefined}\n role=\"button\"\n tabIndex={0}\n aria-current={isSelected ? \"true\" : undefined}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleActivate(e.shiftKey);\n }\n }}\n className={cn(\n \"group relative flex w-full cursor-pointer items-center gap-3.5 rounded-l-xl rounded-r-none px-3 py-3 text-left select-none\",\n isSelected && !isChecked\n ? \"bg-muted\"\n : \"bg-background hover:bg-muted\",\n isChecked && \"bg-primary/10\",\n highlight && \"animate-highlight-fade\",\n )}\n >\n {isChecked && (\n <div className=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full\">\n <Check className=\"size-3\" />\n </div>\n )}\n <div\n className={cn(\n \"text-muted-foreground relative flex size-12 shrink-0 items-center justify-center overflow-hidden rounded-xl text-base font-semibold transition-colors\",\n isSelected && !isChecked ? \"bg-background\" : \"bg-muted\",\n )}\n >\n {contact.avatar_url ? (\n <img\n alt={name}\n src={contact.avatar_url}\n className=\"size-12 object-cover\"\n />\n ) : (\n <span aria-hidden=\"true\">{getInitials(name)}</span>\n )}\n </div>\n\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-foreground block truncate text-sm font-semibold tracking-tight\">\n {name}\n </span>\n {secondary && (\n <span className=\"text-muted-foreground mt-0.5 block truncate text-sm\">\n {secondary}\n </span>\n )}\n </div>\n\n {isSelected && (\n <ChevronRight\n className=\"text-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport { ChevronRight } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@fluid-app/ui-primitives\";\n\nfunction ContextMenu({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Root>): React.JSX.Element {\n return <ContextMenuPrimitive.Root data-slot=\"context-menu\" {...props} />;\n}\n\nfunction ContextMenuTrigger({\n ...props\n}: React.ComponentProps<\n typeof ContextMenuPrimitive.Trigger\n>): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Trigger data-slot=\"context-menu-trigger\" {...props} />\n );\n}\n\nfunction ContextMenuContent({\n className,\n ...props\n}: React.ComponentProps<\n typeof ContextMenuPrimitive.Content\n>): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Portal>\n <ContextMenuPrimitive.Content\n data-slot=\"context-menu-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md\",\n className,\n )}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n );\n}\n\nfunction ContextMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: \"default\" | \"destructive\";\n}): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Item\n data-slot=\"context-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:!text-destructive relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction ContextMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {\n inset?: boolean;\n}): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Label\n data-slot=\"context-menu-label\"\n data-inset={inset}\n className={cn(\n \"text-muted-foreground px-2 py-1.5 text-xs font-medium data-[inset]:pl-8\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction ContextMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<\n typeof ContextMenuPrimitive.Separator\n>): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Separator\n data-slot=\"context-menu-separator\"\n className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nfunction ContextMenuSub({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>): React.JSX.Element {\n return <ContextMenuPrimitive.Sub data-slot=\"context-menu-sub\" {...props} />;\n}\n\nfunction ContextMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n}): React.JSX.Element {\n return (\n <ContextMenuPrimitive.SubTrigger\n data-slot=\"context-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" />\n </ContextMenuPrimitive.SubTrigger>\n );\n}\n\nfunction ContextMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<\n typeof ContextMenuPrimitive.SubContent\n>): React.JSX.Element {\n return (\n <ContextMenuPrimitive.SubContent\n data-slot=\"context-menu-sub-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport {\n ContextMenu,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuSeparator,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n};\n","\"use client\";\n\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n MoreHorizontal,\n Plus,\n Search,\n Settings,\n Trash2,\n Users,\n} from \"lucide-react\";\nimport {\n Button,\n cn,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n fluidToast,\n Input,\n Skeleton,\n} from \"@fluid-app/ui-primitives\";\nimport { useInfiniteContacts } from \"@fluid-app/contacts-core/hooks/use-infinite-contacts\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"../../../hooks/groups/invalidate-contact-caches\";\nimport { useBulkDeleteContacts } from \"../../../hooks/groups/use-bulk-delete-contacts\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { useGroups } from \"../../../hooks/groups/use-groups\";\nimport { ContactsSidebarRow } from \"./ContactsSidebarRow\";\nimport {\n ContextMenu,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuSeparator,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from \"./ContextMenu\";\n\nexport interface ContactsSidebarProps {\n selectedContactId: string | null;\n highlightContactId?: string | null;\n onSelect: (id: string | null) => void;\n onAdd: () => void;\n onManageGroups?: () => void;\n onCreateGroup?: () => void;\n highlightGroupName?: string | null;\n onDeleteContact?: (contact: Contact) => void;\n}\n\nconst DEBOUNCE_MS = 200;\n\ntype FilterValue =\n | { kind: \"all\" }\n | { kind: \"status\"; status: \"lead\" | \"customer\" }\n | { kind: \"group\"; tag: string };\n\ninterface BuiltInFilter {\n id: string;\n label: string;\n value: FilterValue;\n}\n\nfunction useBuiltInFilters(): BuiltInFilter[] {\n const { t } = useContactsTranslation();\n return useMemo(\n () => [\n { id: \"all\", label: t(\"filter_all\"), value: { kind: \"all\" } as const },\n {\n id: \"status:lead\",\n label: t(\"filter_leads\"),\n value: { kind: \"status\" as const, status: \"lead\" as const },\n },\n {\n id: \"status:customer\",\n label: t(\"filter_customers\"),\n value: { kind: \"status\" as const, status: \"customer\" as const },\n },\n ],\n [t],\n );\n}\n\nfunction filterId(value: FilterValue): string {\n if (value.kind === \"all\") return \"all\";\n if (value.kind === \"status\") return `status:${value.status}`;\n return `group:${value.tag}`;\n}\n\nexport function ContactsSidebar({\n selectedContactId,\n highlightContactId,\n onSelect,\n onAdd,\n onManageGroups,\n onCreateGroup,\n highlightGroupName,\n onDeleteContact,\n}: ContactsSidebarProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const builtInFilters = useBuiltInFilters();\n const [searchInput, setSearchInput] = useState(\"\");\n const [debouncedSearch, setDebouncedSearch] = useState(\"\");\n const [revealedContactId, setRevealedContactId] = useState<string | null>(\n null,\n );\n const handleRevealChange = useCallback(\n (id: string, open: boolean) => setRevealedContactId(open ? id : null),\n [],\n );\n const handleDismissRevealed = useCallback(\n () => setRevealedContactId(null),\n [],\n );\n const [filter, setFilter] = useState<FilterValue>({ kind: \"all\" });\n const [checkedIds, setCheckedIds] = useState<Set<string>>(new Set());\n const [contextTargetId, setContextTargetId] = useState<string | null>(null);\n\n const api = useContactsCrud();\n const queryClient = useQueryClient();\n const bulkDelete = useBulkDeleteContacts();\n\n useEffect(() => {\n const handle = window.setTimeout(() => {\n setDebouncedSearch(searchInput.trim());\n }, DEBOUNCE_MS);\n return () => window.clearTimeout(handle);\n }, [searchInput]);\n\n const { data: groups = [] } = useGroups();\n\n const queryParams = useMemo(\n () => ({\n search_query: debouncedSearch || undefined,\n tags: filter.kind === \"group\" ? [filter.tag] : undefined,\n sort_by: \"full_name\",\n sort_direction: \"asc\",\n per_page: 50,\n }),\n [debouncedSearch, filter],\n );\n\n const {\n data,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n fetchNextPage,\n isError,\n } = useInfiniteContacts(queryParams);\n\n const contacts: Contact[] = useMemo(\n () => data?.pages.flatMap((page) => page.contacts ?? []) ?? [],\n [data],\n );\n\n const visibleContacts = useMemo(() => {\n if (filter.kind === \"status\") {\n return contacts.filter((c) => c.status === filter.status);\n }\n return contacts;\n }, [contacts, filter]);\n\n const sentinelRef = useRef<HTMLDivElement>(null);\n\n // Auto-select the first contact on initial load so the right pane shows\n // detail instead of the empty state. Desktop only — on mobile the layout\n // hides the sidebar when a contact is selected, so auto-selecting would\n // drop the rep straight into a detail view with no list visible. Ref\n // guards re-fires so explicit deselects (back button, post-delete, filter\n // changes) don't get clobbered.\n const hasAutoSelectedRef = useRef(false);\n useEffect(() => {\n if (hasAutoSelectedRef.current) return;\n if (selectedContactId) {\n hasAutoSelectedRef.current = true;\n return;\n }\n if (isLoading || visibleContacts.length === 0) return;\n const isDesktop =\n typeof window === \"undefined\" ||\n window.matchMedia(\"(min-width: 768px)\").matches;\n if (!isDesktop) {\n hasAutoSelectedRef.current = true;\n return;\n }\n const first = visibleContacts[0];\n if (first) {\n hasAutoSelectedRef.current = true;\n onSelect(String(first.id));\n }\n }, [selectedContactId, isLoading, visibleContacts, onSelect]);\n\n useEffect(() => {\n const sentinel = sentinelRef.current;\n if (!sentinel || !hasNextPage) return;\n\n const observer = new IntersectionObserver((entries) => {\n const entry = entries[0];\n if (entry?.isIntersecting && !isFetchingNextPage) {\n fetchNextPage();\n }\n });\n\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [hasNextPage, isFetchingNextPage, fetchNextPage]);\n\n const activeFilterId = filterId(filter);\n\n const handleShiftSelect = useCallback((id: string) => {\n setCheckedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n }, []);\n\n const handleNormalSelect = useCallback(\n (id: string) => {\n setCheckedIds(new Set());\n onSelect(id);\n },\n [onSelect],\n );\n\n const handleContextMenu = useCallback(\n (_e: React.MouseEvent, contact: Contact) => {\n const id = String(contact.id);\n setContextTargetId(id);\n // If the right-clicked contact isn't already part of a multi-select,\n // collapse the selection down to just this one so the menu acts on it.\n if (!checkedIds.has(id)) {\n setCheckedIds(new Set([id]));\n }\n },\n [checkedIds],\n );\n\n const getTargetContacts = useCallback((): Contact[] => {\n if (checkedIds.size > 0) {\n return visibleContacts.filter((c) => checkedIds.has(String(c.id)));\n }\n if (contextTargetId) {\n const single = visibleContacts.find(\n (c) => String(c.id) === contextTargetId,\n );\n return single ? [single] : [];\n }\n return [];\n }, [checkedIds, contextTargetId, visibleContacts]);\n\n const handleBulkDelete = useCallback(() => {\n const targets = getTargetContacts();\n if (targets.length === 0) return;\n const ids = targets.map((c) => c.id);\n bulkDelete.mutate(ids, {\n onSuccess: () => {\n if (\n selectedContactId &&\n ids.some((id) => String(id) === selectedContactId)\n ) {\n onSelect(null);\n }\n setCheckedIds(new Set());\n setContextTargetId(null);\n },\n });\n }, [getTargetContacts, bulkDelete, selectedContactId, onSelect]);\n\n const handleAddToGroup = useCallback(\n (groupName: string) => {\n const targets = getTargetContacts();\n if (targets.length === 0) return;\n const toUpdate = targets.filter((contact) => {\n const currentTags = Array.isArray(contact.tags) ? contact.tags : [];\n return !currentTags.includes(groupName);\n });\n if (toUpdate.length === 0) {\n setCheckedIds(new Set());\n setContextTargetId(null);\n return;\n }\n const promises = toUpdate.map((contact) => {\n const currentTags = Array.isArray(contact.tags) ? contact.tags : [];\n return api.updateContact(String(contact.id), {\n tags: [...currentTags, groupName],\n });\n });\n Promise.allSettled(promises).then((results) => {\n invalidateContactCaches(queryClient);\n const failed = results.filter((r) => r.status === \"rejected\").length;\n const succeeded = toUpdate.length - failed;\n if (failed === 0) {\n fluidToast({\n title:\n succeeded === 1\n ? t(\"contacts_added_to_group_one\", {\n count: succeeded,\n group: groupName,\n })\n : t(\"contacts_added_to_group_other\", {\n count: succeeded,\n group: groupName,\n }),\n type: \"success\",\n });\n } else {\n fluidToast({\n title:\n toUpdate.length === 1\n ? t(\"contacts_add_to_group_failed_one\", { group: groupName })\n : t(\"contacts_add_to_group_failed_other\", { group: groupName }),\n type: \"error\",\n });\n }\n setCheckedIds(new Set());\n setContextTargetId(null);\n });\n },\n [getTargetContacts, api, queryClient, t],\n );\n\n const targetCount =\n checkedIds.size > 0 ? checkedIds.size : contextTargetId ? 1 : 0;\n\n return (\n <>\n <div className=\"border-border/50 border-b px-6 py-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"bg-muted focus-within:ring-foreground/20 flex min-w-0 flex-1 items-center gap-2 rounded-lg px-3 py-1.5 transition focus-within:ring-2\">\n <Search\n className=\"text-muted-foreground size-3.5 shrink-0\"\n aria-hidden=\"true\"\n />\n <Input\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n placeholder={t(\"search_placeholder\")}\n type=\"search\"\n className=\"placeholder:text-muted-foreground/80 h-auto flex-1 border-0 bg-transparent p-0 text-xs font-medium shadow-none focus-visible:ring-0\"\n aria-label={t(\"search_placeholder\")}\n />\n </div>\n <Button type=\"button\" size=\"sm\" onClick={onAdd}>\n <Plus className=\"size-3.5\" aria-hidden=\"true\" />\n {t(\"add\")}\n </Button>\n </div>\n </div>\n\n <FilterPills\n activeId={activeFilterId}\n builtInFilters={builtInFilters}\n groups={groups.map((g) => g.name)}\n onChange={setFilter}\n onManageGroups={onManageGroups}\n onCreateGroup={onCreateGroup}\n highlightGroupName={highlightGroupName}\n />\n\n <div className=\"flex-1 overflow-y-auto px-3 pb-8\">\n {isError ? (\n <div className=\"text-muted-foreground px-4 py-8 text-center text-sm\">\n {t(\"error_loading_list\")}\n </div>\n ) : isLoading ? (\n <SidebarSkeleton />\n ) : visibleContacts.length === 0 ? (\n // Status filters apply client-side, so an empty visible list with\n // more pages still pending means matching contacts may be on later\n // pages. Keep the sentinel mounted so the IntersectionObserver can\n // continue paging until we either find matches or exhaust the data.\n <div className=\"space-y-2\">\n {hasNextPage || isFetchingNextPage ? (\n <div className=\"text-muted-foreground px-4 py-8 text-center text-sm\">\n {t(\"searching\")}\n </div>\n ) : (\n <div className=\"text-muted-foreground px-4 py-8 text-center text-sm\">\n {debouncedSearch\n ? t(\"no_contacts_search\", { term: debouncedSearch })\n : filter.kind === \"all\"\n ? t(\"no_contacts_yet\")\n : t(\"no_contacts_filter\")}\n </div>\n )}\n {hasNextPage && (\n <div ref={sentinelRef} aria-hidden=\"true\" className=\"h-4\" />\n )}\n </div>\n ) : (\n <ContextMenu\n onOpenChange={(open) => {\n if (!open) setContextTargetId(null);\n }}\n >\n <ContextMenuTrigger asChild>\n <div className=\"space-y-1\">\n {visibleContacts.map((contact) => (\n <ContactsSidebarRow\n key={contact.id}\n contact={contact}\n isSelected={String(contact.id) === selectedContactId}\n isChecked={checkedIds.has(String(contact.id))}\n highlight={String(contact.id) === highlightContactId}\n revealed={revealedContactId === String(contact.id)}\n onRevealChange={handleRevealChange}\n onDismissRevealed={handleDismissRevealed}\n onSelect={handleNormalSelect}\n onShiftSelect={handleShiftSelect}\n onContextMenu={handleContextMenu}\n onDelete={onDeleteContact}\n />\n ))}\n <div ref={sentinelRef} aria-hidden=\"true\" className=\"h-4\" />\n {isFetchingNextPage && (\n <div className=\"text-muted-foreground py-3 text-center text-xs\">\n {t(\"loading_more\")}\n </div>\n )}\n </div>\n </ContextMenuTrigger>\n <ContextMenuContent className=\"min-w-48\">\n <ContextMenuLabel>\n {targetCount === 1\n ? t(\"groups_selected_count_one\", { count: targetCount })\n : t(\"groups_selected_count_other\", { count: targetCount })}\n </ContextMenuLabel>\n <ContextMenuSeparator />\n <ContextMenuSub>\n <ContextMenuSubTrigger>\n <Users className=\"size-4\" aria-hidden=\"true\" />\n {t(\"groups_add_to_group\")}\n </ContextMenuSubTrigger>\n <ContextMenuSubContent>\n {groups.length === 0 ? (\n <ContextMenuItem disabled>\n {t(\"groups_no_groups_yet\")}\n </ContextMenuItem>\n ) : (\n groups.map((group) => (\n <ContextMenuItem\n key={group.id}\n onSelect={() => handleAddToGroup(group.name)}\n >\n <div\n className=\"flex size-5 shrink-0 items-center justify-center rounded-full text-xs\"\n style={{\n backgroundColor:\n group.avatar_background ?? \"var(--color-muted)\",\n }}\n aria-hidden=\"true\"\n >\n {group.avatar ?? (\n <Users className=\"text-muted-foreground size-3\" />\n )}\n </div>\n {group.name}\n </ContextMenuItem>\n ))\n )}\n </ContextMenuSubContent>\n </ContextMenuSub>\n <ContextMenuSeparator />\n <ContextMenuItem\n variant=\"destructive\"\n onSelect={handleBulkDelete}\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {t(\"delete\")}\n </ContextMenuItem>\n </ContextMenuContent>\n </ContextMenu>\n )}\n </div>\n </>\n );\n}\n\ninterface FilterPillsProps {\n activeId: string;\n builtInFilters: BuiltInFilter[];\n groups: string[];\n onChange: (filter: FilterValue) => void;\n onManageGroups?: () => void;\n onCreateGroup?: () => void;\n highlightGroupName?: string | null;\n}\n\nfunction FilterPills({\n activeId,\n builtInFilters,\n groups,\n onChange,\n onManageGroups,\n onCreateGroup,\n highlightGroupName,\n}: FilterPillsProps) {\n const { t } = useContactsTranslation();\n const allFilters = useMemo<BuiltInFilter[]>(\n () => [\n ...builtInFilters,\n ...groups.map((tag) => ({\n id: `group:${tag}`,\n label: tag,\n value: { kind: \"group\" as const, tag },\n })),\n ],\n [builtInFilters, groups],\n );\n\n return (\n <div className=\"flex items-center pt-4 pb-4\">\n <div className=\"flex-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\">\n <div className=\"flex gap-1.5 pl-6\">\n {allFilters.map(({ id, label, value }) => {\n const isActive = id === activeId;\n const isHighlighted =\n highlightGroupName && id === `group:${highlightGroupName}`;\n return (\n <button\n key={id}\n type=\"button\"\n onClick={() => onChange(value)}\n aria-pressed={isActive}\n className={cn(\n \"shrink-0 rounded-full px-4 py-1.5 text-sm font-semibold capitalize transition-colors\",\n isActive\n ? \"bg-primary text-primary-foreground\"\n : \"border-border/50 bg-muted text-foreground hover:bg-muted/70 border\",\n isHighlighted && \"animate-highlight-fade\",\n )}\n >\n {label}\n </button>\n );\n })}\n </div>\n </div>\n {(onManageGroups || onCreateGroup) && (\n <div className=\"flex shrink-0 items-center gap-2 pr-6 pl-3\">\n <div className=\"bg-border h-6 w-px\" aria-hidden=\"true\" />\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex items-center justify-center rounded-full p-1.5 transition-colors\"\n aria-label={t(\"groups_options_aria\")}\n >\n <MoreHorizontal className=\"size-4\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {onManageGroups && (\n <DropdownMenuItem onClick={onManageGroups}>\n <Settings className=\"size-4\" aria-hidden=\"true\" />\n {t(\"groups_manage_title\")}\n </DropdownMenuItem>\n )}\n {onCreateGroup && (\n <DropdownMenuItem onClick={onCreateGroup}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n {t(\"groups_create_title\")}\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )}\n </div>\n );\n}\n\nfunction SidebarSkeleton() {\n return (\n <div className=\"space-y-1.5 px-1\">\n {[0, 1, 2, 3, 4].map((i) => (\n <div\n key={i}\n className=\"flex items-center gap-3 rounded-xl p-3\"\n aria-hidden=\"true\"\n >\n <Skeleton className=\"size-12 shrink-0 rounded-xl\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-3.5 w-3/5\" />\n <Skeleton className=\"h-3 w-4/5\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useMemo } from \"react\";\nimport { useFormContext, useWatch } from \"react-hook-form\";\nimport type { EditContactFormData } from \"../../schemas/contactFormSchema\";\nimport {\n cn,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@fluid-app/ui-primitives\";\nimport { Combobox } from \"@fluid-app/ui-components/components/Combobox\";\n\nconst DEFAULT_COUNTRIES: { name: string; value: string }[] = [];\n\nconst statusOptions = [\n { name: \"New\", value: \"new\" },\n { name: \"Active\", value: \"active\" },\n { name: \"Inactive\", value: \"inactive\" },\n { name: \"Cold\", value: \"cold\" },\n { name: \"Lead\", value: \"lead\" },\n { name: \"Customer\", value: \"customer\" },\n];\n\ntype AvatarPickerRenderProps = {\n value: string | null;\n onChange: (url: string | null) => void;\n};\n\ntype ContactDetailsFormProps = {\n className?: string;\n countries?: { name: string; value: string }[];\n renderAvatarPicker?: (props: AvatarPickerRenderProps) => React.ReactNode;\n};\n\nexport const ContactDetailsForm: React.FC<ContactDetailsFormProps> = ({\n className,\n countries = DEFAULT_COUNTRIES,\n renderAvatarPicker,\n}) => {\n const { control, watch, setValue } = useFormContext<EditContactFormData>();\n const currentStatus = useWatch({ control, name: \"status\" });\n const avatarUrl: string | null =\n (watch(\"avatar_url\") as string | null | undefined) ?? null;\n\n const effectiveStatusOptions = useMemo(() => {\n if (\n currentStatus &&\n typeof currentStatus === \"string\" &&\n !statusOptions.some((o) => o.value === currentStatus)\n ) {\n return [\n {\n name:\n currentStatus.charAt(0).toUpperCase() +\n currentStatus.slice(1).replace(/_/g, \" \"),\n value: currentStatus,\n },\n ...statusOptions,\n ];\n }\n return statusOptions;\n }, [currentStatus]);\n\n const firstInitial =\n (watch(\"first_name\") as string | null | undefined)?.[0] ?? \"\";\n const lastInitial =\n (watch(\"last_name\") as string | null | undefined)?.[0] ?? \"\";\n const initials =\n [firstInitial, lastInitial].filter(Boolean).join(\"\").toUpperCase() || \"?\";\n\n return (\n <div className={cn(\"space-y-6\", className)}>\n {renderAvatarPicker && (\n <div className=\"flex flex-col items-center gap-3\">\n <div className=\"border-border bg-background relative size-20 shrink-0 overflow-hidden rounded-full border-2\">\n {avatarUrl ? (\n <img\n src={avatarUrl}\n alt=\"\"\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"text-muted-foreground flex h-full w-full items-center justify-center text-lg font-semibold\">\n {initials}\n </div>\n )}\n </div>\n {renderAvatarPicker({\n value: avatarUrl,\n onChange: (url) =>\n setValue(\"avatar_url\", url ?? \"\", { shouldDirty: true }),\n })}\n </div>\n )}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <FormField\n control={control}\n name=\"first_name\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n First Name\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter first name\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"last_name\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Last Name\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter last name\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"email\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Email\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter email address\"\n type=\"email\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"phone\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Phone\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter phone number\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"status\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Status\n </FormLabel>\n <Select value={field.value ?? \"\"} onValueChange={field.onChange}>\n <FormControl>\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder=\"Select status\" />\n </SelectTrigger>\n </FormControl>\n <SelectContent position=\"popper\" sideOffset={4}>\n {effectiveStatusOptions.map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>\n {opt.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"address\"\n render={({ field }) => (\n <FormItem className=\"lg:col-span-2\">\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Full Address\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter street address\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"city\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n City\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter city\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"state\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n State/Province\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter state or province\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"postal_code\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Postal Code\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter postal code\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"country_code\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Country\n </FormLabel>\n <FormControl>\n <Combobox\n options={countries.map((c) => ({\n label: c.name,\n value: c.value,\n }))}\n value={field.value ?? \"\"}\n onValueChange={field.onChange}\n placeholder=\"Select country\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n </div>\n );\n};\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useContactDetail(\n contactId: string,\n queryKeyPrefix = \"contacts\",\n) {\n const api = useContactsCrud();\n\n return useQuery({\n queryKey: CONTACTS_QUERY_KEYS.detail(queryKeyPrefix, contactId),\n queryFn: () => api.getContact(contactId),\n enabled: !!contactId,\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\ntype UpdateInput = {\n id: string;\n data: Record<string, unknown>;\n};\n\nexport function useUpdateContactMutation(\n contactId: string,\n queryKeyPrefix = \"contacts\",\n options?: {\n onSuccess?: () => void;\n onError?: (error: unknown) => void;\n },\n) {\n const queryClient = useQueryClient();\n const api = useContactsCrud();\n\n return useMutation({\n mutationFn: ({ id, data }: UpdateInput) => api.updateContact(id, data),\n onSuccess: () => {\n fluidToast({ title: \"Contact updated successfully\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(queryKeyPrefix),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to save contact\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n options?.onError?.(error);\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useDeleteContactMutation(\n queryKeyPrefix = \"contacts\",\n options?: {\n onSuccess?: () => void;\n onError?: (error: unknown) => void;\n },\n) {\n const queryClient = useQueryClient();\n const api = useContactsCrud();\n\n return useMutation({\n mutationFn: (contactId: string) => api.deleteContact(contactId),\n onSuccess: () => {\n fluidToast({ title: \"Contact deleted successfully\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(queryKeyPrefix),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to delete contact\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n options?.onError?.(error);\n },\n });\n}\n","import { z } from \"zod\";\n\n/**\n * Form schema for creating a contact.\n * Matches CompanyContactCreate / ContactCreate from the OpenAPI spec.\n *\n * @see CompanyContactCreate in company_contacts.d.ts\n * @see ContactCreate in users_contacts.d.ts\n */\nexport const createContactFormSchema = z.object({\n first_name: z.string().min(1, { message: \"First name is required\" }),\n last_name: z.string().min(1, { message: \"Last name is required\" }),\n status: z.string().nullable().optional(),\n email: z.string().email().or(z.literal(\"\")).nullable().optional(),\n phone: z.string().nullable().optional(),\n address: z.string().nullable().optional(),\n city: z.string().nullable().optional(),\n state: z.string().nullable().optional(),\n postal_code: z.string().nullable().optional(),\n country_code: z.coerce.string().nullable().optional(),\n language_code: z.coerce.string().nullable().optional(),\n affiliate: z.record(z.string(), z.unknown()).nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport type CreateContactFormData = z.infer<typeof createContactFormSchema>;\n\n/**\n * Form schema for editing a contact.\n * Same fields as create plus id. Uses .passthrough() so extra fields\n * from the Contact read model (full_name, avatar_url, etc.) don't\n * cause validation failures.\n *\n * @see CompanyContactUpdate in company_contacts.d.ts\n */\nexport const editContactFormSchema = createContactFormSchema.passthrough();\n\nexport type EditContactFormData = z.infer<typeof editContactFormSchema>;\n","\"use client\";\n\nimport { useMemo, useCallback } from \"react\";\nimport { useZodForm, fluidToast } from \"@fluid-app/ui-primitives\";\nimport type { UseFormReturn } from \"react-hook-form\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useContactDetail } from \"./useContactDetail\";\nimport { useUpdateContactMutation } from \"./useUpdateContactMutation\";\nimport { useDeleteContactMutation } from \"./useDeleteContactMutation\";\nimport {\n createContactFormSchema,\n editContactFormSchema,\n type EditContactFormData,\n} from \"../schemas/contactFormSchema\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\n\nconst mutableKeys = Object.keys(\n createContactFormSchema.shape,\n) as (keyof EditContactFormData)[];\n\nexport function useContactDetailPage(\n contactId: string,\n options?: {\n queryKeyPrefix?: string;\n getCountries?: () => Promise<{ id: number; name: string; iso?: string }[]>;\n onDeleteSuccess?: () => void;\n onSaveSuccess?: () => void;\n },\n): {\n contact: Contact | undefined;\n isLoading: boolean;\n methods: UseFormReturn<EditContactFormData>;\n countryOptions: { name: string; value: string }[];\n isDirty: boolean;\n isSubmitting: boolean;\n isDeleting: boolean;\n onSave: () => void;\n onDelete: () => void;\n} {\n const queryKeyPrefix = options?.queryKeyPrefix ?? \"contacts\";\n\n const { data, isLoading } = useContactDetail(contactId, queryKeyPrefix);\n\n const { data: countries } = useQuery({\n queryKey: [\"countries\"],\n queryFn: options?.getCountries ?? (() => Promise.resolve([])),\n enabled: !!options?.getCountries,\n });\n\n const countryOptions = useMemo(\n () =>\n [\n ...(countries?.map((c) => ({\n name: c.name,\n value: c.iso ?? c.id.toString(),\n })) ?? []),\n ].sort((a, b) => a.name.localeCompare(b.name)),\n [countries],\n );\n\n const contact = data?.contact;\n\n // Map nested country object to the ISO code the form select expects\n const formValues = useMemo(() => {\n if (!contact) return undefined;\n return {\n ...contact,\n country_code:\n contact.country?.iso ?? contact.country_id?.toString() ?? null,\n } as unknown as EditContactFormData;\n }, [contact]);\n\n const methods = useZodForm<EditContactFormData>(editContactFormSchema, {\n values: formValues,\n mode: \"onBlur\",\n });\n\n const updateMutation = useUpdateContactMutation(contactId, queryKeyPrefix, {\n onSuccess: () => {\n methods.reset(methods.getValues());\n options?.onSaveSuccess?.();\n },\n });\n\n const deleteMutation = useDeleteContactMutation(queryKeyPrefix, {\n onSuccess: () => {\n options?.onDeleteSuccess?.();\n },\n });\n\n const onSave = useCallback(() => {\n methods.handleSubmit(\n (formData) => {\n const payload: Record<string, unknown> = {};\n for (const key of mutableKeys) {\n if (key in formData) {\n payload[key] = formData[key];\n }\n }\n\n updateMutation.mutate({\n id: contactId,\n data: payload,\n });\n },\n (errors) => {\n const errorMessages = Object.entries(errors)\n .map(([field, err]) => {\n const msg =\n typeof err?.message === \"string\" ? err.message : \"invalid\";\n return `${field.replace(/_/g, \" \")}: ${msg}`;\n })\n .join(\", \");\n fluidToast({\n title: \"Please fix the form errors before saving\",\n description: errorMessages || undefined,\n type: \"error\",\n });\n },\n )();\n }, [methods, updateMutation, contactId]);\n\n const onDelete = useCallback(() => {\n deleteMutation.mutate(contactId);\n }, [deleteMutation, contactId]);\n\n return {\n contact,\n isLoading,\n methods,\n countryOptions,\n isDirty: methods.formState.isDirty,\n isSubmitting: updateMutation.isPending,\n isDeleting: deleteMutation.isPending,\n onSave,\n onDelete,\n };\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useTasksApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { ContactTask } from \"@fluid-app/contacts-core/types\";\n\nexport type { ContactTask };\n\nexport const CONTACT_TASKS_QUERY_KEY = (contactId: string) =>\n contactsKeys.tasks(contactId);\n\nexport function useContactTasks(contactId: string) {\n const api = useTasksApi();\n\n return useQuery({\n queryKey: contactsKeys.tasks(contactId),\n queryFn: () => api.listTasks(contactId),\n enabled: !!contactId,\n select: (data) => data.tasks,\n });\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useNotesApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { ContactNote } from \"@fluid-app/contacts-core/types\";\n\nexport type { ContactNote };\n\nexport const CONTACT_NOTES_QUERY_KEY = (contactId: string) =>\n contactsKeys.notes(contactId);\n\nexport function useContactNotes(contactId: string) {\n const api = useNotesApi();\n\n return useQuery({\n queryKey: contactsKeys.notes(contactId),\n queryFn: () => api.listNotes(contactId),\n enabled: !!contactId,\n select: (data) => data.notes,\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useGroupsApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport type { CreateGroupInput } from \"@fluid-app/contacts-core/types\";\n\nexport function useCreateGroup() {\n const api = useGroupsApi();\n const queryClient = useQueryClient();\n const { t } = useContactsTranslation();\n\n return useMutation({\n mutationFn: (input: CreateGroupInput) => {\n if (!api) throw new Error(\"GroupsApi is not available\");\n return api.createGroup(input);\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: contactsKeys.groups() });\n },\n onError: (error) => {\n fluidToast({\n title: t(\"groups_create_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useUpdateContactTags(\n contactId: string,\n queryKeyPrefix = \"sdk-contacts\",\n options?: {\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n },\n) {\n const api = useContactsCrud();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (tags: string[]) => api.updateContact(contactId, { tags }),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(queryKeyPrefix),\n });\n queryClient.invalidateQueries({\n queryKey: [\"portal-contacts\"],\n });\n options?.onSuccess?.();\n },\n onError: options?.onError,\n });\n}\n","import React from \"react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\n\nconst statusStyles: Record<string, string> = {\n // Contact statuses\n new: \"border-[var(--status-new-border)] bg-[var(--status-new)] text-[var(--status-new-foreground)]\",\n active:\n \"border-[var(--status-active-border)] bg-[var(--status-active)] text-[var(--status-active-foreground)]\",\n inactive: \"border-border bg-muted text-muted-foreground\",\n lead: \"border-[var(--status-lead-border)] bg-[var(--status-lead)] text-[var(--status-lead-foreground)]\",\n customer:\n \"border-[var(--status-customer-border)] bg-[var(--status-customer)] text-[var(--status-customer-foreground)]\",\n // Semantic categories (orders, subscriptions, etc.)\n success:\n \"border-[var(--badge-success-border)] bg-[var(--badge-success)] text-[var(--badge-success-foreground)]\",\n warning:\n \"border-[var(--badge-warning-border)] bg-[var(--badge-warning)] text-[var(--badge-warning-foreground)]\",\n danger:\n \"border-[var(--badge-danger-border)] bg-[var(--badge-danger)] text-[var(--badge-danger-foreground)]\",\n info: \"border-[var(--badge-info-border)] bg-[var(--badge-info)] text-[var(--badge-info-foreground)]\",\n neutral: \"border-border bg-muted text-muted-foreground\",\n notice:\n \"border-[var(--badge-notice-border)] bg-[var(--badge-notice)] text-[var(--badge-notice-foreground)]\",\n accent:\n \"border-[var(--badge-accent-border)] bg-[var(--badge-accent)] text-[var(--badge-accent-foreground)]\",\n};\n\nconst defaultStyle = \"border-border bg-muted text-muted-foreground\";\n\nexport type StatusBadgeVariant = keyof typeof statusStyles;\n\nexport function getStatusStyle(status: string): string {\n return statusStyles[status] ?? defaultStyle;\n}\n\nexport function StatusBadge({\n status,\n label,\n className,\n}: {\n status: string;\n label?: string;\n className?: string;\n}): React.JSX.Element {\n return (\n <span\n className={cn(\n \"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold capitalize\",\n getStatusStyle(status),\n className,\n )}\n >\n {label ?? status}\n </span>\n );\n}\n","\"use client\";\n\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Check, Plus } from \"lucide-react\";\nimport type { ContactGroup } from \"@fluid-app/contacts-core/types\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport {\n Button,\n cn,\n Input,\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@fluid-app/ui-primitives\";\n\nconst DEFAULT_SUGGESTIONS = [\n \"Customer\",\n \"Cold\",\n \"Hot\",\n \"New\",\n \"Leaders\",\n \"Pros\",\n];\n\nexport interface InlineGroupsEditorProps {\n contactTags: string[];\n availableGroups: ContactGroup[];\n onSave: (tags: string[]) => void;\n onCreateGroup?: (name: string) => void | Promise<void>;\n isSaving?: boolean;\n}\n\nexport function InlineGroupsEditor({\n contactTags,\n availableGroups,\n onSave,\n onCreateGroup,\n isSaving = false,\n}: InlineGroupsEditorProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [open, setOpen] = useState(false);\n const [draftTags, setDraftTags] = useState<string[]>([]);\n const [searchText, setSearchText] = useState(\"\");\n const [prevTags, setPrevTags] = useState<string[]>([]);\n const [newTags, setNewTags] = useState<Set<string>>(new Set());\n const [removingTags, setRemovingTags] = useState<Set<string>>(new Set());\n const [displayTags, setDisplayTags] = useState<string[]>(contactTags);\n const prevContactTagsRef = useRef<string[]>(contactTags);\n\n // Sync displayTags with contactTags, but delay removals for animation.\n // Comparing the previous and current contactTags (rather than displayTags)\n // keeps this effect free of a self-referential dependency.\n useEffect(() => {\n const prev = prevContactTagsRef.current;\n const removed = prev.filter((t) => !contactTags.includes(t));\n const added = contactTags.filter((t) => !prev.includes(t));\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n if (removed.length > 0) {\n setRemovingTags(new Set(removed));\n timer = setTimeout(() => {\n setDisplayTags(contactTags);\n setRemovingTags(new Set());\n }, 300);\n } else if (added.length > 0) {\n setDisplayTags(contactTags);\n } else if (\n prev.length !== contactTags.length ||\n prev.some((t, i) => contactTags[i] !== t)\n ) {\n setDisplayTags(contactTags);\n }\n\n prevContactTagsRef.current = contactTags;\n return () => {\n if (timer) clearTimeout(timer);\n };\n }, [contactTags]);\n\n useEffect(() => {\n if (newTags.size === 0) return;\n const timer = setTimeout(() => setNewTags(new Set()), 2000);\n return () => clearTimeout(timer);\n }, [newTags]);\n\n const handleOpen = useCallback(() => {\n setDraftTags([...contactTags]);\n setPrevTags([...contactTags]);\n setSearchText(\"\");\n setOpen(true);\n }, [contactTags]);\n\n const handleCancel = useCallback(() => {\n setOpen(false);\n setSearchText(\"\");\n }, []);\n\n const handleSave = useCallback(() => {\n const added = new Set(draftTags.filter((t) => !prevTags.includes(t)));\n onSave(draftTags);\n setOpen(false);\n setSearchText(\"\");\n if (added.size > 0) {\n setNewTags(added);\n }\n }, [draftTags, prevTags, onSave]);\n\n const toggleTag = useCallback((tag: string) => {\n setDraftTags((prev) =>\n prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag],\n );\n }, []);\n\n const groupsByName = useMemo(() => {\n const map = new Map<string, ContactGroup>();\n for (const g of availableGroups) {\n map.set(g.name, g);\n }\n return map;\n }, [availableGroups]);\n\n const allGroups = useMemo(() => {\n const groupNames = availableGroups.map((g) => g.name);\n return Array.from(new Set([...groupNames, ...DEFAULT_SUGGESTIONS]));\n }, [availableGroups]);\n\n const filtered = useMemo(() => {\n const lower = searchText.toLowerCase();\n if (!lower) return allGroups;\n return allGroups.filter((name) => name.toLowerCase().includes(lower));\n }, [allGroups, searchText]);\n\n const canCreateNew =\n !!onCreateGroup &&\n searchText.trim() &&\n !allGroups.some((s) => s.toLowerCase() === searchText.trim().toLowerCase());\n\n return (\n <Popover open={open} onOpenChange={(v) => !v && handleCancel()}>\n <PopoverTrigger asChild>\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleOpen}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleOpen();\n }\n }}\n className=\"group/groups flex cursor-pointer flex-wrap items-center gap-1.5\"\n >\n {displayTags.map((tag) => (\n <span\n key={tag}\n className={cn(\n \"bg-muted text-foreground inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium transition-all duration-300\",\n newTags.has(tag) &&\n \"animate-[badge-in_0.3s_ease-out,highlight-fade_2s_ease-out]\",\n removingTags.has(tag) &&\n \"animate-[badge-out_0.3s_ease-in_forwards]\",\n )}\n >\n {tag}\n </span>\n ))}\n <span\n className={cn(\n \"bg-muted text-muted-foreground hover:bg-muted/70 inline-flex items-center justify-center rounded-full px-2 py-0.5 text-xs font-medium transition-colors\",\n )}\n >\n <Plus className=\"size-3.5\" />\n </span>\n </div>\n </PopoverTrigger>\n\n <PopoverContent\n align=\"start\"\n className=\"bg-popover border-border z-50 w-72 rounded-lg border p-0 shadow-md\"\n >\n {/* Search */}\n <div className=\"p-1\">\n <Input\n type=\"text\"\n value={searchText}\n onChange={(e) => setSearchText(e.target.value)}\n placeholder={t(\"groups_inline_search_placeholder\")}\n />\n </div>\n\n {/* Group list */}\n <div className=\"max-h-48 overflow-y-auto py-1\">\n {filtered.map((name) => {\n const isSelected = draftTags.includes(name);\n const group = groupsByName.get(name);\n return (\n <button\n key={name}\n type=\"button\"\n onClick={() => toggleTag(name)}\n className=\"hover:bg-muted flex w-full items-center gap-2.5 px-3 py-2.5 text-left text-sm\"\n >\n {group?.avatar ? (\n <span\n className=\"flex size-5 shrink-0 items-center justify-center rounded-full text-xs\"\n style={{\n backgroundColor:\n group.avatar_background ?? \"var(--color-muted)\",\n }}\n >\n {group.avatar}\n </span>\n ) : (\n <span className=\"bg-muted flex size-5 shrink-0 items-center justify-center rounded-full text-[10px] font-medium\">\n {name[0]?.toUpperCase()}\n </span>\n )}\n <span className=\"text-foreground flex-1 truncate\">{name}</span>\n {isSelected && (\n <Check className=\"text-foreground size-4 shrink-0\" />\n )}\n </button>\n );\n })}\n {canCreateNew && (\n <button\n type=\"button\"\n onClick={async () => {\n const trimmed = searchText.trim();\n if (trimmed && !draftTags.includes(trimmed)) {\n try {\n await onCreateGroup?.(trimmed);\n } catch {\n return;\n }\n const updated = [...draftTags, trimmed];\n const added = new Set(\n updated.filter((t) => !prevTags.includes(t)),\n );\n onSave(updated);\n setOpen(false);\n setSearchText(\"\");\n setNewTags(added);\n }\n }}\n className=\"hover:bg-muted text-primary flex w-full items-center gap-2 px-3 py-2 text-left text-sm font-medium\"\n >\n <Plus className=\"size-3.5\" />\n {t(\"groups_inline_create\", { name: searchText.trim() })}\n </button>\n )}\n {filtered.length === 0 && !canCreateNew && (\n <p className=\"text-muted-foreground py-4 text-center text-sm\">\n {t(\"groups_inline_no_groups_found\")}\n </p>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"border-border flex items-center justify-between border-t px-3 py-2\">\n <span className=\"text-muted-foreground text-xs\">\n {draftTags.length === 1\n ? t(\"groups_inline_selected_one\", { count: draftTags.length })\n : t(\"groups_inline_selected_other\", { count: draftTags.length })}\n </span>\n <div className=\"flex gap-2\">\n <Button variant=\"ghost\" size=\"sm\" onClick={handleCancel}>\n {t(\"cancel\")}\n </Button>\n <Button size=\"sm\" onClick={handleSave} disabled={isSaving}>\n {isSaving ? t(\"saving\") : t(\"save\")}\n </Button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { ListTodo, StickyNote } from \"lucide-react\";\nimport type { Contact, ContactGroup } from \"@fluid-app/contacts-core/types\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { StatusBadge } from \"../../../../shared/components/contacts/statusBadge\";\nimport { InlineGroupsEditor } from \"./InlineGroupsEditor\";\nimport { getDisplayName, getInitials, getRelativeUpdated } from \"./utils\";\n\nexport interface ContactDetailHeroProps {\n contact: Contact;\n tasksCount: number;\n notesCount: number;\n contactTags: string[];\n availableGroups: ContactGroup[];\n onTagsSave: (tags: string[]) => void;\n onCreateGroup?: (name: string) => void | Promise<void>;\n isTagsSaving?: boolean;\n}\n\nexport function ContactDetailHero({\n contact,\n tasksCount,\n notesCount,\n contactTags,\n availableGroups,\n onTagsSave,\n onCreateGroup,\n isTagsSaving,\n}: ContactDetailHeroProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const name = getDisplayName(contact);\n const status = contact.status?.trim();\n const lastUpdated = getRelativeUpdated(contact);\n\n return (\n <div className=\"flex flex-col gap-6 md:flex-row md:items-center md:justify-between md:gap-8\">\n <div className=\"flex flex-col items-start gap-4 md:flex-row md:items-center md:gap-5\">\n <div className=\"bg-muted relative flex size-20 shrink-0 items-center justify-center overflow-hidden rounded-2xl md:size-24\">\n {contact.avatar_url ? (\n <img\n alt={name}\n src={contact.avatar_url}\n className=\"size-full object-cover\"\n />\n ) : (\n <span\n aria-hidden=\"true\"\n className=\"text-muted-foreground text-2xl font-bold tracking-tight md:text-3xl\"\n >\n {getInitials(name)}\n </span>\n )}\n </div>\n\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"text-foreground text-2xl leading-tight font-bold tracking-tight md:text-3xl\">\n {name}\n </h2>\n <div className=\"mt-2.5 flex flex-wrap items-center gap-2\">\n {status && <StatusBadge status={status} />}\n <InlineGroupsEditor\n contactTags={contactTags}\n availableGroups={availableGroups}\n onSave={onTagsSave}\n onCreateGroup={onCreateGroup}\n isSaving={isTagsSaving}\n />\n </div>\n {lastUpdated && (\n <span className=\"text-muted-foreground mt-1.5 text-xs\">\n {t(\"last_updated\", { date: lastUpdated })}\n </span>\n )}\n </div>\n </div>\n\n <div className=\"flex shrink-0 items-center gap-6 md:gap-8\">\n <Stat label={t(\"tab_tasks\")} value={tasksCount} icon={ListTodo} />\n <div className=\"bg-border h-10 w-px\" aria-hidden=\"true\" />\n <Stat label={t(\"tab_notes\")} value={notesCount} icon={StickyNote} />\n </div>\n </div>\n );\n}\n\ninterface StatProps {\n label: string;\n value: number;\n icon: React.ComponentType<{ className?: string; \"aria-hidden\"?: boolean }>;\n}\n\nfunction Stat({ label, value, icon: Icon }: StatProps) {\n return (\n <div className=\"flex flex-col items-start gap-1\">\n <div className=\"text-muted-foreground flex items-center gap-1.5\">\n <Icon className=\"size-3.5\" aria-hidden={true} />\n <span className=\"text-xs font-medium\">{label}</span>\n </div>\n <span className=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">\n {value}\n </span>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Check, Copy, Mail, MapPin, Phone, Plus } from \"lucide-react\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\n\nexport interface ContactInfoRowProps {\n contact: Contact;\n /** Click handler invoked when an empty-state row is activated. */\n onEditEmpty?: () => void;\n}\n\nfunction buildAddressLine(contact: Contact): string | null {\n const parts = [\n contact.address,\n contact.city,\n contact.state,\n contact.postal_code,\n ].filter((part): part is string => Boolean(part?.trim()));\n if (parts.length === 0) return null;\n return parts.join(\", \");\n}\n\nexport function ContactInfoRow({\n contact,\n onEditEmpty,\n}: ContactInfoRowProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const address = buildAddressLine(contact);\n\n return (\n <div className=\"border-border/50 divide-border/50 mt-6 divide-y overflow-hidden rounded-2xl border\">\n <InfoRow\n icon={Mail}\n label={t(\"label_email\")}\n value={contact.email}\n href={contact.email ? `mailto:${contact.email}` : undefined}\n onEditEmpty={onEditEmpty}\n />\n <InfoRow\n icon={Phone}\n label={t(\"label_phone\")}\n value={contact.phone}\n href={contact.phone ? `tel:${contact.phone}` : undefined}\n onEditEmpty={onEditEmpty}\n />\n <InfoRow\n icon={MapPin}\n label={t(\"label_address\")}\n value={address}\n href={\n address\n ? `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(address)}`\n : undefined\n }\n external={true}\n onEditEmpty={onEditEmpty}\n />\n </div>\n );\n}\n\ninterface InfoRowProps {\n icon: React.ComponentType<{ className?: string; \"aria-hidden\"?: boolean }>;\n label: string;\n value: string | null | undefined;\n href: string | undefined;\n external?: boolean;\n onEditEmpty?: () => void;\n}\n\nfunction InfoRow({\n icon: Icon,\n label,\n value,\n href,\n external = false,\n onEditEmpty,\n}: InfoRowProps) {\n const { t } = useContactsTranslation();\n const trimmed = value?.trim();\n const isEmpty = !trimmed;\n const [copied, setCopied] = useState(false);\n\n const handleCopy = () => {\n if (!trimmed) return;\n if (typeof navigator === \"undefined\" || !navigator.clipboard) return;\n navigator.clipboard\n .writeText(trimmed)\n .then(() => {\n setCopied(true);\n window.setTimeout(() => setCopied(false), 1500);\n })\n .catch(() => {\n // clipboard write can fail in insecure contexts; silently noop\n });\n };\n\n if (isEmpty) {\n const addText = t(\"add_field\", { field: label });\n if (!onEditEmpty) {\n return (\n <div className=\"flex items-center gap-3 px-4 py-2.5 md:px-5\">\n <div className=\"border-border/50 text-muted-foreground/50 flex size-9 shrink-0 items-center justify-center rounded-full border-2 border-dashed\">\n <Icon className=\"size-4\" aria-hidden={true} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-muted-foreground text-xs font-medium\">\n {label}\n </div>\n <div className=\"text-muted-foreground/70 truncate text-sm italic\">\n {addText}\n </div>\n </div>\n <Plus\n className=\"text-muted-foreground/40 size-4 shrink-0\"\n aria-hidden={true}\n />\n </div>\n );\n }\n return (\n <button\n type=\"button\"\n onClick={onEditEmpty}\n aria-label={addText}\n className=\"hover:bg-muted/60 group flex w-full items-center gap-3 px-4 py-2.5 text-left transition-colors md:px-5\"\n >\n <div className=\"border-border/50 text-muted-foreground/50 group-hover:border-foreground/30 group-hover:text-muted-foreground flex size-9 shrink-0 items-center justify-center rounded-full border-2 border-dashed transition-colors\">\n <Icon className=\"size-4\" aria-hidden={true} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-muted-foreground text-xs font-medium\">\n {label}\n </div>\n <div className=\"text-muted-foreground/70 group-hover:text-muted-foreground truncate text-sm italic transition-colors\">\n {addText}\n </div>\n </div>\n <Plus\n className=\"text-muted-foreground/40 group-hover:text-foreground size-4 shrink-0 transition-colors\"\n aria-hidden={true}\n />\n </button>\n );\n }\n\n return (\n <div className=\"hover:bg-muted/60 group flex items-center transition-colors\">\n <a\n href={href}\n {...(external ? { target: \"_blank\", rel: \"noopener noreferrer\" } : {})}\n className=\"flex min-w-0 flex-1 items-center gap-3 px-4 py-2.5 md:px-5\"\n >\n <div className=\"bg-muted text-muted-foreground group-hover:bg-muted/70 group-hover:text-foreground flex size-9 shrink-0 items-center justify-center rounded-full transition-colors\">\n <Icon className=\"size-4\" aria-hidden={true} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-muted-foreground text-xs font-medium\">\n {label}\n </div>\n <div className=\"text-foreground truncate text-sm font-semibold\">\n {trimmed}\n </div>\n </div>\n </a>\n <button\n type=\"button\"\n onClick={handleCopy}\n aria-label={\n copied\n ? t(\"copied_field\", { field: label })\n : t(\"copy_field\", { field: label })\n }\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground mr-3 flex size-8 shrink-0 items-center justify-center rounded-md transition-colors\"\n >\n {copied ? (\n <Check className=\"text-primary size-3.5\" aria-hidden={true} />\n ) : (\n <Copy className=\"size-3.5\" aria-hidden={true} />\n )}\n </button>\n </div>\n );\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useTasksApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useToggleTaskCompletion(contactId: string) {\n const queryClient = useQueryClient();\n const api = useTasksApi();\n\n return useMutation({\n mutationFn: ({\n taskId,\n isCompleted,\n }: {\n taskId: number;\n isCompleted: boolean;\n }) =>\n api.updateTask(taskId, contactId, {\n completed_at: isCompleted ? null : new Date().toISOString(),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: contactsKeys.tasks(contactId),\n });\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to update task\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useTasksApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useDeleteContactTask(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useTasksApi();\n\n return useMutation({\n mutationFn: (taskId: number) => api.deleteTask(taskId, contactId),\n onSuccess: () => {\n fluidToast({ title: \"Task deleted\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.tasks(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to delete task\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useTasksApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { UpdateTaskInput } from \"@fluid-app/contacts-core/types\";\n\nexport type { UpdateTaskInput };\n\nexport function useUpdateContactTask(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useTasksApi();\n\n return useMutation({\n mutationFn: ({\n taskId,\n input,\n }: {\n taskId: number;\n input: UpdateTaskInput;\n }) => api.updateTask(taskId, contactId, input),\n onSuccess: () => {\n fluidToast({ title: \"Task updated\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.tasks(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to update task\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","export function formatDateForDisplay(dateStr: string): string {\n const date = new Date(dateStr);\n return date.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n}\n","\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { useEditor, EditorContent } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport Heading from \"@tiptap/extension-heading\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport TextAlign from \"@tiptap/extension-text-align\";\nimport Underline from \"@tiptap/extension-underline\";\nimport {\n AlignLeft,\n AlignCenter,\n AlignRight,\n AlignJustify,\n List,\n ListOrdered,\n Calendar,\n X,\n} from \"lucide-react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport { formatDateForDisplay } from \"../../utils/format-date\";\n\nexport interface NoteTaskEditorProps {\n titlePlaceholder?: string;\n bodyPlaceholder?: string;\n onChange?: (content: {\n title: string;\n body: string;\n dueDate?: string;\n }) => void;\n className?: string;\n /** Pre-populate the title (for edit mode) */\n initialTitle?: string;\n /** Pre-populate the body (for edit mode) */\n initialBody?: string;\n /** Show due date picker */\n showDueDate?: boolean;\n /** Pre-populate the due date (ISO string, for edit mode) */\n initialDueDate?: string;\n /** When false, the editor is body-only (no H1 title). Default true. */\n showTitle?: boolean;\n /** Override for the editor content area min-height class */\n editorClassName?: string;\n}\n\nfunction extractTitleAndBody(editor: ReturnType<typeof useEditor>): {\n title: string;\n body: string;\n} {\n if (!editor) return { title: \"\", body: \"\" };\n\n const doc = editor.state.doc;\n let title = \"\";\n const bodyParts: string[] = [];\n\n doc.forEach((node) => {\n if (node.type.name === \"heading\" && !title) {\n title = node.textContent.trim();\n } else {\n const text = node.textContent.trim();\n if (text) bodyParts.push(text);\n }\n });\n\n return { title, body: bodyParts.join(\"\\n\") };\n}\n\nfunction extractBodyOnly(editor: ReturnType<typeof useEditor>): string {\n if (!editor) return \"\";\n const parts: string[] = [];\n editor.state.doc.forEach((node) => {\n const text = node.textContent.trim();\n if (text) parts.push(text);\n });\n return parts.join(\"\\n\");\n}\n\nexport function NoteTaskEditor({\n titlePlaceholder = \"New Note\",\n bodyPlaceholder = \"Start writing...\",\n onChange,\n className,\n initialTitle,\n initialBody,\n showDueDate = false,\n initialDueDate,\n showTitle = true,\n editorClassName,\n}: NoteTaskEditorProps): React.JSX.Element {\n const [dueDate, setDueDate] = useState<string | undefined>(initialDueDate);\n const dueDateRef = useRef(initialDueDate);\n const dateInputRef = useRef<HTMLInputElement>(null);\n\n // Keep ref in sync with state so onUpdate always reads the latest value\n useEffect(() => {\n dueDateRef.current = dueDate;\n }, [dueDate]);\n\n const initialContent = showTitle\n ? initialTitle || initialBody\n ? `<h1>${initialTitle ?? \"\"}</h1>${initialBody ?? \"\"}`\n : undefined\n : initialBody || undefined;\n\n const extensions = [\n StarterKit.configure({\n heading: showTitle ? false : { levels: [] as const },\n bulletList: {\n keepMarks: true,\n keepAttributes: false,\n },\n orderedList: {\n keepMarks: true,\n keepAttributes: false,\n },\n }),\n ...(showTitle ? [Heading.configure({ levels: [1] })] : []),\n Placeholder.configure({\n placeholder: ({ node }) => {\n if (node.type.name === \"heading\") {\n return titlePlaceholder;\n }\n return bodyPlaceholder;\n },\n }),\n TextAlign.configure({\n types: showTitle ? [\"heading\", \"paragraph\"] : [\"paragraph\"],\n alignments: [\"left\", \"center\", \"right\", \"justify\"],\n }),\n Underline,\n ];\n\n const defaultContent = showTitle\n ? {\n type: \"doc\" as const,\n content: [{ type: \"heading\" as const, attrs: { level: 1 } }],\n }\n : undefined;\n\n const editor = useEditor({\n extensions,\n content: initialContent ?? defaultContent,\n onUpdate: ({ editor }) => {\n if (showTitle) {\n const { title, body } = extractTitleAndBody(editor);\n onChange?.({ title, body, dueDate: dueDateRef.current });\n } else {\n const body = extractBodyOnly(editor);\n onChange?.({ title: \"\", body, dueDate: dueDateRef.current });\n }\n },\n });\n\n const fireOnChange = () => {\n if (!editor || !onChange) return;\n if (showTitle) {\n const { title, body } = extractTitleAndBody(editor);\n onChange({ title, body, dueDate });\n } else {\n const body = extractBodyOnly(editor);\n onChange({ title: \"\", body, dueDate });\n }\n };\n\n // Fire onChange once on mount so the parent's ref is populated with the\n // initial values before the user makes any edits.\n useEffect(() => {\n fireOnChange();\n // We only want this to run once after the editor is first created.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editor]);\n\n // Notify parent when due date changes\n useEffect(() => {\n fireOnChange();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dueDate]);\n\n const buttonBase =\n \"flex h-7 w-7 items-center justify-center rounded text-xs transition-colors\";\n const buttonActive = \"bg-muted text-primary\";\n const buttonInactive = \"text-muted-foreground hover:bg-muted/50\";\n\n const toolbarSeparator = <div className=\"bg-border mx-1 h-5 w-px\" />;\n\n return (\n <div\n className={cn(\n \"border-border/50 flex flex-col overflow-hidden rounded-lg border\",\n className,\n )}\n >\n {/* Toolbar */}\n <div className=\"border-border/50 bg-muted/50 flex items-center gap-0.5 border-b px-2 py-1.5\">\n {/* Bold */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleBold().run()}\n disabled={!editor?.can().chain().focus().toggleBold().run()}\n className={cn(\n buttonBase,\n \"font-bold\",\n editor?.isActive(\"bold\") ? buttonActive : buttonInactive,\n )}\n title=\"Bold\"\n >\n B\n </button>\n\n {/* Italic */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleItalic().run()}\n disabled={!editor?.can().chain().focus().toggleItalic().run()}\n className={cn(\n buttonBase,\n \"italic\",\n editor?.isActive(\"italic\") ? buttonActive : buttonInactive,\n )}\n title=\"Italic\"\n >\n I\n </button>\n\n {/* Underline */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleUnderline().run()}\n disabled={!editor?.can().chain().focus().toggleUnderline().run()}\n className={cn(\n buttonBase,\n \"underline\",\n editor?.isActive(\"underline\") ? buttonActive : buttonInactive,\n )}\n title=\"Underline\"\n >\n U\n </button>\n\n {toolbarSeparator}\n\n {/* Align left */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().setTextAlign(\"left\").run()}\n className={cn(\n buttonBase,\n editor?.isActive({ textAlign: \"left\" })\n ? buttonActive\n : buttonInactive,\n )}\n title=\"Align left\"\n >\n <AlignLeft className=\"size-3.5\" />\n </button>\n\n {/* Align center */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().setTextAlign(\"center\").run()}\n className={cn(\n buttonBase,\n editor?.isActive({ textAlign: \"center\" })\n ? buttonActive\n : buttonInactive,\n )}\n title=\"Align center\"\n >\n <AlignCenter className=\"size-3.5\" />\n </button>\n\n {/* Align right */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().setTextAlign(\"right\").run()}\n className={cn(\n buttonBase,\n editor?.isActive({ textAlign: \"right\" })\n ? buttonActive\n : buttonInactive,\n )}\n title=\"Align right\"\n >\n <AlignRight className=\"size-3.5\" />\n </button>\n\n {/* Align justify */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().setTextAlign(\"justify\").run()}\n className={cn(\n buttonBase,\n editor?.isActive({ textAlign: \"justify\" })\n ? buttonActive\n : buttonInactive,\n )}\n title=\"Justify\"\n >\n <AlignJustify className=\"size-3.5\" />\n </button>\n\n {toolbarSeparator}\n\n {/* Bullet list */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleBulletList().run()}\n className={cn(\n buttonBase,\n editor?.isActive(\"bulletList\") ? buttonActive : buttonInactive,\n )}\n title=\"Bullet list\"\n >\n <List className=\"size-3.5\" />\n </button>\n\n {/* Ordered list */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleOrderedList().run()}\n className={cn(\n buttonBase,\n editor?.isActive(\"orderedList\") ? buttonActive : buttonInactive,\n )}\n title=\"Ordered list\"\n >\n <ListOrdered className=\"size-3.5\" />\n </button>\n\n {showDueDate && (\n <>\n {toolbarSeparator}\n {/* Due date */}\n {dueDate ? (\n <div className=\"bg-primary/10 flex items-center gap-1 rounded px-2 py-1\">\n <Calendar className=\"text-primary size-3.5\" />\n <span className=\"text-primary text-xs font-medium\">\n {formatDateForDisplay(dueDate)}\n </span>\n <button\n type=\"button\"\n onClick={() => setDueDate(undefined)}\n className=\"text-primary/60 hover:text-primary ml-1\"\n title=\"Remove due date\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ) : (\n <>\n <button\n type=\"button\"\n onClick={() => dateInputRef.current?.showPicker()}\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex h-7 cursor-pointer items-center gap-1 rounded px-2 text-xs font-medium transition-colors\"\n >\n <Calendar className=\"size-3.5\" />\n <span>Due date</span>\n </button>\n <input\n ref={dateInputRef}\n type=\"date\"\n className=\"invisible absolute size-0\"\n onChange={(e) => {\n if (e.target.value) {\n // Convert YYYY-MM-DD to ISO datetime at local midnight\n const localDate = new Date(e.target.value + \"T00:00:00\");\n setDueDate(localDate.toISOString());\n }\n }}\n />\n </>\n )}\n </>\n )}\n </div>\n\n {/* Editor area */}\n <EditorContent\n editor={editor}\n className={editorClassName ?? \"min-h-[60vh] flex-1 overflow-y-auto p-4\"}\n />\n\n <style>{`\n .ProseMirror {\n outline: none;\n }\n\n .ProseMirror h1 {\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.3;\n margin-bottom: 0.5rem;\n }\n\n .ProseMirror h1.is-empty::before,\n .ProseMirror p.is-empty::before {\n color: var(--color-muted-foreground);\n content: attr(data-placeholder);\n float: left;\n height: 0;\n pointer-events: none;\n }\n\n .ProseMirror ul {\n list-style-type: disc;\n padding-left: 1.5rem;\n margin: 0.5rem 0;\n }\n\n .ProseMirror ol {\n list-style-type: decimal;\n padding-left: 1.5rem;\n margin: 0.5rem 0;\n }\n\n .ProseMirror li {\n margin: 0.25rem 0;\n display: list-item;\n }\n\n .ProseMirror li > p {\n margin: 0;\n }\n `}</style>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport { Calendar, X } from \"lucide-react\";\nimport {\n Button,\n Input,\n Sheet,\n SheetContent,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n} from \"@fluid-app/ui-primitives\";\nimport { NoteTaskEditor } from \"./note-task-editor\";\nimport { formatDateForDisplay } from \"../../utils/format-date\";\n\nexport interface NoteTaskModalProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n mode: \"create\" | \"edit\";\n type: \"note\" | \"task\";\n initialTitle?: string;\n initialBody?: string;\n initialDueDate?: string;\n showDueDate?: boolean;\n onSave: (data: { title: string; body: string; dueDate?: string }) => void;\n isPending?: boolean;\n isCompleted?: boolean;\n onToggleComplete?: () => void;\n isTogglePending?: boolean;\n}\n\nexport function NoteTaskModal({\n open,\n onOpenChange,\n mode,\n type,\n initialTitle = \"\",\n initialBody = \"\",\n initialDueDate,\n showDueDate = false,\n onSave,\n isPending = false,\n isCompleted,\n onToggleComplete,\n isTogglePending = false,\n}: NoteTaskModalProps): React.JSX.Element {\n const [title, setTitle] = useState(initialTitle);\n const [body, setBody] = useState(initialBody);\n const dateInputRef = useRef<HTMLInputElement>(null);\n const [dueDate, setDueDate] = useState<string | undefined>(initialDueDate);\n\n const typeLabel = type === \"note\" ? \"Note\" : \"Task\";\n const sheetTitle = mode === \"edit\" ? `Edit ${typeLabel}` : `New ${typeLabel}`;\n\n const requiresBody = type === \"note\";\n const canSave =\n !!title.trim() && (!requiresBody || !!body.trim()) && !isPending;\n\n const handleSave = () => {\n if (!canSave) return;\n onSave({\n title: title.trim(),\n body,\n dueDate,\n });\n };\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent className=\"flex w-full flex-col sm:max-w-lg\">\n <SheetHeader>\n <SheetTitle>{sheetTitle}</SheetTitle>\n </SheetHeader>\n\n <div className=\"flex min-h-0 flex-1 flex-col gap-3\">\n <Input\n placeholder={`${typeLabel} title`}\n value={title}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setTitle(e.target.value)\n }\n autoFocus\n />\n\n <NoteTaskEditor\n showTitle={false}\n bodyPlaceholder=\"Start writing...\"\n initialBody={initialBody}\n editorClassName=\"min-h-[200px] flex-1 overflow-y-auto p-4\"\n onChange={(content) => {\n setBody(content.body);\n }}\n />\n\n {showDueDate && (\n <div className=\"flex items-center gap-2\">\n {dueDate ? (\n <div className=\"bg-primary/10 inline-flex items-center gap-1.5 rounded-md px-2.5 py-1.5\">\n <Calendar className=\"text-primary size-3.5\" />\n <span className=\"text-primary text-sm font-medium\">\n Due {formatDateForDisplay(dueDate)}\n </span>\n <button\n type=\"button\"\n onClick={() => setDueDate(undefined)}\n className=\"text-primary/60 hover:text-primary ml-1\"\n title=\"Remove due date\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ) : (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={() => dateInputRef.current?.showPicker()}\n className=\"text-muted-foreground hover:text-foreground hover:bg-muted inline-flex cursor-pointer items-center gap-1.5 rounded-md px-2.5 py-1.5 text-sm font-medium transition-colors\"\n >\n <Calendar className=\"size-3.5\" />\n <span>Add due date</span>\n </button>\n <input\n ref={dateInputRef}\n type=\"date\"\n className=\"invisible absolute size-0\"\n onChange={(e) => {\n if (e.target.value) {\n const localDate = new Date(\n e.target.value + \"T00:00:00\",\n );\n setDueDate(localDate.toISOString());\n }\n }}\n />\n </div>\n )}\n </div>\n )}\n </div>\n\n <SheetFooter className=\"flex-row justify-end gap-2 border-t pt-4\">\n {mode === \"edit\" && onToggleComplete && (\n <Button\n variant=\"outline\"\n onClick={onToggleComplete}\n disabled={isTogglePending}\n className=\"mr-auto\"\n >\n {isCompleted ? \"Mark Incomplete\" : \"Mark Complete\"}\n </Button>\n )}\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={!canSave}>\n {isPending ? \"Saving...\" : \"Save\"}\n </Button>\n </SheetFooter>\n </SheetContent>\n </Sheet>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Calendar, CircleCheck, EllipsisVertical } from \"lucide-react\";\nimport {\n cn,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@fluid-app/ui-primitives\";\nimport { parseTaskBody } from \"@fluid-app/contacts-core/parse-task-body\";\nimport { startOfLocalDay } from \"@fluid-app/contacts-core/iso-date\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport type { ContactTask } from \"../../hooks/contacts/use-contact-tasks\";\nimport { useToggleTaskCompletion } from \"../../hooks/contacts/use-toggle-task-completion\";\nimport { useDeleteContactTask } from \"../../hooks/contacts/use-delete-contact-task\";\nimport { useUpdateContactTask } from \"../../hooks/contacts/use-update-contact-task\";\nimport { NoteTaskModal } from \"../editor/note-task-modal\";\n\n// ---------------------------------------------------------------------------\n// Date helpers\n// ---------------------------------------------------------------------------\n\nfunction formatDueDate(dateStr: string): string {\n const date = new Date(dateStr);\n return date.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n}\n\ntype ContactsT = ReturnType<typeof useContactsTranslation>[\"t\"];\n\nfunction formatRelativeTime(dateStr: string, t: ContactsT): string {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) {\n return date.toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n }\n if (diffDays === 1) return t(\"task_yesterday\");\n return diffDays === 1\n ? t(\"task_days_ago_one\")\n : t(\"task_days_ago_other\", { count: diffDays });\n}\n\ntype DueClassification = {\n label: string;\n tone: \"overdue\" | \"today\" | \"tomorrow\" | \"future\" | \"done\";\n};\n\nfunction classifyDue(\n dueAt: string,\n isCompleted: boolean,\n t: ContactsT,\n): DueClassification {\n if (isCompleted) {\n return {\n label: t(\"task_due\", { date: formatDueDate(dueAt) }),\n tone: \"done\",\n };\n }\n const due = startOfLocalDay(dueAt);\n const today = startOfLocalDay(new Date());\n const tomorrow = new Date(today);\n tomorrow.setDate(today.getDate() + 1);\n\n const dueTime = due.getTime();\n if (dueTime < today.getTime()) {\n return {\n label: t(\"task_overdue_due\", { date: formatDueDate(dueAt) }),\n tone: \"overdue\",\n };\n }\n if (dueTime === today.getTime())\n return { label: t(\"quick_today\"), tone: \"today\" };\n if (dueTime === tomorrow.getTime())\n return { label: t(\"quick_tomorrow\"), tone: \"tomorrow\" };\n return { label: formatDueDate(dueAt), tone: \"future\" };\n}\n\nconst DUE_TONE_CLASS: Record<DueClassification[\"tone\"], string> = {\n overdue: \"bg-destructive/10 text-destructive\",\n today: \"bg-primary/10 text-primary\",\n tomorrow: \"bg-primary/10 text-primary\",\n future: \"bg-muted text-muted-foreground\",\n done: \"bg-muted text-muted-foreground\",\n};\n\n// ---------------------------------------------------------------------------\n// Task card\n// ---------------------------------------------------------------------------\n\ninterface TaskCardProps {\n task: ContactTask;\n toggleCompletion: ReturnType<typeof useToggleTaskCompletion>;\n onEdit: (task: ContactTask) => void;\n onDeleteClick: (task: ContactTask) => void;\n}\n\nfunction TaskCard({\n task,\n toggleCompletion,\n onEdit,\n onDeleteClick,\n}: TaskCardProps) {\n const { t } = useContactsTranslation();\n const isCompleted = !!task.completed_at;\n\n const { title, body: bodyText } = parseTaskBody(task.body ?? \"\");\n\n const timestamp = task.created_at\n ? formatRelativeTime(task.created_at, t)\n : \"\";\n const due = task.due_at ? classifyDue(task.due_at, isCompleted, t) : null;\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={() => onEdit(task)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onEdit(task);\n }\n }}\n className=\"group border-border/50 hover:border-foreground/20 hover:bg-muted/40 relative cursor-pointer rounded-xl border p-4 transition-all hover:shadow-sm\"\n >\n <div className=\"flex items-start gap-3\">\n {/* Checkbox */}\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n toggleCompletion.mutate({\n taskId: task.id,\n isCompleted: isCompleted,\n });\n }}\n disabled={toggleCompletion.isPending}\n className=\"mt-0.5 shrink-0 transition-transform hover:scale-110 disabled:cursor-not-allowed disabled:opacity-50\"\n aria-label={isCompleted ? t(\"mark_as_open\") : t(\"mark_as_completed\")}\n >\n {isCompleted ? (\n <CircleCheck className=\"text-primary size-5\" aria-hidden=\"true\" />\n ) : (\n <div className=\"border-muted-foreground/40 group-hover:border-primary size-5 rounded-full border-2 transition-colors\" />\n )}\n </button>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <h4\n className={cn(\n \"text-foreground line-clamp-2 text-sm leading-snug font-semibold\",\n isCompleted && \"text-muted-foreground line-through\",\n )}\n >\n {title}\n </h4>\n\n {/* Body text */}\n {bodyText && (\n <p\n className={cn(\n \"text-muted-foreground mt-1 line-clamp-2 text-xs leading-relaxed\",\n isCompleted && \"line-through\",\n )}\n >\n {bodyText}\n </p>\n )}\n\n {/* Meta row */}\n {(due || timestamp) && (\n <div className=\"mt-2.5 flex flex-wrap items-center gap-1.5\">\n {due && (\n <span\n className={cn(\n \"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium\",\n DUE_TONE_CLASS[due.tone],\n )}\n >\n <Calendar className=\"size-3\" aria-hidden=\"true\" />\n {due.label}\n </span>\n )}\n {timestamp && (\n <span className=\"text-muted-foreground/60 text-xs\">\n {timestamp}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n\n {/* Hover-revealed menu */}\n <div className=\"absolute top-3 right-3 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n onClick={(e) => e.stopPropagation()}\n aria-label={t(\"task_actions\")}\n >\n <EllipsisVertical className=\"size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n className=\"text-destructive\"\n onClick={(e) => {\n e.stopPropagation();\n onDeleteClick(task);\n }}\n >\n {t(\"delete\")}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport interface TaskListProps {\n tasks: ContactTask[];\n isLoading?: boolean;\n contactId: string;\n /**\n * Retained for backwards compatibility — currently has no effect since the\n * inline composer always renders above the list. Will be removed once all\n * consumers stop passing it.\n */\n hideHeader?: boolean;\n}\n\nexport function TaskList({\n tasks,\n isLoading,\n contactId,\n}: TaskListProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [taskToDelete, setTaskToDelete] = useState<ContactTask | null>(null);\n const [editingTask, setEditingTask] = useState<ContactTask | null>(null);\n\n const toggleCompletion = useToggleTaskCompletion(contactId);\n const deleteTask = useDeleteContactTask(contactId, {\n onSuccess: () => setTaskToDelete(null),\n });\n const updateTask = useUpdateContactTask(contactId, {\n onSuccess: () => setEditingTask(null),\n });\n\n const handleSave = (data: {\n title: string;\n body: string;\n dueDate?: string;\n }) => {\n if (!editingTask) return;\n const taskBody = data.body ? `${data.title}\\n\\n${data.body}` : data.title;\n updateTask.mutate({\n taskId: editingTask.id,\n input: { body: taskBody, due_at: data.dueDate ?? null },\n });\n };\n\n const editingParsed = editingTask\n ? parseTaskBody(editingTask.body ?? \"\")\n : null;\n\n const handleModalOpenChange = (open: boolean) => {\n if (!open) setEditingTask(null);\n };\n\n if (isLoading) {\n return (\n <div className=\"flex flex-col gap-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"border-border/50 bg-muted/50 h-32 animate-pulse rounded-xl border\"\n />\n ))}\n </div>\n );\n }\n\n if (tasks.length === 0) return <></>;\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-col gap-3\">\n {tasks.map((task) => (\n <TaskCard\n key={task.id}\n task={task}\n toggleCompletion={toggleCompletion}\n onEdit={setEditingTask}\n onDeleteClick={setTaskToDelete}\n />\n ))}\n </div>\n\n {/* Edit modal — create flow lives in InlineTaskComposer */}\n <NoteTaskModal\n key={editingTask?.id ?? \"edit\"}\n open={editingTask !== null}\n onOpenChange={handleModalOpenChange}\n mode=\"edit\"\n type=\"task\"\n initialTitle={editingParsed?.title ?? \"\"}\n initialBody={editingParsed?.body ?? \"\"}\n initialDueDate={editingTask?.due_at ?? undefined}\n showDueDate\n onSave={handleSave}\n isPending={updateTask.isPending}\n isCompleted={editingTask ? !!editingTask.completed_at : undefined}\n onToggleComplete={\n editingTask\n ? () =>\n toggleCompletion.mutate(\n {\n taskId: editingTask.id,\n isCompleted: !!editingTask.completed_at,\n },\n { onSuccess: () => setEditingTask(null) },\n )\n : undefined\n }\n isTogglePending={toggleCompletion.isPending}\n />\n\n {/* Delete confirmation modal */}\n <AlertDialog\n open={taskToDelete !== null}\n onOpenChange={(open) => {\n if (!open) setTaskToDelete(null);\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{t(\"delete_task_title\")}</AlertDialogTitle>\n <AlertDialogDescription>\n {t(\"delete_task_confirm\")}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>{t(\"cancel\")}</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => {\n if (taskToDelete) {\n deleteTask.mutate(taskToDelete.id);\n }\n }}\n >\n {t(\"delete\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Plus } from \"lucide-react\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { TaskComposerForm } from \"./task-composer-form\";\n\nexport interface InlineTaskComposerProps {\n contactId: string;\n}\n\nexport function InlineTaskComposer({\n contactId,\n}: InlineTaskComposerProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [isOpen, setIsOpen] = useState(false);\n\n if (!isOpen) {\n return (\n <button\n type=\"button\"\n onClick={() => setIsOpen(true)}\n className=\"border-border/50 text-muted-foreground hover:border-foreground/30 hover:bg-muted/40 hover:text-foreground flex w-full items-center gap-3 rounded-xl border border-dashed px-5 py-4 text-sm font-medium transition-colors\"\n >\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n {t(\"new_task\")}\n </button>\n );\n }\n\n const close = () => setIsOpen(false);\n return (\n <TaskComposerForm contactId={contactId} onClose={close} onDone={close} />\n );\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useNotesApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useDeleteContactNote(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useNotesApi();\n\n return useMutation({\n mutationFn: (noteId: number) => api.deleteNote(noteId, contactId),\n onSuccess: () => {\n fluidToast({ title: \"Note deleted\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.notes(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to delete note\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useNotesApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { UpdateNoteInput } from \"@fluid-app/contacts-core/types\";\n\nexport type { UpdateNoteInput };\n\nexport function useUpdateContactNote(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useNotesApi();\n\n return useMutation({\n mutationFn: ({\n noteId,\n input,\n }: {\n noteId: number;\n input: UpdateNoteInput;\n }) => api.updateNote(noteId, contactId, input),\n onSuccess: () => {\n fluidToast({ title: \"Note updated\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.notes(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to update note\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useNotesApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { CreateNoteInput } from \"@fluid-app/contacts-core/types\";\n\nexport type { CreateNoteInput };\n\nexport function useCreateContactNote(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useNotesApi();\n\n return useMutation({\n mutationFn: (input: CreateNoteInput) => api.createNote(contactId, input),\n onSuccess: () => {\n fluidToast({ title: \"Note created\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.notes(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to create note\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { useCreateContactNote } from \"../../hooks/notes/use-create-contact-note\";\n\nexport interface InlineNoteComposerProps {\n contactId: string;\n}\n\nfunction detectMacPlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n // Prefer userAgentData.platform when available (modern Chromium); fall back\n // to userAgent string. navigator.platform is deprecated.\n const uaData = (\n navigator as Navigator & {\n userAgentData?: { platform?: string };\n }\n ).userAgentData;\n const platform = uaData?.platform ?? navigator.userAgent ?? \"\";\n return /Mac|iPhone|iPad/i.test(platform);\n}\n\nexport function InlineNoteComposer({\n contactId,\n}: InlineNoteComposerProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [body, setBody] = useState(\"\");\n const [isFocused, setIsFocused] = useState(false);\n const [isMac, setIsMac] = useState(false);\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n\n // Detect platform on mount only — avoids SSR hydration mismatch from reading\n // navigator at module load.\n useEffect(() => {\n setIsMac(detectMacPlatform());\n }, []);\n\n const createNote = useCreateContactNote(contactId, {\n onSuccess: () => {\n setBody(\"\");\n textareaRef.current?.blur();\n },\n });\n\n const submit = () => {\n const trimmed = body.trim();\n if (!trimmed || createNote.isPending) return;\n const firstLine = trimmed.split(\"\\n\")[0]?.slice(0, 120) ?? \"Note\";\n createNote.mutate({ title: firstLine, body: trimmed });\n };\n\n const canSubmit = body.trim().length > 0 && !createNote.isPending;\n\n return (\n <div\n className={cn(\n \"border-border/50 focus-within:border-foreground/30 rounded-2xl border p-4 transition-colors\",\n isFocused && \"border-foreground/30\",\n )}\n >\n <textarea\n ref={textareaRef}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") {\n e.preventDefault();\n submit();\n }\n }}\n placeholder={t(\"note_placeholder\")}\n aria-label={t(\"note_body_aria\")}\n rows={3}\n className=\"placeholder:text-muted-foreground text-foreground min-h-[80px] w-full resize-none border-0 bg-transparent text-sm leading-relaxed outline-none\"\n />\n <div className=\"mt-3 flex items-center justify-between gap-3\">\n <span className=\"text-muted-foreground text-xs\">\n {isMac ? t(\"tip_save_shortcut_mac\") : t(\"tip_save_shortcut_other\")}\n </span>\n <button\n type=\"button\"\n onClick={submit}\n disabled={!canSubmit}\n className=\"bg-primary text-primary-foreground hover:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground inline-flex shrink-0 items-center gap-1.5 rounded-full px-4 py-1.5 text-xs font-semibold transition-colors disabled:cursor-not-allowed\"\n >\n {createNote.isPending ? t(\"adding\") : t(\"add_note\")}\n </button>\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Calendar, Paperclip, EllipsisVertical } from \"lucide-react\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Button,\n cn,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@fluid-app/ui-primitives\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport type { ContactNote } from \"../../hooks/notes/use-contact-notes\";\nimport { useDeleteContactNote } from \"../../hooks/notes/use-delete-contact-note\";\nimport { useUpdateContactNote } from \"../../hooks/notes/use-update-contact-note\";\nimport { NoteTaskModal } from \"../editor/note-task-modal\";\nimport { InlineNoteComposer } from \"./inline-note-composer\";\n\n// ---------------------------------------------------------------------------\n// Date helpers\n// ---------------------------------------------------------------------------\n\nfunction formatDueDate(dateStr: string): string {\n const date = new Date(dateStr);\n return date.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n}\n\ntype ContactsT = ReturnType<typeof useContactsTranslation>[\"t\"];\n\nfunction formatRelativeNote(dateStr: string, t: ContactsT): string {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) {\n return date.toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n }\n if (diffDays === 1) return t(\"task_yesterday\");\n if (diffDays < 7) return t(\"task_days_ago_other\", { count: diffDays });\n return formatDueDate(dateStr);\n}\n\n// ---------------------------------------------------------------------------\n// Note card\n// ---------------------------------------------------------------------------\n\nfunction NoteCard({\n note,\n onEdit,\n onDelete,\n}: {\n note: ContactNote;\n onEdit: (note: ContactNote) => void;\n onDelete: (note: ContactNote) => void;\n}) {\n const { t } = useContactsTranslation();\n const assetCount = note.assets?.length ?? 0;\n const showTitle =\n !!note.title?.trim() && note.title.trim() !== note.body?.trim();\n const dueDateValue = note.due_at ?? note.due_date ?? null;\n const createdLabel = note.created_at\n ? formatRelativeNote(note.created_at, t)\n : null;\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={() => onEdit(note)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onEdit(note);\n }\n }}\n className=\"group border-border/50 hover:border-foreground/20 hover:bg-muted/40 relative cursor-pointer rounded-xl border p-4 transition-all hover:shadow-sm\"\n >\n {showTitle && (\n <h4 className=\"text-foreground line-clamp-1 text-sm font-semibold\">\n {note.title}\n </h4>\n )}\n\n <p\n className={cn(\n \"text-foreground line-clamp-4 text-sm leading-relaxed whitespace-pre-wrap\",\n showTitle && \"text-muted-foreground mt-1\",\n )}\n >\n {note.body}\n </p>\n\n {(createdLabel || dueDateValue || assetCount > 0) && (\n <div className=\"mt-2.5 flex flex-wrap items-center gap-3\">\n {createdLabel && (\n <span className=\"text-muted-foreground/70 text-xs\">\n {createdLabel}\n </span>\n )}\n {dueDateValue && (\n <span className=\"bg-primary/10 text-primary inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium\">\n <Calendar className=\"size-3\" aria-hidden=\"true\" />\n {t(\"task_due\", { date: formatDueDate(dueDateValue) })}\n </span>\n )}\n {assetCount > 0 && (\n <span className=\"text-muted-foreground inline-flex items-center gap-1 text-xs\">\n <Paperclip className=\"size-3\" aria-hidden=\"true\" />\n {assetCount === 1\n ? t(\"attachment_one\")\n : t(\"attachment_other\", { count: assetCount })}\n </span>\n )}\n </div>\n )}\n\n <div className=\"absolute top-3 right-3 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n onClick={(e) => e.stopPropagation()}\n aria-label={t(\"note_actions\")}\n >\n <EllipsisVertical className=\"size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n className=\"text-destructive\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(note);\n }}\n >\n {t(\"delete\")}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport interface NotesListProps {\n notes: ContactNote[];\n isLoading?: boolean;\n contactId: string;\n}\n\nexport function NotesList({\n notes,\n isLoading,\n contactId,\n}: NotesListProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [noteToDelete, setNoteToDelete] = useState<ContactNote | null>(null);\n const [editingNote, setEditingNote] = useState<ContactNote | null>(null);\n\n const deleteNote = useDeleteContactNote(contactId, {\n onSuccess: () => setNoteToDelete(null),\n });\n const updateNote = useUpdateContactNote(contactId, {\n onSuccess: () => setEditingNote(null),\n });\n\n const handleEditSave = (data: { title: string; body: string }) => {\n if (!editingNote) return;\n updateNote.mutate({\n noteId: editingNote.id,\n input: { title: data.title, body: data.body },\n });\n };\n\n return (\n <div className=\"space-y-4\">\n <InlineNoteComposer contactId={contactId} />\n\n {isLoading ? (\n <div className=\"flex flex-col gap-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"border-border/50 bg-muted/50 h-20 animate-pulse rounded-xl border\"\n />\n ))}\n </div>\n ) : notes.length === 0 ? null : (\n <div className=\"flex flex-col gap-3\">\n {notes.map((note) => (\n <NoteCard\n key={note.id}\n note={note}\n onEdit={setEditingNote}\n onDelete={setNoteToDelete}\n />\n ))}\n </div>\n )}\n\n {/* Edit modal — create flow now lives in InlineNoteComposer */}\n <NoteTaskModal\n key={editingNote?.id ?? \"edit\"}\n open={editingNote !== null}\n onOpenChange={(open) => {\n if (!open) setEditingNote(null);\n }}\n mode=\"edit\"\n type=\"note\"\n initialTitle={editingNote?.title ?? \"\"}\n initialBody={editingNote?.body ?? \"\"}\n onSave={handleEditSave}\n isPending={updateNote.isPending}\n />\n\n {/* Delete confirmation */}\n <AlertDialog\n open={!!noteToDelete}\n onOpenChange={(open) => {\n if (!open) setNoteToDelete(null);\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{t(\"delete_note_title\")}</AlertDialogTitle>\n <AlertDialogDescription>\n {t(\"delete_note_irreversible\")}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>{t(\"cancel\")}</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => {\n if (noteToDelete) {\n deleteNote.mutate(noteToDelete.id);\n }\n }}\n >\n {t(\"delete\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { TaskList } from \"../../tasks/task-list\";\nimport { InlineTaskComposer } from \"../../tasks/inline-task-composer\";\nimport { NotesList } from \"../../notes/notes-list\";\nimport type { ContactTask } from \"../../../hooks/contacts/use-contact-tasks\";\nimport type { ContactNote } from \"../../../hooks/notes/use-contact-notes\";\n\nconst VISIBLE_TABS = [\"Tasks\", \"Notes\"] as const;\nexport type TabType = (typeof VISIBLE_TABS)[number];\n\nexport interface ContactDetailTabsProps {\n contactId: string;\n tasks: ContactTask[];\n isLoadingTasks: boolean;\n notes: ContactNote[];\n isLoadingNotes: boolean;\n activeTab: TabType;\n onTabChange: (tab: TabType) => void;\n}\n\nexport function ContactDetailTabs({\n contactId,\n tasks,\n isLoadingTasks,\n notes,\n isLoadingNotes,\n activeTab,\n onTabChange,\n}: ContactDetailTabsProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const tabLabels: Record<TabType, string> = {\n Tasks: t(\"tab_tasks\"),\n Notes: t(\"tab_notes\"),\n };\n return (\n <div className=\"mt-8\">\n <div className=\"border-border/50 flex items-center gap-1 border-b\">\n {VISIBLE_TABS.map((tab) => {\n const count = tab === \"Tasks\" ? tasks.length : notes.length;\n const isActive = activeTab === tab;\n return (\n <button\n key={tab}\n type=\"button\"\n onClick={() => onTabChange(tab)}\n className={cn(\n \"relative flex items-center gap-1.5 px-3 py-2.5 text-sm font-semibold transition-colors\",\n isActive\n ? \"text-foreground\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n >\n {tabLabels[tab]}\n <span\n className={cn(\n \"rounded-full px-1.5 text-xs leading-5 font-bold\",\n isActive\n ? \"bg-primary text-primary-foreground\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {count}\n </span>\n {isActive && (\n <span\n className=\"bg-primary absolute inset-x-0 -bottom-px h-0.5\"\n aria-hidden=\"true\"\n />\n )}\n </button>\n );\n })}\n </div>\n\n <div className=\"pt-6\">\n {activeTab === \"Tasks\" && (\n <div className=\"space-y-4\">\n <InlineTaskComposer contactId={contactId} />\n <TaskList\n tasks={tasks}\n isLoading={isLoadingTasks}\n contactId={contactId}\n hideHeader\n />\n </div>\n )}\n\n {activeTab === \"Notes\" && (\n <NotesList\n notes={notes}\n isLoading={isLoadingNotes}\n contactId={contactId}\n />\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useCallback, useState } from \"react\";\nimport { FormProvider } from \"react-hook-form\";\nimport {\n ChevronLeft,\n Mail,\n MoreHorizontal,\n Pencil,\n Phone,\n Trash2,\n} from \"lucide-react\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Button,\n cn,\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Spinner,\n fluidToast,\n} from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { ContactDetailsForm } from \"../../../../shared/components/contacts/contactDetailsForm\";\nimport { useContactDetailPage } from \"../../../../shared/hooks/useContactDetailPage\";\nimport { useContactTasks } from \"../../../hooks/contacts/use-contact-tasks\";\nimport { useContactNotes } from \"../../../hooks/notes/use-contact-notes\";\nimport { useCreateGroup } from \"../../../hooks/groups/use-create-group\";\nimport { useGroups } from \"../../../hooks/groups/use-groups\";\nimport { useUpdateContactTags } from \"../../../hooks/groups/use-update-contact-tags\";\nimport { ContactDetailHero } from \"./ContactDetailHero\";\nimport { ContactInfoRow } from \"./ContactInfoRow\";\nimport { ContactDetailTabs, type TabType } from \"./ContactDetailTabs\";\nimport { getDisplayName } from \"./utils\";\n\nexport interface ContactDetailPaneProps {\n contactId: string;\n queryKeyPrefix: string;\n getCountries: () => Promise<{ id: number; name: string; iso?: string }[]>;\n /** Callback to clear selection (used by mobile back button + on delete). */\n onBack: () => void;\n}\n\nexport function ContactDetailPane({\n contactId,\n queryKeyPrefix,\n getCountries,\n onBack,\n}: ContactDetailPaneProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const {\n contact,\n isLoading,\n methods,\n countryOptions,\n isDirty,\n isSubmitting,\n isDeleting,\n onSave,\n onDelete,\n } = useContactDetailPage(contactId, {\n queryKeyPrefix,\n getCountries,\n onDeleteSuccess: onBack,\n onSaveSuccess: () => setEditProfileOpen(false),\n });\n\n const { data: tasks = [], isLoading: isLoadingTasks } =\n useContactTasks(contactId);\n const { data: notes = [], isLoading: isLoadingNotes } =\n useContactNotes(contactId);\n\n const { data: groups = [] } = useGroups();\n const updateTagsMutation = useUpdateContactTags(contactId, queryKeyPrefix, {\n onError: (error) => {\n fluidToast({\n title: t(\"groups_tags_save_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n },\n });\n const createGroupMutation = useCreateGroup();\n\n const [confirmDelete, setConfirmDelete] = useState(false);\n const [activeTab, setActiveTab] = useState<TabType>(\"Tasks\");\n const [editProfileOpen, setEditProfileOpen] = useState(false);\n\n // Close the dialog before dispatching: on success the pane unmounts via\n // onDeleteSuccess; on a non-throwing failure the dialog would otherwise\n // dangle open with the toast already shown.\n const handleConfirmDelete = useCallback(() => {\n setConfirmDelete(false);\n onDelete();\n }, [onDelete]);\n\n if (isLoading) {\n return <ContactDetailSkeleton onBack={onBack} />;\n }\n\n if (!contact) {\n return (\n <div className=\"flex h-full flex-1 flex-col\">\n <DetailTopBar\n onBack={onBack}\n phone={null}\n email={null}\n onDelete={null}\n onEditProfile={null}\n />\n <div className=\"mx-auto flex max-w-md flex-col items-center px-6 py-16 text-center\">\n <h2 className=\"text-foreground text-base font-semibold\">\n {t(\"error_loading\")}\n </h2>\n <p className=\"text-muted-foreground mt-2 text-sm\">\n {t(\"error_loading_description\")}\n </p>\n </div>\n </div>\n );\n }\n\n const fullName = getDisplayName(contact);\n\n return (\n <FormProvider {...methods}>\n <div className=\"flex h-full flex-1 flex-col\">\n <DetailTopBar\n onBack={onBack}\n phone={contact.phone ?? null}\n email={contact.email ?? null}\n onDelete={() => setConfirmDelete(true)}\n onEditProfile={() => setEditProfileOpen(true)}\n />\n\n <div className=\"flex-1 overflow-y-auto\">\n <div className=\"mx-auto w-full max-w-[900px] px-6 pt-8 pb-16 md:px-8 md:pt-10\">\n <ContactDetailHero\n contact={contact}\n tasksCount={tasks.length}\n notesCount={notes.length}\n contactTags={Array.isArray(contact.tags) ? contact.tags : []}\n availableGroups={groups}\n onTagsSave={(tags) => updateTagsMutation.mutate(tags)}\n onCreateGroup={async (name) => {\n await createGroupMutation.mutateAsync({ name });\n }}\n isTagsSaving={updateTagsMutation.isPending}\n />\n <ContactInfoRow\n contact={contact}\n onEditEmpty={() => setEditProfileOpen(true)}\n />\n <ContactDetailTabs\n contactId={contactId}\n tasks={tasks}\n isLoadingTasks={isLoadingTasks}\n notes={notes}\n isLoadingNotes={isLoadingNotes}\n activeTab={activeTab}\n onTabChange={setActiveTab}\n />\n </div>\n </div>\n\n <Dialog\n open={editProfileOpen}\n onOpenChange={(open) => {\n if (!open && isSubmitting) return;\n setEditProfileOpen(open);\n }}\n >\n <DialogContent className=\"max-h-[90vh] max-w-2xl overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>\n {t(\"edit_contact_name\", { name: fullName })}\n </DialogTitle>\n </DialogHeader>\n <ContactDetailsForm countries={countryOptions} />\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => setEditProfileOpen(false)}\n disabled={isSubmitting}\n >\n {t(\"cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={onSave}\n disabled={!isDirty || isSubmitting}\n aria-busy={isSubmitting}\n >\n {isSubmitting && <Spinner className=\"size-4\" />}\n {isSubmitting ? t(\"saving\") : t(\"save_changes\")}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n <AlertDialog open={confirmDelete} onOpenChange={setConfirmDelete}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {t(\"delete_name\", { name: fullName })}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {t(\"delete_confirm_permanent\")}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isDeleting}>\n {t(\"cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={handleConfirmDelete}\n disabled={isDeleting}\n >\n {isDeleting ? t(\"deleting\") : t(\"delete_contact\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n </FormProvider>\n );\n}\n\ninterface DetailTopBarProps {\n onBack: () => void;\n phone: string | null;\n email: string | null;\n onDelete: (() => void) | null;\n onEditProfile: (() => void) | null;\n}\n\nfunction DetailTopBar({\n onBack,\n phone,\n email,\n onDelete,\n onEditProfile,\n}: DetailTopBarProps) {\n const { t } = useContactsTranslation();\n return (\n <div className=\"border-border/50 bg-background/90 sticky top-0 z-10 flex items-center justify-between border-b px-4 py-3 backdrop-blur md:px-8\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={onBack}\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex size-8 items-center justify-center rounded-full transition-colors md:hidden\"\n aria-label={t(\"back_to_contacts\")}\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n <span className=\"text-muted-foreground hidden text-xs font-semibold tracking-widest uppercase md:inline\">\n {t(\"contact_label\")}\n </span>\n </div>\n <div className=\"flex items-center gap-1\">\n {onEditProfile && (\n <button\n type=\"button\"\n onClick={onEditProfile}\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex size-8 items-center justify-center rounded-full transition-colors\"\n aria-label={t(\"edit_profile\")}\n >\n <Pencil className=\"size-4\" aria-hidden=\"true\" />\n </button>\n )}\n <ActionLink\n href={phone ? `tel:${phone}` : null}\n label={t(\"label_call\")}\n icon={<Phone className=\"size-4\" aria-hidden=\"true\" />}\n />\n <ActionLink\n href={email ? `mailto:${email}` : null}\n label={t(\"label_email\")}\n icon={<Mail className=\"size-4\" aria-hidden=\"true\" />}\n />\n {onDelete && (\n <>\n <div className=\"bg-border mx-1 h-5 w-px\" aria-hidden=\"true\" />\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex size-8 items-center justify-center rounded-full transition-colors\"\n aria-label={t(\"more_actions\")}\n >\n <MoreHorizontal className=\"size-4\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n className=\"text-destructive\"\n onClick={onDelete}\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {t(\"delete_contact\")}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </>\n )}\n </div>\n </div>\n );\n}\n\ninterface ActionLinkProps {\n href: string | null;\n label: string;\n icon: React.ReactNode;\n}\n\nfunction ActionLink({ href, label, icon }: ActionLinkProps) {\n const baseClass =\n \"flex size-8 items-center justify-center rounded-full transition-colors\";\n if (!href) {\n return (\n <span\n aria-label={`${label} (unavailable)`}\n className={cn(baseClass, \"text-muted-foreground/40 cursor-default\")}\n >\n {icon}\n </span>\n );\n }\n return (\n <a\n href={href}\n aria-label={label}\n className={cn(\n baseClass,\n \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n )}\n >\n {icon}\n </a>\n );\n}\n\nfunction ContactDetailSkeleton({ onBack }: { onBack: () => void }) {\n return (\n <div className=\"flex h-full flex-1 flex-col\">\n <DetailTopBar\n onBack={onBack}\n phone={null}\n email={null}\n onDelete={null}\n onEditProfile={null}\n />\n <div className=\"mx-auto w-full max-w-[900px] flex-1 space-y-6 px-6 pt-8 pb-16 md:px-8 md:pt-10\">\n <div className=\"flex items-start gap-5\">\n <div className=\"bg-muted size-20 animate-pulse rounded-xl\" />\n <div className=\"flex-1 space-y-3\">\n <div className=\"bg-muted h-7 w-48 animate-pulse rounded\" />\n <div className=\"bg-muted h-4 w-24 animate-pulse rounded\" />\n </div>\n </div>\n <div className=\"bg-muted h-24 animate-pulse rounded-xl\" />\n <div className=\"bg-muted h-64 animate-pulse rounded-xl\" />\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Users } from \"lucide-react\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\n\nexport function ContactsEmptyState(): React.JSX.Element {\n const { t } = useContactsTranslation();\n return (\n <div className=\"hidden h-full flex-1 flex-col items-center justify-center px-8 text-center md:flex\">\n <div className=\"bg-muted text-muted-foreground flex size-16 items-center justify-center rounded-xl\">\n <Users className=\"size-7\" aria-hidden=\"true\" />\n </div>\n <h2 className=\"text-foreground mt-5 text-base font-semibold\">\n {t(\"empty_select_contact\")}\n </h2>\n <p className=\"text-muted-foreground mt-1 max-w-xs text-sm\">\n {t(\"empty_select_description\")}\n </p>\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { ContactsSidebar } from \"./ContactsSidebar\";\nimport { ContactDetailPane } from \"./ContactDetailPane\";\nimport { ContactsEmptyState } from \"./ContactsEmptyState\";\n\nexport interface RepContactsLayoutProps {\n selectedContactId: string | null;\n highlightContactId?: string | null;\n onSelect: (id: string | null) => void;\n onAdd: () => void;\n onManageGroups?: () => void;\n onCreateGroup?: () => void;\n highlightGroupName?: string | null;\n onDeleteContact?: (contact: Contact) => void;\n queryKeyPrefix: string;\n getCountries: () => Promise<{ id: number; name: string; iso?: string }[]>;\n}\n\nexport function RepContactsLayout({\n selectedContactId,\n highlightContactId,\n onSelect,\n onAdd,\n onManageGroups,\n onCreateGroup,\n highlightGroupName,\n onDeleteContact,\n queryKeyPrefix,\n getCountries,\n}: RepContactsLayoutProps): React.JSX.Element {\n return (\n <div className=\"bg-background flex h-full overflow-hidden\">\n <aside\n className={cn(\n \"border-border/50 bg-background w-full shrink-0 overflow-hidden border-r md:flex md:w-[420px] md:flex-col\",\n selectedContactId ? \"hidden\" : \"flex flex-col\",\n )}\n >\n <ContactsSidebar\n selectedContactId={selectedContactId}\n highlightContactId={highlightContactId}\n onSelect={onSelect}\n onAdd={onAdd}\n onManageGroups={onManageGroups}\n onCreateGroup={onCreateGroup}\n highlightGroupName={highlightGroupName}\n onDeleteContact={onDeleteContact}\n />\n </aside>\n\n <main\n className={cn(\n \"bg-background relative flex-1 md:flex md:flex-col\",\n selectedContactId ? \"flex flex-col\" : \"hidden md:flex\",\n )}\n >\n {selectedContactId ? (\n <ContactDetailPane\n key={selectedContactId}\n contactId={selectedContactId}\n queryKeyPrefix={queryKeyPrefix}\n getCountries={getCountries}\n onBack={() => onSelect(null)}\n />\n ) : (\n <ContactsEmptyState />\n )}\n </main>\n </div>\n );\n}\n","import e,{useRef as r,useMemo as t,useEffect as n,useState as o,useCallback as a,useLayoutEffect as l}from\"react\";function u(){return(u=Object.assign||function(e){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])}return e}).apply(this,arguments)}function c(e,r){if(null==e)return{};var t,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r.indexOf(t=a[n])>=0||(o[t]=e[t]);return o}function i(e){var t=r(e),n=r(function(e){t.current&&t.current(e)});return t.current=e,n.current}var s=function(e,r,t){return void 0===r&&(r=0),void 0===t&&(t=1),e>t?t:e<r?r:e},f=function(e){return\"touches\"in e},v=function(e){return e&&e.ownerDocument.defaultView||self},d=function(e,r,t){var n=e.getBoundingClientRect(),o=f(r)?function(e,r){for(var t=0;t<e.length;t++)if(e[t].identifier===r)return e[t];return e[0]}(r.touches,t):r;return{left:s((o.pageX-(n.left+v(e).pageXOffset))/n.width),top:s((o.pageY-(n.top+v(e).pageYOffset))/n.height)}},h=function(e){!f(e)&&e.preventDefault()},m=e.memo(function(o){var a=o.onMove,l=o.onKey,s=c(o,[\"onMove\",\"onKey\"]),m=r(null),g=i(a),p=i(l),b=r(null),_=r(!1),x=t(function(){var e=function(e){h(e),(f(e)?e.touches.length>0:e.buttons>0)&&m.current?g(d(m.current,e,b.current)):t(!1)},r=function(){return t(!1)};function t(t){var n=_.current,o=v(m.current),a=t?o.addEventListener:o.removeEventListener;a(n?\"touchmove\":\"mousemove\",e),a(n?\"touchend\":\"mouseup\",r)}return[function(e){var r=e.nativeEvent,n=m.current;if(n&&(h(r),!function(e,r){return r&&!f(e)}(r,_.current)&&n)){if(f(r)){_.current=!0;var o=r.changedTouches||[];o.length&&(b.current=o[0].identifier)}n.focus(),g(d(n,r,b.current)),t(!0)}},function(e){var r=e.which||e.keyCode;r<37||r>40||(e.preventDefault(),p({left:39===r?.05:37===r?-.05:0,top:40===r?.05:38===r?-.05:0}))},t]},[p,g]),C=x[0],E=x[1],H=x[2];return n(function(){return H},[H]),e.createElement(\"div\",u({},s,{onTouchStart:C,onMouseDown:C,className:\"react-colorful__interactive\",ref:m,onKeyDown:E,tabIndex:0,role:\"slider\"}))}),g=function(e){return e.filter(Boolean).join(\" \")},p=function(r){var t=r.color,n=r.left,o=r.top,a=void 0===o?.5:o,l=g([\"react-colorful__pointer\",r.className]);return e.createElement(\"div\",{className:l,style:{top:100*a+\"%\",left:100*n+\"%\"}},e.createElement(\"div\",{className:\"react-colorful__pointer-fill\",style:{backgroundColor:t}}))},b=function(e,r,t){return void 0===r&&(r=0),void 0===t&&(t=Math.pow(10,r)),Math.round(t*e)/t},_={grad:.9,turn:360,rad:360/(2*Math.PI)},x=function(e){return L(C(e))},C=function(e){return\"#\"===e[0]&&(e=e.substring(1)),e.length<6?{r:parseInt(e[0]+e[0],16),g:parseInt(e[1]+e[1],16),b:parseInt(e[2]+e[2],16),a:4===e.length?b(parseInt(e[3]+e[3],16)/255,2):1}:{r:parseInt(e.substring(0,2),16),g:parseInt(e.substring(2,4),16),b:parseInt(e.substring(4,6),16),a:8===e.length?b(parseInt(e.substring(6,8),16)/255,2):1}},E=function(e,r){return void 0===r&&(r=\"deg\"),Number(e)*(_[r]||1)},H=function(e){var r=/hsla?\\(?\\s*(-?\\d*\\.?\\d+)(deg|rad|grad|turn)?[,\\s]+(-?\\d*\\.?\\d+)%?[,\\s]+(-?\\d*\\.?\\d+)%?,?\\s*[/\\s]*(-?\\d*\\.?\\d+)?(%)?\\s*\\)?/i.exec(e);return r?N({h:E(r[1],r[2]),s:Number(r[3]),l:Number(r[4]),a:void 0===r[5]?1:Number(r[5])/(r[6]?100:1)}):{h:0,s:0,v:0,a:1}},M=H,N=function(e){var r=e.s,t=e.l;return{h:e.h,s:(r*=(t<50?t:100-t)/100)>0?2*r/(t+r)*100:0,v:t+r,a:e.a}},w=function(e){return K(I(e))},y=function(e){var r=e.s,t=e.v,n=e.a,o=(200-r)*t/100;return{h:b(e.h),s:b(o>0&&o<200?r*t/100/(o<=100?o:200-o)*100:0),l:b(o/2),a:b(n,2)}},q=function(e){var r=y(e);return\"hsl(\"+r.h+\", \"+r.s+\"%, \"+r.l+\"%)\"},k=function(e){var r=y(e);return\"hsla(\"+r.h+\", \"+r.s+\"%, \"+r.l+\"%, \"+r.a+\")\"},I=function(e){var r=e.h,t=e.s,n=e.v,o=e.a;r=r/360*6,t/=100,n/=100;var a=Math.floor(r),l=n*(1-t),u=n*(1-(r-a)*t),c=n*(1-(1-r+a)*t),i=a%6;return{r:b(255*[n,u,l,l,c,n][i]),g:b(255*[c,n,n,u,l,l][i]),b:b(255*[l,l,c,n,n,u][i]),a:b(o,2)}},O=function(e){var r=/hsva?\\(?\\s*(-?\\d*\\.?\\d+)(deg|rad|grad|turn)?[,\\s]+(-?\\d*\\.?\\d+)%?[,\\s]+(-?\\d*\\.?\\d+)%?,?\\s*[/\\s]*(-?\\d*\\.?\\d+)?(%)?\\s*\\)?/i.exec(e);return r?A({h:E(r[1],r[2]),s:Number(r[3]),v:Number(r[4]),a:void 0===r[5]?1:Number(r[5])/(r[6]?100:1)}):{h:0,s:0,v:0,a:1}},j=O,z=function(e){var r=/rgba?\\(?\\s*(-?\\d*\\.?\\d+)(%)?[,\\s]+(-?\\d*\\.?\\d+)(%)?[,\\s]+(-?\\d*\\.?\\d+)(%)?,?\\s*[/\\s]*(-?\\d*\\.?\\d+)?(%)?\\s*\\)?/i.exec(e);return r?L({r:Number(r[1])/(r[2]?100/255:1),g:Number(r[3])/(r[4]?100/255:1),b:Number(r[5])/(r[6]?100/255:1),a:void 0===r[7]?1:Number(r[7])/(r[8]?100:1)}):{h:0,s:0,v:0,a:1}},B=z,D=function(e){var r=e.toString(16);return r.length<2?\"0\"+r:r},K=function(e){var r=e.r,t=e.g,n=e.b,o=e.a,a=o<1?D(b(255*o)):\"\";return\"#\"+D(r)+D(t)+D(n)+a},L=function(e){var r=e.r,t=e.g,n=e.b,o=e.a,a=Math.max(r,t,n),l=a-Math.min(r,t,n),u=l?a===r?(t-n)/l:a===t?2+(n-r)/l:4+(r-t)/l:0;return{h:b(60*(u<0?u+6:u)),s:b(a?l/a*100:0),v:b(a/255*100),a:o}},A=function(e){return{h:b(e.h),s:b(e.s),v:b(e.v),a:b(e.a,2)}},S=e.memo(function(r){var t=r.hue,n=r.onChange,o=g([\"react-colorful__hue\",r.className]);return e.createElement(\"div\",{className:o},e.createElement(m,{onMove:function(e){n({h:360*e.left})},onKey:function(e){n({h:s(t+360*e.left,0,360)})},\"aria-label\":\"Hue\",\"aria-valuenow\":b(t),\"aria-valuemax\":\"360\",\"aria-valuemin\":\"0\"},e.createElement(p,{className:\"react-colorful__hue-pointer\",left:t/360,color:q({h:t,s:100,v:100,a:1})})))}),T=e.memo(function(r){var t=r.hsva,n=r.onChange,o={backgroundColor:q({h:t.h,s:100,v:100,a:1})};return e.createElement(\"div\",{className:\"react-colorful__saturation\",style:o},e.createElement(m,{onMove:function(e){n({s:100*e.left,v:100-100*e.top})},onKey:function(e){n({s:s(t.s+100*e.left,0,100),v:s(t.v-100*e.top,0,100)})},\"aria-label\":\"Color\",\"aria-valuetext\":\"Saturation \"+b(t.s)+\"%, Brightness \"+b(t.v)+\"%\"},e.createElement(p,{className:\"react-colorful__saturation-pointer\",top:1-t.v/100,left:t.s/100,color:q(t)})))}),F=function(e,r){if(e===r)return!0;for(var t in e)if(e[t]!==r[t])return!1;return!0},P=function(e,r){return e.replace(/\\s/g,\"\")===r.replace(/\\s/g,\"\")},X=function(e,r){return e.toLowerCase()===r.toLowerCase()||F(C(e),C(r))};function Y(e,t,l){var u=i(l),c=o(function(){return e.toHsva(t)}),s=c[0],f=c[1],v=r({color:t,hsva:s});n(function(){if(!e.equal(t,v.current.color)){var r=e.toHsva(t);v.current={hsva:r,color:t},f(r)}},[t,e]),n(function(){var r;F(s,v.current.hsva)||e.equal(r=e.fromHsva(s),v.current.color)||(v.current={hsva:s,color:r},u(r))},[s,e,u]);var d=a(function(e){f(function(r){return Object.assign({},r,e)})},[]);return[s,d]}var R,V=\"undefined\"!=typeof window?l:n,$=function(){return R||(\"undefined\"!=typeof __webpack_nonce__?__webpack_nonce__:void 0)},G=function(e){R=e},J=new Map,Q=function(e){V(function(){var r=e.current?e.current.ownerDocument:document;if(void 0!==r&&!J.has(r)){var t=r.createElement(\"style\");t.innerHTML='.react-colorful{position:relative;display:flex;flex-direction:column;width:200px;height:200px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.react-colorful__saturation{position:relative;flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(0deg,#000,transparent),linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.react-colorful__alpha-gradient,.react-colorful__pointer-fill{content:\"\";position:absolute;left:0;top:0;right:0;bottom:0;pointer-events:none;border-radius:inherit}.react-colorful__alpha-gradient,.react-colorful__saturation{box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}.react-colorful__alpha,.react-colorful__hue{position:relative;height:24px}.react-colorful__hue{background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.react-colorful__last-control{border-radius:0 0 8px 8px}.react-colorful__interactive{position:absolute;left:0;top:0;right:0;bottom:0;border-radius:inherit;outline:none;touch-action:none}.react-colorful__pointer{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}.react-colorful__interactive:focus .react-colorful__pointer{transform:translate(-50%,-50%) scale(1.1)}.react-colorful__alpha,.react-colorful__alpha-pointer{background-color:#fff;background-image:url(\\'data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill-opacity=\".05\"><path d=\"M8 0h8v8H8zM0 8h8v8H0z\"/></svg>\\')}.react-colorful__saturation-pointer{z-index:3}.react-colorful__hue-pointer{z-index:2}',J.set(r,t);var n=$();n&&t.setAttribute(\"nonce\",n),r.head.appendChild(t)}},[])},U=function(t){var n=t.className,o=t.colorModel,a=t.color,l=void 0===a?o.defaultColor:a,i=t.onChange,s=c(t,[\"className\",\"colorModel\",\"color\",\"onChange\"]),f=r(null);Q(f);var v=Y(o,l,i),d=v[0],h=v[1],m=g([\"react-colorful\",n]);return e.createElement(\"div\",u({},s,{ref:f,className:m}),e.createElement(T,{hsva:d,onChange:h}),e.createElement(S,{hue:d.h,onChange:h,className:\"react-colorful__last-control\"}))},W={defaultColor:\"000\",toHsva:x,fromHsva:function(e){return w({h:e.h,s:e.s,v:e.v,a:1})},equal:X},Z=function(r){return e.createElement(U,u({},r,{colorModel:W}))},ee=function(r){var t=r.className,n=r.hsva,o=r.onChange,a={backgroundImage:\"linear-gradient(90deg, \"+k(Object.assign({},n,{a:0}))+\", \"+k(Object.assign({},n,{a:1}))+\")\"},l=g([\"react-colorful__alpha\",t]),u=b(100*n.a);return e.createElement(\"div\",{className:l},e.createElement(\"div\",{className:\"react-colorful__alpha-gradient\",style:a}),e.createElement(m,{onMove:function(e){o({a:e.left})},onKey:function(e){o({a:s(n.a+e.left)})},\"aria-label\":\"Alpha\",\"aria-valuetext\":u+\"%\",\"aria-valuenow\":u,\"aria-valuemin\":\"0\",\"aria-valuemax\":\"100\"},e.createElement(p,{className:\"react-colorful__alpha-pointer\",left:n.a,color:k(n)})))},re=function(t){var n=t.className,o=t.colorModel,a=t.color,l=void 0===a?o.defaultColor:a,i=t.onChange,s=c(t,[\"className\",\"colorModel\",\"color\",\"onChange\"]),f=r(null);Q(f);var v=Y(o,l,i),d=v[0],h=v[1],m=g([\"react-colorful\",n]);return e.createElement(\"div\",u({},s,{ref:f,className:m}),e.createElement(T,{hsva:d,onChange:h}),e.createElement(S,{hue:d.h,onChange:h}),e.createElement(ee,{hsva:d,onChange:h,className:\"react-colorful__last-control\"}))},te={defaultColor:\"0001\",toHsva:x,fromHsva:w,equal:X},ne=function(r){return e.createElement(re,u({},r,{colorModel:te}))},oe={defaultColor:{h:0,s:0,l:0,a:1},toHsva:N,fromHsva:y,equal:F},ae=function(r){return e.createElement(re,u({},r,{colorModel:oe}))},le={defaultColor:\"hsla(0, 0%, 0%, 1)\",toHsva:H,fromHsva:k,equal:P},ue=function(r){return e.createElement(re,u({},r,{colorModel:le}))},ce={defaultColor:{h:0,s:0,l:0},toHsva:function(e){return N({h:e.h,s:e.s,l:e.l,a:1})},fromHsva:function(e){return{h:(r=y(e)).h,s:r.s,l:r.l};var r},equal:F},ie=function(r){return e.createElement(U,u({},r,{colorModel:ce}))},se={defaultColor:\"hsl(0, 0%, 0%)\",toHsva:M,fromHsva:q,equal:P},fe=function(r){return e.createElement(U,u({},r,{colorModel:se}))},ve={defaultColor:{h:0,s:0,v:0,a:1},toHsva:function(e){return e},fromHsva:A,equal:F},de=function(r){return e.createElement(re,u({},r,{colorModel:ve}))},he={defaultColor:\"hsva(0, 0%, 0%, 1)\",toHsva:O,fromHsva:function(e){var r=A(e);return\"hsva(\"+r.h+\", \"+r.s+\"%, \"+r.v+\"%, \"+r.a+\")\"},equal:P},me=function(r){return e.createElement(re,u({},r,{colorModel:he}))},ge={defaultColor:{h:0,s:0,v:0},toHsva:function(e){return{h:e.h,s:e.s,v:e.v,a:1}},fromHsva:function(e){var r=A(e);return{h:r.h,s:r.s,v:r.v}},equal:F},pe=function(r){return e.createElement(U,u({},r,{colorModel:ge}))},be={defaultColor:\"hsv(0, 0%, 0%)\",toHsva:j,fromHsva:function(e){var r=A(e);return\"hsv(\"+r.h+\", \"+r.s+\"%, \"+r.v+\"%)\"},equal:P},_e=function(r){return e.createElement(U,u({},r,{colorModel:be}))},xe={defaultColor:{r:0,g:0,b:0,a:1},toHsva:L,fromHsva:I,equal:F},Ce=function(r){return e.createElement(re,u({},r,{colorModel:xe}))},Ee={defaultColor:\"rgba(0, 0, 0, 1)\",toHsva:z,fromHsva:function(e){var r=I(e);return\"rgba(\"+r.r+\", \"+r.g+\", \"+r.b+\", \"+r.a+\")\"},equal:P},He=function(r){return e.createElement(re,u({},r,{colorModel:Ee}))},Me={defaultColor:{r:0,g:0,b:0},toHsva:function(e){return L({r:e.r,g:e.g,b:e.b,a:1})},fromHsva:function(e){return{r:(r=I(e)).r,g:r.g,b:r.b};var r},equal:F},Ne=function(r){return e.createElement(U,u({},r,{colorModel:Me}))},we={defaultColor:\"rgb(0, 0, 0)\",toHsva:B,fromHsva:function(e){var r=I(e);return\"rgb(\"+r.r+\", \"+r.g+\", \"+r.b+\")\"},equal:P},ye=function(r){return e.createElement(U,u({},r,{colorModel:we}))},qe=/^#?([0-9A-F]{3,8})$/i,ke=function(r){var t=r.color,l=void 0===t?\"\":t,s=r.onChange,f=r.onBlur,v=r.escape,d=r.validate,h=r.format,m=r.process,g=c(r,[\"color\",\"onChange\",\"onBlur\",\"escape\",\"validate\",\"format\",\"process\"]),p=o(function(){return v(l)}),b=p[0],_=p[1],x=i(s),C=i(f),E=a(function(e){var r=v(e.target.value);_(r),d(r)&&x(m?m(r):r)},[v,m,d,x]),H=a(function(e){d(e.target.value)||_(v(l)),C(e)},[l,v,d,C]);return n(function(){_(v(l))},[l,v]),e.createElement(\"input\",u({},g,{value:h?h(b):b,spellCheck:\"false\",onChange:E,onBlur:H}))},Ie=function(e){return\"#\"+e},Oe=function(r){var t=r.prefixed,n=r.alpha,o=c(r,[\"prefixed\",\"alpha\"]),l=a(function(e){return e.replace(/([^0-9A-F]+)/gi,\"\").substring(0,n?8:6)},[n]),i=a(function(e){return function(e,r){var t=qe.exec(e),n=t?t[1].length:0;return 3===n||6===n||!!r&&4===n||!!r&&8===n}(e,n)},[n]);return e.createElement(ke,u({},o,{escape:l,format:t?Ie:void 0,process:Ie,validate:i}))};export{ne as HexAlphaColorPicker,Oe as HexColorInput,Z as HexColorPicker,ie as HslColorPicker,fe as HslStringColorPicker,ae as HslaColorPicker,ue as HslaStringColorPicker,pe as HsvColorPicker,_e as HsvStringColorPicker,de as HsvaColorPicker,me as HsvaStringColorPicker,Ne as RgbColorPicker,ye as RgbStringColorPicker,Ce as RgbaColorPicker,He as RgbaStringColorPicker,G as setNonce};\n//# sourceMappingURL=index.module.js.map\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useGroupsApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"./invalidate-contact-caches\";\n\nexport function useDeleteGroup() {\n const api = useGroupsApi();\n const queryClient = useQueryClient();\n const { t } = useContactsTranslation();\n\n return useMutation({\n mutationFn: (groupId: number) => {\n if (!api) throw new Error(\"GroupsApi is not available\");\n return api.deleteGroup(groupId);\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: contactsKeys.groups() });\n invalidateContactCaches(queryClient);\n },\n onError: (error) => {\n fluidToast({\n title: t(\"groups_delete_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useGroupsApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"./invalidate-contact-caches\";\nimport type { UpdateGroupInput } from \"@fluid-app/contacts-core/types\";\n\nexport function useUpdateGroup() {\n const api = useGroupsApi();\n const queryClient = useQueryClient();\n const { t } = useContactsTranslation();\n\n return useMutation({\n mutationFn: ({\n groupId,\n input,\n }: {\n groupId: number;\n input: UpdateGroupInput;\n }) => {\n if (!api) throw new Error(\"GroupsApi is not available\");\n return api.updateGroup(groupId, input);\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: contactsKeys.groups() });\n invalidateContactCaches(queryClient);\n },\n onError: (error) => {\n fluidToast({\n title: t(\"groups_update_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n },\n });\n}\n","\"use client\";\n\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport {\n ChevronLeft,\n Loader,\n Pencil,\n Plus,\n Search,\n Trash2,\n Users,\n X,\n} from \"lucide-react\";\nimport {\n EmojiPicker as EmojiPickerPrimitive,\n type EmojiPickerListCategoryHeaderProps,\n type EmojiPickerListEmojiProps,\n type EmojiPickerListRowProps,\n} from \"frimousse\";\nimport { HexColorPicker, HexColorInput } from \"react-colorful\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Button,\n cn,\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n IconButton,\n Input,\n Label,\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n Skeleton,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n fluidToast,\n} from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport type { Contact, ContactGroup } from \"@fluid-app/contacts-core/types\";\nimport { invalidateContactCaches } from \"../../../hooks/groups/invalidate-contact-caches\";\nimport { useGroups } from \"../../../hooks/groups/use-groups\";\nimport { useCreateGroup } from \"../../../hooks/groups/use-create-group\";\nimport { useDeleteGroup } from \"../../../hooks/groups/use-delete-group\";\nimport { useUpdateGroup } from \"../../../hooks/groups/use-update-group\";\n\nconst PRESET_COLORS = [\n \"#ef4444\",\n \"#f97316\",\n \"#eab308\",\n \"#22c55e\",\n \"#14b8a6\",\n \"#06b6d4\",\n \"#3b82f6\",\n \"#6366f1\",\n \"#8b5cf6\",\n \"#ec4899\",\n] as const;\n\ntype ColorTranslationKey =\n | \"groups_color_red\"\n | \"groups_color_orange\"\n | \"groups_color_yellow\"\n | \"groups_color_green\"\n | \"groups_color_teal\"\n | \"groups_color_cyan\"\n | \"groups_color_blue\"\n | \"groups_color_indigo\"\n | \"groups_color_purple\"\n | \"groups_color_pink\";\n\nconst PRESET_COLOR_KEYS = {\n \"#ef4444\": \"groups_color_red\",\n \"#f97316\": \"groups_color_orange\",\n \"#eab308\": \"groups_color_yellow\",\n \"#22c55e\": \"groups_color_green\",\n \"#14b8a6\": \"groups_color_teal\",\n \"#06b6d4\": \"groups_color_cyan\",\n \"#3b82f6\": \"groups_color_blue\",\n \"#6366f1\": \"groups_color_indigo\",\n \"#8b5cf6\": \"groups_color_purple\",\n \"#ec4899\": \"groups_color_pink\",\n} as const satisfies Record<\n (typeof PRESET_COLORS)[number],\n ColorTranslationKey\n>;\n\nexport interface GroupsManagePageProps {\n onBack: () => void;\n onSelectContact?: (contactId: string) => void;\n initialCreateOpen?: boolean;\n}\n\nexport function GroupsManagePage({\n onBack,\n onSelectContact,\n initialCreateOpen,\n}: GroupsManagePageProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const { data: groups = [], isLoading } = useGroups();\n const deleteGroup = useDeleteGroup();\n\n const [dialogMode, setDialogMode] = useState<\n { mode: \"create\" } | { mode: \"edit\"; group: ContactGroup } | null\n >(initialCreateOpen ? { mode: \"create\" } : null);\n const [deleteTarget, setDeleteTarget] = useState<ContactGroup | null>(null);\n const [highlightGroupId, setHighlightGroupId] = useState<number | null>(null);\n\n useEffect(() => {\n if (highlightGroupId == null) return;\n const timer = setTimeout(() => setHighlightGroupId(null), 2000);\n return () => clearTimeout(timer);\n }, [highlightGroupId]);\n\n const handleDelete = useCallback(() => {\n if (!deleteTarget) return;\n deleteGroup.mutate(deleteTarget.id, {\n onSuccess: () => {\n fluidToast({\n title: t(\"groups_deleted_toast\", { name: deleteTarget.name }),\n type: \"success\",\n });\n setDeleteTarget(null);\n },\n onError: () => {\n setDeleteTarget(null);\n },\n });\n }, [deleteTarget, deleteGroup, t]);\n\n return (\n <div className=\"flex h-full flex-col\">\n <div className=\"border-border/50 flex items-center justify-between border-b px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n <IconButton\n icon={ChevronLeft}\n onClick={onBack}\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground rounded-full\"\n aria-label={t(\"groups_back_to_contacts\")}\n />\n <h2 className=\"text-foreground text-lg font-semibold\">\n {t(\"groups_manage_title\")}\n </h2>\n </div>\n <Button size=\"sm\" onClick={() => setDialogMode({ mode: \"create\" })}>\n <Plus className=\"size-4\" />\n {t(\"groups_new_group\")}\n </Button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-6 py-6\">\n <div className=\"mx-auto max-w-[857px]\">\n {isLoading ? (\n <GroupsSkeleton />\n ) : groups.length === 0 ? (\n <div className=\"text-muted-foreground py-16 text-center text-sm\">\n {t(\"groups_empty\")}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {groups.map((group) => (\n <GroupRow\n key={group.id}\n group={group}\n highlight={highlightGroupId === group.id}\n onEdit={() => setDialogMode({ mode: \"edit\", group })}\n onDelete={() => setDeleteTarget(group)}\n onSelectContact={onSelectContact}\n />\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Create / Edit group dialog */}\n {dialogMode && (\n <GroupDialog\n key={dialogMode.mode === \"edit\" ? dialogMode.group.id : \"create\"}\n mode={dialogMode.mode}\n group={dialogMode.mode === \"edit\" ? dialogMode.group : undefined}\n open={!!dialogMode}\n onOpenChange={(open) => !open && setDialogMode(null)}\n onGroupCreated={(groupId) => {\n setHighlightGroupId(groupId);\n }}\n />\n )}\n\n {/* Delete confirmation dialog */}\n <AlertDialog\n open={!!deleteTarget}\n onOpenChange={(open) => !open && setDeleteTarget(null)}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{t(\"groups_delete_title\")}</AlertDialogTitle>\n <AlertDialogDescription>\n {t(\"groups_delete_confirm\", { name: deleteTarget?.name ?? \"\" })}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={deleteGroup.isPending}>\n {t(\"cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={handleDelete}\n disabled={deleteGroup.isPending}\n >\n {deleteGroup.isPending ? t(\"deleting\") : t(\"delete\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n}\n\n// ---- Shared Group Dialog (Create + Edit) ----\n\nexport interface GroupDialogProps {\n mode: \"create\" | \"edit\";\n group?: ContactGroup;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onGroupCreated?: (groupId: number) => void;\n onGroupCreatedWithName?: (name: string) => void;\n}\n\nexport function GroupDialog({\n mode,\n group,\n open,\n onOpenChange,\n onGroupCreated,\n onGroupCreatedWithName,\n}: GroupDialogProps) {\n const { t } = useContactsTranslation();\n const createGroup = useCreateGroup();\n const updateGroup = useUpdateGroup();\n const isPending =\n mode === \"create\" ? createGroup.isPending : updateGroup.isPending;\n\n const [name, setName] = useState(group?.name ?? \"\");\n const [avatar, setAvatar] = useState(group?.avatar ?? \"\");\n const [avatarBackground, setAvatarBackground] = useState(\n group?.avatar_background ?? \"#6366f1\",\n );\n\n const handleSave = useCallback(() => {\n const trimmedName = name.trim();\n if (!trimmedName) return;\n\n if (mode === \"create\") {\n createGroup.mutate(\n {\n name: trimmedName,\n avatar: avatar || undefined,\n avatar_background: avatarBackground || undefined,\n },\n {\n onSuccess: (data) => {\n fluidToast({\n title: t(\"groups_created_toast\", { name: trimmedName }),\n type: \"success\",\n });\n onOpenChange(false);\n if (data.group.id) onGroupCreated?.(data.group.id);\n onGroupCreatedWithName?.(trimmedName);\n },\n },\n );\n } else if (group) {\n updateGroup.mutate(\n {\n groupId: group.id,\n input: {\n name: trimmedName,\n avatar: avatar || undefined,\n avatar_background: avatarBackground || undefined,\n },\n },\n {\n onSuccess: () => {\n fluidToast({ title: t(\"groups_updated_toast\"), type: \"success\" });\n onOpenChange(false);\n },\n },\n );\n }\n }, [\n mode,\n name,\n avatar,\n avatarBackground,\n group,\n createGroup,\n updateGroup,\n onOpenChange,\n onGroupCreated,\n onGroupCreatedWithName,\n t,\n ]);\n\n const previewBg = avatarBackground || \"#6366f1\";\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-lg\">\n <DialogHeader>\n <DialogTitle>\n {mode === \"create\"\n ? t(\"groups_create_title\")\n : t(\"groups_edit_title\")}\n </DialogTitle>\n </DialogHeader>\n\n <div className=\"space-y-5 py-2\">\n {/* Avatar preview + name */}\n <div className=\"flex items-center gap-5\">\n <div className=\"flex flex-col items-center gap-1\">\n <div className=\"relative\">\n <div\n className=\"flex size-20 items-center justify-center rounded-full text-4xl transition-colors\"\n style={{ backgroundColor: previewBg }}\n >\n {avatar || <Users className=\"size-8 text-white/60\" />}\n </div>\n {avatar && (\n <IconButton\n icon={X}\n onClick={() => setAvatar(\"\")}\n className=\"bg-foreground/80 text-background hover:bg-foreground absolute -top-1 -right-1 size-5 rounded-full [&_svg:not([class*='size-'])]:size-3\"\n aria-label={t(\"groups_remove_emoji\")}\n />\n )}\n </div>\n <span className=\"text-muted-foreground text-xs\">\n {t(\"groups_avatar\")}\n </span>\n </div>\n <div className=\"flex-1 space-y-1.5\">\n <Label className=\"text-foreground\">\n {t(\"groups_name_label\")}\n </Label>\n <Input\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t(\"groups_name_placeholder\")}\n />\n </div>\n </div>\n\n {/* Tabs: Change Emoji / Change Color */}\n <Tabs defaultValue=\"emoji\">\n <TabsList className=\"border-border h-auto w-full justify-center gap-6 rounded-none border-b bg-transparent p-0\">\n <TabsTrigger\n value=\"emoji\"\n className=\"text-muted-foreground hover:text-foreground data-[state=active]:text-primary data-[state=active]:border-primary h-auto flex-none rounded-none border-0 border-b-2 border-transparent bg-transparent pb-2 shadow-none data-[state=active]:bg-transparent data-[state=active]:shadow-none\"\n >\n {t(\"groups_tab_change_emoji\")}\n </TabsTrigger>\n <TabsTrigger\n value=\"color\"\n className=\"text-muted-foreground hover:text-foreground data-[state=active]:text-primary data-[state=active]:border-primary h-auto flex-none rounded-none border-0 border-b-2 border-transparent bg-transparent pb-2 shadow-none data-[state=active]:bg-transparent data-[state=active]:shadow-none\"\n >\n {t(\"groups_tab_change_color\")}\n </TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"emoji\" className=\"pt-4\">\n <EmojiPickerPrimitive.Root\n className=\"bg-popover flex h-64 w-full flex-col overflow-hidden rounded-lg\"\n onEmojiSelect={(emoji) => setAvatar(emoji.emoji)}\n >\n <EmojiPickerPrimitive.Viewport className=\"relative flex-1 outline-hidden\">\n <EmojiPickerPrimitive.Loading className=\"text-muted-foreground absolute inset-0 flex items-center justify-center\">\n <Loader className=\"size-4 animate-spin\" />\n </EmojiPickerPrimitive.Loading>\n <EmojiPickerPrimitive.Empty className=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm\">\n {t(\"groups_no_emoji_found\")}\n </EmojiPickerPrimitive.Empty>\n <EmojiPickerPrimitive.List\n className=\"pb-1 select-none\"\n components={{\n Row: EmojiPickerRow,\n Emoji: EmojiPickerEmoji,\n CategoryHeader: EmojiPickerCategoryHeader,\n }}\n />\n </EmojiPickerPrimitive.Viewport>\n </EmojiPickerPrimitive.Root>\n </TabsContent>\n\n <TabsContent value=\"color\" className=\"pt-4\">\n <div className=\"space-y-4\">\n <HexColorPicker\n color={avatarBackground || \"#6366f1\"}\n onChange={setAvatarBackground}\n className=\"h-40 w-full\"\n />\n <div className=\"flex items-center gap-3\">\n <div className=\"border-input flex items-center gap-1 rounded-md border px-3 py-1.5\">\n <span className=\"text-muted-foreground text-sm\">#</span>\n <HexColorInput\n color={avatarBackground || \"6366f1\"}\n onChange={setAvatarBackground}\n className=\"text-foreground w-20 bg-transparent text-sm outline-none\"\n />\n </div>\n </div>\n <div className=\"flex justify-between\">\n {PRESET_COLORS.map((color) => (\n <button\n key={color}\n type=\"button\"\n onClick={() => setAvatarBackground(color)}\n className={cn(\n \"size-7 rounded-full transition-all\",\n avatarBackground === color\n ? \"ring-primary ring-2 ring-offset-2\"\n : \"hover:scale-110\",\n )}\n style={{ backgroundColor: color }}\n aria-label={t(PRESET_COLOR_KEYS[color])}\n />\n ))}\n </div>\n </div>\n </TabsContent>\n </Tabs>\n </div>\n\n <DialogFooter>\n <Button\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={isPending}\n >\n {t(\"groups_close\")}\n </Button>\n <Button onClick={handleSave} disabled={!name.trim() || isPending}>\n {isPending\n ? mode === \"create\"\n ? t(\"groups_creating\")\n : t(\"saving\")\n : mode === \"create\"\n ? t(\"groups_create\")\n : t(\"save\")}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\n// ---- Frimousse sub-components ----\n// Visually distinct from @fluid-app/messaging-ui's EmojiPicker (larger emoji\n// size-12 vs size-8, centered row layout). Sharing would require a more\n// flexible component API; for now this small duplication is intentional.\n\nfunction EmojiPickerRow({\n children,\n ref: _ref,\n ...props\n}: EmojiPickerListRowProps) {\n return (\n <div {...props} className=\"flex scroll-my-1 justify-center px-1\">\n {children}\n </div>\n );\n}\n\nfunction EmojiPickerEmoji({\n emoji,\n className,\n ref: _ref,\n ...props\n}: EmojiPickerListEmojiProps) {\n return (\n <button\n {...props}\n className={cn(\n \"data-[active]:bg-foreground/10 flex aspect-square size-12 items-center justify-center rounded-md text-3xl\",\n className,\n )}\n >\n {emoji.emoji}\n </button>\n );\n}\n\nfunction EmojiPickerCategoryHeader({\n category,\n ref: _ref,\n ...props\n}: EmojiPickerListCategoryHeaderProps) {\n return (\n <div\n {...props}\n className=\"bg-popover text-muted-foreground px-3 pt-3.5 pb-2 text-xs leading-none\"\n >\n {category.label}\n </div>\n );\n}\n\n// ---- Group Row ----\n\nfunction GroupRow({\n group,\n highlight,\n onEdit,\n onDelete,\n onSelectContact,\n}: {\n group: ContactGroup;\n highlight?: boolean;\n onEdit: () => void;\n onDelete: () => void;\n onSelectContact?: (contactId: string) => void;\n}) {\n const { t } = useContactsTranslation();\n const backgroundColor = group.avatar_background ?? \"var(--color-muted)\";\n const [drawerOpen, setDrawerOpen] = useState(false);\n\n return (\n <>\n <div\n className={cn(\n \"group/row border-border/50 hover:bg-muted/50 focus-within:bg-muted/50 flex cursor-pointer items-center gap-4 rounded-lg border px-4 py-3 transition-colors\",\n highlight && \"animate-highlight-fade\",\n )}\n onClick={() => setDrawerOpen(true)}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n setDrawerOpen(true);\n }\n }}\n >\n <div\n className=\"flex size-10 shrink-0 items-center justify-center rounded-full text-lg\"\n style={{ backgroundColor }}\n >\n {group.avatar ?? <Users className=\"text-muted-foreground size-4\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-foreground text-sm font-semibold\">{group.name}</p>\n <p className=\"text-muted-foreground text-xs\">\n {group.contacts_count === 1\n ? t(\"groups_contact_one\", { count: group.contacts_count })\n : t(\"groups_contact_other\", { count: group.contacts_count })}\n </p>\n </div>\n <div className=\"flex items-center gap-1 opacity-0 transition-opacity group-focus-within/row:opacity-100 group-hover/row:opacity-100\">\n <IconButton\n icon={Pencil}\n onClick={(e) => {\n e.stopPropagation();\n onEdit();\n }}\n className=\"text-muted-foreground hover:text-foreground rounded-full focus:opacity-100\"\n aria-label={t(\"groups_edit_aria\", { name: group.name })}\n />\n <IconButton\n icon={Trash2}\n onClick={(e) => {\n e.stopPropagation();\n onDelete();\n }}\n className=\"text-muted-foreground hover:text-destructive rounded-full focus:opacity-100\"\n aria-label={t(\"groups_delete_aria\", { name: group.name })}\n />\n </div>\n </div>\n\n <GroupMembersDrawer\n group={group}\n open={drawerOpen}\n onOpenChange={setDrawerOpen}\n contactCount={group.contacts_count}\n onSelectContact={onSelectContact}\n />\n </>\n );\n}\n\n// ---- Group Members Drawer ----\n\ninterface GroupMembersDrawerProps {\n group: ContactGroup;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n contactCount: number;\n onSelectContact?: (contactId: string) => void;\n}\n\nfunction GroupMembersDrawer({\n group,\n open,\n onOpenChange,\n contactCount,\n onSelectContact,\n}: GroupMembersDrawerProps) {\n const { t } = useContactsTranslation();\n const api = useContactsCrud();\n const queryClient = useQueryClient();\n const backgroundColor = group.avatar_background ?? \"var(--color-muted)\";\n const [addSearch, setAddSearch] = useState(\"\");\n const [recentlyAddedId, setRecentlyAddedId] = useState<number | null>(null);\n\n useEffect(() => {\n if (recentlyAddedId == null) return;\n const timer = setTimeout(() => setRecentlyAddedId(null), 2000);\n return () => clearTimeout(timer);\n }, [recentlyAddedId]);\n\n const { data: members, isLoading: isLoadingMembers } = useQuery({\n queryKey: contactsKeys.groupMembers(group.name),\n queryFn: async () => {\n const result = await api.listContacts({\n tags: [group.name],\n per_page: 100,\n });\n return result.contacts;\n },\n enabled: open,\n });\n\n const { data: searchResults } = useQuery({\n queryKey: contactsKeys.groupAddSearch(group.name, addSearch),\n queryFn: () =>\n api.listContacts({\n search_query: addSearch,\n per_page: 10,\n }),\n enabled: addSearch.length > 0 && open,\n });\n\n const nonMembers = (searchResults?.contacts ?? []).filter(\n (c) => !members?.some((m) => m.id === c.id),\n );\n\n const handleRemoveContact = useCallback(\n (contact: Contact) => {\n const currentTags = Array.isArray(contact.tags) ? contact.tags : [];\n const newTags = currentTags.filter((tag) => tag !== group.name);\n api\n .updateContact(String(contact.id), { tags: newTags })\n .then(() => {\n queryClient.invalidateQueries({\n queryKey: contactsKeys.groupMembers(group.name),\n });\n invalidateContactCaches(queryClient);\n fluidToast({\n title: t(\"groups_member_removed_toast\", {\n contact: contact.full_name ?? \"\",\n group: group.name,\n }),\n type: \"success\",\n });\n })\n .catch((error) => {\n fluidToast({\n title: t(\"groups_member_remove_failed\", {\n contact: contact.full_name ?? \"\",\n group: group.name,\n }),\n description: parseApiErrors(error),\n type: \"error\",\n });\n });\n },\n [api, group.name, queryClient, t],\n );\n\n const handleAddContact = useCallback(\n (contact: Contact) => {\n const currentTags = Array.isArray(contact.tags) ? contact.tags : [];\n if (currentTags.includes(group.name)) return;\n const newTags = [...currentTags, group.name];\n api\n .updateContact(String(contact.id), { tags: newTags })\n .then(() => {\n queryClient.invalidateQueries({\n queryKey: contactsKeys.groupMembers(group.name),\n });\n invalidateContactCaches(queryClient);\n setAddSearch(\"\");\n setRecentlyAddedId(contact.id);\n fluidToast({\n title: t(\"groups_member_added_toast\", {\n contact: contact.full_name ?? \"\",\n group: group.name,\n }),\n type: \"success\",\n });\n })\n .catch((error) => {\n fluidToast({\n title: t(\"groups_member_add_failed\", {\n contact: contact.full_name ?? \"\",\n group: group.name,\n }),\n description: parseApiErrors(error),\n type: \"error\",\n });\n });\n },\n [api, group.name, queryClient, t],\n );\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent side=\"right\" className=\"flex flex-col overflow-hidden p-0\">\n {/* Drawer header */}\n <SheetHeader className=\"border-border/50 border-b px-6 pt-6 pb-4\">\n <div className=\"flex items-center gap-4\">\n <div\n className=\"flex size-12 shrink-0 items-center justify-center rounded-full text-xl\"\n style={{ backgroundColor }}\n >\n {group.avatar ?? <Users className=\"size-5 text-white/60\" />}\n </div>\n <div>\n <SheetTitle>{group.name}</SheetTitle>\n <SheetDescription>\n {contactCount === 1\n ? t(\"groups_member_one\", { count: contactCount })\n : t(\"groups_member_other\", { count: contactCount })}\n </SheetDescription>\n </div>\n </div>\n </SheetHeader>\n\n {/* Search to add contacts */}\n <div className=\"relative border-b px-6 py-3\">\n <div className=\"relative\">\n <Search className=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-3.5 -translate-y-1/2\" />\n <Input\n type=\"text\"\n value={addSearch}\n onChange={(e) => setAddSearch(e.target.value)}\n placeholder={t(\"groups_search_contacts_to_add\")}\n className=\"pl-8\"\n />\n </div>\n {addSearch && nonMembers.length > 0 && (\n <div className=\"bg-popover border-border absolute right-6 left-6 z-10 mt-1 max-h-48 overflow-y-auto rounded-md border shadow-md\">\n {nonMembers.map((contact) => (\n <button\n key={contact.id}\n type=\"button\"\n onClick={() => handleAddContact(contact)}\n className=\"hover:bg-muted flex w-full items-center gap-3 px-3 py-2 text-left text-sm\"\n >\n <div className=\"bg-muted flex size-7 shrink-0 items-center justify-center rounded-full text-xs font-medium\">\n {contact.first_name?.[0] ?? \"\"}\n {contact.last_name?.[0] ?? \"\"}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-foreground truncate text-sm\">\n {contact.full_name}\n </p>\n {contact.email && (\n <p className=\"text-muted-foreground truncate text-xs\">\n {contact.email}\n </p>\n )}\n </div>\n <Plus className=\"text-primary size-4 shrink-0\" />\n </button>\n ))}\n </div>\n )}\n {addSearch && nonMembers.length === 0 && searchResults && (\n <div className=\"bg-popover border-border absolute right-6 left-6 z-10 mt-1 rounded-md border p-3 shadow-md\">\n <p className=\"text-muted-foreground text-center text-sm\">\n {t(\"groups_no_contacts_found\")}\n </p>\n </div>\n )}\n </div>\n\n {/* Members list */}\n <div className=\"flex-1 overflow-y-auto px-6 py-3\">\n {isLoadingMembers ? (\n <div className=\"text-muted-foreground py-8 text-center text-sm\">\n {t(\"groups_loading_members\")}\n </div>\n ) : !members || members.length === 0 ? (\n <div className=\"text-muted-foreground py-8 text-center text-sm\">\n {t(\"groups_empty_members\")}\n </div>\n ) : (\n <div className=\"space-y-1\">\n {members.map((contact) => (\n <div\n key={contact.id}\n className={cn(\n \"group/member hover:bg-muted/50 focus-within:bg-muted/50 flex cursor-pointer items-center gap-3 rounded-md px-2 py-2 transition-colors duration-1000\",\n recentlyAddedId === contact.id && \"animate-highlight-fade\",\n )}\n onClick={() => {\n if (onSelectContact) {\n onOpenChange(false);\n onSelectContact(String(contact.id));\n }\n }}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (\n (e.key === \"Enter\" || e.key === \" \") &&\n onSelectContact\n ) {\n e.preventDefault();\n onOpenChange(false);\n onSelectContact(String(contact.id));\n }\n }}\n >\n <div className=\"bg-muted text-muted-foreground flex size-9 shrink-0 items-center justify-center rounded-full text-xs font-semibold\">\n {contact.first_name?.[0] ?? \"\"}\n {contact.last_name?.[0] ?? \"\"}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-foreground text-sm font-medium\">\n {contact.full_name}\n </p>\n {contact.email && (\n <p className=\"text-muted-foreground truncate text-xs\">\n {contact.email}\n </p>\n )}\n </div>\n <IconButton\n icon={X}\n onClick={(e) => {\n e.stopPropagation();\n handleRemoveContact(contact);\n }}\n className=\"text-muted-foreground hover:text-destructive size-7 rounded-full opacity-0 group-focus-within/member:opacity-100 group-hover/member:opacity-100 focus:opacity-100 [&_svg:not([class*='size-'])]:size-3.5\"\n aria-label={t(\"groups_remove_member_aria\", {\n name: contact.full_name ?? \"\",\n })}\n />\n </div>\n ))}\n </div>\n )}\n </div>\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction GroupsSkeleton() {\n return (\n <div className=\"space-y-2\">\n {[0, 1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"flex items-center gap-4 rounded-lg px-4 py-3\"\n aria-hidden=\"true\"\n >\n <Skeleton className=\"size-10 rounded-full\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-24\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\nimport type { CreateContactFormData } from \"../schemas/contactFormSchema\";\n\nexport function useCreateContactMutation(\n queryKeyPrefix = \"contacts\",\n options?: {\n onSuccess?: (data: { contact: { id: number } }) => void;\n onError?: (error: unknown) => void;\n },\n) {\n const queryClient = useQueryClient();\n const api = useContactsCrud();\n\n return useMutation({\n mutationFn: (data: CreateContactFormData) =>\n api.createContact(data as unknown as Record<string, unknown>),\n onSuccess: (data) => {\n fluidToast({ title: \"Contact created successfully\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(queryKeyPrefix),\n });\n if (queryKeyPrefix !== \"contacts\") {\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(\"contacts\"),\n });\n }\n options?.onSuccess?.(data as unknown as { contact: { id: number } });\n },\n onError: (error) => {\n if (options?.onError) {\n options.onError(error);\n } else {\n fluidToast({\n title: \"Failed to create contact\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n }\n },\n });\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { FormProvider } from \"react-hook-form\";\nimport { useZodForm, fluidToast, cn } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport type { ComponentProps } from \"react\";\nimport type { Contact as ContactType } from \"@fluid-app/contacts-core/types\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"@fluid-app/contacts-ui/portal/hooks/groups/invalidate-contact-caches\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { ContactCreateScreen } from \"@fluid-app/contacts-ui/screens/ContactCreateScreen\";\nimport { RepContactsLayout } from \"@fluid-app/contacts-ui/portal/components/contacts/rep-layout/RepContactsLayout\";\nimport {\n GroupsManagePage,\n GroupDialog,\n} from \"@fluid-app/contacts-ui/portal/components/contacts/rep-layout/GroupsManagePage\";\nimport { ContactDetailsForm } from \"@fluid-app/contacts-ui/shared/components/contacts/contactDetailsForm\";\nimport { useCreateContactMutation } from \"@fluid-app/contacts-ui/shared/hooks/useCreateContactMutation\";\nimport {\n createContactFormSchema,\n type CreateContactFormData,\n} from \"@fluid-app/contacts-ui/shared/schemas/contactFormSchema\";\nimport { useCountriesApi } from \"@fluid-app/store-core/countries-api-context\";\nimport { PortalContactsApiProvider } from \"../contacts/PortalContactsApiProvider\";\nimport { ContactsTranslationBridge } from \"../providers/ContactsTranslationBridge\";\nimport { useAppNavigation } from \"../shell/AppNavigationContext\";\nimport { storeKeys } from \"../account/query-keys\";\n\ntype NavState =\n | { view: \"browse\"; selectedContactId: string | null }\n | { view: \"new\" };\n\ntype ContactsScreenProps = ComponentProps<\"div\"> & {\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Display\n defaultViewMode?: \"list\" | \"grid\";\n\n // Callbacks\n onContactSelect?: (contactId: string) => void;\n onCreateContact?: () => void;\n};\n\nconst QUERY_KEY_PREFIX = \"sdk-contacts\";\n\nfunction ContactBrowseView({\n selectedContactId,\n highlightContactId,\n onSelect,\n onAdd,\n onManageGroups,\n onCreateGroup,\n highlightGroupName,\n}: {\n selectedContactId: string | null;\n highlightContactId?: string | null;\n highlightGroupName?: string | null;\n onSelect: (id: string | null) => void;\n onAdd: () => void;\n onManageGroups: () => void;\n onCreateGroup: () => void;\n}) {\n const { t } = useContactsTranslation();\n const countriesAdapter = useCountriesApi();\n const contactsApi = useContactsCrud();\n const queryClient = useQueryClient();\n\n const getCountries = useCallback(async () => {\n const result = await countriesAdapter.listCountries();\n return result.countries.map((c) => ({ id: 0, name: c.name, iso: c.code }));\n }, [countriesAdapter]);\n\n const handleDeleteContact = useCallback(\n (contact: ContactType) => {\n const name = contact.full_name || t(\"contact_label\");\n contactsApi\n .deleteContact(String(contact.id))\n .then(() => {\n invalidateContactCaches(queryClient);\n if (selectedContactId === String(contact.id)) {\n onSelect(null);\n }\n fluidToast({\n title: t(\"contact_deleted_toast\", { name }),\n type: \"success\",\n });\n })\n .catch((error) => {\n fluidToast({\n title: t(\"contact_delete_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n });\n },\n [contactsApi, queryClient, selectedContactId, onSelect, t],\n );\n\n return (\n <RepContactsLayout\n selectedContactId={selectedContactId}\n highlightContactId={highlightContactId}\n onSelect={onSelect}\n onAdd={onAdd}\n onManageGroups={onManageGroups}\n onCreateGroup={onCreateGroup}\n highlightGroupName={highlightGroupName}\n onDeleteContact={handleDeleteContact}\n queryKeyPrefix={QUERY_KEY_PREFIX}\n getCountries={getCountries}\n />\n );\n}\n\nconst CREATE_DEFAULT_VALUES: CreateContactFormData = {\n first_name: \"\",\n last_name: \"\",\n email: \"\",\n phone: \"\",\n status: \"new\",\n address: \"\",\n city: \"\",\n state: \"\",\n postal_code: \"\",\n country_code: null,\n language_code: null,\n metadata: {},\n affiliate: {},\n};\n\nfunction ContactCreateView({\n onNavigate,\n onCreateContact,\n}: {\n onNavigate: (state: NavState) => void;\n onCreateContact?: () => void;\n}) {\n const formRef = useRef<HTMLFormElement>(null);\n const countriesAdapter = useCountriesApi();\n\n const { data: countriesResponse } = useQuery({\n queryKey: storeKeys.countries(),\n queryFn: () => countriesAdapter.listCountries(),\n });\n\n const countryOptions = useMemo(\n () =>\n (countriesResponse?.countries ?? [])\n .map((c) => ({ name: c.name, value: c.code }))\n .sort((a, b) => a.name.localeCompare(b.name)),\n [countriesResponse],\n );\n\n const methods = useZodForm<CreateContactFormData>(createContactFormSchema, {\n defaultValues: CREATE_DEFAULT_VALUES,\n });\n\n const mutation = useCreateContactMutation(QUERY_KEY_PREFIX, {\n onSuccess: (data) => {\n onCreateContact?.();\n const newContactId = data?.contact?.id;\n if (newContactId) {\n onNavigate({\n view: \"browse\",\n selectedContactId: String(newContactId),\n });\n } else {\n onNavigate({ view: \"browse\", selectedContactId: null });\n }\n },\n });\n\n const { mutate } = mutation;\n\n const onSubmit = useMemo(\n () =>\n methods.handleSubmit(\n (data) => {\n const { affiliate, ...contactFields } = data;\n const payload: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(contactFields)) {\n if (value !== \"\" && value !== null && value !== undefined) {\n payload[key] = value;\n }\n }\n\n if (affiliate && Object.keys(affiliate).length > 0) {\n payload.affiliate = affiliate;\n }\n\n mutate(payload as CreateContactFormData);\n },\n () => {\n // Validation errors are shown inline by react-hook-form field controllers.\n // handleSubmit already populates field errors before calling this callback.\n },\n ),\n [methods, mutate],\n );\n\n const handleNavigateToList = useCallback(() => {\n onNavigate({ view: \"browse\", selectedContactId: null });\n }, [onNavigate]);\n\n return (\n <ContactCreateScreen\n onNavigateToList={handleNavigateToList}\n onSubmit={() => formRef.current?.requestSubmit()}\n isPending={mutation.isPending}\n >\n <FormProvider {...methods}>\n <div className=\"mx-auto max-w-7xl space-y-12 md:px-10 md:py-8\">\n <form\n ref={formRef}\n onSubmit={onSubmit}\n className=\"mx-auto space-y-6 lg:max-w-2xl\"\n >\n <ContactDetailsForm countries={countryOptions} />\n </form>\n </div>\n </FormProvider>\n </ContactCreateScreen>\n );\n}\n\nexport function ContactsScreen({\n onContactSelect,\n onCreateContact,\n /* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */\n background,\n textColor,\n accentColor,\n padding,\n borderRadius,\n defaultViewMode,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n ...divProps\n}: ContactsScreenProps): React.JSX.Element {\n const { currentSlug, navigate } = useAppNavigation();\n const subPage = currentSlug.split(\"/\")[1];\n\n const [nav, setNav] = useState<NavState>({\n view: \"browse\",\n selectedContactId: null,\n });\n const [highlightContactId, setHighlightContactId] = useState<string | null>(\n null,\n );\n\n useEffect(() => {\n if (highlightContactId == null) return;\n const timer = setTimeout(() => setHighlightContactId(null), 2000);\n return () => clearTimeout(timer);\n }, [highlightContactId]);\n\n const handleSelect = useCallback(\n (id: string | null) => {\n setNav({ view: \"browse\", selectedContactId: id });\n if (id) onContactSelect?.(id);\n },\n [onContactSelect],\n );\n\n const handleAdd = useCallback(() => {\n setNav({ view: \"new\" });\n }, []);\n\n const handleManageGroups = useCallback(() => {\n navigate(\"contacts/manage-groups\");\n }, [navigate]);\n\n const [createGroupOpen, setCreateGroupOpen] = useState(false);\n const [highlightGroupName, setHighlightGroupName] = useState<string | null>(\n null,\n );\n\n useEffect(() => {\n if (highlightGroupName == null) return;\n const timer = setTimeout(() => setHighlightGroupName(null), 2000);\n return () => clearTimeout(timer);\n }, [highlightGroupName]);\n\n const handleCreateGroup = useCallback(() => {\n setCreateGroupOpen(true);\n }, []);\n\n return (\n <ContactsTranslationBridge>\n <PortalContactsApiProvider>\n <div {...divProps} className={cn(\"h-full\", divProps.className)}>\n {subPage === \"manage-groups\" ? (\n <GroupsManagePage\n onBack={() => navigate(\"contacts\")}\n onSelectContact={(contactId) => {\n setNav({ view: \"browse\", selectedContactId: contactId });\n navigate(\"contacts\");\n }}\n />\n ) : nav.view === \"new\" ? (\n <ContactCreateView\n onNavigate={(state) => {\n setNav(state);\n if (state.view === \"browse\" && state.selectedContactId) {\n setHighlightContactId(state.selectedContactId);\n }\n }}\n onCreateContact={onCreateContact}\n />\n ) : (\n <ContactBrowseView\n selectedContactId={nav.selectedContactId}\n highlightContactId={highlightContactId}\n onSelect={handleSelect}\n onAdd={handleAdd}\n onManageGroups={handleManageGroups}\n onCreateGroup={handleCreateGroup}\n highlightGroupName={highlightGroupName}\n />\n )}\n <GroupDialog\n key={createGroupOpen ? \"open\" : \"closed\"}\n mode=\"create\"\n open={createGroupOpen}\n onOpenChange={(open) => setCreateGroupOpen(open)}\n onGroupCreatedWithName={(name) => {\n setHighlightGroupName(name);\n }}\n />\n </div>\n </PortalContactsApiProvider>\n </ContactsTranslationBridge>\n );\n}\n\nexport const contactsScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ContactsScreen\",\n displayName: \"Contacts Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"x_google_ignoreList":[39],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ContactsScreen-Co6JOwmr.mjs","names":["ContextMenuPrimitive.Root","ContextMenuPrimitive.Trigger","ContextMenuPrimitive.Portal","ContextMenuPrimitive.Content","ContextMenuPrimitive.Item","ContextMenuPrimitive.Label","ContextMenuPrimitive.Separator","ContextMenuPrimitive.Sub","ContextMenuPrimitive.SubTrigger","ContextMenuPrimitive.SubContent","formatDueDate","r","e","t","n","z","X","o","a","l","EmojiPickerPrimitive","HexColorPicker","HexColorInput"],"sources":["../../../contacts/ui/src/portal/hooks/groups/invalidate-contact-caches.ts","../../../contacts/ui/src/screens/ContactCreateScreen.tsx","../../../contacts/ui/src/portal/hooks/groups/use-bulk-delete-contacts.ts","../../../contacts/ui/src/portal/hooks/groups/use-groups.ts","../../../contacts/ui/src/portal/components/contacts/rep-layout/utils.ts","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactsSidebarRow.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContextMenu.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactsSidebar.tsx","../../../contacts/ui/src/shared/components/contacts/contactDetailsForm.tsx","../../../contacts/ui/src/shared/hooks/useContactDetail.ts","../../../contacts/ui/src/shared/hooks/useUpdateContactMutation.ts","../../../contacts/ui/src/shared/hooks/useDeleteContactMutation.ts","../../../contacts/ui/src/shared/schemas/contactFormSchema.ts","../../../contacts/ui/src/shared/hooks/useContactDetailPage.ts","../../../contacts/ui/src/portal/hooks/contacts/use-contact-tasks.ts","../../../contacts/ui/src/portal/hooks/notes/use-contact-notes.ts","../../../contacts/ui/src/portal/hooks/groups/use-create-group.ts","../../../contacts/ui/src/portal/hooks/groups/use-update-contact-tags.ts","../../../contacts/ui/src/shared/components/contacts/statusBadge.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/InlineGroupsEditor.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactDetailHero.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactInfoRow.tsx","../../../contacts/ui/src/portal/hooks/contacts/use-toggle-task-completion.ts","../../../contacts/ui/src/portal/hooks/contacts/use-delete-contact-task.ts","../../../contacts/ui/src/portal/hooks/contacts/use-update-contact-task.ts","../../../contacts/ui/src/portal/utils/format-date.ts","../../../contacts/ui/src/portal/components/editor/note-task-editor.tsx","../../../contacts/ui/src/portal/components/editor/note-task-modal.tsx","../../../contacts/ui/src/portal/components/tasks/task-list.tsx","../../../contacts/ui/src/portal/components/tasks/inline-task-composer.tsx","../../../contacts/ui/src/portal/hooks/notes/use-delete-contact-note.ts","../../../contacts/ui/src/portal/hooks/notes/use-update-contact-note.ts","../../../contacts/ui/src/portal/hooks/notes/use-create-contact-note.ts","../../../contacts/ui/src/portal/components/notes/inline-note-composer.tsx","../../../contacts/ui/src/portal/components/notes/notes-list.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactDetailTabs.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactDetailPane.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/ContactsEmptyState.tsx","../../../contacts/ui/src/portal/components/contacts/rep-layout/RepContactsLayout.tsx","../../../../node_modules/.pnpm/react-colorful@5.6.1_react-dom@19.2.4_react@19.2.4__react@19.2.4/node_modules/react-colorful/dist/index.mjs","../../../contacts/ui/src/portal/hooks/groups/use-delete-group.ts","../../../contacts/ui/src/portal/hooks/groups/use-update-group.ts","../../../contacts/ui/src/portal/components/contacts/rep-layout/GroupsManagePage.tsx","../../../contacts/ui/src/shared/hooks/useCreateContactMutation.ts","../src/screens/ContactsScreen.tsx"],"sourcesContent":["import type { QueryClient } from \"@tanstack/react-query\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function invalidateContactCaches(queryClient: QueryClient) {\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(\"contacts\"),\n });\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(\"sdk-contacts\"),\n });\n queryClient.invalidateQueries({\n queryKey: [\"portal-contacts\"],\n });\n}\n","\"use client\";\n\nimport React, { type ReactNode } from \"react\";\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n Button,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ScreenHeaderActions,\n ScreenHeaderBreadcrumbs,\n} from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\n\nexport interface ContactCreateScreenProps {\n onNavigateToList: () => void;\n onSubmit: () => void;\n isPending: boolean;\n children: ReactNode;\n}\n\nexport function ContactCreateScreen({\n onNavigateToList,\n onSubmit,\n isPending,\n children,\n}: ContactCreateScreenProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n\n return (\n <>\n <ScreenHeaderActions>\n <Button\n variant=\"outline\"\n onClick={onNavigateToList}\n disabled={isPending}\n >\n {t(\"cancel\")}\n </Button>\n <Button onClick={onSubmit} disabled={isPending}>\n {isPending ? t(\"adding\") : t(\"add_contact\")}\n </Button>\n </ScreenHeaderActions>\n <ScreenHeaderBreadcrumbs>\n <Breadcrumb>\n <BreadcrumbList className=\"text-lg\">\n <BreadcrumbItem>\n <BreadcrumbLink\n href=\"#\"\n onClick={(e) => {\n e.preventDefault();\n onNavigateToList();\n }}\n >\n {t(\"breadcrumb\")}\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage className=\"font-semibold\">\n {t(\"breadcrumb_new\")}\n </BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n </ScreenHeaderBreadcrumbs>\n {children}\n </>\n );\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"./invalidate-contact-caches\";\n\nexport function useBulkDeleteContacts() {\n const api = useContactsCrud();\n const queryClient = useQueryClient();\n const { t } = useContactsTranslation();\n\n return useMutation({\n mutationFn: (ids: number[]) => api.bulkDeleteContacts(ids),\n onSuccess: (_data, ids) => {\n invalidateContactCaches(queryClient);\n const count = ids.length;\n fluidToast({\n title:\n count === 1\n ? t(\"contacts_deleted_one\", { count })\n : t(\"contacts_deleted_other\", { count }),\n type: \"success\",\n });\n },\n onError: (_error, ids) => {\n const count = ids.length;\n fluidToast({\n title:\n count === 1\n ? t(\"contacts_delete_failed_one\")\n : t(\"contacts_delete_failed_other\"),\n description: parseApiErrors(_error),\n type: \"error\",\n });\n },\n });\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useGroupsApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useGroups() {\n const api = useGroupsApi();\n\n return useQuery({\n queryKey: contactsKeys.groups(),\n queryFn: () => api!.listGroups(),\n enabled: !!api,\n select: (data) => data.groups,\n });\n}\n","import type { Contact } from \"@fluid-app/contacts-core/types\";\n\nexport function getDisplayName(contact: Contact): string {\n if (contact.full_name && contact.full_name.trim().length > 0) {\n return contact.full_name;\n }\n const parts = [contact.first_name, contact.last_name].filter(Boolean);\n if (parts.length > 0) return parts.join(\" \");\n if (contact.email) return contact.email;\n return \"Contact\";\n}\n\nexport function getInitials(name: string): string {\n const parts = name.trim().split(/\\s+/);\n const first = parts[0]?.[0] ?? \"\";\n const last = parts.length > 1 ? (parts[parts.length - 1]?.[0] ?? \"\") : \"\";\n return (first + last).toUpperCase() || \"?\";\n}\n\n/** Lowercase relative label derived from `contact.updated_at`.\n * Returns null if the timestamp is missing or unparseable. Lowercase on\n * purpose so callers can compose phrases like \"Last updated 3 days ago\"\n * without an awkward \"Last updated Today\". */\nexport function getRelativeUpdated(contact: Contact): string | null {\n const updated =\n typeof contact.updated_at === \"string\" ? contact.updated_at : null;\n if (!updated) return null;\n const date = new Date(updated);\n if (Number.isNaN(date.getTime())) return null;\n\n const diffMs = Date.now() - date.getTime();\n const day = 1000 * 60 * 60 * 24;\n const diffDays = Math.floor(diffMs / day);\n\n if (diffDays <= 0) return \"today\";\n if (diffDays === 1) return \"yesterday\";\n if (diffDays < 7) return `${diffDays} days ago`;\n if (diffDays < 30) {\n const weeks = Math.floor(diffDays / 7);\n return weeks === 1 ? \"1 week ago\" : `${weeks} weeks ago`;\n }\n if (diffDays < 365) {\n const months = Math.floor(diffDays / 30);\n return months === 1 ? \"1 month ago\" : `${months} months ago`;\n }\n const years = Math.floor(diffDays / 365);\n return years === 1 ? \"1 year ago\" : `${years} years ago`;\n}\n","\"use client\";\n\nimport React, { useCallback, useEffect, useRef } from \"react\";\nimport { Check, ChevronRight, Trash2 } from \"lucide-react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { getDisplayName, getInitials } from \"./utils\";\n\nconst SWIPE_THRESHOLD = 40;\nconst REVEAL_WIDTH = 80;\n\nexport interface ContactsSidebarRowProps {\n contact: Contact;\n isSelected: boolean;\n isChecked?: boolean;\n highlight?: boolean;\n revealed?: boolean;\n onRevealChange?: (contactId: string, open: boolean) => void;\n onDismissRevealed?: () => void;\n onSelect: (id: string) => void;\n onShiftSelect?: (id: string) => void;\n onContextMenu?: (e: React.MouseEvent, contact: Contact) => void;\n onDelete?: (contact: Contact) => void;\n}\n\nexport function ContactsSidebarRow({\n contact,\n isSelected,\n isChecked,\n highlight,\n revealed = false,\n onRevealChange,\n onDismissRevealed,\n onSelect,\n onShiftSelect,\n onContextMenu,\n onDelete,\n}: ContactsSidebarRowProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const name = getDisplayName(contact);\n const id = String(contact.id);\n const secondary = contact.email ?? contact.status?.trim() ?? null;\n\n const cardRef = useRef<HTMLDivElement>(null);\n const offsetRef = useRef(0);\n const animateCloseRef = useRef(false);\n const startXRef = useRef(0);\n const startYRef = useRef(0);\n const activeRef = useRef(false);\n const lockedRef = useRef(false);\n const horizontalRef = useRef(false);\n const didSwipeRef = useRef(false);\n const autoHideRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const mouseDragAbortRef = useRef<AbortController | null>(null);\n\n // Abort any in-flight mouse-drag listeners if the component unmounts.\n useEffect(() => {\n return () => {\n mouseDragAbortRef.current?.abort();\n };\n }, []);\n\n // Direct DOM manipulation for zero-lag transforms\n const setOffset = useCallback(\n (value: number, animate: \"open\" | \"close\" | false) => {\n offsetRef.current = value;\n const el = cardRef.current;\n if (!el) return;\n if (animate === \"open\") {\n el.style.transition =\n \"transform 0.15s cubic-bezier(0.25, 0.1, 0.25, 1)\";\n } else if (animate === \"close\") {\n el.style.transition =\n \"transform 0.35s cubic-bezier(0.25, 0.1, 0.25, 1)\";\n } else {\n el.style.transition = \"none\";\n }\n el.style.transform = `translateX(${value}px)`;\n },\n [],\n );\n\n // Sync with external revealed state\n useEffect(() => {\n if (revealed) {\n setOffset(-REVEAL_WIDTH, false);\n autoHideRef.current = setTimeout(() => {\n animateCloseRef.current = true;\n onRevealChange?.(id, false);\n }, 2000);\n } else if (!activeRef.current) {\n animateCloseRef.current = false;\n setOffset(0, \"close\");\n }\n return () => {\n if (autoHideRef.current) clearTimeout(autoHideRef.current);\n };\n }, [revealed, setOffset, onRevealChange, id]);\n\n const onStart = useCallback(\n (x: number, y: number) => {\n if (!onDelete) return;\n startXRef.current = x;\n startYRef.current = y;\n activeRef.current = true;\n lockedRef.current = false;\n horizontalRef.current = false;\n didSwipeRef.current = false;\n if (autoHideRef.current) clearTimeout(autoHideRef.current);\n // Dismiss other revealed rows immediately\n if (!revealed) onDismissRevealed?.();\n },\n [onDelete, revealed, onDismissRevealed],\n );\n\n const onMove = useCallback(\n (x: number, y: number) => {\n if (!activeRef.current) return;\n const dx = x - startXRef.current;\n const dy = y - startYRef.current;\n\n if (!lockedRef.current) {\n if (Math.abs(dx) < 4 && Math.abs(dy) < 4) return;\n lockedRef.current = true;\n horizontalRef.current = Math.abs(dx) > Math.abs(dy);\n if (!horizontalRef.current) return;\n }\n if (!horizontalRef.current) return;\n\n didSwipeRef.current = true;\n const base = revealed ? -REVEAL_WIDTH : 0;\n const offset = Math.max(-REVEAL_WIDTH, Math.min(0, base + dx));\n setOffset(offset, false);\n },\n [revealed, setOffset],\n );\n\n const onEnd = useCallback(() => {\n if (!activeRef.current) return;\n activeRef.current = false;\n\n if (!didSwipeRef.current) return;\n\n const offset = offsetRef.current;\n if (offset < -SWIPE_THRESHOLD) {\n setOffset(-REVEAL_WIDTH, \"open\");\n onRevealChange?.(id, true);\n } else {\n setOffset(0, \"close\");\n onRevealChange?.(id, false);\n }\n }, [setOffset, onRevealChange, id]);\n\n // Touch\n const handleTouchStart = useCallback(\n (e: React.TouchEvent) => {\n const t = e.touches[0];\n if (t) onStart(t.clientX, t.clientY);\n },\n [onStart],\n );\n const handleTouchMove = useCallback(\n (e: React.TouchEvent) => {\n const t = e.touches[0];\n if (t) onMove(t.clientX, t.clientY);\n },\n [onMove],\n );\n\n // Mouse drag\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (e.button !== 0) return;\n onStart(e.clientX, e.clientY);\n mouseDragAbortRef.current?.abort();\n const controller = new AbortController();\n mouseDragAbortRef.current = controller;\n const { signal } = controller;\n window.addEventListener(\n \"mousemove\",\n (me) => onMove(me.clientX, me.clientY),\n { signal },\n );\n window.addEventListener(\n \"mouseup\",\n () => {\n onEnd();\n controller.abort();\n if (mouseDragAbortRef.current === controller) {\n mouseDragAbortRef.current = null;\n }\n },\n { signal },\n );\n },\n [onStart, onMove, onEnd],\n );\n\n // Trackpad two-finger swipe\n const wheelAccum = useRef(0);\n const wheelTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const handleWheel = useCallback(\n (e: React.WheelEvent) => {\n if (!onDelete) return;\n if (Math.abs(e.deltaX) <= Math.abs(e.deltaY)) return;\n\n // On first wheel event of a gesture, dismiss others\n if (!wheelTimer.current && !revealed) {\n onDismissRevealed?.();\n }\n\n wheelAccum.current += e.deltaX;\n const base = revealed ? -REVEAL_WIDTH : 0;\n const offset = Math.max(\n -REVEAL_WIDTH,\n Math.min(0, base - wheelAccum.current),\n );\n setOffset(offset, false);\n\n if (wheelTimer.current) clearTimeout(wheelTimer.current);\n wheelTimer.current = setTimeout(() => {\n const final = offsetRef.current;\n if (final < -SWIPE_THRESHOLD) {\n setOffset(-REVEAL_WIDTH, \"open\");\n onRevealChange?.(id, true);\n } else {\n setOffset(0, \"close\");\n onRevealChange?.(id, false);\n }\n wheelAccum.current = 0;\n wheelTimer.current = null;\n }, 80);\n },\n [onDelete, revealed, onDismissRevealed, setOffset, onRevealChange, id],\n );\n\n useEffect(() => {\n return () => {\n if (wheelTimer.current) clearTimeout(wheelTimer.current);\n };\n }, []);\n\n const handleActivate = useCallback(\n (shiftKey: boolean) => {\n if (didSwipeRef.current) {\n didSwipeRef.current = false;\n return;\n }\n if (revealed) {\n animateCloseRef.current = true;\n onRevealChange?.(id, false);\n return;\n }\n if (shiftKey && onShiftSelect) {\n onShiftSelect(id);\n return;\n }\n onSelect(id);\n },\n [revealed, onRevealChange, onSelect, onShiftSelect, id],\n );\n\n const handleClick = useCallback(\n (e: React.MouseEvent) => handleActivate(e.shiftKey),\n [handleActivate],\n );\n\n const handleContextMenu = useCallback(\n (e: React.MouseEvent) => {\n if (onContextMenu) {\n e.preventDefault();\n onContextMenu(e, contact);\n }\n },\n [onContextMenu, contact],\n );\n\n const handleDelete = useCallback(() => {\n onRevealChange?.(id, false);\n onDelete?.(contact);\n }, [onDelete, onRevealChange, contact, id]);\n\n return (\n <div className=\"relative overflow-hidden rounded-xl\">\n {onDelete && !isChecked && (\n <div\n className=\"bg-destructive text-destructive-foreground absolute inset-y-0 right-0 flex w-[88px] cursor-pointer flex-col items-center justify-center gap-1 pl-2\"\n onPointerDown={(e) => {\n e.stopPropagation();\n e.preventDefault();\n handleDelete();\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleDelete();\n }\n }}\n role=\"button\"\n tabIndex={0}\n aria-label={t(\"delete_contact_aria\", { name })}\n >\n <Trash2 className=\"size-5\" />\n <span className=\"text-xs font-medium\">{t(\"delete\")}</span>\n </div>\n )}\n\n <div\n ref={cardRef}\n onClick={handleClick}\n onContextMenu={handleContextMenu}\n onTouchStart={onDelete ? handleTouchStart : undefined}\n onTouchMove={onDelete ? handleTouchMove : undefined}\n onTouchEnd={onDelete ? onEnd : undefined}\n onMouseDown={onDelete ? handleMouseDown : undefined}\n onWheel={onDelete ? handleWheel : undefined}\n role=\"button\"\n tabIndex={0}\n aria-current={isSelected ? \"true\" : undefined}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleActivate(e.shiftKey);\n }\n }}\n className={cn(\n \"group relative flex w-full cursor-pointer items-center gap-3.5 rounded-l-xl rounded-r-none px-3 py-3 text-left select-none\",\n isSelected && !isChecked\n ? \"bg-muted\"\n : \"bg-background hover:bg-muted\",\n isChecked && \"bg-primary/10\",\n highlight && \"animate-highlight-fade\",\n )}\n >\n {isChecked && (\n <div className=\"bg-primary text-primary-foreground flex size-5 shrink-0 items-center justify-center rounded-full\">\n <Check className=\"size-3\" />\n </div>\n )}\n <div\n className={cn(\n \"text-muted-foreground relative flex size-12 shrink-0 items-center justify-center overflow-hidden rounded-xl text-base font-semibold transition-colors\",\n isSelected && !isChecked ? \"bg-background\" : \"bg-muted\",\n )}\n >\n {contact.avatar_url ? (\n <img\n alt={name}\n src={contact.avatar_url}\n className=\"size-12 object-cover\"\n />\n ) : (\n <span aria-hidden=\"true\">{getInitials(name)}</span>\n )}\n </div>\n\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-foreground block truncate text-sm font-semibold tracking-tight\">\n {name}\n </span>\n {secondary && (\n <span className=\"text-muted-foreground mt-0.5 block truncate text-sm\">\n {secondary}\n </span>\n )}\n </div>\n\n {isSelected && (\n <ChevronRight\n className=\"text-foreground size-4 shrink-0\"\n aria-hidden=\"true\"\n />\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport { ChevronRight } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@fluid-app/ui-primitives\";\n\nfunction ContextMenu({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Root>): React.JSX.Element {\n return <ContextMenuPrimitive.Root data-slot=\"context-menu\" {...props} />;\n}\n\nfunction ContextMenuTrigger({\n ...props\n}: React.ComponentProps<\n typeof ContextMenuPrimitive.Trigger\n>): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Trigger data-slot=\"context-menu-trigger\" {...props} />\n );\n}\n\nfunction ContextMenuContent({\n className,\n ...props\n}: React.ComponentProps<\n typeof ContextMenuPrimitive.Content\n>): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Portal>\n <ContextMenuPrimitive.Content\n data-slot=\"context-menu-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md\",\n className,\n )}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n );\n}\n\nfunction ContextMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: \"default\" | \"destructive\";\n}): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Item\n data-slot=\"context-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:!text-destructive relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction ContextMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {\n inset?: boolean;\n}): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Label\n data-slot=\"context-menu-label\"\n data-inset={inset}\n className={cn(\n \"text-muted-foreground px-2 py-1.5 text-xs font-medium data-[inset]:pl-8\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction ContextMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<\n typeof ContextMenuPrimitive.Separator\n>): React.JSX.Element {\n return (\n <ContextMenuPrimitive.Separator\n data-slot=\"context-menu-separator\"\n className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nfunction ContextMenuSub({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>): React.JSX.Element {\n return <ContextMenuPrimitive.Sub data-slot=\"context-menu-sub\" {...props} />;\n}\n\nfunction ContextMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n}): React.JSX.Element {\n return (\n <ContextMenuPrimitive.SubTrigger\n data-slot=\"context-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" />\n </ContextMenuPrimitive.SubTrigger>\n );\n}\n\nfunction ContextMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<\n typeof ContextMenuPrimitive.SubContent\n>): React.JSX.Element {\n return (\n <ContextMenuPrimitive.SubContent\n data-slot=\"context-menu-sub-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport {\n ContextMenu,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuSeparator,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n};\n","\"use client\";\n\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n MoreHorizontal,\n Plus,\n Search,\n Settings,\n Trash2,\n Users,\n} from \"lucide-react\";\nimport {\n Button,\n cn,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n fluidToast,\n Input,\n Skeleton,\n} from \"@fluid-app/ui-primitives\";\nimport { useInfiniteContacts } from \"@fluid-app/contacts-core/hooks/use-infinite-contacts\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"../../../hooks/groups/invalidate-contact-caches\";\nimport { useBulkDeleteContacts } from \"../../../hooks/groups/use-bulk-delete-contacts\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { useGroups } from \"../../../hooks/groups/use-groups\";\nimport { ContactsSidebarRow } from \"./ContactsSidebarRow\";\nimport {\n ContextMenu,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuSeparator,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from \"./ContextMenu\";\n\nexport interface ContactsSidebarProps {\n selectedContactId: string | null;\n highlightContactId?: string | null;\n onSelect: (id: string | null) => void;\n onAdd: () => void;\n onManageGroups?: () => void;\n onCreateGroup?: () => void;\n highlightGroupName?: string | null;\n onDeleteContact?: (contact: Contact) => void;\n}\n\nconst DEBOUNCE_MS = 200;\n\ntype FilterValue =\n | { kind: \"all\" }\n | { kind: \"status\"; status: \"lead\" | \"customer\" }\n | { kind: \"group\"; tag: string };\n\ninterface BuiltInFilter {\n id: string;\n label: string;\n value: FilterValue;\n}\n\nfunction useBuiltInFilters(): BuiltInFilter[] {\n const { t } = useContactsTranslation();\n return useMemo(\n () => [\n { id: \"all\", label: t(\"filter_all\"), value: { kind: \"all\" } as const },\n {\n id: \"status:lead\",\n label: t(\"filter_leads\"),\n value: { kind: \"status\" as const, status: \"lead\" as const },\n },\n {\n id: \"status:customer\",\n label: t(\"filter_customers\"),\n value: { kind: \"status\" as const, status: \"customer\" as const },\n },\n ],\n [t],\n );\n}\n\nfunction filterId(value: FilterValue): string {\n if (value.kind === \"all\") return \"all\";\n if (value.kind === \"status\") return `status:${value.status}`;\n return `group:${value.tag}`;\n}\n\nexport function ContactsSidebar({\n selectedContactId,\n highlightContactId,\n onSelect,\n onAdd,\n onManageGroups,\n onCreateGroup,\n highlightGroupName,\n onDeleteContact,\n}: ContactsSidebarProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const builtInFilters = useBuiltInFilters();\n const [searchInput, setSearchInput] = useState(\"\");\n const [debouncedSearch, setDebouncedSearch] = useState(\"\");\n const [revealedContactId, setRevealedContactId] = useState<string | null>(\n null,\n );\n const handleRevealChange = useCallback(\n (id: string, open: boolean) => setRevealedContactId(open ? id : null),\n [],\n );\n const handleDismissRevealed = useCallback(\n () => setRevealedContactId(null),\n [],\n );\n const [filter, setFilter] = useState<FilterValue>({ kind: \"all\" });\n const [checkedIds, setCheckedIds] = useState<Set<string>>(new Set());\n const [contextTargetId, setContextTargetId] = useState<string | null>(null);\n\n const api = useContactsCrud();\n const queryClient = useQueryClient();\n const bulkDelete = useBulkDeleteContacts();\n\n useEffect(() => {\n const handle = window.setTimeout(() => {\n setDebouncedSearch(searchInput.trim());\n }, DEBOUNCE_MS);\n return () => window.clearTimeout(handle);\n }, [searchInput]);\n\n const { data: groups = [] } = useGroups();\n\n const queryParams = useMemo(\n () => ({\n search_query: debouncedSearch || undefined,\n tags: filter.kind === \"group\" ? [filter.tag] : undefined,\n sort_by: \"full_name\",\n sort_direction: \"asc\",\n per_page: 50,\n }),\n [debouncedSearch, filter],\n );\n\n const {\n data,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n fetchNextPage,\n isError,\n } = useInfiniteContacts(queryParams);\n\n const contacts: Contact[] = useMemo(\n () => data?.pages.flatMap((page) => page.contacts ?? []) ?? [],\n [data],\n );\n\n const visibleContacts = useMemo(() => {\n if (filter.kind === \"status\") {\n return contacts.filter((c) => c.status === filter.status);\n }\n return contacts;\n }, [contacts, filter]);\n\n const sentinelRef = useRef<HTMLDivElement>(null);\n\n // Auto-select the first contact on initial load so the right pane shows\n // detail instead of the empty state. Desktop only — on mobile the layout\n // hides the sidebar when a contact is selected, so auto-selecting would\n // drop the rep straight into a detail view with no list visible. Ref\n // guards re-fires so explicit deselects (back button, post-delete, filter\n // changes) don't get clobbered.\n const hasAutoSelectedRef = useRef(false);\n useEffect(() => {\n if (hasAutoSelectedRef.current) return;\n if (selectedContactId) {\n hasAutoSelectedRef.current = true;\n return;\n }\n if (isLoading || visibleContacts.length === 0) return;\n const isDesktop =\n typeof window === \"undefined\" ||\n window.matchMedia(\"(min-width: 768px)\").matches;\n if (!isDesktop) {\n hasAutoSelectedRef.current = true;\n return;\n }\n const first = visibleContacts[0];\n if (first) {\n hasAutoSelectedRef.current = true;\n onSelect(String(first.id));\n }\n }, [selectedContactId, isLoading, visibleContacts, onSelect]);\n\n useEffect(() => {\n const sentinel = sentinelRef.current;\n if (!sentinel || !hasNextPage) return;\n\n const observer = new IntersectionObserver((entries) => {\n const entry = entries[0];\n if (entry?.isIntersecting && !isFetchingNextPage) {\n fetchNextPage();\n }\n });\n\n observer.observe(sentinel);\n return () => observer.disconnect();\n }, [hasNextPage, isFetchingNextPage, fetchNextPage]);\n\n const activeFilterId = filterId(filter);\n\n const handleShiftSelect = useCallback((id: string) => {\n setCheckedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n }, []);\n\n const handleNormalSelect = useCallback(\n (id: string) => {\n setCheckedIds(new Set());\n onSelect(id);\n },\n [onSelect],\n );\n\n const handleContextMenu = useCallback(\n (_e: React.MouseEvent, contact: Contact) => {\n const id = String(contact.id);\n setContextTargetId(id);\n // If the right-clicked contact isn't already part of a multi-select,\n // collapse the selection down to just this one so the menu acts on it.\n if (!checkedIds.has(id)) {\n setCheckedIds(new Set([id]));\n }\n },\n [checkedIds],\n );\n\n const getTargetContacts = useCallback((): Contact[] => {\n if (checkedIds.size > 0) {\n return visibleContacts.filter((c) => checkedIds.has(String(c.id)));\n }\n if (contextTargetId) {\n const single = visibleContacts.find(\n (c) => String(c.id) === contextTargetId,\n );\n return single ? [single] : [];\n }\n return [];\n }, [checkedIds, contextTargetId, visibleContacts]);\n\n const handleBulkDelete = useCallback(() => {\n const targets = getTargetContacts();\n if (targets.length === 0) return;\n const ids = targets.map((c) => c.id);\n bulkDelete.mutate(ids, {\n onSuccess: () => {\n if (\n selectedContactId &&\n ids.some((id) => String(id) === selectedContactId)\n ) {\n onSelect(null);\n }\n setCheckedIds(new Set());\n setContextTargetId(null);\n },\n });\n }, [getTargetContacts, bulkDelete, selectedContactId, onSelect]);\n\n const handleAddToGroup = useCallback(\n (groupName: string) => {\n const targets = getTargetContacts();\n if (targets.length === 0) return;\n const toUpdate = targets.filter((contact) => {\n const currentTags = Array.isArray(contact.tags) ? contact.tags : [];\n return !currentTags.includes(groupName);\n });\n if (toUpdate.length === 0) {\n setCheckedIds(new Set());\n setContextTargetId(null);\n return;\n }\n const promises = toUpdate.map((contact) => {\n const currentTags = Array.isArray(contact.tags) ? contact.tags : [];\n return api.updateContact(String(contact.id), {\n tags: [...currentTags, groupName],\n });\n });\n Promise.allSettled(promises).then((results) => {\n invalidateContactCaches(queryClient);\n const failed = results.filter((r) => r.status === \"rejected\").length;\n const succeeded = toUpdate.length - failed;\n if (failed === 0) {\n fluidToast({\n title:\n succeeded === 1\n ? t(\"contacts_added_to_group_one\", {\n count: succeeded,\n group: groupName,\n })\n : t(\"contacts_added_to_group_other\", {\n count: succeeded,\n group: groupName,\n }),\n type: \"success\",\n });\n } else {\n fluidToast({\n title:\n toUpdate.length === 1\n ? t(\"contacts_add_to_group_failed_one\", { group: groupName })\n : t(\"contacts_add_to_group_failed_other\", { group: groupName }),\n type: \"error\",\n });\n }\n setCheckedIds(new Set());\n setContextTargetId(null);\n });\n },\n [getTargetContacts, api, queryClient, t],\n );\n\n const targetCount =\n checkedIds.size > 0 ? checkedIds.size : contextTargetId ? 1 : 0;\n\n return (\n <>\n <div className=\"border-border/50 border-b px-6 py-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"bg-muted focus-within:ring-foreground/20 flex min-w-0 flex-1 items-center gap-2 rounded-lg px-3 py-1.5 transition focus-within:ring-2\">\n <Search\n className=\"text-muted-foreground size-3.5 shrink-0\"\n aria-hidden=\"true\"\n />\n <Input\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n placeholder={t(\"search_placeholder\")}\n type=\"search\"\n className=\"placeholder:text-muted-foreground/80 h-auto flex-1 border-0 bg-transparent p-0 text-xs font-medium shadow-none focus-visible:ring-0\"\n aria-label={t(\"search_placeholder\")}\n />\n </div>\n <Button type=\"button\" size=\"sm\" onClick={onAdd}>\n <Plus className=\"size-3.5\" aria-hidden=\"true\" />\n {t(\"add\")}\n </Button>\n </div>\n </div>\n\n <FilterPills\n activeId={activeFilterId}\n builtInFilters={builtInFilters}\n groups={groups.map((g) => g.name)}\n onChange={setFilter}\n onManageGroups={onManageGroups}\n onCreateGroup={onCreateGroup}\n highlightGroupName={highlightGroupName}\n />\n\n <div className=\"flex-1 overflow-y-auto px-3 pb-8\">\n {isError ? (\n <div className=\"text-muted-foreground px-4 py-8 text-center text-sm\">\n {t(\"error_loading_list\")}\n </div>\n ) : isLoading ? (\n <SidebarSkeleton />\n ) : visibleContacts.length === 0 ? (\n // Status filters apply client-side, so an empty visible list with\n // more pages still pending means matching contacts may be on later\n // pages. Keep the sentinel mounted so the IntersectionObserver can\n // continue paging until we either find matches or exhaust the data.\n <div className=\"space-y-2\">\n {hasNextPage || isFetchingNextPage ? (\n <div className=\"text-muted-foreground px-4 py-8 text-center text-sm\">\n {t(\"searching\")}\n </div>\n ) : (\n <div className=\"text-muted-foreground px-4 py-8 text-center text-sm\">\n {debouncedSearch\n ? t(\"no_contacts_search\", { term: debouncedSearch })\n : filter.kind === \"all\"\n ? t(\"no_contacts_yet\")\n : t(\"no_contacts_filter\")}\n </div>\n )}\n {hasNextPage && (\n <div ref={sentinelRef} aria-hidden=\"true\" className=\"h-4\" />\n )}\n </div>\n ) : (\n <ContextMenu\n onOpenChange={(open) => {\n if (!open) setContextTargetId(null);\n }}\n >\n <ContextMenuTrigger asChild>\n <div className=\"space-y-1\">\n {visibleContacts.map((contact) => (\n <ContactsSidebarRow\n key={contact.id}\n contact={contact}\n isSelected={String(contact.id) === selectedContactId}\n isChecked={checkedIds.has(String(contact.id))}\n highlight={String(contact.id) === highlightContactId}\n revealed={revealedContactId === String(contact.id)}\n onRevealChange={handleRevealChange}\n onDismissRevealed={handleDismissRevealed}\n onSelect={handleNormalSelect}\n onShiftSelect={handleShiftSelect}\n onContextMenu={handleContextMenu}\n onDelete={onDeleteContact}\n />\n ))}\n <div ref={sentinelRef} aria-hidden=\"true\" className=\"h-4\" />\n {isFetchingNextPage && (\n <div className=\"text-muted-foreground py-3 text-center text-xs\">\n {t(\"loading_more\")}\n </div>\n )}\n </div>\n </ContextMenuTrigger>\n <ContextMenuContent className=\"min-w-48\">\n <ContextMenuLabel>\n {targetCount === 1\n ? t(\"groups_selected_count_one\", { count: targetCount })\n : t(\"groups_selected_count_other\", { count: targetCount })}\n </ContextMenuLabel>\n <ContextMenuSeparator />\n <ContextMenuSub>\n <ContextMenuSubTrigger>\n <Users className=\"size-4\" aria-hidden=\"true\" />\n {t(\"groups_add_to_group\")}\n </ContextMenuSubTrigger>\n <ContextMenuSubContent>\n {groups.length === 0 ? (\n <ContextMenuItem disabled>\n {t(\"groups_no_groups_yet\")}\n </ContextMenuItem>\n ) : (\n groups.map((group) => (\n <ContextMenuItem\n key={group.id}\n onSelect={() => handleAddToGroup(group.name)}\n >\n <div\n className=\"flex size-5 shrink-0 items-center justify-center rounded-full text-xs\"\n style={{\n backgroundColor:\n group.avatar_background ?? \"var(--color-muted)\",\n }}\n aria-hidden=\"true\"\n >\n {group.avatar ?? (\n <Users className=\"text-muted-foreground size-3\" />\n )}\n </div>\n {group.name}\n </ContextMenuItem>\n ))\n )}\n </ContextMenuSubContent>\n </ContextMenuSub>\n <ContextMenuSeparator />\n <ContextMenuItem\n variant=\"destructive\"\n onSelect={handleBulkDelete}\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {t(\"delete\")}\n </ContextMenuItem>\n </ContextMenuContent>\n </ContextMenu>\n )}\n </div>\n </>\n );\n}\n\ninterface FilterPillsProps {\n activeId: string;\n builtInFilters: BuiltInFilter[];\n groups: string[];\n onChange: (filter: FilterValue) => void;\n onManageGroups?: () => void;\n onCreateGroup?: () => void;\n highlightGroupName?: string | null;\n}\n\nfunction FilterPills({\n activeId,\n builtInFilters,\n groups,\n onChange,\n onManageGroups,\n onCreateGroup,\n highlightGroupName,\n}: FilterPillsProps) {\n const { t } = useContactsTranslation();\n const allFilters = useMemo<BuiltInFilter[]>(\n () => [\n ...builtInFilters,\n ...groups.map((tag) => ({\n id: `group:${tag}`,\n label: tag,\n value: { kind: \"group\" as const, tag },\n })),\n ],\n [builtInFilters, groups],\n );\n\n return (\n <div className=\"flex items-center pt-4 pb-4\">\n <div className=\"flex-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\">\n <div className=\"flex gap-1.5 pl-6\">\n {allFilters.map(({ id, label, value }) => {\n const isActive = id === activeId;\n const isHighlighted =\n highlightGroupName && id === `group:${highlightGroupName}`;\n return (\n <button\n key={id}\n type=\"button\"\n onClick={() => onChange(value)}\n aria-pressed={isActive}\n className={cn(\n \"shrink-0 rounded-full px-4 py-1.5 text-sm font-semibold capitalize transition-colors\",\n isActive\n ? \"bg-primary text-primary-foreground\"\n : \"border-border/50 bg-muted text-foreground hover:bg-muted/70 border\",\n isHighlighted && \"animate-highlight-fade\",\n )}\n >\n {label}\n </button>\n );\n })}\n </div>\n </div>\n {(onManageGroups || onCreateGroup) && (\n <div className=\"flex shrink-0 items-center gap-2 pr-6 pl-3\">\n <div className=\"bg-border h-6 w-px\" aria-hidden=\"true\" />\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex items-center justify-center rounded-full p-1.5 transition-colors\"\n aria-label={t(\"groups_options_aria\")}\n >\n <MoreHorizontal className=\"size-4\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {onManageGroups && (\n <DropdownMenuItem onClick={onManageGroups}>\n <Settings className=\"size-4\" aria-hidden=\"true\" />\n {t(\"groups_manage_title\")}\n </DropdownMenuItem>\n )}\n {onCreateGroup && (\n <DropdownMenuItem onClick={onCreateGroup}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n {t(\"groups_create_title\")}\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )}\n </div>\n );\n}\n\nfunction SidebarSkeleton() {\n return (\n <div className=\"space-y-1.5 px-1\">\n {[0, 1, 2, 3, 4].map((i) => (\n <div\n key={i}\n className=\"flex items-center gap-3 rounded-xl p-3\"\n aria-hidden=\"true\"\n >\n <Skeleton className=\"size-12 shrink-0 rounded-xl\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-3.5 w-3/5\" />\n <Skeleton className=\"h-3 w-4/5\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useMemo } from \"react\";\nimport { useFormContext, useWatch } from \"react-hook-form\";\nimport type { EditContactFormData } from \"../../schemas/contactFormSchema\";\nimport {\n cn,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@fluid-app/ui-primitives\";\nimport { Combobox } from \"@fluid-app/ui-components/components/Combobox\";\n\nconst DEFAULT_COUNTRIES: { name: string; value: string }[] = [];\n\nconst statusOptions = [\n { name: \"New\", value: \"new\" },\n { name: \"Active\", value: \"active\" },\n { name: \"Inactive\", value: \"inactive\" },\n { name: \"Cold\", value: \"cold\" },\n { name: \"Lead\", value: \"lead\" },\n { name: \"Customer\", value: \"customer\" },\n];\n\ntype AvatarPickerRenderProps = {\n value: string | null;\n onChange: (url: string | null) => void;\n};\n\ntype ContactDetailsFormProps = {\n className?: string;\n countries?: { name: string; value: string }[];\n renderAvatarPicker?: (props: AvatarPickerRenderProps) => React.ReactNode;\n};\n\nexport const ContactDetailsForm: React.FC<ContactDetailsFormProps> = ({\n className,\n countries = DEFAULT_COUNTRIES,\n renderAvatarPicker,\n}) => {\n const { control, watch, setValue } = useFormContext<EditContactFormData>();\n const currentStatus = useWatch({ control, name: \"status\" });\n const avatarUrl: string | null =\n (watch(\"avatar_url\") as string | null | undefined) ?? null;\n\n const effectiveStatusOptions = useMemo(() => {\n if (\n currentStatus &&\n typeof currentStatus === \"string\" &&\n !statusOptions.some((o) => o.value === currentStatus)\n ) {\n return [\n {\n name:\n currentStatus.charAt(0).toUpperCase() +\n currentStatus.slice(1).replace(/_/g, \" \"),\n value: currentStatus,\n },\n ...statusOptions,\n ];\n }\n return statusOptions;\n }, [currentStatus]);\n\n const firstInitial =\n (watch(\"first_name\") as string | null | undefined)?.[0] ?? \"\";\n const lastInitial =\n (watch(\"last_name\") as string | null | undefined)?.[0] ?? \"\";\n const initials =\n [firstInitial, lastInitial].filter(Boolean).join(\"\").toUpperCase() || \"?\";\n\n return (\n <div className={cn(\"space-y-6\", className)}>\n {renderAvatarPicker && (\n <div className=\"flex flex-col items-center gap-3\">\n <div className=\"border-border bg-background relative size-20 shrink-0 overflow-hidden rounded-full border-2\">\n {avatarUrl ? (\n <img\n src={avatarUrl}\n alt=\"\"\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"text-muted-foreground flex h-full w-full items-center justify-center text-lg font-semibold\">\n {initials}\n </div>\n )}\n </div>\n {renderAvatarPicker({\n value: avatarUrl,\n onChange: (url) =>\n setValue(\"avatar_url\", url ?? \"\", { shouldDirty: true }),\n })}\n </div>\n )}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <FormField\n control={control}\n name=\"first_name\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n First Name\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter first name\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"last_name\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Last Name\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter last name\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"email\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Email\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter email address\"\n type=\"email\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"phone\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Phone\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter phone number\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"status\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Status\n </FormLabel>\n <Select value={field.value ?? \"\"} onValueChange={field.onChange}>\n <FormControl>\n <SelectTrigger className=\"w-full\">\n <SelectValue placeholder=\"Select status\" />\n </SelectTrigger>\n </FormControl>\n <SelectContent position=\"popper\" sideOffset={4}>\n {effectiveStatusOptions.map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>\n {opt.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"address\"\n render={({ field }) => (\n <FormItem className=\"lg:col-span-2\">\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Full Address\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter street address\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"city\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n City\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter city\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"state\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n State/Province\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter state or province\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"postal_code\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Postal Code\n </FormLabel>\n <FormControl>\n <Input\n placeholder=\"Enter postal code\"\n {...field}\n value={field.value ?? \"\"}\n className=\"ring-input\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <FormField\n control={control}\n name=\"country_code\"\n render={({ field }) => (\n <FormItem>\n <FormLabel className=\"font-inter text-foreground font-medium\">\n Country\n </FormLabel>\n <FormControl>\n <Combobox\n options={countries.map((c) => ({\n label: c.name,\n value: c.value,\n }))}\n value={field.value ?? \"\"}\n onValueChange={field.onChange}\n placeholder=\"Select country\"\n />\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n </div>\n </div>\n );\n};\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useContactDetail(\n contactId: string,\n queryKeyPrefix = \"contacts\",\n) {\n const api = useContactsCrud();\n\n return useQuery({\n queryKey: CONTACTS_QUERY_KEYS.detail(queryKeyPrefix, contactId),\n queryFn: () => api.getContact(contactId),\n enabled: !!contactId,\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\ntype UpdateInput = {\n id: string;\n data: Record<string, unknown>;\n};\n\nexport function useUpdateContactMutation(\n contactId: string,\n queryKeyPrefix = \"contacts\",\n options?: {\n onSuccess?: () => void;\n onError?: (error: unknown) => void;\n },\n) {\n const queryClient = useQueryClient();\n const api = useContactsCrud();\n\n return useMutation({\n mutationFn: ({ id, data }: UpdateInput) => api.updateContact(id, data),\n onSuccess: () => {\n fluidToast({ title: \"Contact updated successfully\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(queryKeyPrefix),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to save contact\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n options?.onError?.(error);\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useDeleteContactMutation(\n queryKeyPrefix = \"contacts\",\n options?: {\n onSuccess?: () => void;\n onError?: (error: unknown) => void;\n },\n) {\n const queryClient = useQueryClient();\n const api = useContactsCrud();\n\n return useMutation({\n mutationFn: (contactId: string) => api.deleteContact(contactId),\n onSuccess: () => {\n fluidToast({ title: \"Contact deleted successfully\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(queryKeyPrefix),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to delete contact\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n options?.onError?.(error);\n },\n });\n}\n","import { z } from \"zod\";\n\n/**\n * Form schema for creating a contact.\n * Matches CompanyContactCreate / ContactCreate from the OpenAPI spec.\n *\n * @see CompanyContactCreate in company_contacts.d.ts\n * @see ContactCreate in users_contacts.d.ts\n */\nexport const createContactFormSchema = z.object({\n first_name: z.string().min(1, { message: \"First name is required\" }),\n last_name: z.string().min(1, { message: \"Last name is required\" }),\n status: z.string().nullable().optional(),\n email: z.string().email().or(z.literal(\"\")).nullable().optional(),\n phone: z.string().nullable().optional(),\n address: z.string().nullable().optional(),\n city: z.string().nullable().optional(),\n state: z.string().nullable().optional(),\n postal_code: z.string().nullable().optional(),\n country_code: z.coerce.string().nullable().optional(),\n language_code: z.coerce.string().nullable().optional(),\n affiliate: z.record(z.string(), z.unknown()).nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport type CreateContactFormData = z.infer<typeof createContactFormSchema>;\n\n/**\n * Form schema for editing a contact.\n * Same fields as create plus id. Uses .passthrough() so extra fields\n * from the Contact read model (full_name, avatar_url, etc.) don't\n * cause validation failures.\n *\n * @see CompanyContactUpdate in company_contacts.d.ts\n */\nexport const editContactFormSchema = createContactFormSchema.passthrough();\n\nexport type EditContactFormData = z.infer<typeof editContactFormSchema>;\n","\"use client\";\n\nimport { useMemo, useCallback } from \"react\";\nimport { useZodForm, fluidToast } from \"@fluid-app/ui-primitives\";\nimport type { UseFormReturn } from \"react-hook-form\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useContactDetail } from \"./useContactDetail\";\nimport { useUpdateContactMutation } from \"./useUpdateContactMutation\";\nimport { useDeleteContactMutation } from \"./useDeleteContactMutation\";\nimport {\n createContactFormSchema,\n editContactFormSchema,\n type EditContactFormData,\n} from \"../schemas/contactFormSchema\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\n\nconst mutableKeys = Object.keys(\n createContactFormSchema.shape,\n) as (keyof EditContactFormData)[];\n\nexport function useContactDetailPage(\n contactId: string,\n options?: {\n queryKeyPrefix?: string;\n getCountries?: () => Promise<{ id: number; name: string; iso?: string }[]>;\n onDeleteSuccess?: () => void;\n onSaveSuccess?: () => void;\n },\n): {\n contact: Contact | undefined;\n isLoading: boolean;\n methods: UseFormReturn<EditContactFormData>;\n countryOptions: { name: string; value: string }[];\n isDirty: boolean;\n isSubmitting: boolean;\n isDeleting: boolean;\n onSave: () => void;\n onDelete: () => void;\n} {\n const queryKeyPrefix = options?.queryKeyPrefix ?? \"contacts\";\n\n const { data, isLoading } = useContactDetail(contactId, queryKeyPrefix);\n\n const { data: countries } = useQuery({\n queryKey: [\"countries\"],\n queryFn: options?.getCountries ?? (() => Promise.resolve([])),\n enabled: !!options?.getCountries,\n });\n\n const countryOptions = useMemo(\n () =>\n [\n ...(countries?.map((c) => ({\n name: c.name,\n value: c.iso ?? c.id.toString(),\n })) ?? []),\n ].sort((a, b) => a.name.localeCompare(b.name)),\n [countries],\n );\n\n const contact = data?.contact;\n\n // Map nested country object to the ISO code the form select expects\n const formValues = useMemo(() => {\n if (!contact) return undefined;\n return {\n ...contact,\n country_code:\n contact.country?.iso ?? contact.country_id?.toString() ?? null,\n } as unknown as EditContactFormData;\n }, [contact]);\n\n const methods = useZodForm<EditContactFormData>(editContactFormSchema, {\n values: formValues,\n mode: \"onBlur\",\n });\n\n const updateMutation = useUpdateContactMutation(contactId, queryKeyPrefix, {\n onSuccess: () => {\n methods.reset(methods.getValues());\n options?.onSaveSuccess?.();\n },\n });\n\n const deleteMutation = useDeleteContactMutation(queryKeyPrefix, {\n onSuccess: () => {\n options?.onDeleteSuccess?.();\n },\n });\n\n const onSave = useCallback(() => {\n methods.handleSubmit(\n (formData) => {\n const payload: Record<string, unknown> = {};\n for (const key of mutableKeys) {\n if (key in formData) {\n payload[key] = formData[key];\n }\n }\n\n updateMutation.mutate({\n id: contactId,\n data: payload,\n });\n },\n (errors) => {\n const errorMessages = Object.entries(errors)\n .map(([field, err]) => {\n const msg =\n typeof err?.message === \"string\" ? err.message : \"invalid\";\n return `${field.replace(/_/g, \" \")}: ${msg}`;\n })\n .join(\", \");\n fluidToast({\n title: \"Please fix the form errors before saving\",\n description: errorMessages || undefined,\n type: \"error\",\n });\n },\n )();\n }, [methods, updateMutation, contactId]);\n\n const onDelete = useCallback(() => {\n deleteMutation.mutate(contactId);\n }, [deleteMutation, contactId]);\n\n return {\n contact,\n isLoading,\n methods,\n countryOptions,\n isDirty: methods.formState.isDirty,\n isSubmitting: updateMutation.isPending,\n isDeleting: deleteMutation.isPending,\n onSave,\n onDelete,\n };\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useTasksApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { ContactTask } from \"@fluid-app/contacts-core/types\";\n\nexport type { ContactTask };\n\nexport const CONTACT_TASKS_QUERY_KEY = (contactId: string) =>\n contactsKeys.tasks(contactId);\n\nexport function useContactTasks(contactId: string) {\n const api = useTasksApi();\n\n return useQuery({\n queryKey: contactsKeys.tasks(contactId),\n queryFn: () => api.listTasks(contactId),\n enabled: !!contactId,\n select: (data) => data.tasks,\n });\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useNotesApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { ContactNote } from \"@fluid-app/contacts-core/types\";\n\nexport type { ContactNote };\n\nexport const CONTACT_NOTES_QUERY_KEY = (contactId: string) =>\n contactsKeys.notes(contactId);\n\nexport function useContactNotes(contactId: string) {\n const api = useNotesApi();\n\n return useQuery({\n queryKey: contactsKeys.notes(contactId),\n queryFn: () => api.listNotes(contactId),\n enabled: !!contactId,\n select: (data) => data.notes,\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useGroupsApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport type { CreateGroupInput } from \"@fluid-app/contacts-core/types\";\n\nexport function useCreateGroup() {\n const api = useGroupsApi();\n const queryClient = useQueryClient();\n const { t } = useContactsTranslation();\n\n return useMutation({\n mutationFn: (input: CreateGroupInput) => {\n if (!api) throw new Error(\"GroupsApi is not available\");\n return api.createGroup(input);\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: contactsKeys.groups() });\n },\n onError: (error) => {\n fluidToast({\n title: t(\"groups_create_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useUpdateContactTags(\n contactId: string,\n queryKeyPrefix = \"sdk-contacts\",\n options?: {\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n },\n) {\n const api = useContactsCrud();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (tags: string[]) => api.updateContact(contactId, { tags }),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(queryKeyPrefix),\n });\n queryClient.invalidateQueries({\n queryKey: [\"portal-contacts\"],\n });\n options?.onSuccess?.();\n },\n onError: options?.onError,\n });\n}\n","import React from \"react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\n\nconst statusStyles: Record<string, string> = {\n // Contact statuses\n new: \"border-[var(--status-new-border)] bg-[var(--status-new)] text-[var(--status-new-foreground)]\",\n active:\n \"border-[var(--status-active-border)] bg-[var(--status-active)] text-[var(--status-active-foreground)]\",\n inactive: \"border-border bg-muted text-muted-foreground\",\n lead: \"border-[var(--status-lead-border)] bg-[var(--status-lead)] text-[var(--status-lead-foreground)]\",\n customer:\n \"border-[var(--status-customer-border)] bg-[var(--status-customer)] text-[var(--status-customer-foreground)]\",\n // Semantic categories (orders, subscriptions, etc.)\n success:\n \"border-[var(--badge-success-border)] bg-[var(--badge-success)] text-[var(--badge-success-foreground)]\",\n warning:\n \"border-[var(--badge-warning-border)] bg-[var(--badge-warning)] text-[var(--badge-warning-foreground)]\",\n danger:\n \"border-[var(--badge-danger-border)] bg-[var(--badge-danger)] text-[var(--badge-danger-foreground)]\",\n info: \"border-[var(--badge-info-border)] bg-[var(--badge-info)] text-[var(--badge-info-foreground)]\",\n neutral: \"border-border bg-muted text-muted-foreground\",\n notice:\n \"border-[var(--badge-notice-border)] bg-[var(--badge-notice)] text-[var(--badge-notice-foreground)]\",\n accent:\n \"border-[var(--badge-accent-border)] bg-[var(--badge-accent)] text-[var(--badge-accent-foreground)]\",\n};\n\nconst defaultStyle = \"border-border bg-muted text-muted-foreground\";\n\nexport type StatusBadgeVariant = keyof typeof statusStyles;\n\nexport function getStatusStyle(status: string): string {\n return statusStyles[status] ?? defaultStyle;\n}\n\nexport function StatusBadge({\n status,\n label,\n className,\n}: {\n status: string;\n label?: string;\n className?: string;\n}): React.JSX.Element {\n return (\n <span\n className={cn(\n \"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold capitalize\",\n getStatusStyle(status),\n className,\n )}\n >\n {label ?? status}\n </span>\n );\n}\n","\"use client\";\n\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Check, Plus } from \"lucide-react\";\nimport type { ContactGroup } from \"@fluid-app/contacts-core/types\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport {\n Button,\n cn,\n Input,\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@fluid-app/ui-primitives\";\n\nconst DEFAULT_SUGGESTIONS = [\n \"Customer\",\n \"Cold\",\n \"Hot\",\n \"New\",\n \"Leaders\",\n \"Pros\",\n];\n\nexport interface InlineGroupsEditorProps {\n contactTags: string[];\n availableGroups: ContactGroup[];\n onSave: (tags: string[]) => void;\n onCreateGroup?: (name: string) => void | Promise<void>;\n isSaving?: boolean;\n}\n\nexport function InlineGroupsEditor({\n contactTags,\n availableGroups,\n onSave,\n onCreateGroup,\n isSaving = false,\n}: InlineGroupsEditorProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [open, setOpen] = useState(false);\n const [draftTags, setDraftTags] = useState<string[]>([]);\n const [searchText, setSearchText] = useState(\"\");\n const [prevTags, setPrevTags] = useState<string[]>([]);\n const [newTags, setNewTags] = useState<Set<string>>(new Set());\n const [removingTags, setRemovingTags] = useState<Set<string>>(new Set());\n const [displayTags, setDisplayTags] = useState<string[]>(contactTags);\n const prevContactTagsRef = useRef<string[]>(contactTags);\n\n // Sync displayTags with contactTags, but delay removals for animation.\n // Comparing the previous and current contactTags (rather than displayTags)\n // keeps this effect free of a self-referential dependency.\n useEffect(() => {\n const prev = prevContactTagsRef.current;\n const removed = prev.filter((t) => !contactTags.includes(t));\n const added = contactTags.filter((t) => !prev.includes(t));\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n if (removed.length > 0) {\n setRemovingTags(new Set(removed));\n timer = setTimeout(() => {\n setDisplayTags(contactTags);\n setRemovingTags(new Set());\n }, 300);\n } else if (added.length > 0) {\n setDisplayTags(contactTags);\n } else if (\n prev.length !== contactTags.length ||\n prev.some((t, i) => contactTags[i] !== t)\n ) {\n setDisplayTags(contactTags);\n }\n\n prevContactTagsRef.current = contactTags;\n return () => {\n if (timer) clearTimeout(timer);\n };\n }, [contactTags]);\n\n useEffect(() => {\n if (newTags.size === 0) return;\n const timer = setTimeout(() => setNewTags(new Set()), 2000);\n return () => clearTimeout(timer);\n }, [newTags]);\n\n const handleOpen = useCallback(() => {\n setDraftTags([...contactTags]);\n setPrevTags([...contactTags]);\n setSearchText(\"\");\n setOpen(true);\n }, [contactTags]);\n\n const handleCancel = useCallback(() => {\n setOpen(false);\n setSearchText(\"\");\n }, []);\n\n const handleSave = useCallback(() => {\n const added = new Set(draftTags.filter((t) => !prevTags.includes(t)));\n onSave(draftTags);\n setOpen(false);\n setSearchText(\"\");\n if (added.size > 0) {\n setNewTags(added);\n }\n }, [draftTags, prevTags, onSave]);\n\n const toggleTag = useCallback((tag: string) => {\n setDraftTags((prev) =>\n prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag],\n );\n }, []);\n\n const groupsByName = useMemo(() => {\n const map = new Map<string, ContactGroup>();\n for (const g of availableGroups) {\n map.set(g.name, g);\n }\n return map;\n }, [availableGroups]);\n\n const allGroups = useMemo(() => {\n const groupNames = availableGroups.map((g) => g.name);\n return Array.from(new Set([...groupNames, ...DEFAULT_SUGGESTIONS]));\n }, [availableGroups]);\n\n const filtered = useMemo(() => {\n const lower = searchText.toLowerCase();\n if (!lower) return allGroups;\n return allGroups.filter((name) => name.toLowerCase().includes(lower));\n }, [allGroups, searchText]);\n\n const canCreateNew =\n !!onCreateGroup &&\n searchText.trim() &&\n !allGroups.some((s) => s.toLowerCase() === searchText.trim().toLowerCase());\n\n return (\n <Popover open={open} onOpenChange={(v) => !v && handleCancel()}>\n <PopoverTrigger asChild>\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleOpen}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleOpen();\n }\n }}\n className=\"group/groups flex cursor-pointer flex-wrap items-center gap-1.5\"\n >\n {displayTags.map((tag) => (\n <span\n key={tag}\n className={cn(\n \"bg-muted text-foreground inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium transition-all duration-300\",\n newTags.has(tag) &&\n \"animate-[badge-in_0.3s_ease-out,highlight-fade_2s_ease-out]\",\n removingTags.has(tag) &&\n \"animate-[badge-out_0.3s_ease-in_forwards]\",\n )}\n >\n {tag}\n </span>\n ))}\n <span\n className={cn(\n \"bg-muted text-muted-foreground hover:bg-muted/70 inline-flex items-center justify-center rounded-full px-2 py-0.5 text-xs font-medium transition-colors\",\n )}\n >\n <Plus className=\"size-3.5\" />\n </span>\n </div>\n </PopoverTrigger>\n\n <PopoverContent\n align=\"start\"\n className=\"bg-popover border-border z-50 w-72 rounded-lg border p-0 shadow-md\"\n >\n {/* Search */}\n <div className=\"p-1\">\n <Input\n type=\"text\"\n value={searchText}\n onChange={(e) => setSearchText(e.target.value)}\n placeholder={t(\"groups_inline_search_placeholder\")}\n />\n </div>\n\n {/* Group list */}\n <div className=\"max-h-48 overflow-y-auto py-1\">\n {filtered.map((name) => {\n const isSelected = draftTags.includes(name);\n const group = groupsByName.get(name);\n return (\n <button\n key={name}\n type=\"button\"\n onClick={() => toggleTag(name)}\n className=\"hover:bg-muted flex w-full items-center gap-2.5 px-3 py-2.5 text-left text-sm\"\n >\n {group?.avatar ? (\n <span\n className=\"flex size-5 shrink-0 items-center justify-center rounded-full text-xs\"\n style={{\n backgroundColor:\n group.avatar_background ?? \"var(--color-muted)\",\n }}\n >\n {group.avatar}\n </span>\n ) : (\n <span className=\"bg-muted flex size-5 shrink-0 items-center justify-center rounded-full text-[10px] font-medium\">\n {name[0]?.toUpperCase()}\n </span>\n )}\n <span className=\"text-foreground flex-1 truncate\">{name}</span>\n {isSelected && (\n <Check className=\"text-foreground size-4 shrink-0\" />\n )}\n </button>\n );\n })}\n {canCreateNew && (\n <button\n type=\"button\"\n onClick={async () => {\n const trimmed = searchText.trim();\n if (trimmed && !draftTags.includes(trimmed)) {\n try {\n await onCreateGroup?.(trimmed);\n } catch {\n return;\n }\n const updated = [...draftTags, trimmed];\n const added = new Set(\n updated.filter((t) => !prevTags.includes(t)),\n );\n onSave(updated);\n setOpen(false);\n setSearchText(\"\");\n setNewTags(added);\n }\n }}\n className=\"hover:bg-muted text-primary flex w-full items-center gap-2 px-3 py-2 text-left text-sm font-medium\"\n >\n <Plus className=\"size-3.5\" />\n {t(\"groups_inline_create\", { name: searchText.trim() })}\n </button>\n )}\n {filtered.length === 0 && !canCreateNew && (\n <p className=\"text-muted-foreground py-4 text-center text-sm\">\n {t(\"groups_inline_no_groups_found\")}\n </p>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"border-border flex items-center justify-between border-t px-3 py-2\">\n <span className=\"text-muted-foreground text-xs\">\n {draftTags.length === 1\n ? t(\"groups_inline_selected_one\", { count: draftTags.length })\n : t(\"groups_inline_selected_other\", { count: draftTags.length })}\n </span>\n <div className=\"flex gap-2\">\n <Button variant=\"ghost\" size=\"sm\" onClick={handleCancel}>\n {t(\"cancel\")}\n </Button>\n <Button size=\"sm\" onClick={handleSave} disabled={isSaving}>\n {isSaving ? t(\"saving\") : t(\"save\")}\n </Button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { ListTodo, StickyNote } from \"lucide-react\";\nimport type { Contact, ContactGroup } from \"@fluid-app/contacts-core/types\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { StatusBadge } from \"../../../../shared/components/contacts/statusBadge\";\nimport { InlineGroupsEditor } from \"./InlineGroupsEditor\";\nimport { getDisplayName, getInitials, getRelativeUpdated } from \"./utils\";\n\nexport interface ContactDetailHeroProps {\n contact: Contact;\n tasksCount: number;\n notesCount: number;\n contactTags: string[];\n availableGroups: ContactGroup[];\n onTagsSave: (tags: string[]) => void;\n onCreateGroup?: (name: string) => void | Promise<void>;\n isTagsSaving?: boolean;\n}\n\nexport function ContactDetailHero({\n contact,\n tasksCount,\n notesCount,\n contactTags,\n availableGroups,\n onTagsSave,\n onCreateGroup,\n isTagsSaving,\n}: ContactDetailHeroProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const name = getDisplayName(contact);\n const status = contact.status?.trim();\n const lastUpdated = getRelativeUpdated(contact);\n\n return (\n <div className=\"flex flex-col gap-6 md:flex-row md:items-center md:justify-between md:gap-8\">\n <div className=\"flex flex-col items-start gap-4 md:flex-row md:items-center md:gap-5\">\n <div className=\"bg-muted relative flex size-20 shrink-0 items-center justify-center overflow-hidden rounded-2xl md:size-24\">\n {contact.avatar_url ? (\n <img\n alt={name}\n src={contact.avatar_url}\n className=\"size-full object-cover\"\n />\n ) : (\n <span\n aria-hidden=\"true\"\n className=\"text-muted-foreground text-2xl font-bold tracking-tight md:text-3xl\"\n >\n {getInitials(name)}\n </span>\n )}\n </div>\n\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"text-foreground text-2xl leading-tight font-bold tracking-tight md:text-3xl\">\n {name}\n </h2>\n <div className=\"mt-2.5 flex flex-wrap items-center gap-2\">\n {status && <StatusBadge status={status} />}\n <InlineGroupsEditor\n contactTags={contactTags}\n availableGroups={availableGroups}\n onSave={onTagsSave}\n onCreateGroup={onCreateGroup}\n isSaving={isTagsSaving}\n />\n </div>\n {lastUpdated && (\n <span className=\"text-muted-foreground mt-1.5 text-xs\">\n {t(\"last_updated\", { date: lastUpdated })}\n </span>\n )}\n </div>\n </div>\n\n <div className=\"flex shrink-0 items-center gap-6 md:gap-8\">\n <Stat label={t(\"tab_tasks\")} value={tasksCount} icon={ListTodo} />\n <div className=\"bg-border h-10 w-px\" aria-hidden=\"true\" />\n <Stat label={t(\"tab_notes\")} value={notesCount} icon={StickyNote} />\n </div>\n </div>\n );\n}\n\ninterface StatProps {\n label: string;\n value: number;\n icon: React.ComponentType<{ className?: string; \"aria-hidden\"?: boolean }>;\n}\n\nfunction Stat({ label, value, icon: Icon }: StatProps) {\n return (\n <div className=\"flex flex-col items-start gap-1\">\n <div className=\"text-muted-foreground flex items-center gap-1.5\">\n <Icon className=\"size-3.5\" aria-hidden={true} />\n <span className=\"text-xs font-medium\">{label}</span>\n </div>\n <span className=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">\n {value}\n </span>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Check, Copy, Mail, MapPin, Phone, Plus } from \"lucide-react\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\n\nexport interface ContactInfoRowProps {\n contact: Contact;\n /** Click handler invoked when an empty-state row is activated. */\n onEditEmpty?: () => void;\n}\n\nfunction buildAddressLine(contact: Contact): string | null {\n const parts = [\n contact.address,\n contact.city,\n contact.state,\n contact.postal_code,\n ].filter((part): part is string => Boolean(part?.trim()));\n if (parts.length === 0) return null;\n return parts.join(\", \");\n}\n\nexport function ContactInfoRow({\n contact,\n onEditEmpty,\n}: ContactInfoRowProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const address = buildAddressLine(contact);\n\n return (\n <div className=\"border-border/50 divide-border/50 mt-6 divide-y overflow-hidden rounded-2xl border\">\n <InfoRow\n icon={Mail}\n label={t(\"label_email\")}\n value={contact.email}\n href={contact.email ? `mailto:${contact.email}` : undefined}\n onEditEmpty={onEditEmpty}\n />\n <InfoRow\n icon={Phone}\n label={t(\"label_phone\")}\n value={contact.phone}\n href={contact.phone ? `tel:${contact.phone}` : undefined}\n onEditEmpty={onEditEmpty}\n />\n <InfoRow\n icon={MapPin}\n label={t(\"label_address\")}\n value={address}\n href={\n address\n ? `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(address)}`\n : undefined\n }\n external={true}\n onEditEmpty={onEditEmpty}\n />\n </div>\n );\n}\n\ninterface InfoRowProps {\n icon: React.ComponentType<{ className?: string; \"aria-hidden\"?: boolean }>;\n label: string;\n value: string | null | undefined;\n href: string | undefined;\n external?: boolean;\n onEditEmpty?: () => void;\n}\n\nfunction InfoRow({\n icon: Icon,\n label,\n value,\n href,\n external = false,\n onEditEmpty,\n}: InfoRowProps) {\n const { t } = useContactsTranslation();\n const trimmed = value?.trim();\n const isEmpty = !trimmed;\n const [copied, setCopied] = useState(false);\n\n const handleCopy = () => {\n if (!trimmed) return;\n if (typeof navigator === \"undefined\" || !navigator.clipboard) return;\n navigator.clipboard\n .writeText(trimmed)\n .then(() => {\n setCopied(true);\n window.setTimeout(() => setCopied(false), 1500);\n })\n .catch(() => {\n // clipboard write can fail in insecure contexts; silently noop\n });\n };\n\n if (isEmpty) {\n const addText = t(\"add_field\", { field: label });\n if (!onEditEmpty) {\n return (\n <div className=\"flex items-center gap-3 px-4 py-2.5 md:px-5\">\n <div className=\"border-border/50 text-muted-foreground/50 flex size-9 shrink-0 items-center justify-center rounded-full border-2 border-dashed\">\n <Icon className=\"size-4\" aria-hidden={true} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-muted-foreground text-xs font-medium\">\n {label}\n </div>\n <div className=\"text-muted-foreground/70 truncate text-sm italic\">\n {addText}\n </div>\n </div>\n <Plus\n className=\"text-muted-foreground/40 size-4 shrink-0\"\n aria-hidden={true}\n />\n </div>\n );\n }\n return (\n <button\n type=\"button\"\n onClick={onEditEmpty}\n aria-label={addText}\n className=\"hover:bg-muted/60 group flex w-full items-center gap-3 px-4 py-2.5 text-left transition-colors md:px-5\"\n >\n <div className=\"border-border/50 text-muted-foreground/50 group-hover:border-foreground/30 group-hover:text-muted-foreground flex size-9 shrink-0 items-center justify-center rounded-full border-2 border-dashed transition-colors\">\n <Icon className=\"size-4\" aria-hidden={true} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-muted-foreground text-xs font-medium\">\n {label}\n </div>\n <div className=\"text-muted-foreground/70 group-hover:text-muted-foreground truncate text-sm italic transition-colors\">\n {addText}\n </div>\n </div>\n <Plus\n className=\"text-muted-foreground/40 group-hover:text-foreground size-4 shrink-0 transition-colors\"\n aria-hidden={true}\n />\n </button>\n );\n }\n\n return (\n <div className=\"hover:bg-muted/60 group flex items-center transition-colors\">\n <a\n href={href}\n {...(external ? { target: \"_blank\", rel: \"noopener noreferrer\" } : {})}\n className=\"flex min-w-0 flex-1 items-center gap-3 px-4 py-2.5 md:px-5\"\n >\n <div className=\"bg-muted text-muted-foreground group-hover:bg-muted/70 group-hover:text-foreground flex size-9 shrink-0 items-center justify-center rounded-full transition-colors\">\n <Icon className=\"size-4\" aria-hidden={true} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-muted-foreground text-xs font-medium\">\n {label}\n </div>\n <div className=\"text-foreground truncate text-sm font-semibold\">\n {trimmed}\n </div>\n </div>\n </a>\n <button\n type=\"button\"\n onClick={handleCopy}\n aria-label={\n copied\n ? t(\"copied_field\", { field: label })\n : t(\"copy_field\", { field: label })\n }\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground mr-3 flex size-8 shrink-0 items-center justify-center rounded-md transition-colors\"\n >\n {copied ? (\n <Check className=\"text-primary size-3.5\" aria-hidden={true} />\n ) : (\n <Copy className=\"size-3.5\" aria-hidden={true} />\n )}\n </button>\n </div>\n );\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useTasksApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useToggleTaskCompletion(contactId: string) {\n const queryClient = useQueryClient();\n const api = useTasksApi();\n\n return useMutation({\n mutationFn: ({\n taskId,\n isCompleted,\n }: {\n taskId: number;\n isCompleted: boolean;\n }) =>\n api.updateTask(taskId, contactId, {\n completed_at: isCompleted ? null : new Date().toISOString(),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: contactsKeys.tasks(contactId),\n });\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to update task\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useTasksApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useDeleteContactTask(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useTasksApi();\n\n return useMutation({\n mutationFn: (taskId: number) => api.deleteTask(taskId, contactId),\n onSuccess: () => {\n fluidToast({ title: \"Task deleted\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.tasks(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to delete task\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useTasksApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { UpdateTaskInput } from \"@fluid-app/contacts-core/types\";\n\nexport type { UpdateTaskInput };\n\nexport function useUpdateContactTask(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useTasksApi();\n\n return useMutation({\n mutationFn: ({\n taskId,\n input,\n }: {\n taskId: number;\n input: UpdateTaskInput;\n }) => api.updateTask(taskId, contactId, input),\n onSuccess: () => {\n fluidToast({ title: \"Task updated\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.tasks(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to update task\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","export function formatDateForDisplay(dateStr: string): string {\n const date = new Date(dateStr);\n return date.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n}\n","\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { useEditor, EditorContent } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport Heading from \"@tiptap/extension-heading\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport TextAlign from \"@tiptap/extension-text-align\";\nimport Underline from \"@tiptap/extension-underline\";\nimport {\n AlignLeft,\n AlignCenter,\n AlignRight,\n AlignJustify,\n List,\n ListOrdered,\n Calendar,\n X,\n} from \"lucide-react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport { formatDateForDisplay } from \"../../utils/format-date\";\n\nexport interface NoteTaskEditorProps {\n titlePlaceholder?: string;\n bodyPlaceholder?: string;\n onChange?: (content: {\n title: string;\n body: string;\n dueDate?: string;\n }) => void;\n className?: string;\n /** Pre-populate the title (for edit mode) */\n initialTitle?: string;\n /** Pre-populate the body (for edit mode) */\n initialBody?: string;\n /** Show due date picker */\n showDueDate?: boolean;\n /** Pre-populate the due date (ISO string, for edit mode) */\n initialDueDate?: string;\n /** When false, the editor is body-only (no H1 title). Default true. */\n showTitle?: boolean;\n /** Override for the editor content area min-height class */\n editorClassName?: string;\n}\n\nfunction extractTitleAndBody(editor: ReturnType<typeof useEditor>): {\n title: string;\n body: string;\n} {\n if (!editor) return { title: \"\", body: \"\" };\n\n const doc = editor.state.doc;\n let title = \"\";\n const bodyParts: string[] = [];\n\n doc.forEach((node) => {\n if (node.type.name === \"heading\" && !title) {\n title = node.textContent.trim();\n } else {\n const text = node.textContent.trim();\n if (text) bodyParts.push(text);\n }\n });\n\n return { title, body: bodyParts.join(\"\\n\") };\n}\n\nfunction extractBodyOnly(editor: ReturnType<typeof useEditor>): string {\n if (!editor) return \"\";\n const parts: string[] = [];\n editor.state.doc.forEach((node) => {\n const text = node.textContent.trim();\n if (text) parts.push(text);\n });\n return parts.join(\"\\n\");\n}\n\nexport function NoteTaskEditor({\n titlePlaceholder = \"New Note\",\n bodyPlaceholder = \"Start writing...\",\n onChange,\n className,\n initialTitle,\n initialBody,\n showDueDate = false,\n initialDueDate,\n showTitle = true,\n editorClassName,\n}: NoteTaskEditorProps): React.JSX.Element {\n const [dueDate, setDueDate] = useState<string | undefined>(initialDueDate);\n const dueDateRef = useRef(initialDueDate);\n const dateInputRef = useRef<HTMLInputElement>(null);\n\n // Keep ref in sync with state so onUpdate always reads the latest value\n useEffect(() => {\n dueDateRef.current = dueDate;\n }, [dueDate]);\n\n const initialContent = showTitle\n ? initialTitle || initialBody\n ? `<h1>${initialTitle ?? \"\"}</h1>${initialBody ?? \"\"}`\n : undefined\n : initialBody || undefined;\n\n const extensions = [\n StarterKit.configure({\n heading: showTitle ? false : { levels: [] as const },\n bulletList: {\n keepMarks: true,\n keepAttributes: false,\n },\n orderedList: {\n keepMarks: true,\n keepAttributes: false,\n },\n }),\n ...(showTitle ? [Heading.configure({ levels: [1] })] : []),\n Placeholder.configure({\n placeholder: ({ node }) => {\n if (node.type.name === \"heading\") {\n return titlePlaceholder;\n }\n return bodyPlaceholder;\n },\n }),\n TextAlign.configure({\n types: showTitle ? [\"heading\", \"paragraph\"] : [\"paragraph\"],\n alignments: [\"left\", \"center\", \"right\", \"justify\"],\n }),\n Underline,\n ];\n\n const defaultContent = showTitle\n ? {\n type: \"doc\" as const,\n content: [{ type: \"heading\" as const, attrs: { level: 1 } }],\n }\n : undefined;\n\n const editor = useEditor({\n extensions,\n content: initialContent ?? defaultContent,\n onUpdate: ({ editor }) => {\n if (showTitle) {\n const { title, body } = extractTitleAndBody(editor);\n onChange?.({ title, body, dueDate: dueDateRef.current });\n } else {\n const body = extractBodyOnly(editor);\n onChange?.({ title: \"\", body, dueDate: dueDateRef.current });\n }\n },\n });\n\n const fireOnChange = () => {\n if (!editor || !onChange) return;\n if (showTitle) {\n const { title, body } = extractTitleAndBody(editor);\n onChange({ title, body, dueDate });\n } else {\n const body = extractBodyOnly(editor);\n onChange({ title: \"\", body, dueDate });\n }\n };\n\n // Fire onChange once on mount so the parent's ref is populated with the\n // initial values before the user makes any edits.\n useEffect(() => {\n fireOnChange();\n // We only want this to run once after the editor is first created.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [editor]);\n\n // Notify parent when due date changes\n useEffect(() => {\n fireOnChange();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dueDate]);\n\n const buttonBase =\n \"flex h-7 w-7 items-center justify-center rounded text-xs transition-colors\";\n const buttonActive = \"bg-muted text-primary\";\n const buttonInactive = \"text-muted-foreground hover:bg-muted/50\";\n\n const toolbarSeparator = <div className=\"bg-border mx-1 h-5 w-px\" />;\n\n return (\n <div\n className={cn(\n \"border-border/50 flex flex-col overflow-hidden rounded-lg border\",\n className,\n )}\n >\n {/* Toolbar */}\n <div className=\"border-border/50 bg-muted/50 flex items-center gap-0.5 border-b px-2 py-1.5\">\n {/* Bold */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleBold().run()}\n disabled={!editor?.can().chain().focus().toggleBold().run()}\n className={cn(\n buttonBase,\n \"font-bold\",\n editor?.isActive(\"bold\") ? buttonActive : buttonInactive,\n )}\n title=\"Bold\"\n >\n B\n </button>\n\n {/* Italic */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleItalic().run()}\n disabled={!editor?.can().chain().focus().toggleItalic().run()}\n className={cn(\n buttonBase,\n \"italic\",\n editor?.isActive(\"italic\") ? buttonActive : buttonInactive,\n )}\n title=\"Italic\"\n >\n I\n </button>\n\n {/* Underline */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleUnderline().run()}\n disabled={!editor?.can().chain().focus().toggleUnderline().run()}\n className={cn(\n buttonBase,\n \"underline\",\n editor?.isActive(\"underline\") ? buttonActive : buttonInactive,\n )}\n title=\"Underline\"\n >\n U\n </button>\n\n {toolbarSeparator}\n\n {/* Align left */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().setTextAlign(\"left\").run()}\n className={cn(\n buttonBase,\n editor?.isActive({ textAlign: \"left\" })\n ? buttonActive\n : buttonInactive,\n )}\n title=\"Align left\"\n >\n <AlignLeft className=\"size-3.5\" />\n </button>\n\n {/* Align center */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().setTextAlign(\"center\").run()}\n className={cn(\n buttonBase,\n editor?.isActive({ textAlign: \"center\" })\n ? buttonActive\n : buttonInactive,\n )}\n title=\"Align center\"\n >\n <AlignCenter className=\"size-3.5\" />\n </button>\n\n {/* Align right */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().setTextAlign(\"right\").run()}\n className={cn(\n buttonBase,\n editor?.isActive({ textAlign: \"right\" })\n ? buttonActive\n : buttonInactive,\n )}\n title=\"Align right\"\n >\n <AlignRight className=\"size-3.5\" />\n </button>\n\n {/* Align justify */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().setTextAlign(\"justify\").run()}\n className={cn(\n buttonBase,\n editor?.isActive({ textAlign: \"justify\" })\n ? buttonActive\n : buttonInactive,\n )}\n title=\"Justify\"\n >\n <AlignJustify className=\"size-3.5\" />\n </button>\n\n {toolbarSeparator}\n\n {/* Bullet list */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleBulletList().run()}\n className={cn(\n buttonBase,\n editor?.isActive(\"bulletList\") ? buttonActive : buttonInactive,\n )}\n title=\"Bullet list\"\n >\n <List className=\"size-3.5\" />\n </button>\n\n {/* Ordered list */}\n <button\n type=\"button\"\n onClick={() => editor?.chain().focus().toggleOrderedList().run()}\n className={cn(\n buttonBase,\n editor?.isActive(\"orderedList\") ? buttonActive : buttonInactive,\n )}\n title=\"Ordered list\"\n >\n <ListOrdered className=\"size-3.5\" />\n </button>\n\n {showDueDate && (\n <>\n {toolbarSeparator}\n {/* Due date */}\n {dueDate ? (\n <div className=\"bg-primary/10 flex items-center gap-1 rounded px-2 py-1\">\n <Calendar className=\"text-primary size-3.5\" />\n <span className=\"text-primary text-xs font-medium\">\n {formatDateForDisplay(dueDate)}\n </span>\n <button\n type=\"button\"\n onClick={() => setDueDate(undefined)}\n className=\"text-primary/60 hover:text-primary ml-1\"\n title=\"Remove due date\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ) : (\n <>\n <button\n type=\"button\"\n onClick={() => dateInputRef.current?.showPicker()}\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex h-7 cursor-pointer items-center gap-1 rounded px-2 text-xs font-medium transition-colors\"\n >\n <Calendar className=\"size-3.5\" />\n <span>Due date</span>\n </button>\n <input\n ref={dateInputRef}\n type=\"date\"\n className=\"invisible absolute size-0\"\n onChange={(e) => {\n if (e.target.value) {\n // Convert YYYY-MM-DD to ISO datetime at local midnight\n const localDate = new Date(e.target.value + \"T00:00:00\");\n setDueDate(localDate.toISOString());\n }\n }}\n />\n </>\n )}\n </>\n )}\n </div>\n\n {/* Editor area */}\n <EditorContent\n editor={editor}\n className={editorClassName ?? \"min-h-[60vh] flex-1 overflow-y-auto p-4\"}\n />\n\n <style>{`\n .ProseMirror {\n outline: none;\n }\n\n .ProseMirror h1 {\n font-size: 1.5rem;\n font-weight: 600;\n line-height: 1.3;\n margin-bottom: 0.5rem;\n }\n\n .ProseMirror h1.is-empty::before,\n .ProseMirror p.is-empty::before {\n color: var(--color-muted-foreground);\n content: attr(data-placeholder);\n float: left;\n height: 0;\n pointer-events: none;\n }\n\n .ProseMirror ul {\n list-style-type: disc;\n padding-left: 1.5rem;\n margin: 0.5rem 0;\n }\n\n .ProseMirror ol {\n list-style-type: decimal;\n padding-left: 1.5rem;\n margin: 0.5rem 0;\n }\n\n .ProseMirror li {\n margin: 0.25rem 0;\n display: list-item;\n }\n\n .ProseMirror li > p {\n margin: 0;\n }\n `}</style>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport { Calendar, X } from \"lucide-react\";\nimport {\n Button,\n Input,\n Sheet,\n SheetContent,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n} from \"@fluid-app/ui-primitives\";\nimport { NoteTaskEditor } from \"./note-task-editor\";\nimport { formatDateForDisplay } from \"../../utils/format-date\";\n\nexport interface NoteTaskModalProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n mode: \"create\" | \"edit\";\n type: \"note\" | \"task\";\n initialTitle?: string;\n initialBody?: string;\n initialDueDate?: string;\n showDueDate?: boolean;\n onSave: (data: { title: string; body: string; dueDate?: string }) => void;\n isPending?: boolean;\n isCompleted?: boolean;\n onToggleComplete?: () => void;\n isTogglePending?: boolean;\n}\n\nexport function NoteTaskModal({\n open,\n onOpenChange,\n mode,\n type,\n initialTitle = \"\",\n initialBody = \"\",\n initialDueDate,\n showDueDate = false,\n onSave,\n isPending = false,\n isCompleted,\n onToggleComplete,\n isTogglePending = false,\n}: NoteTaskModalProps): React.JSX.Element {\n const [title, setTitle] = useState(initialTitle);\n const [body, setBody] = useState(initialBody);\n const dateInputRef = useRef<HTMLInputElement>(null);\n const [dueDate, setDueDate] = useState<string | undefined>(initialDueDate);\n\n const typeLabel = type === \"note\" ? \"Note\" : \"Task\";\n const sheetTitle = mode === \"edit\" ? `Edit ${typeLabel}` : `New ${typeLabel}`;\n\n const requiresBody = type === \"note\";\n const canSave =\n !!title.trim() && (!requiresBody || !!body.trim()) && !isPending;\n\n const handleSave = () => {\n if (!canSave) return;\n onSave({\n title: title.trim(),\n body,\n dueDate,\n });\n };\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent className=\"flex w-full flex-col sm:max-w-lg\">\n <SheetHeader>\n <SheetTitle>{sheetTitle}</SheetTitle>\n </SheetHeader>\n\n <div className=\"flex min-h-0 flex-1 flex-col gap-3\">\n <Input\n placeholder={`${typeLabel} title`}\n value={title}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setTitle(e.target.value)\n }\n autoFocus\n />\n\n <NoteTaskEditor\n showTitle={false}\n bodyPlaceholder=\"Start writing...\"\n initialBody={initialBody}\n editorClassName=\"min-h-[200px] flex-1 overflow-y-auto p-4\"\n onChange={(content) => {\n setBody(content.body);\n }}\n />\n\n {showDueDate && (\n <div className=\"flex items-center gap-2\">\n {dueDate ? (\n <div className=\"bg-primary/10 inline-flex items-center gap-1.5 rounded-md px-2.5 py-1.5\">\n <Calendar className=\"text-primary size-3.5\" />\n <span className=\"text-primary text-sm font-medium\">\n Due {formatDateForDisplay(dueDate)}\n </span>\n <button\n type=\"button\"\n onClick={() => setDueDate(undefined)}\n className=\"text-primary/60 hover:text-primary ml-1\"\n title=\"Remove due date\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ) : (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={() => dateInputRef.current?.showPicker()}\n className=\"text-muted-foreground hover:text-foreground hover:bg-muted inline-flex cursor-pointer items-center gap-1.5 rounded-md px-2.5 py-1.5 text-sm font-medium transition-colors\"\n >\n <Calendar className=\"size-3.5\" />\n <span>Add due date</span>\n </button>\n <input\n ref={dateInputRef}\n type=\"date\"\n className=\"invisible absolute size-0\"\n onChange={(e) => {\n if (e.target.value) {\n const localDate = new Date(\n e.target.value + \"T00:00:00\",\n );\n setDueDate(localDate.toISOString());\n }\n }}\n />\n </div>\n )}\n </div>\n )}\n </div>\n\n <SheetFooter className=\"flex-row justify-end gap-2 border-t pt-4\">\n {mode === \"edit\" && onToggleComplete && (\n <Button\n variant=\"outline\"\n onClick={onToggleComplete}\n disabled={isTogglePending}\n className=\"mr-auto\"\n >\n {isCompleted ? \"Mark Incomplete\" : \"Mark Complete\"}\n </Button>\n )}\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={!canSave}>\n {isPending ? \"Saving...\" : \"Save\"}\n </Button>\n </SheetFooter>\n </SheetContent>\n </Sheet>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Calendar, CircleCheck, EllipsisVertical } from \"lucide-react\";\nimport {\n cn,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@fluid-app/ui-primitives\";\nimport { parseTaskBody } from \"@fluid-app/contacts-core/parse-task-body\";\nimport { startOfLocalDay } from \"@fluid-app/contacts-core/iso-date\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport type { ContactTask } from \"../../hooks/contacts/use-contact-tasks\";\nimport { useToggleTaskCompletion } from \"../../hooks/contacts/use-toggle-task-completion\";\nimport { useDeleteContactTask } from \"../../hooks/contacts/use-delete-contact-task\";\nimport { useUpdateContactTask } from \"../../hooks/contacts/use-update-contact-task\";\nimport { NoteTaskModal } from \"../editor/note-task-modal\";\n\n// ---------------------------------------------------------------------------\n// Date helpers\n// ---------------------------------------------------------------------------\n\nfunction formatDueDate(dateStr: string): string {\n const date = new Date(dateStr);\n return date.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n}\n\ntype ContactsT = ReturnType<typeof useContactsTranslation>[\"t\"];\n\nfunction formatRelativeTime(dateStr: string, t: ContactsT): string {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) {\n return date.toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n }\n if (diffDays === 1) return t(\"task_yesterday\");\n return diffDays === 1\n ? t(\"task_days_ago_one\")\n : t(\"task_days_ago_other\", { count: diffDays });\n}\n\ntype DueClassification = {\n label: string;\n tone: \"overdue\" | \"today\" | \"tomorrow\" | \"future\" | \"done\";\n};\n\nfunction classifyDue(\n dueAt: string,\n isCompleted: boolean,\n t: ContactsT,\n): DueClassification {\n if (isCompleted) {\n return {\n label: t(\"task_due\", { date: formatDueDate(dueAt) }),\n tone: \"done\",\n };\n }\n const due = startOfLocalDay(dueAt);\n const today = startOfLocalDay(new Date());\n const tomorrow = new Date(today);\n tomorrow.setDate(today.getDate() + 1);\n\n const dueTime = due.getTime();\n if (dueTime < today.getTime()) {\n return {\n label: t(\"task_overdue_due\", { date: formatDueDate(dueAt) }),\n tone: \"overdue\",\n };\n }\n if (dueTime === today.getTime())\n return { label: t(\"quick_today\"), tone: \"today\" };\n if (dueTime === tomorrow.getTime())\n return { label: t(\"quick_tomorrow\"), tone: \"tomorrow\" };\n return { label: formatDueDate(dueAt), tone: \"future\" };\n}\n\nconst DUE_TONE_CLASS: Record<DueClassification[\"tone\"], string> = {\n overdue: \"bg-destructive/10 text-destructive\",\n today: \"bg-primary/10 text-primary\",\n tomorrow: \"bg-primary/10 text-primary\",\n future: \"bg-muted text-muted-foreground\",\n done: \"bg-muted text-muted-foreground\",\n};\n\n// ---------------------------------------------------------------------------\n// Task card\n// ---------------------------------------------------------------------------\n\ninterface TaskCardProps {\n task: ContactTask;\n toggleCompletion: ReturnType<typeof useToggleTaskCompletion>;\n onEdit: (task: ContactTask) => void;\n onDeleteClick: (task: ContactTask) => void;\n}\n\nfunction TaskCard({\n task,\n toggleCompletion,\n onEdit,\n onDeleteClick,\n}: TaskCardProps) {\n const { t } = useContactsTranslation();\n const isCompleted = !!task.completed_at;\n\n const { title, body: bodyText } = parseTaskBody(task.body ?? \"\");\n\n const timestamp = task.created_at\n ? formatRelativeTime(task.created_at, t)\n : \"\";\n const due = task.due_at ? classifyDue(task.due_at, isCompleted, t) : null;\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={() => onEdit(task)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onEdit(task);\n }\n }}\n className=\"group border-border/50 hover:border-foreground/20 hover:bg-muted/40 relative cursor-pointer rounded-xl border p-4 transition-all hover:shadow-sm\"\n >\n <div className=\"flex items-start gap-3\">\n {/* Checkbox */}\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n toggleCompletion.mutate({\n taskId: task.id,\n isCompleted: isCompleted,\n });\n }}\n disabled={toggleCompletion.isPending}\n className=\"mt-0.5 shrink-0 transition-transform hover:scale-110 disabled:cursor-not-allowed disabled:opacity-50\"\n aria-label={isCompleted ? t(\"mark_as_open\") : t(\"mark_as_completed\")}\n >\n {isCompleted ? (\n <CircleCheck className=\"text-primary size-5\" aria-hidden=\"true\" />\n ) : (\n <div className=\"border-muted-foreground/40 group-hover:border-primary size-5 rounded-full border-2 transition-colors\" />\n )}\n </button>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <h4\n className={cn(\n \"text-foreground line-clamp-2 text-sm leading-snug font-semibold\",\n isCompleted && \"text-muted-foreground line-through\",\n )}\n >\n {title}\n </h4>\n\n {/* Body text */}\n {bodyText && (\n <p\n className={cn(\n \"text-muted-foreground mt-1 line-clamp-2 text-xs leading-relaxed\",\n isCompleted && \"line-through\",\n )}\n >\n {bodyText}\n </p>\n )}\n\n {/* Meta row */}\n {(due || timestamp) && (\n <div className=\"mt-2.5 flex flex-wrap items-center gap-1.5\">\n {due && (\n <span\n className={cn(\n \"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium\",\n DUE_TONE_CLASS[due.tone],\n )}\n >\n <Calendar className=\"size-3\" aria-hidden=\"true\" />\n {due.label}\n </span>\n )}\n {timestamp && (\n <span className=\"text-muted-foreground/60 text-xs\">\n {timestamp}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n\n {/* Hover-revealed menu */}\n <div className=\"absolute top-3 right-3 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n onClick={(e) => e.stopPropagation()}\n aria-label={t(\"task_actions\")}\n >\n <EllipsisVertical className=\"size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n className=\"text-destructive\"\n onClick={(e) => {\n e.stopPropagation();\n onDeleteClick(task);\n }}\n >\n {t(\"delete\")}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport interface TaskListProps {\n tasks: ContactTask[];\n isLoading?: boolean;\n contactId: string;\n /**\n * Retained for backwards compatibility — currently has no effect since the\n * inline composer always renders above the list. Will be removed once all\n * consumers stop passing it.\n */\n hideHeader?: boolean;\n}\n\nexport function TaskList({\n tasks,\n isLoading,\n contactId,\n}: TaskListProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [taskToDelete, setTaskToDelete] = useState<ContactTask | null>(null);\n const [editingTask, setEditingTask] = useState<ContactTask | null>(null);\n\n const toggleCompletion = useToggleTaskCompletion(contactId);\n const deleteTask = useDeleteContactTask(contactId, {\n onSuccess: () => setTaskToDelete(null),\n });\n const updateTask = useUpdateContactTask(contactId, {\n onSuccess: () => setEditingTask(null),\n });\n\n const handleSave = (data: {\n title: string;\n body: string;\n dueDate?: string;\n }) => {\n if (!editingTask) return;\n const taskBody = data.body ? `${data.title}\\n\\n${data.body}` : data.title;\n updateTask.mutate({\n taskId: editingTask.id,\n input: { body: taskBody, due_at: data.dueDate ?? null },\n });\n };\n\n const editingParsed = editingTask\n ? parseTaskBody(editingTask.body ?? \"\")\n : null;\n\n const handleModalOpenChange = (open: boolean) => {\n if (!open) setEditingTask(null);\n };\n\n if (isLoading) {\n return (\n <div className=\"flex flex-col gap-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"border-border/50 bg-muted/50 h-32 animate-pulse rounded-xl border\"\n />\n ))}\n </div>\n );\n }\n\n if (tasks.length === 0) return <></>;\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-col gap-3\">\n {tasks.map((task) => (\n <TaskCard\n key={task.id}\n task={task}\n toggleCompletion={toggleCompletion}\n onEdit={setEditingTask}\n onDeleteClick={setTaskToDelete}\n />\n ))}\n </div>\n\n {/* Edit modal — create flow lives in InlineTaskComposer */}\n <NoteTaskModal\n key={editingTask?.id ?? \"edit\"}\n open={editingTask !== null}\n onOpenChange={handleModalOpenChange}\n mode=\"edit\"\n type=\"task\"\n initialTitle={editingParsed?.title ?? \"\"}\n initialBody={editingParsed?.body ?? \"\"}\n initialDueDate={editingTask?.due_at ?? undefined}\n showDueDate\n onSave={handleSave}\n isPending={updateTask.isPending}\n isCompleted={editingTask ? !!editingTask.completed_at : undefined}\n onToggleComplete={\n editingTask\n ? () =>\n toggleCompletion.mutate(\n {\n taskId: editingTask.id,\n isCompleted: !!editingTask.completed_at,\n },\n { onSuccess: () => setEditingTask(null) },\n )\n : undefined\n }\n isTogglePending={toggleCompletion.isPending}\n />\n\n {/* Delete confirmation modal */}\n <AlertDialog\n open={taskToDelete !== null}\n onOpenChange={(open) => {\n if (!open) setTaskToDelete(null);\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{t(\"delete_task_title\")}</AlertDialogTitle>\n <AlertDialogDescription>\n {t(\"delete_task_confirm\")}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>{t(\"cancel\")}</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => {\n if (taskToDelete) {\n deleteTask.mutate(taskToDelete.id);\n }\n }}\n >\n {t(\"delete\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Plus } from \"lucide-react\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { TaskComposerForm } from \"./task-composer-form\";\n\nexport interface InlineTaskComposerProps {\n contactId: string;\n}\n\nexport function InlineTaskComposer({\n contactId,\n}: InlineTaskComposerProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [isOpen, setIsOpen] = useState(false);\n\n if (!isOpen) {\n return (\n <button\n type=\"button\"\n onClick={() => setIsOpen(true)}\n className=\"border-border/50 text-muted-foreground hover:border-foreground/30 hover:bg-muted/40 hover:text-foreground flex w-full items-center gap-3 rounded-xl border border-dashed px-5 py-4 text-sm font-medium transition-colors\"\n >\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n {t(\"new_task\")}\n </button>\n );\n }\n\n const close = () => setIsOpen(false);\n return (\n <TaskComposerForm contactId={contactId} onClose={close} onDone={close} />\n );\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useNotesApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\n\nexport function useDeleteContactNote(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useNotesApi();\n\n return useMutation({\n mutationFn: (noteId: number) => api.deleteNote(noteId, contactId),\n onSuccess: () => {\n fluidToast({ title: \"Note deleted\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.notes(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to delete note\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useNotesApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { UpdateNoteInput } from \"@fluid-app/contacts-core/types\";\n\nexport type { UpdateNoteInput };\n\nexport function useUpdateContactNote(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useNotesApi();\n\n return useMutation({\n mutationFn: ({\n noteId,\n input,\n }: {\n noteId: number;\n input: UpdateNoteInput;\n }) => api.updateNote(noteId, contactId, input),\n onSuccess: () => {\n fluidToast({ title: \"Note updated\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.notes(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to update note\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useNotesApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport type { CreateNoteInput } from \"@fluid-app/contacts-core/types\";\n\nexport type { CreateNoteInput };\n\nexport function useCreateContactNote(\n contactId: string,\n options?: { onSuccess?: () => void },\n) {\n const queryClient = useQueryClient();\n const api = useNotesApi();\n\n return useMutation({\n mutationFn: (input: CreateNoteInput) => api.createNote(contactId, input),\n onSuccess: () => {\n fluidToast({ title: \"Note created\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: contactsKeys.notes(contactId),\n });\n options?.onSuccess?.();\n },\n onError: (error) => {\n fluidToast({\n title: \"Failed to create note\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n },\n });\n}\n","\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { useCreateContactNote } from \"../../hooks/notes/use-create-contact-note\";\n\nexport interface InlineNoteComposerProps {\n contactId: string;\n}\n\nfunction detectMacPlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n // Prefer userAgentData.platform when available (modern Chromium); fall back\n // to userAgent string. navigator.platform is deprecated.\n const uaData = (\n navigator as Navigator & {\n userAgentData?: { platform?: string };\n }\n ).userAgentData;\n const platform = uaData?.platform ?? navigator.userAgent ?? \"\";\n return /Mac|iPhone|iPad/i.test(platform);\n}\n\nexport function InlineNoteComposer({\n contactId,\n}: InlineNoteComposerProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [body, setBody] = useState(\"\");\n const [isFocused, setIsFocused] = useState(false);\n const [isMac, setIsMac] = useState(false);\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n\n // Detect platform on mount only — avoids SSR hydration mismatch from reading\n // navigator at module load.\n useEffect(() => {\n setIsMac(detectMacPlatform());\n }, []);\n\n const createNote = useCreateContactNote(contactId, {\n onSuccess: () => {\n setBody(\"\");\n textareaRef.current?.blur();\n },\n });\n\n const submit = () => {\n const trimmed = body.trim();\n if (!trimmed || createNote.isPending) return;\n const firstLine = trimmed.split(\"\\n\")[0]?.slice(0, 120) ?? \"Note\";\n createNote.mutate({ title: firstLine, body: trimmed });\n };\n\n const canSubmit = body.trim().length > 0 && !createNote.isPending;\n\n return (\n <div\n className={cn(\n \"border-border/50 focus-within:border-foreground/30 rounded-2xl border p-4 transition-colors\",\n isFocused && \"border-foreground/30\",\n )}\n >\n <textarea\n ref={textareaRef}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") {\n e.preventDefault();\n submit();\n }\n }}\n placeholder={t(\"note_placeholder\")}\n aria-label={t(\"note_body_aria\")}\n rows={3}\n className=\"placeholder:text-muted-foreground text-foreground min-h-[80px] w-full resize-none border-0 bg-transparent text-sm leading-relaxed outline-none\"\n />\n <div className=\"mt-3 flex items-center justify-between gap-3\">\n <span className=\"text-muted-foreground text-xs\">\n {isMac ? t(\"tip_save_shortcut_mac\") : t(\"tip_save_shortcut_other\")}\n </span>\n <button\n type=\"button\"\n onClick={submit}\n disabled={!canSubmit}\n className=\"bg-primary text-primary-foreground hover:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground inline-flex shrink-0 items-center gap-1.5 rounded-full px-4 py-1.5 text-xs font-semibold transition-colors disabled:cursor-not-allowed\"\n >\n {createNote.isPending ? t(\"adding\") : t(\"add_note\")}\n </button>\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Calendar, Paperclip, EllipsisVertical } from \"lucide-react\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Button,\n cn,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@fluid-app/ui-primitives\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport type { ContactNote } from \"../../hooks/notes/use-contact-notes\";\nimport { useDeleteContactNote } from \"../../hooks/notes/use-delete-contact-note\";\nimport { useUpdateContactNote } from \"../../hooks/notes/use-update-contact-note\";\nimport { NoteTaskModal } from \"../editor/note-task-modal\";\nimport { InlineNoteComposer } from \"./inline-note-composer\";\n\n// ---------------------------------------------------------------------------\n// Date helpers\n// ---------------------------------------------------------------------------\n\nfunction formatDueDate(dateStr: string): string {\n const date = new Date(dateStr);\n return date.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n}\n\ntype ContactsT = ReturnType<typeof useContactsTranslation>[\"t\"];\n\nfunction formatRelativeNote(dateStr: string, t: ContactsT): string {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) {\n return date.toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n }\n if (diffDays === 1) return t(\"task_yesterday\");\n if (diffDays < 7) return t(\"task_days_ago_other\", { count: diffDays });\n return formatDueDate(dateStr);\n}\n\n// ---------------------------------------------------------------------------\n// Note card\n// ---------------------------------------------------------------------------\n\nfunction NoteCard({\n note,\n onEdit,\n onDelete,\n}: {\n note: ContactNote;\n onEdit: (note: ContactNote) => void;\n onDelete: (note: ContactNote) => void;\n}) {\n const { t } = useContactsTranslation();\n const assetCount = note.assets?.length ?? 0;\n const showTitle =\n !!note.title?.trim() && note.title.trim() !== note.body?.trim();\n const dueDateValue = note.due_at ?? note.due_date ?? null;\n const createdLabel = note.created_at\n ? formatRelativeNote(note.created_at, t)\n : null;\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={() => onEdit(note)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onEdit(note);\n }\n }}\n className=\"group border-border/50 hover:border-foreground/20 hover:bg-muted/40 relative cursor-pointer rounded-xl border p-4 transition-all hover:shadow-sm\"\n >\n {showTitle && (\n <h4 className=\"text-foreground line-clamp-1 text-sm font-semibold\">\n {note.title}\n </h4>\n )}\n\n <p\n className={cn(\n \"text-foreground line-clamp-4 text-sm leading-relaxed whitespace-pre-wrap\",\n showTitle && \"text-muted-foreground mt-1\",\n )}\n >\n {note.body}\n </p>\n\n {(createdLabel || dueDateValue || assetCount > 0) && (\n <div className=\"mt-2.5 flex flex-wrap items-center gap-3\">\n {createdLabel && (\n <span className=\"text-muted-foreground/70 text-xs\">\n {createdLabel}\n </span>\n )}\n {dueDateValue && (\n <span className=\"bg-primary/10 text-primary inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium\">\n <Calendar className=\"size-3\" aria-hidden=\"true\" />\n {t(\"task_due\", { date: formatDueDate(dueDateValue) })}\n </span>\n )}\n {assetCount > 0 && (\n <span className=\"text-muted-foreground inline-flex items-center gap-1 text-xs\">\n <Paperclip className=\"size-3\" aria-hidden=\"true\" />\n {assetCount === 1\n ? t(\"attachment_one\")\n : t(\"attachment_other\", { count: assetCount })}\n </span>\n )}\n </div>\n )}\n\n <div className=\"absolute top-3 right-3 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n onClick={(e) => e.stopPropagation()}\n aria-label={t(\"note_actions\")}\n >\n <EllipsisVertical className=\"size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n className=\"text-destructive\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(note);\n }}\n >\n {t(\"delete\")}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport interface NotesListProps {\n notes: ContactNote[];\n isLoading?: boolean;\n contactId: string;\n}\n\nexport function NotesList({\n notes,\n isLoading,\n contactId,\n}: NotesListProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const [noteToDelete, setNoteToDelete] = useState<ContactNote | null>(null);\n const [editingNote, setEditingNote] = useState<ContactNote | null>(null);\n\n const deleteNote = useDeleteContactNote(contactId, {\n onSuccess: () => setNoteToDelete(null),\n });\n const updateNote = useUpdateContactNote(contactId, {\n onSuccess: () => setEditingNote(null),\n });\n\n const handleEditSave = (data: { title: string; body: string }) => {\n if (!editingNote) return;\n updateNote.mutate({\n noteId: editingNote.id,\n input: { title: data.title, body: data.body },\n });\n };\n\n return (\n <div className=\"space-y-4\">\n <InlineNoteComposer contactId={contactId} />\n\n {isLoading ? (\n <div className=\"flex flex-col gap-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"border-border/50 bg-muted/50 h-20 animate-pulse rounded-xl border\"\n />\n ))}\n </div>\n ) : notes.length === 0 ? null : (\n <div className=\"flex flex-col gap-3\">\n {notes.map((note) => (\n <NoteCard\n key={note.id}\n note={note}\n onEdit={setEditingNote}\n onDelete={setNoteToDelete}\n />\n ))}\n </div>\n )}\n\n {/* Edit modal — create flow now lives in InlineNoteComposer */}\n <NoteTaskModal\n key={editingNote?.id ?? \"edit\"}\n open={editingNote !== null}\n onOpenChange={(open) => {\n if (!open) setEditingNote(null);\n }}\n mode=\"edit\"\n type=\"note\"\n initialTitle={editingNote?.title ?? \"\"}\n initialBody={editingNote?.body ?? \"\"}\n onSave={handleEditSave}\n isPending={updateNote.isPending}\n />\n\n {/* Delete confirmation */}\n <AlertDialog\n open={!!noteToDelete}\n onOpenChange={(open) => {\n if (!open) setNoteToDelete(null);\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{t(\"delete_note_title\")}</AlertDialogTitle>\n <AlertDialogDescription>\n {t(\"delete_note_irreversible\")}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>{t(\"cancel\")}</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => {\n if (noteToDelete) {\n deleteNote.mutate(noteToDelete.id);\n }\n }}\n >\n {t(\"delete\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { TaskList } from \"../../tasks/task-list\";\nimport { InlineTaskComposer } from \"../../tasks/inline-task-composer\";\nimport { NotesList } from \"../../notes/notes-list\";\nimport type { ContactTask } from \"../../../hooks/contacts/use-contact-tasks\";\nimport type { ContactNote } from \"../../../hooks/notes/use-contact-notes\";\n\nconst VISIBLE_TABS = [\"Tasks\", \"Notes\"] as const;\nexport type TabType = (typeof VISIBLE_TABS)[number];\n\nexport interface ContactDetailTabsProps {\n contactId: string;\n tasks: ContactTask[];\n isLoadingTasks: boolean;\n notes: ContactNote[];\n isLoadingNotes: boolean;\n activeTab: TabType;\n onTabChange: (tab: TabType) => void;\n}\n\nexport function ContactDetailTabs({\n contactId,\n tasks,\n isLoadingTasks,\n notes,\n isLoadingNotes,\n activeTab,\n onTabChange,\n}: ContactDetailTabsProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const tabLabels: Record<TabType, string> = {\n Tasks: t(\"tab_tasks\"),\n Notes: t(\"tab_notes\"),\n };\n return (\n <div className=\"mt-8\">\n <div className=\"border-border/50 flex items-center gap-1 border-b\">\n {VISIBLE_TABS.map((tab) => {\n const count = tab === \"Tasks\" ? tasks.length : notes.length;\n const isActive = activeTab === tab;\n return (\n <button\n key={tab}\n type=\"button\"\n onClick={() => onTabChange(tab)}\n className={cn(\n \"relative flex items-center gap-1.5 px-3 py-2.5 text-sm font-semibold transition-colors\",\n isActive\n ? \"text-foreground\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n >\n {tabLabels[tab]}\n <span\n className={cn(\n \"rounded-full px-1.5 text-xs leading-5 font-bold\",\n isActive\n ? \"bg-primary text-primary-foreground\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {count}\n </span>\n {isActive && (\n <span\n className=\"bg-primary absolute inset-x-0 -bottom-px h-0.5\"\n aria-hidden=\"true\"\n />\n )}\n </button>\n );\n })}\n </div>\n\n <div className=\"pt-6\">\n {activeTab === \"Tasks\" && (\n <div className=\"space-y-4\">\n <InlineTaskComposer contactId={contactId} />\n <TaskList\n tasks={tasks}\n isLoading={isLoadingTasks}\n contactId={contactId}\n hideHeader\n />\n </div>\n )}\n\n {activeTab === \"Notes\" && (\n <NotesList\n notes={notes}\n isLoading={isLoadingNotes}\n contactId={contactId}\n />\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useCallback, useState } from \"react\";\nimport { FormProvider } from \"react-hook-form\";\nimport {\n ChevronLeft,\n Mail,\n MoreHorizontal,\n Pencil,\n Phone,\n Trash2,\n} from \"lucide-react\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Button,\n cn,\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Spinner,\n fluidToast,\n} from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { ContactDetailsForm } from \"../../../../shared/components/contacts/contactDetailsForm\";\nimport { useContactDetailPage } from \"../../../../shared/hooks/useContactDetailPage\";\nimport { useContactTasks } from \"../../../hooks/contacts/use-contact-tasks\";\nimport { useContactNotes } from \"../../../hooks/notes/use-contact-notes\";\nimport { useCreateGroup } from \"../../../hooks/groups/use-create-group\";\nimport { useGroups } from \"../../../hooks/groups/use-groups\";\nimport { useUpdateContactTags } from \"../../../hooks/groups/use-update-contact-tags\";\nimport { ContactDetailHero } from \"./ContactDetailHero\";\nimport { ContactInfoRow } from \"./ContactInfoRow\";\nimport { ContactDetailTabs, type TabType } from \"./ContactDetailTabs\";\nimport { getDisplayName } from \"./utils\";\n\nexport interface ContactDetailPaneProps {\n contactId: string;\n queryKeyPrefix: string;\n getCountries: () => Promise<{ id: number; name: string; iso?: string }[]>;\n /** Callback to clear selection (used by mobile back button + on delete). */\n onBack: () => void;\n}\n\nexport function ContactDetailPane({\n contactId,\n queryKeyPrefix,\n getCountries,\n onBack,\n}: ContactDetailPaneProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const {\n contact,\n isLoading,\n methods,\n countryOptions,\n isDirty,\n isSubmitting,\n isDeleting,\n onSave,\n onDelete,\n } = useContactDetailPage(contactId, {\n queryKeyPrefix,\n getCountries,\n onDeleteSuccess: onBack,\n onSaveSuccess: () => setEditProfileOpen(false),\n });\n\n const { data: tasks = [], isLoading: isLoadingTasks } =\n useContactTasks(contactId);\n const { data: notes = [], isLoading: isLoadingNotes } =\n useContactNotes(contactId);\n\n const { data: groups = [] } = useGroups();\n const updateTagsMutation = useUpdateContactTags(contactId, queryKeyPrefix, {\n onError: (error) => {\n fluidToast({\n title: t(\"groups_tags_save_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n },\n });\n const createGroupMutation = useCreateGroup();\n\n const [confirmDelete, setConfirmDelete] = useState(false);\n const [activeTab, setActiveTab] = useState<TabType>(\"Tasks\");\n const [editProfileOpen, setEditProfileOpen] = useState(false);\n\n // Close the dialog before dispatching: on success the pane unmounts via\n // onDeleteSuccess; on a non-throwing failure the dialog would otherwise\n // dangle open with the toast already shown.\n const handleConfirmDelete = useCallback(() => {\n setConfirmDelete(false);\n onDelete();\n }, [onDelete]);\n\n if (isLoading) {\n return <ContactDetailSkeleton onBack={onBack} />;\n }\n\n if (!contact) {\n return (\n <div className=\"flex h-full flex-1 flex-col\">\n <DetailTopBar\n onBack={onBack}\n phone={null}\n email={null}\n onDelete={null}\n onEditProfile={null}\n />\n <div className=\"mx-auto flex max-w-md flex-col items-center px-6 py-16 text-center\">\n <h2 className=\"text-foreground text-base font-semibold\">\n {t(\"error_loading\")}\n </h2>\n <p className=\"text-muted-foreground mt-2 text-sm\">\n {t(\"error_loading_description\")}\n </p>\n </div>\n </div>\n );\n }\n\n const fullName = getDisplayName(contact);\n\n return (\n <FormProvider {...methods}>\n <div className=\"flex h-full flex-1 flex-col\">\n <DetailTopBar\n onBack={onBack}\n phone={contact.phone ?? null}\n email={contact.email ?? null}\n onDelete={() => setConfirmDelete(true)}\n onEditProfile={() => setEditProfileOpen(true)}\n />\n\n <div className=\"flex-1 overflow-y-auto\">\n <div className=\"mx-auto w-full max-w-[900px] px-6 pt-8 pb-16 md:px-8 md:pt-10\">\n <ContactDetailHero\n contact={contact}\n tasksCount={tasks.length}\n notesCount={notes.length}\n contactTags={Array.isArray(contact.tags) ? contact.tags : []}\n availableGroups={groups}\n onTagsSave={(tags) => updateTagsMutation.mutate(tags)}\n onCreateGroup={async (name) => {\n await createGroupMutation.mutateAsync({ name });\n }}\n isTagsSaving={updateTagsMutation.isPending}\n />\n <ContactInfoRow\n contact={contact}\n onEditEmpty={() => setEditProfileOpen(true)}\n />\n <ContactDetailTabs\n contactId={contactId}\n tasks={tasks}\n isLoadingTasks={isLoadingTasks}\n notes={notes}\n isLoadingNotes={isLoadingNotes}\n activeTab={activeTab}\n onTabChange={setActiveTab}\n />\n </div>\n </div>\n\n <Dialog\n open={editProfileOpen}\n onOpenChange={(open) => {\n if (!open && isSubmitting) return;\n setEditProfileOpen(open);\n }}\n >\n <DialogContent className=\"max-h-[90vh] max-w-2xl overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>\n {t(\"edit_contact_name\", { name: fullName })}\n </DialogTitle>\n </DialogHeader>\n <ContactDetailsForm countries={countryOptions} />\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => setEditProfileOpen(false)}\n disabled={isSubmitting}\n >\n {t(\"cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={onSave}\n disabled={!isDirty || isSubmitting}\n aria-busy={isSubmitting}\n >\n {isSubmitting && <Spinner className=\"size-4\" />}\n {isSubmitting ? t(\"saving\") : t(\"save_changes\")}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n <AlertDialog open={confirmDelete} onOpenChange={setConfirmDelete}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {t(\"delete_name\", { name: fullName })}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {t(\"delete_confirm_permanent\")}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isDeleting}>\n {t(\"cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={handleConfirmDelete}\n disabled={isDeleting}\n >\n {isDeleting ? t(\"deleting\") : t(\"delete_contact\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n </FormProvider>\n );\n}\n\ninterface DetailTopBarProps {\n onBack: () => void;\n phone: string | null;\n email: string | null;\n onDelete: (() => void) | null;\n onEditProfile: (() => void) | null;\n}\n\nfunction DetailTopBar({\n onBack,\n phone,\n email,\n onDelete,\n onEditProfile,\n}: DetailTopBarProps) {\n const { t } = useContactsTranslation();\n return (\n <div className=\"border-border/50 bg-background/90 sticky top-0 z-10 flex items-center justify-between border-b px-4 py-3 backdrop-blur md:px-8\">\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={onBack}\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex size-8 items-center justify-center rounded-full transition-colors md:hidden\"\n aria-label={t(\"back_to_contacts\")}\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n <span className=\"text-muted-foreground hidden text-xs font-semibold tracking-widest uppercase md:inline\">\n {t(\"contact_label\")}\n </span>\n </div>\n <div className=\"flex items-center gap-1\">\n {onEditProfile && (\n <button\n type=\"button\"\n onClick={onEditProfile}\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex size-8 items-center justify-center rounded-full transition-colors\"\n aria-label={t(\"edit_profile\")}\n >\n <Pencil className=\"size-4\" aria-hidden=\"true\" />\n </button>\n )}\n <ActionLink\n href={phone ? `tel:${phone}` : null}\n label={t(\"label_call\")}\n icon={<Phone className=\"size-4\" aria-hidden=\"true\" />}\n />\n <ActionLink\n href={email ? `mailto:${email}` : null}\n label={t(\"label_email\")}\n icon={<Mail className=\"size-4\" aria-hidden=\"true\" />}\n />\n {onDelete && (\n <>\n <div className=\"bg-border mx-1 h-5 w-px\" aria-hidden=\"true\" />\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground flex size-8 items-center justify-center rounded-full transition-colors\"\n aria-label={t(\"more_actions\")}\n >\n <MoreHorizontal className=\"size-4\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n className=\"text-destructive\"\n onClick={onDelete}\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {t(\"delete_contact\")}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </>\n )}\n </div>\n </div>\n );\n}\n\ninterface ActionLinkProps {\n href: string | null;\n label: string;\n icon: React.ReactNode;\n}\n\nfunction ActionLink({ href, label, icon }: ActionLinkProps) {\n const baseClass =\n \"flex size-8 items-center justify-center rounded-full transition-colors\";\n if (!href) {\n return (\n <span\n aria-label={`${label} (unavailable)`}\n className={cn(baseClass, \"text-muted-foreground/40 cursor-default\")}\n >\n {icon}\n </span>\n );\n }\n return (\n <a\n href={href}\n aria-label={label}\n className={cn(\n baseClass,\n \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n )}\n >\n {icon}\n </a>\n );\n}\n\nfunction ContactDetailSkeleton({ onBack }: { onBack: () => void }) {\n return (\n <div className=\"flex h-full flex-1 flex-col\">\n <DetailTopBar\n onBack={onBack}\n phone={null}\n email={null}\n onDelete={null}\n onEditProfile={null}\n />\n <div className=\"mx-auto w-full max-w-[900px] flex-1 space-y-6 px-6 pt-8 pb-16 md:px-8 md:pt-10\">\n <div className=\"flex items-start gap-5\">\n <div className=\"bg-muted size-20 animate-pulse rounded-xl\" />\n <div className=\"flex-1 space-y-3\">\n <div className=\"bg-muted h-7 w-48 animate-pulse rounded\" />\n <div className=\"bg-muted h-4 w-24 animate-pulse rounded\" />\n </div>\n </div>\n <div className=\"bg-muted h-24 animate-pulse rounded-xl\" />\n <div className=\"bg-muted h-64 animate-pulse rounded-xl\" />\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Users } from \"lucide-react\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\n\nexport function ContactsEmptyState(): React.JSX.Element {\n const { t } = useContactsTranslation();\n return (\n <div className=\"hidden h-full flex-1 flex-col items-center justify-center px-8 text-center md:flex\">\n <div className=\"bg-muted text-muted-foreground flex size-16 items-center justify-center rounded-xl\">\n <Users className=\"size-7\" aria-hidden=\"true\" />\n </div>\n <h2 className=\"text-foreground mt-5 text-base font-semibold\">\n {t(\"empty_select_contact\")}\n </h2>\n <p className=\"text-muted-foreground mt-1 max-w-xs text-sm\">\n {t(\"empty_select_description\")}\n </p>\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@fluid-app/ui-primitives\";\nimport type { Contact } from \"@fluid-app/contacts-core/types\";\nimport { ContactsSidebar } from \"./ContactsSidebar\";\nimport { ContactDetailPane } from \"./ContactDetailPane\";\nimport { ContactsEmptyState } from \"./ContactsEmptyState\";\n\nexport interface RepContactsLayoutProps {\n selectedContactId: string | null;\n highlightContactId?: string | null;\n onSelect: (id: string | null) => void;\n onAdd: () => void;\n onManageGroups?: () => void;\n onCreateGroup?: () => void;\n highlightGroupName?: string | null;\n onDeleteContact?: (contact: Contact) => void;\n queryKeyPrefix: string;\n getCountries: () => Promise<{ id: number; name: string; iso?: string }[]>;\n}\n\nexport function RepContactsLayout({\n selectedContactId,\n highlightContactId,\n onSelect,\n onAdd,\n onManageGroups,\n onCreateGroup,\n highlightGroupName,\n onDeleteContact,\n queryKeyPrefix,\n getCountries,\n}: RepContactsLayoutProps): React.JSX.Element {\n return (\n <div className=\"bg-background flex h-full overflow-hidden\">\n <aside\n className={cn(\n \"border-border/50 bg-background w-full shrink-0 overflow-hidden border-r md:flex md:w-[420px] md:flex-col\",\n selectedContactId ? \"hidden\" : \"flex flex-col\",\n )}\n >\n <ContactsSidebar\n selectedContactId={selectedContactId}\n highlightContactId={highlightContactId}\n onSelect={onSelect}\n onAdd={onAdd}\n onManageGroups={onManageGroups}\n onCreateGroup={onCreateGroup}\n highlightGroupName={highlightGroupName}\n onDeleteContact={onDeleteContact}\n />\n </aside>\n\n <main\n className={cn(\n \"bg-background relative flex-1 md:flex md:flex-col\",\n selectedContactId ? \"flex flex-col\" : \"hidden md:flex\",\n )}\n >\n {selectedContactId ? (\n <ContactDetailPane\n key={selectedContactId}\n contactId={selectedContactId}\n queryKeyPrefix={queryKeyPrefix}\n getCountries={getCountries}\n onBack={() => onSelect(null)}\n />\n ) : (\n <ContactsEmptyState />\n )}\n </main>\n </div>\n );\n}\n","import e,{useRef as r,useMemo as t,useEffect as n,useState as o,useCallback as a,useLayoutEffect as l}from\"react\";function u(){return(u=Object.assign||function(e){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])}return e}).apply(this,arguments)}function c(e,r){if(null==e)return{};var t,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r.indexOf(t=a[n])>=0||(o[t]=e[t]);return o}function i(e){var t=r(e),n=r(function(e){t.current&&t.current(e)});return t.current=e,n.current}var s=function(e,r,t){return void 0===r&&(r=0),void 0===t&&(t=1),e>t?t:e<r?r:e},f=function(e){return\"touches\"in e},v=function(e){return e&&e.ownerDocument.defaultView||self},d=function(e,r,t){var n=e.getBoundingClientRect(),o=f(r)?function(e,r){for(var t=0;t<e.length;t++)if(e[t].identifier===r)return e[t];return e[0]}(r.touches,t):r;return{left:s((o.pageX-(n.left+v(e).pageXOffset))/n.width),top:s((o.pageY-(n.top+v(e).pageYOffset))/n.height)}},h=function(e){!f(e)&&e.preventDefault()},m=e.memo(function(o){var a=o.onMove,l=o.onKey,s=c(o,[\"onMove\",\"onKey\"]),m=r(null),g=i(a),p=i(l),b=r(null),_=r(!1),x=t(function(){var e=function(e){h(e),(f(e)?e.touches.length>0:e.buttons>0)&&m.current?g(d(m.current,e,b.current)):t(!1)},r=function(){return t(!1)};function t(t){var n=_.current,o=v(m.current),a=t?o.addEventListener:o.removeEventListener;a(n?\"touchmove\":\"mousemove\",e),a(n?\"touchend\":\"mouseup\",r)}return[function(e){var r=e.nativeEvent,n=m.current;if(n&&(h(r),!function(e,r){return r&&!f(e)}(r,_.current)&&n)){if(f(r)){_.current=!0;var o=r.changedTouches||[];o.length&&(b.current=o[0].identifier)}n.focus(),g(d(n,r,b.current)),t(!0)}},function(e){var r=e.which||e.keyCode;r<37||r>40||(e.preventDefault(),p({left:39===r?.05:37===r?-.05:0,top:40===r?.05:38===r?-.05:0}))},t]},[p,g]),C=x[0],E=x[1],H=x[2];return n(function(){return H},[H]),e.createElement(\"div\",u({},s,{onTouchStart:C,onMouseDown:C,className:\"react-colorful__interactive\",ref:m,onKeyDown:E,tabIndex:0,role:\"slider\"}))}),g=function(e){return e.filter(Boolean).join(\" \")},p=function(r){var t=r.color,n=r.left,o=r.top,a=void 0===o?.5:o,l=g([\"react-colorful__pointer\",r.className]);return e.createElement(\"div\",{className:l,style:{top:100*a+\"%\",left:100*n+\"%\"}},e.createElement(\"div\",{className:\"react-colorful__pointer-fill\",style:{backgroundColor:t}}))},b=function(e,r,t){return void 0===r&&(r=0),void 0===t&&(t=Math.pow(10,r)),Math.round(t*e)/t},_={grad:.9,turn:360,rad:360/(2*Math.PI)},x=function(e){return L(C(e))},C=function(e){return\"#\"===e[0]&&(e=e.substring(1)),e.length<6?{r:parseInt(e[0]+e[0],16),g:parseInt(e[1]+e[1],16),b:parseInt(e[2]+e[2],16),a:4===e.length?b(parseInt(e[3]+e[3],16)/255,2):1}:{r:parseInt(e.substring(0,2),16),g:parseInt(e.substring(2,4),16),b:parseInt(e.substring(4,6),16),a:8===e.length?b(parseInt(e.substring(6,8),16)/255,2):1}},E=function(e,r){return void 0===r&&(r=\"deg\"),Number(e)*(_[r]||1)},H=function(e){var r=/hsla?\\(?\\s*(-?\\d*\\.?\\d+)(deg|rad|grad|turn)?[,\\s]+(-?\\d*\\.?\\d+)%?[,\\s]+(-?\\d*\\.?\\d+)%?,?\\s*[/\\s]*(-?\\d*\\.?\\d+)?(%)?\\s*\\)?/i.exec(e);return r?N({h:E(r[1],r[2]),s:Number(r[3]),l:Number(r[4]),a:void 0===r[5]?1:Number(r[5])/(r[6]?100:1)}):{h:0,s:0,v:0,a:1}},M=H,N=function(e){var r=e.s,t=e.l;return{h:e.h,s:(r*=(t<50?t:100-t)/100)>0?2*r/(t+r)*100:0,v:t+r,a:e.a}},w=function(e){return K(I(e))},y=function(e){var r=e.s,t=e.v,n=e.a,o=(200-r)*t/100;return{h:b(e.h),s:b(o>0&&o<200?r*t/100/(o<=100?o:200-o)*100:0),l:b(o/2),a:b(n,2)}},q=function(e){var r=y(e);return\"hsl(\"+r.h+\", \"+r.s+\"%, \"+r.l+\"%)\"},k=function(e){var r=y(e);return\"hsla(\"+r.h+\", \"+r.s+\"%, \"+r.l+\"%, \"+r.a+\")\"},I=function(e){var r=e.h,t=e.s,n=e.v,o=e.a;r=r/360*6,t/=100,n/=100;var a=Math.floor(r),l=n*(1-t),u=n*(1-(r-a)*t),c=n*(1-(1-r+a)*t),i=a%6;return{r:b(255*[n,u,l,l,c,n][i]),g:b(255*[c,n,n,u,l,l][i]),b:b(255*[l,l,c,n,n,u][i]),a:b(o,2)}},O=function(e){var r=/hsva?\\(?\\s*(-?\\d*\\.?\\d+)(deg|rad|grad|turn)?[,\\s]+(-?\\d*\\.?\\d+)%?[,\\s]+(-?\\d*\\.?\\d+)%?,?\\s*[/\\s]*(-?\\d*\\.?\\d+)?(%)?\\s*\\)?/i.exec(e);return r?A({h:E(r[1],r[2]),s:Number(r[3]),v:Number(r[4]),a:void 0===r[5]?1:Number(r[5])/(r[6]?100:1)}):{h:0,s:0,v:0,a:1}},j=O,z=function(e){var r=/rgba?\\(?\\s*(-?\\d*\\.?\\d+)(%)?[,\\s]+(-?\\d*\\.?\\d+)(%)?[,\\s]+(-?\\d*\\.?\\d+)(%)?,?\\s*[/\\s]*(-?\\d*\\.?\\d+)?(%)?\\s*\\)?/i.exec(e);return r?L({r:Number(r[1])/(r[2]?100/255:1),g:Number(r[3])/(r[4]?100/255:1),b:Number(r[5])/(r[6]?100/255:1),a:void 0===r[7]?1:Number(r[7])/(r[8]?100:1)}):{h:0,s:0,v:0,a:1}},B=z,D=function(e){var r=e.toString(16);return r.length<2?\"0\"+r:r},K=function(e){var r=e.r,t=e.g,n=e.b,o=e.a,a=o<1?D(b(255*o)):\"\";return\"#\"+D(r)+D(t)+D(n)+a},L=function(e){var r=e.r,t=e.g,n=e.b,o=e.a,a=Math.max(r,t,n),l=a-Math.min(r,t,n),u=l?a===r?(t-n)/l:a===t?2+(n-r)/l:4+(r-t)/l:0;return{h:b(60*(u<0?u+6:u)),s:b(a?l/a*100:0),v:b(a/255*100),a:o}},A=function(e){return{h:b(e.h),s:b(e.s),v:b(e.v),a:b(e.a,2)}},S=e.memo(function(r){var t=r.hue,n=r.onChange,o=g([\"react-colorful__hue\",r.className]);return e.createElement(\"div\",{className:o},e.createElement(m,{onMove:function(e){n({h:360*e.left})},onKey:function(e){n({h:s(t+360*e.left,0,360)})},\"aria-label\":\"Hue\",\"aria-valuenow\":b(t),\"aria-valuemax\":\"360\",\"aria-valuemin\":\"0\"},e.createElement(p,{className:\"react-colorful__hue-pointer\",left:t/360,color:q({h:t,s:100,v:100,a:1})})))}),T=e.memo(function(r){var t=r.hsva,n=r.onChange,o={backgroundColor:q({h:t.h,s:100,v:100,a:1})};return e.createElement(\"div\",{className:\"react-colorful__saturation\",style:o},e.createElement(m,{onMove:function(e){n({s:100*e.left,v:100-100*e.top})},onKey:function(e){n({s:s(t.s+100*e.left,0,100),v:s(t.v-100*e.top,0,100)})},\"aria-label\":\"Color\",\"aria-valuetext\":\"Saturation \"+b(t.s)+\"%, Brightness \"+b(t.v)+\"%\"},e.createElement(p,{className:\"react-colorful__saturation-pointer\",top:1-t.v/100,left:t.s/100,color:q(t)})))}),F=function(e,r){if(e===r)return!0;for(var t in e)if(e[t]!==r[t])return!1;return!0},P=function(e,r){return e.replace(/\\s/g,\"\")===r.replace(/\\s/g,\"\")},X=function(e,r){return e.toLowerCase()===r.toLowerCase()||F(C(e),C(r))};function Y(e,t,l){var u=i(l),c=o(function(){return e.toHsva(t)}),s=c[0],f=c[1],v=r({color:t,hsva:s});n(function(){if(!e.equal(t,v.current.color)){var r=e.toHsva(t);v.current={hsva:r,color:t},f(r)}},[t,e]),n(function(){var r;F(s,v.current.hsva)||e.equal(r=e.fromHsva(s),v.current.color)||(v.current={hsva:s,color:r},u(r))},[s,e,u]);var d=a(function(e){f(function(r){return Object.assign({},r,e)})},[]);return[s,d]}var R,V=\"undefined\"!=typeof window?l:n,$=function(){return R||(\"undefined\"!=typeof __webpack_nonce__?__webpack_nonce__:void 0)},G=function(e){R=e},J=new Map,Q=function(e){V(function(){var r=e.current?e.current.ownerDocument:document;if(void 0!==r&&!J.has(r)){var t=r.createElement(\"style\");t.innerHTML='.react-colorful{position:relative;display:flex;flex-direction:column;width:200px;height:200px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.react-colorful__saturation{position:relative;flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(0deg,#000,transparent),linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.react-colorful__alpha-gradient,.react-colorful__pointer-fill{content:\"\";position:absolute;left:0;top:0;right:0;bottom:0;pointer-events:none;border-radius:inherit}.react-colorful__alpha-gradient,.react-colorful__saturation{box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}.react-colorful__alpha,.react-colorful__hue{position:relative;height:24px}.react-colorful__hue{background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.react-colorful__last-control{border-radius:0 0 8px 8px}.react-colorful__interactive{position:absolute;left:0;top:0;right:0;bottom:0;border-radius:inherit;outline:none;touch-action:none}.react-colorful__pointer{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}.react-colorful__interactive:focus .react-colorful__pointer{transform:translate(-50%,-50%) scale(1.1)}.react-colorful__alpha,.react-colorful__alpha-pointer{background-color:#fff;background-image:url(\\'data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill-opacity=\".05\"><path d=\"M8 0h8v8H8zM0 8h8v8H0z\"/></svg>\\')}.react-colorful__saturation-pointer{z-index:3}.react-colorful__hue-pointer{z-index:2}',J.set(r,t);var n=$();n&&t.setAttribute(\"nonce\",n),r.head.appendChild(t)}},[])},U=function(t){var n=t.className,o=t.colorModel,a=t.color,l=void 0===a?o.defaultColor:a,i=t.onChange,s=c(t,[\"className\",\"colorModel\",\"color\",\"onChange\"]),f=r(null);Q(f);var v=Y(o,l,i),d=v[0],h=v[1],m=g([\"react-colorful\",n]);return e.createElement(\"div\",u({},s,{ref:f,className:m}),e.createElement(T,{hsva:d,onChange:h}),e.createElement(S,{hue:d.h,onChange:h,className:\"react-colorful__last-control\"}))},W={defaultColor:\"000\",toHsva:x,fromHsva:function(e){return w({h:e.h,s:e.s,v:e.v,a:1})},equal:X},Z=function(r){return e.createElement(U,u({},r,{colorModel:W}))},ee=function(r){var t=r.className,n=r.hsva,o=r.onChange,a={backgroundImage:\"linear-gradient(90deg, \"+k(Object.assign({},n,{a:0}))+\", \"+k(Object.assign({},n,{a:1}))+\")\"},l=g([\"react-colorful__alpha\",t]),u=b(100*n.a);return e.createElement(\"div\",{className:l},e.createElement(\"div\",{className:\"react-colorful__alpha-gradient\",style:a}),e.createElement(m,{onMove:function(e){o({a:e.left})},onKey:function(e){o({a:s(n.a+e.left)})},\"aria-label\":\"Alpha\",\"aria-valuetext\":u+\"%\",\"aria-valuenow\":u,\"aria-valuemin\":\"0\",\"aria-valuemax\":\"100\"},e.createElement(p,{className:\"react-colorful__alpha-pointer\",left:n.a,color:k(n)})))},re=function(t){var n=t.className,o=t.colorModel,a=t.color,l=void 0===a?o.defaultColor:a,i=t.onChange,s=c(t,[\"className\",\"colorModel\",\"color\",\"onChange\"]),f=r(null);Q(f);var v=Y(o,l,i),d=v[0],h=v[1],m=g([\"react-colorful\",n]);return e.createElement(\"div\",u({},s,{ref:f,className:m}),e.createElement(T,{hsva:d,onChange:h}),e.createElement(S,{hue:d.h,onChange:h}),e.createElement(ee,{hsva:d,onChange:h,className:\"react-colorful__last-control\"}))},te={defaultColor:\"0001\",toHsva:x,fromHsva:w,equal:X},ne=function(r){return e.createElement(re,u({},r,{colorModel:te}))},oe={defaultColor:{h:0,s:0,l:0,a:1},toHsva:N,fromHsva:y,equal:F},ae=function(r){return e.createElement(re,u({},r,{colorModel:oe}))},le={defaultColor:\"hsla(0, 0%, 0%, 1)\",toHsva:H,fromHsva:k,equal:P},ue=function(r){return e.createElement(re,u({},r,{colorModel:le}))},ce={defaultColor:{h:0,s:0,l:0},toHsva:function(e){return N({h:e.h,s:e.s,l:e.l,a:1})},fromHsva:function(e){return{h:(r=y(e)).h,s:r.s,l:r.l};var r},equal:F},ie=function(r){return e.createElement(U,u({},r,{colorModel:ce}))},se={defaultColor:\"hsl(0, 0%, 0%)\",toHsva:M,fromHsva:q,equal:P},fe=function(r){return e.createElement(U,u({},r,{colorModel:se}))},ve={defaultColor:{h:0,s:0,v:0,a:1},toHsva:function(e){return e},fromHsva:A,equal:F},de=function(r){return e.createElement(re,u({},r,{colorModel:ve}))},he={defaultColor:\"hsva(0, 0%, 0%, 1)\",toHsva:O,fromHsva:function(e){var r=A(e);return\"hsva(\"+r.h+\", \"+r.s+\"%, \"+r.v+\"%, \"+r.a+\")\"},equal:P},me=function(r){return e.createElement(re,u({},r,{colorModel:he}))},ge={defaultColor:{h:0,s:0,v:0},toHsva:function(e){return{h:e.h,s:e.s,v:e.v,a:1}},fromHsva:function(e){var r=A(e);return{h:r.h,s:r.s,v:r.v}},equal:F},pe=function(r){return e.createElement(U,u({},r,{colorModel:ge}))},be={defaultColor:\"hsv(0, 0%, 0%)\",toHsva:j,fromHsva:function(e){var r=A(e);return\"hsv(\"+r.h+\", \"+r.s+\"%, \"+r.v+\"%)\"},equal:P},_e=function(r){return e.createElement(U,u({},r,{colorModel:be}))},xe={defaultColor:{r:0,g:0,b:0,a:1},toHsva:L,fromHsva:I,equal:F},Ce=function(r){return e.createElement(re,u({},r,{colorModel:xe}))},Ee={defaultColor:\"rgba(0, 0, 0, 1)\",toHsva:z,fromHsva:function(e){var r=I(e);return\"rgba(\"+r.r+\", \"+r.g+\", \"+r.b+\", \"+r.a+\")\"},equal:P},He=function(r){return e.createElement(re,u({},r,{colorModel:Ee}))},Me={defaultColor:{r:0,g:0,b:0},toHsva:function(e){return L({r:e.r,g:e.g,b:e.b,a:1})},fromHsva:function(e){return{r:(r=I(e)).r,g:r.g,b:r.b};var r},equal:F},Ne=function(r){return e.createElement(U,u({},r,{colorModel:Me}))},we={defaultColor:\"rgb(0, 0, 0)\",toHsva:B,fromHsva:function(e){var r=I(e);return\"rgb(\"+r.r+\", \"+r.g+\", \"+r.b+\")\"},equal:P},ye=function(r){return e.createElement(U,u({},r,{colorModel:we}))},qe=/^#?([0-9A-F]{3,8})$/i,ke=function(r){var t=r.color,l=void 0===t?\"\":t,s=r.onChange,f=r.onBlur,v=r.escape,d=r.validate,h=r.format,m=r.process,g=c(r,[\"color\",\"onChange\",\"onBlur\",\"escape\",\"validate\",\"format\",\"process\"]),p=o(function(){return v(l)}),b=p[0],_=p[1],x=i(s),C=i(f),E=a(function(e){var r=v(e.target.value);_(r),d(r)&&x(m?m(r):r)},[v,m,d,x]),H=a(function(e){d(e.target.value)||_(v(l)),C(e)},[l,v,d,C]);return n(function(){_(v(l))},[l,v]),e.createElement(\"input\",u({},g,{value:h?h(b):b,spellCheck:\"false\",onChange:E,onBlur:H}))},Ie=function(e){return\"#\"+e},Oe=function(r){var t=r.prefixed,n=r.alpha,o=c(r,[\"prefixed\",\"alpha\"]),l=a(function(e){return e.replace(/([^0-9A-F]+)/gi,\"\").substring(0,n?8:6)},[n]),i=a(function(e){return function(e,r){var t=qe.exec(e),n=t?t[1].length:0;return 3===n||6===n||!!r&&4===n||!!r&&8===n}(e,n)},[n]);return e.createElement(ke,u({},o,{escape:l,format:t?Ie:void 0,process:Ie,validate:i}))};export{ne as HexAlphaColorPicker,Oe as HexColorInput,Z as HexColorPicker,ie as HslColorPicker,fe as HslStringColorPicker,ae as HslaColorPicker,ue as HslaStringColorPicker,pe as HsvColorPicker,_e as HsvStringColorPicker,de as HsvaColorPicker,me as HsvaStringColorPicker,Ne as RgbColorPicker,ye as RgbStringColorPicker,Ce as RgbaColorPicker,He as RgbaStringColorPicker,G as setNonce};\n//# sourceMappingURL=index.module.js.map\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useGroupsApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"./invalidate-contact-caches\";\n\nexport function useDeleteGroup() {\n const api = useGroupsApi();\n const queryClient = useQueryClient();\n const { t } = useContactsTranslation();\n\n return useMutation({\n mutationFn: (groupId: number) => {\n if (!api) throw new Error(\"GroupsApi is not available\");\n return api.deleteGroup(groupId);\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: contactsKeys.groups() });\n invalidateContactCaches(queryClient);\n },\n onError: (error) => {\n fluidToast({\n title: t(\"groups_delete_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n },\n });\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useGroupsApi } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"./invalidate-contact-caches\";\nimport type { UpdateGroupInput } from \"@fluid-app/contacts-core/types\";\n\nexport function useUpdateGroup() {\n const api = useGroupsApi();\n const queryClient = useQueryClient();\n const { t } = useContactsTranslation();\n\n return useMutation({\n mutationFn: ({\n groupId,\n input,\n }: {\n groupId: number;\n input: UpdateGroupInput;\n }) => {\n if (!api) throw new Error(\"GroupsApi is not available\");\n return api.updateGroup(groupId, input);\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: contactsKeys.groups() });\n invalidateContactCaches(queryClient);\n },\n onError: (error) => {\n fluidToast({\n title: t(\"groups_update_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n },\n });\n}\n","\"use client\";\n\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport {\n ChevronLeft,\n Loader,\n Pencil,\n Plus,\n Search,\n Trash2,\n Users,\n X,\n} from \"lucide-react\";\nimport {\n EmojiPicker as EmojiPickerPrimitive,\n type EmojiPickerListCategoryHeaderProps,\n type EmojiPickerListEmojiProps,\n type EmojiPickerListRowProps,\n} from \"frimousse\";\nimport { HexColorPicker, HexColorInput } from \"react-colorful\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Button,\n cn,\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n IconButton,\n Input,\n Label,\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n Skeleton,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n fluidToast,\n} from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { contactsKeys } from \"@fluid-app/contacts-core/query-keys\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport type { Contact, ContactGroup } from \"@fluid-app/contacts-core/types\";\nimport { invalidateContactCaches } from \"../../../hooks/groups/invalidate-contact-caches\";\nimport { useGroups } from \"../../../hooks/groups/use-groups\";\nimport { useCreateGroup } from \"../../../hooks/groups/use-create-group\";\nimport { useDeleteGroup } from \"../../../hooks/groups/use-delete-group\";\nimport { useUpdateGroup } from \"../../../hooks/groups/use-update-group\";\n\nconst PRESET_COLORS = [\n \"#ef4444\",\n \"#f97316\",\n \"#eab308\",\n \"#22c55e\",\n \"#14b8a6\",\n \"#06b6d4\",\n \"#3b82f6\",\n \"#6366f1\",\n \"#8b5cf6\",\n \"#ec4899\",\n] as const;\n\ntype ColorTranslationKey =\n | \"groups_color_red\"\n | \"groups_color_orange\"\n | \"groups_color_yellow\"\n | \"groups_color_green\"\n | \"groups_color_teal\"\n | \"groups_color_cyan\"\n | \"groups_color_blue\"\n | \"groups_color_indigo\"\n | \"groups_color_purple\"\n | \"groups_color_pink\";\n\nconst PRESET_COLOR_KEYS = {\n \"#ef4444\": \"groups_color_red\",\n \"#f97316\": \"groups_color_orange\",\n \"#eab308\": \"groups_color_yellow\",\n \"#22c55e\": \"groups_color_green\",\n \"#14b8a6\": \"groups_color_teal\",\n \"#06b6d4\": \"groups_color_cyan\",\n \"#3b82f6\": \"groups_color_blue\",\n \"#6366f1\": \"groups_color_indigo\",\n \"#8b5cf6\": \"groups_color_purple\",\n \"#ec4899\": \"groups_color_pink\",\n} as const satisfies Record<\n (typeof PRESET_COLORS)[number],\n ColorTranslationKey\n>;\n\nexport interface GroupsManagePageProps {\n onBack: () => void;\n onSelectContact?: (contactId: string) => void;\n initialCreateOpen?: boolean;\n}\n\nexport function GroupsManagePage({\n onBack,\n onSelectContact,\n initialCreateOpen,\n}: GroupsManagePageProps): React.JSX.Element {\n const { t } = useContactsTranslation();\n const { data: groups = [], isLoading } = useGroups();\n const deleteGroup = useDeleteGroup();\n\n const [dialogMode, setDialogMode] = useState<\n { mode: \"create\" } | { mode: \"edit\"; group: ContactGroup } | null\n >(initialCreateOpen ? { mode: \"create\" } : null);\n const [deleteTarget, setDeleteTarget] = useState<ContactGroup | null>(null);\n const [highlightGroupId, setHighlightGroupId] = useState<number | null>(null);\n\n useEffect(() => {\n if (highlightGroupId == null) return;\n const timer = setTimeout(() => setHighlightGroupId(null), 2000);\n return () => clearTimeout(timer);\n }, [highlightGroupId]);\n\n const handleDelete = useCallback(() => {\n if (!deleteTarget) return;\n deleteGroup.mutate(deleteTarget.id, {\n onSuccess: () => {\n fluidToast({\n title: t(\"groups_deleted_toast\", { name: deleteTarget.name }),\n type: \"success\",\n });\n setDeleteTarget(null);\n },\n onError: () => {\n setDeleteTarget(null);\n },\n });\n }, [deleteTarget, deleteGroup, t]);\n\n return (\n <div className=\"flex h-full flex-col\">\n <div className=\"border-border/50 flex items-center justify-between border-b px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n <IconButton\n icon={ChevronLeft}\n onClick={onBack}\n className=\"text-muted-foreground hover:bg-muted hover:text-foreground rounded-full\"\n aria-label={t(\"groups_back_to_contacts\")}\n />\n <h2 className=\"text-foreground text-lg font-semibold\">\n {t(\"groups_manage_title\")}\n </h2>\n </div>\n <Button size=\"sm\" onClick={() => setDialogMode({ mode: \"create\" })}>\n <Plus className=\"size-4\" />\n {t(\"groups_new_group\")}\n </Button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-6 py-6\">\n <div className=\"mx-auto max-w-[857px]\">\n {isLoading ? (\n <GroupsSkeleton />\n ) : groups.length === 0 ? (\n <div className=\"text-muted-foreground py-16 text-center text-sm\">\n {t(\"groups_empty\")}\n </div>\n ) : (\n <div className=\"space-y-2\">\n {groups.map((group) => (\n <GroupRow\n key={group.id}\n group={group}\n highlight={highlightGroupId === group.id}\n onEdit={() => setDialogMode({ mode: \"edit\", group })}\n onDelete={() => setDeleteTarget(group)}\n onSelectContact={onSelectContact}\n />\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Create / Edit group dialog */}\n {dialogMode && (\n <GroupDialog\n key={dialogMode.mode === \"edit\" ? dialogMode.group.id : \"create\"}\n mode={dialogMode.mode}\n group={dialogMode.mode === \"edit\" ? dialogMode.group : undefined}\n open={!!dialogMode}\n onOpenChange={(open) => !open && setDialogMode(null)}\n onGroupCreated={(groupId) => {\n setHighlightGroupId(groupId);\n }}\n />\n )}\n\n {/* Delete confirmation dialog */}\n <AlertDialog\n open={!!deleteTarget}\n onOpenChange={(open) => !open && setDeleteTarget(null)}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{t(\"groups_delete_title\")}</AlertDialogTitle>\n <AlertDialogDescription>\n {t(\"groups_delete_confirm\", { name: deleteTarget?.name ?? \"\" })}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={deleteGroup.isPending}>\n {t(\"cancel\")}\n </AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={handleDelete}\n disabled={deleteGroup.isPending}\n >\n {deleteGroup.isPending ? t(\"deleting\") : t(\"delete\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n}\n\n// ---- Shared Group Dialog (Create + Edit) ----\n\nexport interface GroupDialogProps {\n mode: \"create\" | \"edit\";\n group?: ContactGroup;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onGroupCreated?: (groupId: number) => void;\n onGroupCreatedWithName?: (name: string) => void;\n}\n\nexport function GroupDialog({\n mode,\n group,\n open,\n onOpenChange,\n onGroupCreated,\n onGroupCreatedWithName,\n}: GroupDialogProps) {\n const { t } = useContactsTranslation();\n const createGroup = useCreateGroup();\n const updateGroup = useUpdateGroup();\n const isPending =\n mode === \"create\" ? createGroup.isPending : updateGroup.isPending;\n\n const [name, setName] = useState(group?.name ?? \"\");\n const [avatar, setAvatar] = useState(group?.avatar ?? \"\");\n const [avatarBackground, setAvatarBackground] = useState(\n group?.avatar_background ?? \"#6366f1\",\n );\n\n const handleSave = useCallback(() => {\n const trimmedName = name.trim();\n if (!trimmedName) return;\n\n if (mode === \"create\") {\n createGroup.mutate(\n {\n name: trimmedName,\n avatar: avatar || undefined,\n avatar_background: avatarBackground || undefined,\n },\n {\n onSuccess: (data) => {\n fluidToast({\n title: t(\"groups_created_toast\", { name: trimmedName }),\n type: \"success\",\n });\n onOpenChange(false);\n if (data.group.id) onGroupCreated?.(data.group.id);\n onGroupCreatedWithName?.(trimmedName);\n },\n },\n );\n } else if (group) {\n updateGroup.mutate(\n {\n groupId: group.id,\n input: {\n name: trimmedName,\n avatar: avatar || undefined,\n avatar_background: avatarBackground || undefined,\n },\n },\n {\n onSuccess: () => {\n fluidToast({ title: t(\"groups_updated_toast\"), type: \"success\" });\n onOpenChange(false);\n },\n },\n );\n }\n }, [\n mode,\n name,\n avatar,\n avatarBackground,\n group,\n createGroup,\n updateGroup,\n onOpenChange,\n onGroupCreated,\n onGroupCreatedWithName,\n t,\n ]);\n\n const previewBg = avatarBackground || \"#6366f1\";\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-lg\">\n <DialogHeader>\n <DialogTitle>\n {mode === \"create\"\n ? t(\"groups_create_title\")\n : t(\"groups_edit_title\")}\n </DialogTitle>\n </DialogHeader>\n\n <div className=\"space-y-5 py-2\">\n {/* Avatar preview + name */}\n <div className=\"flex items-center gap-5\">\n <div className=\"flex flex-col items-center gap-1\">\n <div className=\"relative\">\n <div\n className=\"flex size-20 items-center justify-center rounded-full text-4xl transition-colors\"\n style={{ backgroundColor: previewBg }}\n >\n {avatar || <Users className=\"size-8 text-white/60\" />}\n </div>\n {avatar && (\n <IconButton\n icon={X}\n onClick={() => setAvatar(\"\")}\n className=\"bg-foreground/80 text-background hover:bg-foreground absolute -top-1 -right-1 size-5 rounded-full [&_svg:not([class*='size-'])]:size-3\"\n aria-label={t(\"groups_remove_emoji\")}\n />\n )}\n </div>\n <span className=\"text-muted-foreground text-xs\">\n {t(\"groups_avatar\")}\n </span>\n </div>\n <div className=\"flex-1 space-y-1.5\">\n <Label className=\"text-foreground\">\n {t(\"groups_name_label\")}\n </Label>\n <Input\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t(\"groups_name_placeholder\")}\n />\n </div>\n </div>\n\n {/* Tabs: Change Emoji / Change Color */}\n <Tabs defaultValue=\"emoji\">\n <TabsList className=\"border-border h-auto w-full justify-center gap-6 rounded-none border-b bg-transparent p-0\">\n <TabsTrigger\n value=\"emoji\"\n className=\"text-muted-foreground hover:text-foreground data-[state=active]:text-primary data-[state=active]:border-primary h-auto flex-none rounded-none border-0 border-b-2 border-transparent bg-transparent pb-2 shadow-none data-[state=active]:bg-transparent data-[state=active]:shadow-none\"\n >\n {t(\"groups_tab_change_emoji\")}\n </TabsTrigger>\n <TabsTrigger\n value=\"color\"\n className=\"text-muted-foreground hover:text-foreground data-[state=active]:text-primary data-[state=active]:border-primary h-auto flex-none rounded-none border-0 border-b-2 border-transparent bg-transparent pb-2 shadow-none data-[state=active]:bg-transparent data-[state=active]:shadow-none\"\n >\n {t(\"groups_tab_change_color\")}\n </TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"emoji\" className=\"pt-4\">\n <EmojiPickerPrimitive.Root\n className=\"bg-popover flex h-64 w-full flex-col overflow-hidden rounded-lg\"\n onEmojiSelect={(emoji) => setAvatar(emoji.emoji)}\n >\n <EmojiPickerPrimitive.Viewport className=\"relative flex-1 outline-hidden\">\n <EmojiPickerPrimitive.Loading className=\"text-muted-foreground absolute inset-0 flex items-center justify-center\">\n <Loader className=\"size-4 animate-spin\" />\n </EmojiPickerPrimitive.Loading>\n <EmojiPickerPrimitive.Empty className=\"text-muted-foreground absolute inset-0 flex items-center justify-center text-sm\">\n {t(\"groups_no_emoji_found\")}\n </EmojiPickerPrimitive.Empty>\n <EmojiPickerPrimitive.List\n className=\"pb-1 select-none\"\n components={{\n Row: EmojiPickerRow,\n Emoji: EmojiPickerEmoji,\n CategoryHeader: EmojiPickerCategoryHeader,\n }}\n />\n </EmojiPickerPrimitive.Viewport>\n </EmojiPickerPrimitive.Root>\n </TabsContent>\n\n <TabsContent value=\"color\" className=\"pt-4\">\n <div className=\"space-y-4\">\n <HexColorPicker\n color={avatarBackground || \"#6366f1\"}\n onChange={setAvatarBackground}\n className=\"h-40 w-full\"\n />\n <div className=\"flex items-center gap-3\">\n <div className=\"border-input flex items-center gap-1 rounded-md border px-3 py-1.5\">\n <span className=\"text-muted-foreground text-sm\">#</span>\n <HexColorInput\n color={avatarBackground || \"6366f1\"}\n onChange={setAvatarBackground}\n className=\"text-foreground w-20 bg-transparent text-sm outline-none\"\n />\n </div>\n </div>\n <div className=\"flex justify-between\">\n {PRESET_COLORS.map((color) => (\n <button\n key={color}\n type=\"button\"\n onClick={() => setAvatarBackground(color)}\n className={cn(\n \"size-7 rounded-full transition-all\",\n avatarBackground === color\n ? \"ring-primary ring-2 ring-offset-2\"\n : \"hover:scale-110\",\n )}\n style={{ backgroundColor: color }}\n aria-label={t(PRESET_COLOR_KEYS[color])}\n />\n ))}\n </div>\n </div>\n </TabsContent>\n </Tabs>\n </div>\n\n <DialogFooter>\n <Button\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={isPending}\n >\n {t(\"groups_close\")}\n </Button>\n <Button onClick={handleSave} disabled={!name.trim() || isPending}>\n {isPending\n ? mode === \"create\"\n ? t(\"groups_creating\")\n : t(\"saving\")\n : mode === \"create\"\n ? t(\"groups_create\")\n : t(\"save\")}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\n// ---- Frimousse sub-components ----\n// Visually distinct from @fluid-app/messaging-ui's EmojiPicker (larger emoji\n// size-12 vs size-8, centered row layout). Sharing would require a more\n// flexible component API; for now this small duplication is intentional.\n\nfunction EmojiPickerRow({\n children,\n ref: _ref,\n ...props\n}: EmojiPickerListRowProps) {\n return (\n <div {...props} className=\"flex scroll-my-1 justify-center px-1\">\n {children}\n </div>\n );\n}\n\nfunction EmojiPickerEmoji({\n emoji,\n className,\n ref: _ref,\n ...props\n}: EmojiPickerListEmojiProps) {\n return (\n <button\n {...props}\n className={cn(\n \"data-[active]:bg-foreground/10 flex aspect-square size-12 items-center justify-center rounded-md text-3xl\",\n className,\n )}\n >\n {emoji.emoji}\n </button>\n );\n}\n\nfunction EmojiPickerCategoryHeader({\n category,\n ref: _ref,\n ...props\n}: EmojiPickerListCategoryHeaderProps) {\n return (\n <div\n {...props}\n className=\"bg-popover text-muted-foreground px-3 pt-3.5 pb-2 text-xs leading-none\"\n >\n {category.label}\n </div>\n );\n}\n\n// ---- Group Row ----\n\nfunction GroupRow({\n group,\n highlight,\n onEdit,\n onDelete,\n onSelectContact,\n}: {\n group: ContactGroup;\n highlight?: boolean;\n onEdit: () => void;\n onDelete: () => void;\n onSelectContact?: (contactId: string) => void;\n}) {\n const { t } = useContactsTranslation();\n const backgroundColor = group.avatar_background ?? \"var(--color-muted)\";\n const [drawerOpen, setDrawerOpen] = useState(false);\n\n return (\n <>\n <div\n className={cn(\n \"group/row border-border/50 hover:bg-muted/50 focus-within:bg-muted/50 flex cursor-pointer items-center gap-4 rounded-lg border px-4 py-3 transition-colors\",\n highlight && \"animate-highlight-fade\",\n )}\n onClick={() => setDrawerOpen(true)}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n setDrawerOpen(true);\n }\n }}\n >\n <div\n className=\"flex size-10 shrink-0 items-center justify-center rounded-full text-lg\"\n style={{ backgroundColor }}\n >\n {group.avatar ?? <Users className=\"text-muted-foreground size-4\" />}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-foreground text-sm font-semibold\">{group.name}</p>\n <p className=\"text-muted-foreground text-xs\">\n {group.contacts_count === 1\n ? t(\"groups_contact_one\", { count: group.contacts_count })\n : t(\"groups_contact_other\", { count: group.contacts_count })}\n </p>\n </div>\n <div className=\"flex items-center gap-1 opacity-0 transition-opacity group-focus-within/row:opacity-100 group-hover/row:opacity-100\">\n <IconButton\n icon={Pencil}\n onClick={(e) => {\n e.stopPropagation();\n onEdit();\n }}\n className=\"text-muted-foreground hover:text-foreground rounded-full focus:opacity-100\"\n aria-label={t(\"groups_edit_aria\", { name: group.name })}\n />\n <IconButton\n icon={Trash2}\n onClick={(e) => {\n e.stopPropagation();\n onDelete();\n }}\n className=\"text-muted-foreground hover:text-destructive rounded-full focus:opacity-100\"\n aria-label={t(\"groups_delete_aria\", { name: group.name })}\n />\n </div>\n </div>\n\n <GroupMembersDrawer\n group={group}\n open={drawerOpen}\n onOpenChange={setDrawerOpen}\n contactCount={group.contacts_count}\n onSelectContact={onSelectContact}\n />\n </>\n );\n}\n\n// ---- Group Members Drawer ----\n\ninterface GroupMembersDrawerProps {\n group: ContactGroup;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n contactCount: number;\n onSelectContact?: (contactId: string) => void;\n}\n\nfunction GroupMembersDrawer({\n group,\n open,\n onOpenChange,\n contactCount,\n onSelectContact,\n}: GroupMembersDrawerProps) {\n const { t } = useContactsTranslation();\n const api = useContactsCrud();\n const queryClient = useQueryClient();\n const backgroundColor = group.avatar_background ?? \"var(--color-muted)\";\n const [addSearch, setAddSearch] = useState(\"\");\n const [recentlyAddedId, setRecentlyAddedId] = useState<number | null>(null);\n\n useEffect(() => {\n if (recentlyAddedId == null) return;\n const timer = setTimeout(() => setRecentlyAddedId(null), 2000);\n return () => clearTimeout(timer);\n }, [recentlyAddedId]);\n\n const { data: members, isLoading: isLoadingMembers } = useQuery({\n queryKey: contactsKeys.groupMembers(group.name),\n queryFn: async () => {\n const result = await api.listContacts({\n tags: [group.name],\n per_page: 100,\n });\n return result.contacts;\n },\n enabled: open,\n });\n\n const { data: searchResults } = useQuery({\n queryKey: contactsKeys.groupAddSearch(group.name, addSearch),\n queryFn: () =>\n api.listContacts({\n search_query: addSearch,\n per_page: 10,\n }),\n enabled: addSearch.length > 0 && open,\n });\n\n const nonMembers = (searchResults?.contacts ?? []).filter(\n (c) => !members?.some((m) => m.id === c.id),\n );\n\n const handleRemoveContact = useCallback(\n (contact: Contact) => {\n const currentTags = Array.isArray(contact.tags) ? contact.tags : [];\n const newTags = currentTags.filter((tag) => tag !== group.name);\n api\n .updateContact(String(contact.id), { tags: newTags })\n .then(() => {\n queryClient.invalidateQueries({\n queryKey: contactsKeys.groupMembers(group.name),\n });\n invalidateContactCaches(queryClient);\n fluidToast({\n title: t(\"groups_member_removed_toast\", {\n contact: contact.full_name ?? \"\",\n group: group.name,\n }),\n type: \"success\",\n });\n })\n .catch((error) => {\n fluidToast({\n title: t(\"groups_member_remove_failed\", {\n contact: contact.full_name ?? \"\",\n group: group.name,\n }),\n description: parseApiErrors(error),\n type: \"error\",\n });\n });\n },\n [api, group.name, queryClient, t],\n );\n\n const handleAddContact = useCallback(\n (contact: Contact) => {\n const currentTags = Array.isArray(contact.tags) ? contact.tags : [];\n if (currentTags.includes(group.name)) return;\n const newTags = [...currentTags, group.name];\n api\n .updateContact(String(contact.id), { tags: newTags })\n .then(() => {\n queryClient.invalidateQueries({\n queryKey: contactsKeys.groupMembers(group.name),\n });\n invalidateContactCaches(queryClient);\n setAddSearch(\"\");\n setRecentlyAddedId(contact.id);\n fluidToast({\n title: t(\"groups_member_added_toast\", {\n contact: contact.full_name ?? \"\",\n group: group.name,\n }),\n type: \"success\",\n });\n })\n .catch((error) => {\n fluidToast({\n title: t(\"groups_member_add_failed\", {\n contact: contact.full_name ?? \"\",\n group: group.name,\n }),\n description: parseApiErrors(error),\n type: \"error\",\n });\n });\n },\n [api, group.name, queryClient, t],\n );\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent side=\"right\" className=\"flex flex-col overflow-hidden p-0\">\n {/* Drawer header */}\n <SheetHeader className=\"border-border/50 border-b px-6 pt-6 pb-4\">\n <div className=\"flex items-center gap-4\">\n <div\n className=\"flex size-12 shrink-0 items-center justify-center rounded-full text-xl\"\n style={{ backgroundColor }}\n >\n {group.avatar ?? <Users className=\"size-5 text-white/60\" />}\n </div>\n <div>\n <SheetTitle>{group.name}</SheetTitle>\n <SheetDescription>\n {contactCount === 1\n ? t(\"groups_member_one\", { count: contactCount })\n : t(\"groups_member_other\", { count: contactCount })}\n </SheetDescription>\n </div>\n </div>\n </SheetHeader>\n\n {/* Search to add contacts */}\n <div className=\"relative border-b px-6 py-3\">\n <div className=\"relative\">\n <Search className=\"text-muted-foreground pointer-events-none absolute top-1/2 left-3 size-3.5 -translate-y-1/2\" />\n <Input\n type=\"text\"\n value={addSearch}\n onChange={(e) => setAddSearch(e.target.value)}\n placeholder={t(\"groups_search_contacts_to_add\")}\n className=\"pl-8\"\n />\n </div>\n {addSearch && nonMembers.length > 0 && (\n <div className=\"bg-popover border-border absolute right-6 left-6 z-10 mt-1 max-h-48 overflow-y-auto rounded-md border shadow-md\">\n {nonMembers.map((contact) => (\n <button\n key={contact.id}\n type=\"button\"\n onClick={() => handleAddContact(contact)}\n className=\"hover:bg-muted flex w-full items-center gap-3 px-3 py-2 text-left text-sm\"\n >\n <div className=\"bg-muted flex size-7 shrink-0 items-center justify-center rounded-full text-xs font-medium\">\n {contact.first_name?.[0] ?? \"\"}\n {contact.last_name?.[0] ?? \"\"}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-foreground truncate text-sm\">\n {contact.full_name}\n </p>\n {contact.email && (\n <p className=\"text-muted-foreground truncate text-xs\">\n {contact.email}\n </p>\n )}\n </div>\n <Plus className=\"text-primary size-4 shrink-0\" />\n </button>\n ))}\n </div>\n )}\n {addSearch && nonMembers.length === 0 && searchResults && (\n <div className=\"bg-popover border-border absolute right-6 left-6 z-10 mt-1 rounded-md border p-3 shadow-md\">\n <p className=\"text-muted-foreground text-center text-sm\">\n {t(\"groups_no_contacts_found\")}\n </p>\n </div>\n )}\n </div>\n\n {/* Members list */}\n <div className=\"flex-1 overflow-y-auto px-6 py-3\">\n {isLoadingMembers ? (\n <div className=\"text-muted-foreground py-8 text-center text-sm\">\n {t(\"groups_loading_members\")}\n </div>\n ) : !members || members.length === 0 ? (\n <div className=\"text-muted-foreground py-8 text-center text-sm\">\n {t(\"groups_empty_members\")}\n </div>\n ) : (\n <div className=\"space-y-1\">\n {members.map((contact) => (\n <div\n key={contact.id}\n className={cn(\n \"group/member hover:bg-muted/50 focus-within:bg-muted/50 flex cursor-pointer items-center gap-3 rounded-md px-2 py-2 transition-colors duration-1000\",\n recentlyAddedId === contact.id && \"animate-highlight-fade\",\n )}\n onClick={() => {\n if (onSelectContact) {\n onOpenChange(false);\n onSelectContact(String(contact.id));\n }\n }}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (\n (e.key === \"Enter\" || e.key === \" \") &&\n onSelectContact\n ) {\n e.preventDefault();\n onOpenChange(false);\n onSelectContact(String(contact.id));\n }\n }}\n >\n <div className=\"bg-muted text-muted-foreground flex size-9 shrink-0 items-center justify-center rounded-full text-xs font-semibold\">\n {contact.first_name?.[0] ?? \"\"}\n {contact.last_name?.[0] ?? \"\"}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-foreground text-sm font-medium\">\n {contact.full_name}\n </p>\n {contact.email && (\n <p className=\"text-muted-foreground truncate text-xs\">\n {contact.email}\n </p>\n )}\n </div>\n <IconButton\n icon={X}\n onClick={(e) => {\n e.stopPropagation();\n handleRemoveContact(contact);\n }}\n className=\"text-muted-foreground hover:text-destructive size-7 rounded-full opacity-0 group-focus-within/member:opacity-100 group-hover/member:opacity-100 focus:opacity-100 [&_svg:not([class*='size-'])]:size-3.5\"\n aria-label={t(\"groups_remove_member_aria\", {\n name: contact.full_name ?? \"\",\n })}\n />\n </div>\n ))}\n </div>\n )}\n </div>\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction GroupsSkeleton() {\n return (\n <div className=\"space-y-2\">\n {[0, 1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"flex items-center gap-4 rounded-lg px-4 py-3\"\n aria-hidden=\"true\"\n >\n <Skeleton className=\"size-10 rounded-full\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-24\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { fluidToast } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { CONTACTS_QUERY_KEYS } from \"@fluid-app/contacts-core/query-keys\";\nimport type { CreateContactFormData } from \"../schemas/contactFormSchema\";\n\nexport function useCreateContactMutation(\n queryKeyPrefix = \"contacts\",\n options?: {\n onSuccess?: (data: { contact: { id: number } }) => void;\n onError?: (error: unknown) => void;\n },\n) {\n const queryClient = useQueryClient();\n const api = useContactsCrud();\n\n return useMutation({\n mutationFn: (data: CreateContactFormData) =>\n api.createContact(data as unknown as Record<string, unknown>),\n onSuccess: (data) => {\n fluidToast({ title: \"Contact created successfully\", type: \"success\" });\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(queryKeyPrefix),\n });\n if (queryKeyPrefix !== \"contacts\") {\n queryClient.invalidateQueries({\n queryKey: CONTACTS_QUERY_KEYS.all(\"contacts\"),\n });\n }\n options?.onSuccess?.(data as unknown as { contact: { id: number } });\n },\n onError: (error) => {\n if (options?.onError) {\n options.onError(error);\n } else {\n fluidToast({\n title: \"Failed to create contact\",\n type: \"error\",\n description: parseApiErrors(error),\n });\n }\n },\n });\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { FormProvider } from \"react-hook-form\";\nimport { useZodForm, fluidToast, cn } from \"@fluid-app/ui-primitives\";\nimport { parseApiErrors } from \"@fluid-app/api-client-core\";\nimport type { ComponentProps } from \"react\";\nimport type { Contact as ContactType } from \"@fluid-app/contacts-core/types\";\nimport { useContactsCrud } from \"@fluid-app/contacts-core/contacts-api-context\";\nimport { useContactsTranslation } from \"@fluid-app/contacts-core/translation-api-context\";\nimport { invalidateContactCaches } from \"@fluid-app/contacts-ui/portal/hooks/groups/invalidate-contact-caches\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { ContactCreateScreen } from \"@fluid-app/contacts-ui/screens/ContactCreateScreen\";\nimport { RepContactsLayout } from \"@fluid-app/contacts-ui/portal/components/contacts/rep-layout/RepContactsLayout\";\nimport {\n GroupsManagePage,\n GroupDialog,\n} from \"@fluid-app/contacts-ui/portal/components/contacts/rep-layout/GroupsManagePage\";\nimport { ContactDetailsForm } from \"@fluid-app/contacts-ui/shared/components/contacts/contactDetailsForm\";\nimport { useCreateContactMutation } from \"@fluid-app/contacts-ui/shared/hooks/useCreateContactMutation\";\nimport {\n createContactFormSchema,\n type CreateContactFormData,\n} from \"@fluid-app/contacts-ui/shared/schemas/contactFormSchema\";\nimport { useCountriesApi } from \"@fluid-app/store-core/countries-api-context\";\nimport { PortalContactsApiProvider } from \"../contacts/PortalContactsApiProvider\";\nimport { ContactsTranslationBridge } from \"../providers/ContactsTranslationBridge\";\nimport { useAppNavigation } from \"../shell/AppNavigationContext\";\nimport { storeKeys } from \"../account/query-keys\";\n\ntype NavState =\n | { view: \"browse\"; selectedContactId: string | null }\n | { view: \"new\" };\n\ntype ContactsScreenProps = ComponentProps<\"div\"> & {\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Display\n defaultViewMode?: \"list\" | \"grid\";\n\n // Callbacks\n onContactSelect?: (contactId: string) => void;\n onCreateContact?: () => void;\n};\n\nconst QUERY_KEY_PREFIX = \"sdk-contacts\";\n\nfunction ContactBrowseView({\n selectedContactId,\n highlightContactId,\n onSelect,\n onAdd,\n onManageGroups,\n onCreateGroup,\n highlightGroupName,\n}: {\n selectedContactId: string | null;\n highlightContactId?: string | null;\n highlightGroupName?: string | null;\n onSelect: (id: string | null) => void;\n onAdd: () => void;\n onManageGroups: () => void;\n onCreateGroup: () => void;\n}) {\n const { t } = useContactsTranslation();\n const countriesAdapter = useCountriesApi();\n const contactsApi = useContactsCrud();\n const queryClient = useQueryClient();\n\n const getCountries = useCallback(async () => {\n const result = await countriesAdapter.listCountries();\n return result.countries.map((c) => ({ id: 0, name: c.name, iso: c.code }));\n }, [countriesAdapter]);\n\n const handleDeleteContact = useCallback(\n (contact: ContactType) => {\n const name = contact.full_name || t(\"contact_label\");\n contactsApi\n .deleteContact(String(contact.id))\n .then(() => {\n invalidateContactCaches(queryClient);\n if (selectedContactId === String(contact.id)) {\n onSelect(null);\n }\n fluidToast({\n title: t(\"contact_deleted_toast\", { name }),\n type: \"success\",\n });\n })\n .catch((error) => {\n fluidToast({\n title: t(\"contact_delete_failed\"),\n description: parseApiErrors(error),\n type: \"error\",\n });\n });\n },\n [contactsApi, queryClient, selectedContactId, onSelect, t],\n );\n\n return (\n <RepContactsLayout\n selectedContactId={selectedContactId}\n highlightContactId={highlightContactId}\n onSelect={onSelect}\n onAdd={onAdd}\n onManageGroups={onManageGroups}\n onCreateGroup={onCreateGroup}\n highlightGroupName={highlightGroupName}\n onDeleteContact={handleDeleteContact}\n queryKeyPrefix={QUERY_KEY_PREFIX}\n getCountries={getCountries}\n />\n );\n}\n\nconst CREATE_DEFAULT_VALUES: CreateContactFormData = {\n first_name: \"\",\n last_name: \"\",\n email: \"\",\n phone: \"\",\n status: \"new\",\n address: \"\",\n city: \"\",\n state: \"\",\n postal_code: \"\",\n country_code: null,\n language_code: null,\n metadata: {},\n affiliate: {},\n};\n\nfunction ContactCreateView({\n onNavigate,\n onCreateContact,\n}: {\n onNavigate: (state: NavState) => void;\n onCreateContact?: () => void;\n}) {\n const formRef = useRef<HTMLFormElement>(null);\n const countriesAdapter = useCountriesApi();\n\n const { data: countriesResponse } = useQuery({\n queryKey: storeKeys.countries(),\n queryFn: () => countriesAdapter.listCountries(),\n });\n\n const countryOptions = useMemo(\n () =>\n (countriesResponse?.countries ?? [])\n .map((c) => ({ name: c.name, value: c.code }))\n .sort((a, b) => a.name.localeCompare(b.name)),\n [countriesResponse],\n );\n\n const methods = useZodForm<CreateContactFormData>(createContactFormSchema, {\n defaultValues: CREATE_DEFAULT_VALUES,\n });\n\n const mutation = useCreateContactMutation(QUERY_KEY_PREFIX, {\n onSuccess: (data) => {\n onCreateContact?.();\n const newContactId = data?.contact?.id;\n if (newContactId) {\n onNavigate({\n view: \"browse\",\n selectedContactId: String(newContactId),\n });\n } else {\n onNavigate({ view: \"browse\", selectedContactId: null });\n }\n },\n });\n\n const { mutate } = mutation;\n\n const onSubmit = useMemo(\n () =>\n methods.handleSubmit(\n (data) => {\n const { affiliate, ...contactFields } = data;\n const payload: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(contactFields)) {\n if (value !== \"\" && value !== null && value !== undefined) {\n payload[key] = value;\n }\n }\n\n if (affiliate && Object.keys(affiliate).length > 0) {\n payload.affiliate = affiliate;\n }\n\n mutate(payload as CreateContactFormData);\n },\n () => {\n // Validation errors are shown inline by react-hook-form field controllers.\n // handleSubmit already populates field errors before calling this callback.\n },\n ),\n [methods, mutate],\n );\n\n const handleNavigateToList = useCallback(() => {\n onNavigate({ view: \"browse\", selectedContactId: null });\n }, [onNavigate]);\n\n return (\n <ContactCreateScreen\n onNavigateToList={handleNavigateToList}\n onSubmit={() => formRef.current?.requestSubmit()}\n isPending={mutation.isPending}\n >\n <FormProvider {...methods}>\n <div className=\"mx-auto max-w-7xl space-y-12 md:px-10 md:py-8\">\n <form\n ref={formRef}\n onSubmit={onSubmit}\n className=\"mx-auto space-y-6 lg:max-w-2xl\"\n >\n <ContactDetailsForm countries={countryOptions} />\n </form>\n </div>\n </FormProvider>\n </ContactCreateScreen>\n );\n}\n\nexport function ContactsScreen({\n onContactSelect,\n onCreateContact,\n /* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */\n background,\n textColor,\n accentColor,\n padding,\n borderRadius,\n defaultViewMode,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n ...divProps\n}: ContactsScreenProps): React.JSX.Element {\n const { currentSlug, navigate } = useAppNavigation();\n const subPage = currentSlug.split(\"/\")[1];\n\n const [nav, setNav] = useState<NavState>({\n view: \"browse\",\n selectedContactId: null,\n });\n const [highlightContactId, setHighlightContactId] = useState<string | null>(\n null,\n );\n\n useEffect(() => {\n if (highlightContactId == null) return;\n const timer = setTimeout(() => setHighlightContactId(null), 2000);\n return () => clearTimeout(timer);\n }, [highlightContactId]);\n\n const handleSelect = useCallback(\n (id: string | null) => {\n setNav({ view: \"browse\", selectedContactId: id });\n if (id) onContactSelect?.(id);\n },\n [onContactSelect],\n );\n\n const handleAdd = useCallback(() => {\n setNav({ view: \"new\" });\n }, []);\n\n const handleManageGroups = useCallback(() => {\n navigate(\"contacts/manage-groups\");\n }, [navigate]);\n\n const [createGroupOpen, setCreateGroupOpen] = useState(false);\n const [highlightGroupName, setHighlightGroupName] = useState<string | null>(\n null,\n );\n\n useEffect(() => {\n if (highlightGroupName == null) return;\n const timer = setTimeout(() => setHighlightGroupName(null), 2000);\n return () => clearTimeout(timer);\n }, [highlightGroupName]);\n\n const handleCreateGroup = useCallback(() => {\n setCreateGroupOpen(true);\n }, []);\n\n return (\n <ContactsTranslationBridge>\n <PortalContactsApiProvider>\n <div {...divProps} className={cn(\"h-full\", divProps.className)}>\n {subPage === \"manage-groups\" ? (\n <GroupsManagePage\n onBack={() => navigate(\"contacts\")}\n onSelectContact={(contactId) => {\n setNav({ view: \"browse\", selectedContactId: contactId });\n navigate(\"contacts\");\n }}\n />\n ) : nav.view === \"new\" ? (\n <ContactCreateView\n onNavigate={(state) => {\n setNav(state);\n if (state.view === \"browse\" && state.selectedContactId) {\n setHighlightContactId(state.selectedContactId);\n }\n }}\n onCreateContact={onCreateContact}\n />\n ) : (\n <ContactBrowseView\n selectedContactId={nav.selectedContactId}\n highlightContactId={highlightContactId}\n onSelect={handleSelect}\n onAdd={handleAdd}\n onManageGroups={handleManageGroups}\n onCreateGroup={handleCreateGroup}\n highlightGroupName={highlightGroupName}\n />\n )}\n <GroupDialog\n key={createGroupOpen ? \"open\" : \"closed\"}\n mode=\"create\"\n open={createGroupOpen}\n onOpenChange={(open) => setCreateGroupOpen(open)}\n onGroupCreatedWithName={(name) => {\n setHighlightGroupName(name);\n }}\n />\n </div>\n </PortalContactsApiProvider>\n </ContactsTranslationBridge>\n );\n}\n\nexport const contactsScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ContactsScreen\",\n displayName: \"Contacts Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"x_google_ignoreList":[39],"mappings":"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"}
|