Update frontend/src/api/hooks.ts
This commit is contained in:
+1
-783
@@ -1,783 +1 @@
|
|||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
§§include(/a0/usr/chats/XttavUaL/messages/hooks_update.ts)
|
||||||
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<T> {
|
|
||||||
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<string, any>;
|
|
||||||
field_permissions?: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
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<any>('/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<PaginatedResponse<any>>(`/users?page=${page}&page_size=${pageSize}`),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUser(id?: string) {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ['users', id],
|
|
||||||
queryFn: () => apiGet<any>(`/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<PaginatedResponse<Company>>(`/companies?${params.toString()}`),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useCompany(id?: string) {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ['companies', id],
|
|
||||||
queryFn: () => apiGet<CompanyDetail>(`/companies/${id}`),
|
|
||||||
enabled: !!id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useCreateCompany() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: (data: Partial<Company>) => apiPost('/companies', data),
|
|
||||||
onSuccess: () => {
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['companies'] });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUpdateCompany() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: ({ id, data }: { id: string; data: Partial<Company> }) =>
|
|
||||||
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<PaginatedResponse<Contact>>(`/contacts?${params.toString()}`),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useContact(id?: string) {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ['contacts', id],
|
|
||||||
queryFn: () => apiGet<ContactDetail>(`/contacts/${id}`),
|
|
||||||
enabled: !!id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useCreateContact() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: (data: Partial<Contact> & { 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<Contact> & { 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<PaginatedResponse<AuditLogEntry>>(`/audit?${params.toString()}`),
|
|
||||||
retry: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useGlobalSearch(query: string, entityTypes?: string[]) {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ['globalSearch', query, entityTypes],
|
|
||||||
queryFn: async (): Promise<SearchResult[]> => {
|
|
||||||
if (!query.trim()) return [];
|
|
||||||
const results: SearchResult[] = [];
|
|
||||||
const types = entityTypes && entityTypes.length > 0 ? entityTypes : ['company', 'contact'];
|
|
||||||
const tasks: Promise<void>[] = [];
|
|
||||||
if (types.includes('company')) {
|
|
||||||
tasks.push(
|
|
||||||
apiGet<PaginatedResponse<Company>>(`/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<PaginatedResponse<Contact>>(`/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<PaginatedResponse<any>>('/notifications'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUnreadNotificationCount() {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ['notifications', 'unread-count'],
|
|
||||||
queryFn: () => apiGet<number>('/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<any>('/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<any>('/roles');
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function usePermissions() {
|
|
||||||
return useQuery({
|
|
||||||
queryKey: ['permissions'],
|
|
||||||
queryFn: () => apiGet<PermissionsResponse>('/roles/permissions'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useCreateRole() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: (data: { name: string; permissions: Record<string, any>; field_permissions: Record<string, any> }) =>
|
|
||||||
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<string, any>; field_permissions?: Record<string, any> } }) =>
|
|
||||||
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<SystemSettings>('/system-settings'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUpdateSystemSettings() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: (data: Partial<SystemSettings>) => 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<Currency>) => apiPost('/currencies', data),
|
|
||||||
onSuccess: () => {
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['currencies'] });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUpdateCurrency() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: ({ id, data }: { id: string; data: Partial<Currency> }) =>
|
|
||||||
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<TaxRate>) => apiPost('/taxes', data),
|
|
||||||
onSuccess: () => {
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['taxes'] });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useUpdateTax() {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: ({ id, data }: { id: string; data: Partial<TaxRate> }) =>
|
|
||||||
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<Sequence>) => 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'] });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user