Some checks failed
E2E / Playwright e2e (push) Has been cancelled
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.
75 lines
2.1 KiB
TypeScript
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,
|
|
})
|
|
}
|