ultisuite-client/lib/api/hooks/use-contact-queries.ts
R3D347HR4Y c87670e90f
Some checks failed
E2E / Playwright e2e (push) Has been cancelled
feat(api): offline-first mail sync w/ TanStack Query
Move mail, compose, contacts, and accounts off mocks onto REST + WS.
Add client, auth store, IDB-backed query cache, offline queue, and
sync bar; hybrid Zustand for UI-only state. Settings still local until
backend has preferences API.
2026-05-23 00:04:28 +02:00

75 lines
2.1 KiB
TypeScript

'use client'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { apiClient, OfflineError } from '../client'
import type { ApiContact, ApiContactSyncResponse } from '../types'
export function useContacts(bookId?: string) {
return useQuery({
queryKey: ['contacts', bookId],
queryFn: () => apiClient.get<ApiContact[]>(`/contacts/books/${bookId}`),
enabled: !!bookId,
staleTime: 5 * 60_000,
})
}
export function useContactBooks() {
return useQuery({
queryKey: ['contact-books'],
queryFn: () => apiClient.get<{ id: string; name: string }[]>('/contacts/books'),
staleTime: 10 * 60_000,
})
}
export function useSyncContacts(bookId?: string, syncToken?: string) {
return useQuery({
queryKey: ['contacts-sync', bookId, syncToken],
queryFn: () =>
apiClient.get<ApiContactSyncResponse>(`/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<ApiContact[]>('/contacts/search', { q: query })
} catch (err) {
if (err instanceof OfflineError) {
const cached = queryClient.getQueriesData<ApiContact[]>({
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<unknown>('/contacts/interactions', { email }),
enabled: !!email,
})
}