import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { apiPost, apiGet, apiPatch, apiDelete, apiClient } from './client'; import { useAuthStore } from '@/store/authStore'; export interface LoginPayload { email: string; password: string; } export interface PasswordResetRequestPayload { email: string; } export interface PasswordResetConfirmPayload { token: string; password: string; } export interface PaginatedResponse { items: T[]; total: number; page: number; page_size: number; } export interface Company { id: string; name: string; account_number?: string | null; industry?: string | null; phone?: string | null; email?: string | null; website?: string | null; description?: string | null; created_at?: string; updated_at?: string; } export interface CompanyDetail extends Company { contacts?: Contact[]; } export interface Contact { id: string; first_name: string; last_name: string; email: string; phone?: string | null; position?: string | null; company_ids?: string[]; created_at?: string; updated_at?: string; } export interface ContactDetail extends Contact { companies?: Company[]; } export interface AuditLogEntry { id: string; timestamp: string; user: string; action: string; entity: string; entity_id?: string; details?: string; } export interface SearchResult { type: 'company' | 'contact'; id: string; name: string; description?: string; url: string; } export interface Role { id: string; name: string; permissions: Record; field_permissions?: Record; } export interface PermissionItem { key: string; label: string; category: string; plugin_name?: string; } export interface PermissionsResponse { system: PermissionItem[]; plugins: PermissionItem[]; all: PermissionItem[]; } export interface Plugin { name: string; display_name?: string; description?: string; version?: string; status: 'discovered' | 'installed' | 'active' | 'inactive'; installed?: boolean; active?: boolean; } export function useLogin() { const { setUser, setError } = useAuthStore(); return useMutation({ mutationFn: (payload: LoginPayload) => apiPost('/auth/login', payload), onSuccess: (data: any) => { setUser(data.user || data); setError(null); }, onError: (error: any) => { setError(error.message || 'Login failed'); }, }); } export function useLogout() { const { logout } = useAuthStore(); const queryClient = useQueryClient(); return useMutation({ mutationFn: () => apiPost('/auth/logout'), onSettled: () => { logout(); queryClient.clear(); }, }); } export function useCurrentUser() { const { setUser, setAuthenticated } = useAuthStore(); return useQuery({ queryKey: ['currentUser'], queryFn: async () => { const data = await apiGet('/auth/me'); setUser(data.user || data); setAuthenticated(true); return data; }, retry: false, staleTime: 5 * 60 * 1000, }); } export function usePasswordResetRequest() { return useMutation({ mutationFn: (payload: PasswordResetRequestPayload) => apiPost('/auth/password-reset/request', payload), }); } export function usePasswordResetConfirm() { return useMutation({ mutationFn: (payload: PasswordResetConfirmPayload) => apiPost('/auth/password-reset/confirm', payload), }); } export function useSwitchTenant() { const { setTenant } = useAuthStore(); const queryClient = useQueryClient(); return useMutation({ mutationFn: (tenantId: string) => apiPost('/auth/switch-tenant', { tenant_id: tenantId }), onSuccess: (data: any) => { setTenant(data.tenant || data); queryClient.invalidateQueries(); }, }); } export function useUsers(page = 1, pageSize = 25) { return useQuery({ queryKey: ['users', page, pageSize], queryFn: () => apiGet>(`/users?page=${page}&page_size=${pageSize}`), }); } export function useUser(id?: string) { return useQuery({ queryKey: ['users', id], queryFn: () => apiGet(`/users/${id}`), enabled: !!id, }); } export function useCreateUser() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: any) => apiPost('/users', data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['users'] }); }, }); } export function useUpdateUser() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: string; data: any }) => apiPatch(`/users/${id}`, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['users'] }); }, }); } export function useDeleteUser() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => apiDelete(`/users/${id}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['users'] }); }, }); } export function useCompanies(page = 1, pageSize = 25, search?: string, industry?: string, sortBy?: string, sortOrder?: string) { const params = new URLSearchParams({ page: String(page), page_size: String(pageSize) }); if (search) params.set('search', search); if (industry) params.set('industry', industry); if (sortBy) params.set('sort_by', sortBy); if (sortOrder) params.set('sort_order', sortOrder); return useQuery({ queryKey: ['companies', page, pageSize, search, industry, sortBy, sortOrder], queryFn: () => apiGet>(`/companies?${params.toString()}`), }); } export function useCompany(id?: string) { return useQuery({ queryKey: ['companies', id], queryFn: () => apiGet(`/companies/${id}`), enabled: !!id, }); } export function useCreateCompany() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: Partial) => apiPost('/companies', data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['companies'] }); }, }); } export function useUpdateCompany() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: string; data: Partial }) => apiPatch(`/companies/${id}`, data), onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: ['companies'] }); queryClient.invalidateQueries({ queryKey: ['companies', variables.id] }); }, }); } export function useDeleteCompany() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => apiDelete(`/companies/${id}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['companies'] }); }, }); } export function useCompanyExport(search?: string, industry?: string) { return useMutation({ mutationFn: async () => { const params = new URLSearchParams({ format: 'csv' }); if (search) params.set('search', search); if (industry) params.set('industry', industry); const response = await apiClient.get(`/companies/export?${params.toString()}`, { responseType: 'blob', }); return response.data; }, }); } export function useCompanyImport() { const queryClient = useQueryClient(); return useMutation({ mutationFn: async (file: File) => { const formData = new FormData(); formData.append('file', file); const response = await apiClient.post('/companies/import', formData, { headers: { 'Content-Type': 'multipart/form-data' }, }); return response.data; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['companies'] }); }, }); } export function useContacts(page = 1, pageSize = 25, search?: string) { const params = new URLSearchParams({ page: String(page), page_size: String(pageSize) }); if (search) params.set('search', search); return useQuery({ queryKey: ['contacts', page, pageSize, search], queryFn: () => apiGet>(`/contacts?${params.toString()}`), }); } export function useContact(id?: string) { return useQuery({ queryKey: ['contacts', id], queryFn: () => apiGet(`/contacts/${id}`), enabled: !!id, }); } export function useCreateContact() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: Partial & { company_ids?: string[] }) => apiPost('/contacts', data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['contacts'] }); }, }); } export function useUpdateContact() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: string; data: Partial & { company_ids?: string[] } }) => apiPatch(`/contacts/${id}`, data), onSuccess: (_data, variables) => { queryClient.invalidateQueries({ queryKey: ['contacts'] }); queryClient.invalidateQueries({ queryKey: ['contacts', variables.id] }); }, }); } export function useDeleteContact() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => apiDelete(`/contacts/${id}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['contacts'] }); }, }); } export function useAuditLog(page = 1, pageSize = 25, filters?: { user?: string; action?: string; entity?: string; dateFrom?: string; dateTo?: string }) { const params = new URLSearchParams({ page: String(page), page_size: String(pageSize) }); if (filters?.user) params.set('user', filters.user); if (filters?.action) params.set('action', filters.action); if (filters?.entity) params.set('entity', filters.entity); if (filters?.dateFrom) params.set('date_from', filters.dateFrom); if (filters?.dateTo) params.set('date_to', filters.dateTo); return useQuery({ queryKey: ['auditLog', page, pageSize, filters], queryFn: () => apiGet>(`/audit?${params.toString()}`), retry: false, }); } export function useGlobalSearch(query: string, entityTypes?: string[]) { return useQuery({ queryKey: ['globalSearch', query, entityTypes], queryFn: async (): Promise => { if (!query.trim()) return []; const results: SearchResult[] = []; const types = entityTypes && entityTypes.length > 0 ? entityTypes : ['company', 'contact']; const tasks: Promise[] = []; if (types.includes('company')) { tasks.push( apiGet>(`/companies?page=1&page_size=10&search=${encodeURIComponent(query)}`) .then((data) => { for (const item of data.items) { results.push({ type: 'company', id: item.id, name: item.name, description: item.industry || item.email || '', url: `/companies/${item.id}`, }); } }) .catch(() => {}) ); } if (types.includes('contact')) { tasks.push( apiGet>(`/contacts?page=1&page_size=10&search=${encodeURIComponent(query)}`) .then((data) => { for (const item of data.items) { results.push({ type: 'contact', id: item.id, name: `${item.first_name} ${item.last_name}`, description: item.email || item.phone || '', url: `/contacts/${item.id}`, }); } }) .catch(() => {}) ); } await Promise.all(tasks); return results; }, enabled: query.trim().length > 0, staleTime: 30 * 1000, }); } export function useNotifications() { return useQuery({ queryKey: ['notifications'], queryFn: () => apiGet>('/notifications'), }); } export function useUnreadNotificationCount() { return useQuery({ queryKey: ['notifications', 'unread-count'], queryFn: () => apiGet('/notifications/unread-count'), }); } export function useMarkNotificationRead() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => apiPatch(`/notifications/${id}/read`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications'] }); }, }); } export function useDeleteNotification() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => apiDelete(`/notifications/${id}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['notifications'] }); }, }); } export function usePlugins() { return useQuery({ queryKey: ['plugins'], queryFn: async () => { const data = await apiGet('/plugins'); return data; }, }); } export function useInstallPlugin() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (name: string) => apiPost(`/plugins/${name}/install`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['plugins'] }); }, }); } export function useActivatePlugin() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (name: string) => apiPost(`/plugins/${name}/activate`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['plugins'] }); }, }); } export function useDeactivatePlugin() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (name: string) => apiPost(`/plugins/${name}/deactivate`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['plugins'] }); }, }); } export function useUninstallPlugin() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ name, removeData }: { name: string; removeData: boolean }) => apiDelete(`/plugins/${name}?remove_data=${removeData}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['plugins'] }); }, }); } export function useRoles() { return useQuery({ queryKey: ['roles'], queryFn: async () => { const data = await apiGet('/roles'); return data; }, }); } export function usePermissions() { return useQuery({ queryKey: ['permissions'], queryFn: () => apiGet('/roles/permissions'), }); } export function useCreateRole() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: { name: string; permissions: Record; field_permissions: Record }) => apiPost('/roles', data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roles'] }); }, }); } export function useUpdateRole() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: string; data: { name?: string; permissions?: Record; field_permissions?: Record } }) => apiPatch(`/roles/${id}`, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roles'] }); }, }); } export function useDeleteRole() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: string) => apiDelete(`/roles/${id}`), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roles'] }); }, }); }