'use client' import { useMemo } from 'react' import { useQuery, useQueryClient } from '@tanstack/react-query' import { apiClient, OfflineError } from '../client' import type { ApiContact, ApiContactSyncResponse } from '../types' export const FALLBACK_CONTACT_BOOK_ID = 'contacts' type ApiContactBook = { id: string; name: string } type ApiContactsListResponse = { contacts: ApiContact[] } export function normalizeContactBooksResponse(booksRaw: unknown): ApiContactBook[] { if (Array.isArray(booksRaw)) return booksRaw as ApiContactBook[] if (booksRaw && typeof booksRaw === 'object' && 'address_books' in booksRaw) { return (booksRaw as { address_books: ApiContactBook[] }).address_books ?? [] } return [] } export async function fetchContactsForBook(bookId: string): Promise { const res = await apiClient.get( `/contacts/books/${bookId}`, ) return Array.isArray(res) ? res : (res.contacts ?? []) } export function useDefaultContactBookId() { const { data: booksRaw } = useContactBooks() return useMemo(() => { const books = normalizeContactBooksResponse(booksRaw) return books[0]?.id ?? FALLBACK_CONTACT_BOOK_ID }, [booksRaw]) } export function useContacts(bookId?: string) { const defaultBookId = useDefaultContactBookId() const resolvedBookId = bookId ?? defaultBookId return useQuery({ queryKey: ['contacts', resolvedBookId], queryFn: () => fetchContactsForBook(resolvedBookId), enabled: !!resolvedBookId, staleTime: 5 * 60_000, }) } export function useContactBooks() { return useQuery({ queryKey: ['contact-books'], queryFn: async () => { const res = await apiClient.get( '/contacts/books', ) return normalizeContactBooksResponse(res) }, staleTime: 10 * 60_000, }) } export function useSyncContacts(bookId?: string, syncToken?: string) { return useQuery({ queryKey: ['contacts-sync', bookId, syncToken], queryFn: () => apiClient.get(`/contacts/books/${bookId}/sync`, { sync_token: syncToken, }), enabled: !!bookId && !!syncToken, }) } export function useSearchContacts(query: string) { const queryClient = useQueryClient() return useQuery({ queryKey: ['contacts-search', query], queryFn: async () => { try { return await apiClient.get('/contacts/search', { q: query }) } catch (err) { if (err instanceof OfflineError) { const cached = queryClient.getQueriesData({ queryKey: ['contacts'], }) const allContacts: ApiContact[] = [] for (const [, data] of cached) { if (data) allContacts.push(...data) } const q = query.toLowerCase() return allContacts.filter( (c) => c.full_name.toLowerCase().includes(q) || c.email?.toLowerCase().includes(q) || c.org?.toLowerCase().includes(q) ) } throw err } }, enabled: query.length >= 2, staleTime: 30_000, }) } export function useContactInteractions(email?: string) { return useQuery({ queryKey: ['contact-interactions', email], queryFn: () => apiClient.get('/contacts/interactions', { email }), enabled: !!email, }) }