diff --git a/frontend/src/api/hooks.ts b/frontend/src/api/hooks.ts index fc92af1..22fe421 100644 --- a/frontend/src/api/hooks.ts +++ b/frontend/src/api/hooks.ts @@ -1,783 +1 @@ -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'] }); - }, - }); -} - -// ═══════════════════════════════════════════════════════════════ -// System Settings, Currency, Tax, Sequence hooks -// ═══════════════════════════════════════════════════════════════ - -export interface Currency { - id: string; - code: string; - name: string; - symbol: string; - is_default: boolean; - created_at?: string; - updated_at?: string; -} - -export interface TaxRate { - id: string; - name: string; - rate: number; - is_default: boolean; - country?: string | null; - created_at?: string; - updated_at?: string; -} - -export interface Sequence { - id: string; - name: string; - prefix: string; - next_number: number; - padding: number; - created_at?: string; - updated_at?: string; -} - -export interface SystemSettings { - id?: string; - company_name: string; - company_legal_form?: string | null; - company_street: string; - company_city: string; - company_zip: string; - company_country: string; - tax_number?: string | null; - vat_id?: string | null; - iban?: string | null; - bic?: string | null; - bank_name?: string | null; - ceo?: string | null; - trade_register?: string | null; - default_currency_id?: string | null; - default_tax_id?: string | null; - invoice_prefix: string; - quote_prefix: string; - payment_terms_days: number; - created_at?: string; - updated_at?: string; -} - -// System Settings -export function useSystemSettings() { - return useQuery({ - queryKey: ['systemSettings'], - queryFn: () => apiGet('/system-settings'), - }); -} - -export function useUpdateSystemSettings() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (data: Partial) => apiClient.put('/system-settings', data).then(r => r.data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['systemSettings'] }); - }, - }); -} - -// Currencies -export function useCurrencies() { - return useQuery({ - queryKey: ['currencies'], - queryFn: () => apiGet<{ items: Currency[]; total: number }>('/currencies'), - }); -} - -export function useCreateCurrency() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (data: Partial) => apiPost('/currencies', data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['currencies'] }); - }, - }); -} - -export function useUpdateCurrency() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: ({ id, data }: { id: string; data: Partial }) => - apiPatch(`/currencies/${id}`, data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['currencies'] }); - }, - }); -} - -export function useDeleteCurrency() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (id: string) => apiDelete(`/currencies/${id}`), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['currencies'] }); - }, - }); -} - -// Taxes -export function useTaxes() { - return useQuery({ - queryKey: ['taxes'], - queryFn: () => apiGet<{ items: TaxRate[]; total: number }>('/taxes'), - }); -} - -export function useCreateTax() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (data: Partial) => apiPost('/taxes', data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['taxes'] }); - }, - }); -} - -export function useUpdateTax() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: ({ id, data }: { id: string; data: Partial }) => - apiPatch(`/taxes/${id}`, data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['taxes'] }); - }, - }); -} - -export function useDeleteTax() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (id: string) => apiDelete(`/taxes/${id}`), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['taxes'] }); - }, - }); -} - -// Sequences -export function useSequences() { - return useQuery({ - queryKey: ['sequences'], - queryFn: () => apiGet<{ items: Sequence[]; total: number }>('/sequences'), - }); -} - -export function useCreateSequence() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (data: Partial) => apiPost('/sequences', data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['sequences'] }); - }, - }); -} - -// Attachments -export interface Attachment { - id: string; - entity_type: string; - entity_id: string; - filename: string; - file_path: string; - mime_type: string; - file_size: number; - uploaded_by?: string | null; - created_at?: string; - updated_at?: string; -} - -export function useAttachments(entityType?: string, entityId?: string) { - return useQuery({ - queryKey: ['attachments', entityType, entityId], - queryFn: () => { - const params = new URLSearchParams(); - if (entityType) params.set('entity_type', entityType); - if (entityId) params.set('entity_id', entityId); - return apiGet<{ items: Attachment[]; total: number }>(`/attachments?${params.toString()}`); - }, - enabled: !!entityType && !!entityId, - }); -} - -export function useUploadAttachment() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: async ({ file, entityType, entityId }: { file: File; entityType: string; entityId: string }) => { - const formData = new FormData(); - formData.append('file', file); - formData.append('entity_type', entityType); - formData.append('entity_id', entityId); - const response = await apiClient.post('/attachments', formData, { - headers: { 'Content-Type': 'multipart/form-data' }, - }); - return response.data; - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['attachments'] }); - }, - }); -} - -export function useDeleteAttachment() { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: (id: string) => apiDelete(`/attachments/${id}`), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['attachments'] }); - }, - }); -} +§§include(/a0/usr/chats/XttavUaL/messages/hooks_update.ts) \ No newline at end of file