/** * Unified Contact (Rentman-style) hooks and standalone API functions. */ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { apiGet, apiPost, apiPut, apiDelete } from './client'; import { PaginatedResponse } from './types'; export interface ContactPerson { id: string; contact_id: string; displayname: string; firstname?: string | null; middle_name?: string | null; lastname?: string | null; function?: string | null; phone?: string | null; mobilephone?: string | null; email?: string | null; street?: string | null; number?: string | null; postalcode?: string | null; city?: string | null; state?: string | null; country?: string | null; tags?: string | null; custom?: Record | null; created_at?: string; updated_at?: string; } export interface UnifiedContact { id: string; type: 'company' | 'person'; displayname: string; name?: string | null; firstname?: string | null; surname?: string | null; suffix?: string | null; ext_name_line?: string | null; gender?: string | null; code?: string | null; accounting_code?: string | null; vendor_accounting_code?: string | null; // Mailing address mailing_street?: string | null; mailing_number?: string | null; mailing_unit_number?: string | null; mailing_district?: string | null; mailing_extra_address_line?: string | null; mailing_postalcode?: string | null; mailing_city?: string | null; mailing_state?: string | null; mailing_country?: string | null; // Visit address visit_street?: string | null; visit_number?: string | null; visit_unit_number?: string | null; visit_district?: string | null; visit_extra_address_line?: string | null; visit_postalcode?: string | null; visit_city?: string | null; visit_state?: string | null; // Invoice address invoice_street?: string | null; invoice_number?: string | null; invoice_unit_number?: string | null; invoice_district?: string | null; invoice_extra_address_line?: string | null; invoice_postalcode?: string | null; invoice_city?: string | null; invoice_state?: string | null; invoice_country?: string | null; country?: string | null; // Communication phone_1?: string | null; phone_2?: string | null; email_1?: string | null; email_2?: string | null; website?: string | null; // Financial vat_code?: string | null; fiscal_code?: string | null; commerce_code?: string | null; purchase_number?: string | null; bic?: string | null; bank_account?: string | null; // Discounts discount_crew: number; discount_transport: number; discount_rental: number; discount_sale: number; discount_subrent: number; discount_total: number; // Geo latitude?: number | null; longitude?: number | null; // Notes projectnote?: string | null; projectnote_title?: string | null; contact_warning?: string | null; tags?: string | null; image?: string | null; custom?: Record | null; folder_id?: string | null; default_person_id?: string | null; admin_contactperson_id?: string | null; contact_persons?: ContactPerson[]; created_at?: string; updated_at?: string; } export function useUnifiedContacts( page = 1, pageSize = 25, search?: string, contactType?: string, sortBy?: string, sortOrder?: string, folderId?: string, ) { const params = new URLSearchParams({ page: String(page), page_size: String(pageSize) }); if (search) params.set('search', search); if (contactType) params.set('type', contactType); if (sortBy) params.set('sort_by', sortBy); if (sortOrder) params.set('sort_order', sortOrder); if (folderId) params.set('folder_id', folderId); return useQuery({ queryKey: ['unifiedContacts', page, pageSize, search, contactType, sortBy, sortOrder, folderId], queryFn: () => apiGet>(`/contacts?${params.toString()}`), }); } export function useUnifiedContact(id?: string) { return useQuery({ queryKey: ['unifiedContacts', id], queryFn: () => apiGet(`/contacts/${id}`), enabled: !!id, }); } export function useCreateUnifiedContact() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: Partial) => apiPost('/contacts', data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['unifiedContacts'] }); }, }); } export function useUpdateUnifiedContact() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: string; data: Partial }) => apiPut(`/contacts/${id}`, data), onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: ['unifiedContacts'] }); queryClient.invalidateQueries({ queryKey: ['unifiedContacts', variables.id] }); }, }); } export function useDeleteUnifiedContact() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, hard }: { id: string; hard?: boolean }) => apiDelete(`/contacts/${id}${hard ? '?hard=true' : ''}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['unifiedContacts'] }); }, }); } export function useContactPersons(contactId?: string) { return useQuery({ queryKey: ['unifiedContacts', contactId, 'persons'], queryFn: () => apiGet<{ items: ContactPerson[] }>(`/contacts/${contactId}/persons`), enabled: !!contactId, }); } export function useCreateContactPerson() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ contactId, data }: { contactId: string; data: Partial }) => apiPost(`/contacts/${contactId}/persons`, data), onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: ['unifiedContacts'] }); queryClient.invalidateQueries({ queryKey: ['unifiedContacts', variables.contactId] }); queryClient.invalidateQueries({ queryKey: ['unifiedContacts', variables.contactId, 'persons'] }); }, }); } export function useUpdateContactPerson() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ contactId, personId, data }: { contactId: string; personId: string; data: Partial }) => apiPut(`/contacts/${contactId}/persons/${personId}`, data), onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: ['unifiedContacts'] }); queryClient.invalidateQueries({ queryKey: ['unifiedContacts', variables.contactId] }); queryClient.invalidateQueries({ queryKey: ['unifiedContacts', variables.contactId, 'persons'] }); }, }); } export function useDeleteContactPerson() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ contactId, personId }: { contactId: string; personId: string }) => apiDelete(`/contacts/${contactId}/persons/${personId}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['unifiedContacts'] }); }, }); } // Standalone API functions (for non-hook usage) export async function fetchContacts( page = 1, pageSize = 25, search?: string, contactType?: string, sortBy?: string, sortOrder?: string, ): Promise> { const params = new URLSearchParams({ page: String(page), page_size: String(pageSize) }); if (search) params.set('search', search); if (contactType) params.set('type', contactType); if (sortBy) params.set('sort_by', sortBy); if (sortOrder) params.set('sort_order', sortOrder); return apiGet>(`/contacts?${params.toString()}`); } export async function fetchContact(id: string): Promise { return apiGet(`/contacts/${id}`); } export async function createContact(data: Partial): Promise { return apiPost('/contacts', data); } export async function updateContact(id: string, data: Partial): Promise { return apiPut(`/contacts/${id}`, data); } export async function deleteContact(id: string, hard?: boolean): Promise { await apiDelete(`/contacts/${id}${hard ? '?hard=true' : ''}`); } export async function fetchContactPersons(contactId: string): Promise<{ items: ContactPerson[] }> { return apiGet<{ items: ContactPerson[] }>(`/contacts/${contactId}/persons`); } export async function createContactPerson(contactId: string, data: Partial): Promise { return apiPost(`/contacts/${contactId}/persons`, data); } export async function updateContactPerson(contactId: string, personId: string, data: Partial): Promise { return apiPut(`/contacts/${contactId}/persons/${personId}`, data); } export async function deleteContactPerson(contactId: string, personId: string): Promise { await apiDelete(`/contacts/${contactId}/persons/${personId}`); }