[SYNC] feat: Add new feature modules with API clients and hooks
- dashboard: api + hooks - geolocation: api + hooks - mcp: api + hooks - payment-terminals: api + hooks - scanning: api + hooks - shared/types: api.types.ts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
3a461cb184
commit
41ae4f195c
152
src/features/dashboard/api/dashboard.api.ts
Normal file
152
src/features/dashboard/api/dashboard.api.ts
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import { api } from '@services/api/axios-instance';
|
||||||
|
import type {
|
||||||
|
Dashboard,
|
||||||
|
DashboardWidget,
|
||||||
|
DashboardFilters,
|
||||||
|
DashboardsResponse,
|
||||||
|
CreateDashboardDto,
|
||||||
|
UpdateDashboardDto,
|
||||||
|
WidgetConfig,
|
||||||
|
DashboardMetrics,
|
||||||
|
} from '../../shared/types/api.types';
|
||||||
|
|
||||||
|
const BASE_URL = '/api/v1/dashboard';
|
||||||
|
|
||||||
|
export const dashboardApi = {
|
||||||
|
// Get all dashboards with filters
|
||||||
|
getAll: async (filters?: DashboardFilters): Promise<DashboardsResponse> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.search) params.append('search', filters.search);
|
||||||
|
if (filters?.userId) params.append('userId', filters.userId);
|
||||||
|
if (filters?.isDefault !== undefined) params.append('isDefault', String(filters.isDefault));
|
||||||
|
if (filters?.isPublic !== undefined) params.append('isPublic', String(filters.isPublic));
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
if (filters?.sortBy) params.append('sortBy', filters.sortBy);
|
||||||
|
if (filters?.sortOrder) params.append('sortOrder', filters.sortOrder);
|
||||||
|
|
||||||
|
const response = await api.get<DashboardsResponse>(`${BASE_URL}?${params.toString()}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get dashboard by ID
|
||||||
|
getById: async (id: string): Promise<Dashboard> => {
|
||||||
|
const response = await api.get<Dashboard>(`${BASE_URL}/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get user's default dashboard
|
||||||
|
getDefault: async (): Promise<Dashboard> => {
|
||||||
|
const response = await api.get<Dashboard>(`${BASE_URL}/default`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Create dashboard
|
||||||
|
create: async (data: CreateDashboardDto): Promise<Dashboard> => {
|
||||||
|
const response = await api.post<Dashboard>(BASE_URL, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update dashboard
|
||||||
|
update: async (id: string, data: UpdateDashboardDto): Promise<Dashboard> => {
|
||||||
|
const response = await api.patch<Dashboard>(`${BASE_URL}/${id}`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Delete dashboard
|
||||||
|
delete: async (id: string): Promise<void> => {
|
||||||
|
await api.delete(`${BASE_URL}/${id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Duplicate dashboard
|
||||||
|
duplicate: async (id: string, name: string): Promise<Dashboard> => {
|
||||||
|
const response = await api.post<Dashboard>(`${BASE_URL}/${id}/duplicate`, { name });
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Set as default dashboard
|
||||||
|
setAsDefault: async (id: string): Promise<Dashboard> => {
|
||||||
|
const response = await api.patch<Dashboard>(`${BASE_URL}/${id}/default`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Share dashboard
|
||||||
|
share: async (id: string, userIds: string[]): Promise<void> => {
|
||||||
|
await api.post(`${BASE_URL}/${id}/share`, { userIds });
|
||||||
|
},
|
||||||
|
|
||||||
|
// Unshare dashboard
|
||||||
|
unshare: async (id: string, userIds: string[]): Promise<void> => {
|
||||||
|
await api.post(`${BASE_URL}/${id}/unshare`, { userIds });
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get dashboard widgets
|
||||||
|
getWidgets: async (dashboardId: string): Promise<DashboardWidget[]> => {
|
||||||
|
const response = await api.get<DashboardWidget[]>(`${BASE_URL}/${dashboardId}/widgets`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Add widget to dashboard
|
||||||
|
addWidget: async (dashboardId: string, widget: CreateDashboardDto): Promise<DashboardWidget> => {
|
||||||
|
const response = await api.post<DashboardWidget>(`${BASE_URL}/${dashboardId}/widgets`, widget);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update widget
|
||||||
|
updateWidget: async (
|
||||||
|
dashboardId: string,
|
||||||
|
widgetId: string,
|
||||||
|
config: WidgetConfig
|
||||||
|
): Promise<DashboardWidget> => {
|
||||||
|
const response = await api.patch<DashboardWidget>(
|
||||||
|
`${BASE_URL}/${dashboardId}/widgets/${widgetId}`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Remove widget from dashboard
|
||||||
|
removeWidget: async (dashboardId: string, widgetId: string): Promise<void> => {
|
||||||
|
await api.delete(`${BASE_URL}/${dashboardId}/widgets/${widgetId}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get dashboard metrics
|
||||||
|
getMetrics: async (dashboardId: string, filters?: any): Promise<DashboardMetrics> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.startDate) params.append('startDate', filters.startDate);
|
||||||
|
if (filters?.endDate) params.append('endDate', filters.endDate);
|
||||||
|
if (filters?.period) params.append('period', filters.period);
|
||||||
|
|
||||||
|
const response = await api.get<DashboardMetrics>(
|
||||||
|
`${BASE_URL}/${dashboardId}/metrics?${params.toString()}`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Refresh dashboard data
|
||||||
|
refresh: async (id: string): Promise<Dashboard> => {
|
||||||
|
const response = await api.post<Dashboard>(`${BASE_URL}/${id}/refresh`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Export dashboard
|
||||||
|
export: async (id: string, format: 'json' | 'pdf' | 'png'): Promise<Blob> => {
|
||||||
|
const response = await api.get(`${BASE_URL}/${id}/export?format=${format}`, {
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Import dashboard
|
||||||
|
import: async (file: File): Promise<Dashboard> => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
const response = await api.post<Dashboard>(`${BASE_URL}/import`, formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
234
src/features/dashboard/hooks/useDashboard.ts
Normal file
234
src/features/dashboard/hooks/useDashboard.ts
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
import { useQuery, useMutation, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
|
||||||
|
import { dashboardApi } from '../api/dashboard.api';
|
||||||
|
import type {
|
||||||
|
Dashboard,
|
||||||
|
DashboardWidget,
|
||||||
|
DashboardFilters,
|
||||||
|
DashboardsResponse,
|
||||||
|
CreateDashboardDto,
|
||||||
|
UpdateDashboardDto,
|
||||||
|
WidgetConfig,
|
||||||
|
DashboardMetrics,
|
||||||
|
} from '../../shared/types/api.types';
|
||||||
|
|
||||||
|
// Query Keys
|
||||||
|
export const dashboardKeys = {
|
||||||
|
all: ['dashboard'] as const,
|
||||||
|
lists: () => [...dashboardKeys.all, 'list'] as const,
|
||||||
|
list: (filters: DashboardFilters) => [...dashboardKeys.lists(), filters] as const,
|
||||||
|
details: () => [...dashboardKeys.all, 'detail'] as const,
|
||||||
|
detail: (id: string) => [...dashboardKeys.details(), id] as const,
|
||||||
|
widgets: (id: string) => [...dashboardKeys.detail(id), 'widgets'] as const,
|
||||||
|
metrics: (id: string) => [...dashboardKeys.detail(id), 'metrics'] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Queries
|
||||||
|
export const useDashboards = (
|
||||||
|
filters?: DashboardFilters,
|
||||||
|
options?: Omit<UseQueryOptions<DashboardsResponse>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: dashboardKeys.list(filters || {}),
|
||||||
|
queryFn: () => dashboardApi.getAll(filters),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDashboard = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<Dashboard>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: dashboardKeys.detail(id),
|
||||||
|
queryFn: () => dashboardApi.getById(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDefaultDashboard = (
|
||||||
|
options?: Omit<UseQueryOptions<Dashboard>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...dashboardKeys.all, 'default'],
|
||||||
|
queryFn: () => dashboardApi.getDefault(),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDashboardWidgets = (
|
||||||
|
dashboardId: string,
|
||||||
|
options?: Omit<UseQueryOptions<DashboardWidget[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: dashboardKeys.widgets(dashboardId),
|
||||||
|
queryFn: () => dashboardApi.getWidgets(dashboardId),
|
||||||
|
enabled: !!dashboardId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDashboardMetrics = (
|
||||||
|
dashboardId: string,
|
||||||
|
filters?: any,
|
||||||
|
options?: Omit<UseQueryOptions<DashboardMetrics>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...dashboardKeys.metrics(dashboardId), filters],
|
||||||
|
queryFn: () => dashboardApi.getMetrics(dashboardId, filters),
|
||||||
|
enabled: !!dashboardId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mutations
|
||||||
|
export const useCreateDashboard = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (data: CreateDashboardDto) => dashboardApi.create(data),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateDashboard = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, data }: { id: string; data: UpdateDashboardDto }) =>
|
||||||
|
dashboardApi.update(id, data),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.lists() });
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.detail(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteDashboard = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => dashboardApi.delete(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDuplicateDashboard = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, name }: { id: string; name: string }) => dashboardApi.duplicate(id, name),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSetAsDefaultDashboard = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => dashboardApi.setAsDefault(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.lists() });
|
||||||
|
queryClient.invalidateQueries({ queryKey: [...dashboardKeys.all, 'default'] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useShareDashboard = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, userIds }: { id: string; userIds: string[] }) =>
|
||||||
|
dashboardApi.share(id, userIds),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.detail(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUnshareDashboard = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, userIds }: { id: string; userIds: string[] }) =>
|
||||||
|
dashboardApi.unshare(id, userIds),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.detail(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAddWidget = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ dashboardId, widget }: { dashboardId: string; widget: CreateDashboardDto }) =>
|
||||||
|
dashboardApi.addWidget(dashboardId, widget),
|
||||||
|
onSuccess: (_, { dashboardId }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.widgets(dashboardId) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.detail(dashboardId) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateWidget = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ dashboardId, widgetId, config }: { dashboardId: string; widgetId: string; config: WidgetConfig }) =>
|
||||||
|
dashboardApi.updateWidget(dashboardId, widgetId, config),
|
||||||
|
onSuccess: (_, { dashboardId }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.widgets(dashboardId) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.detail(dashboardId) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRemoveWidget = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ dashboardId, widgetId }: { dashboardId: string; widgetId: string }) =>
|
||||||
|
dashboardApi.removeWidget(dashboardId, widgetId),
|
||||||
|
onSuccess: (_, { dashboardId }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.widgets(dashboardId) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.detail(dashboardId) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRefreshDashboard = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => dashboardApi.refresh(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.metrics(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useExportDashboard = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, format }: { id: string; format: 'json' | 'pdf' | 'png' }) =>
|
||||||
|
dashboardApi.export(id, format),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useImportDashboard = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (file: File) => dashboardApi.import(file),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: dashboardKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
120
src/features/geolocation/api/geolocation.api.ts
Normal file
120
src/features/geolocation/api/geolocation.api.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import { api } from '@services/api/axios-instance';
|
||||||
|
import type {
|
||||||
|
Geolocation,
|
||||||
|
GeolocationFilters,
|
||||||
|
GeolocationsResponse,
|
||||||
|
CreateGeolocationDto,
|
||||||
|
UpdateGeolocationDto,
|
||||||
|
GeolocationQuery,
|
||||||
|
} from '../../shared/types/api.types';
|
||||||
|
|
||||||
|
const BASE_URL = '/api/v1/geolocation';
|
||||||
|
|
||||||
|
export const geolocationApi = {
|
||||||
|
// Get all geolocations with filters
|
||||||
|
getAll: async (filters?: GeolocationFilters): Promise<GeolocationsResponse> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.search) params.append('search', filters.search);
|
||||||
|
if (filters?.countryId) params.append('countryId', filters.countryId);
|
||||||
|
if (filters?.regionId) params.append('regionId', filters.regionId);
|
||||||
|
if (filters?.cityId) params.append('cityId', filters.cityId);
|
||||||
|
if (filters?.postalCode) params.append('postalCode', filters.postalCode);
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
if (filters?.sortBy) params.append('sortBy', filters.sortBy);
|
||||||
|
if (filters?.sortOrder) params.append('sortOrder', filters.sortOrder);
|
||||||
|
|
||||||
|
const response = await api.get<GeolocationsResponse>(`${BASE_URL}?${params.toString()}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get geolocation by ID
|
||||||
|
getById: async (id: string): Promise<Geolocation> => {
|
||||||
|
const response = await api.get<Geolocation>(`${BASE_URL}/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Create geolocation
|
||||||
|
create: async (data: CreateGeolocationDto): Promise<Geolocation> => {
|
||||||
|
const response = await api.post<Geolocation>(BASE_URL, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update geolocation
|
||||||
|
update: async (id: string, data: UpdateGeolocationDto): Promise<Geolocation> => {
|
||||||
|
const response = await api.patch<Geolocation>(`${BASE_URL}/${id}`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Delete geolocation
|
||||||
|
delete: async (id: string): Promise<void> => {
|
||||||
|
await api.delete(`${BASE_URL}/${id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Geocode address
|
||||||
|
geocode: async (query: GeolocationQuery): Promise<Geolocation[]> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (query.address) params.append('address', query.address);
|
||||||
|
if (query.postalCode) params.append('postalCode', query.postalCode);
|
||||||
|
if (query.city) params.append('city', query.city);
|
||||||
|
if (query.country) params.append('country', query.country);
|
||||||
|
if (query.limit) params.append('limit', String(query.limit));
|
||||||
|
|
||||||
|
const response = await api.get<Geolocation[]>(`${BASE_URL}/geocode?${params.toString()}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Reverse geocode (coordinates to address)
|
||||||
|
reverseGeocode: async (latitude: number, longitude: number): Promise<Geolocation> => {
|
||||||
|
const response = await api.get<Geolocation>(`${BASE_URL}/reverse?lat=${latitude}&lng=${longitude}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get countries
|
||||||
|
getCountries: async (): Promise<Geolocation[]> => {
|
||||||
|
const response = await api.get<Geolocation[]>(`${BASE_URL}/countries`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get regions/states by country
|
||||||
|
getRegions: async (countryId: string): Promise<Geolocation[]> => {
|
||||||
|
const response = await api.get<Geolocation[]>(`${BASE_URL}/countries/${countryId}/regions`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get cities by region
|
||||||
|
getCities: async (regionId: string): Promise<Geolocation[]> => {
|
||||||
|
const response = await api.get<Geolocation[]>(`${BASE_URL}/regions/${regionId}/cities`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Validate postal code
|
||||||
|
validatePostalCode: async (postalCode: string, countryId?: string): Promise<boolean> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append('postalCode', postalCode);
|
||||||
|
if (countryId) params.append('countryId', countryId);
|
||||||
|
|
||||||
|
const response = await api.get<boolean>(`${BASE_URL}/validate-postal-code?${params.toString()}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get timezone by coordinates
|
||||||
|
getTimezone: async (latitude: number, longitude: number): Promise<string> => {
|
||||||
|
const response = await api.get<string>(`${BASE_URL}/timezone?lat=${latitude}&lng=${longitude}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Calculate distance between two points
|
||||||
|
calculateDistance: async (
|
||||||
|
fromLat: number,
|
||||||
|
fromLng: number,
|
||||||
|
toLat: number,
|
||||||
|
toLng: number,
|
||||||
|
unit: 'km' | 'miles' = 'km'
|
||||||
|
): Promise<number> => {
|
||||||
|
const response = await api.get<number>(
|
||||||
|
`${BASE_URL}/distance?fromLat=${fromLat}&fromLng=${fromLng}&toLat=${toLat}&toLng=${toLng}&unit=${unit}`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
177
src/features/geolocation/hooks/useGeolocation.ts
Normal file
177
src/features/geolocation/hooks/useGeolocation.ts
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import { useQuery, useMutation, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
|
||||||
|
import { geolocationApi } from '../api/geolocation.api';
|
||||||
|
import type {
|
||||||
|
Geolocation,
|
||||||
|
GeolocationFilters,
|
||||||
|
GeolocationsResponse,
|
||||||
|
CreateGeolocationDto,
|
||||||
|
UpdateGeolocationDto,
|
||||||
|
GeolocationQuery,
|
||||||
|
} from '../types/api.types';
|
||||||
|
|
||||||
|
// Query Keys
|
||||||
|
export const geolocationKeys = {
|
||||||
|
all: ['geolocation'] as const,
|
||||||
|
lists: () => [...geolocationKeys.all, 'list'] as const,
|
||||||
|
list: (filters: GeolocationFilters) => [...geolocationKeys.lists(), filters] as const,
|
||||||
|
details: () => [...geolocationKeys.all, 'detail'] as const,
|
||||||
|
detail: (id: string) => [...geolocationKeys.details(), id] as const,
|
||||||
|
countries: () => [...geolocationKeys.all, 'countries'] as const,
|
||||||
|
regions: (countryId: string) => [...geolocationKeys.all, 'regions', countryId] as const,
|
||||||
|
cities: (regionId: string) => [...geolocationKeys.all, 'cities', regionId] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Queries
|
||||||
|
export const useGeolocations = (
|
||||||
|
filters?: GeolocationFilters,
|
||||||
|
options?: Omit<UseQueryOptions<GeolocationsResponse>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: geolocationKeys.list(filters || {}),
|
||||||
|
queryFn: () => geolocationApi.getAll(filters),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGeolocation = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<Geolocation>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: geolocationKeys.detail(id),
|
||||||
|
queryFn: () => geolocationApi.getById(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCountries = (
|
||||||
|
options?: Omit<UseQueryOptions<Geolocation[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: geolocationKeys.countries(),
|
||||||
|
queryFn: () => geolocationApi.getCountries(),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRegions = (
|
||||||
|
countryId: string,
|
||||||
|
options?: Omit<UseQueryOptions<Geolocation[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: geolocationKeys.regions(countryId),
|
||||||
|
queryFn: () => geolocationApi.getRegions(countryId),
|
||||||
|
enabled: !!countryId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCities = (
|
||||||
|
regionId: string,
|
||||||
|
options?: Omit<UseQueryOptions<Geolocation[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: geolocationKeys.cities(regionId),
|
||||||
|
queryFn: () => geolocationApi.getCities(regionId),
|
||||||
|
enabled: !!regionId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGeocode = (
|
||||||
|
query: GeolocationQuery,
|
||||||
|
options?: Omit<UseQueryOptions<Geolocation[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...geolocationKeys.all, 'geocode', query],
|
||||||
|
queryFn: () => geolocationApi.geocode(query),
|
||||||
|
enabled: !!(query.address || query.postalCode || query.city || query.country),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useReverseGeocode = (
|
||||||
|
latitude: number,
|
||||||
|
longitude: number,
|
||||||
|
options?: Omit<UseQueryOptions<Geolocation>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...geolocationKeys.all, 'reverse', latitude, longitude],
|
||||||
|
queryFn: () => geolocationApi.reverseGeocode(latitude, longitude),
|
||||||
|
enabled: !!(latitude && longitude),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useTimezone = (
|
||||||
|
latitude: number,
|
||||||
|
longitude: number,
|
||||||
|
options?: Omit<UseQueryOptions<string>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...geolocationKeys.all, 'timezone', latitude, longitude],
|
||||||
|
queryFn: () => geolocationApi.getTimezone(latitude, longitude),
|
||||||
|
enabled: !!(latitude && longitude),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDistance = (
|
||||||
|
fromLat: number,
|
||||||
|
fromLng: number,
|
||||||
|
toLat: number,
|
||||||
|
toLng: number,
|
||||||
|
unit: 'km' | 'miles' = 'km',
|
||||||
|
options?: Omit<UseQueryOptions<number>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...geolocationKeys.all, 'distance', fromLat, fromLng, toLat, toLng, unit],
|
||||||
|
queryFn: () => geolocationApi.calculateDistance(fromLat, fromLng, toLat, toLng, unit),
|
||||||
|
enabled: !!(fromLat && fromLng && toLat && toLng),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mutations
|
||||||
|
export const useCreateGeolocation = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (data: CreateGeolocationDto) => geolocationApi.create(data),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: geolocationKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateGeolocation = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, data }: { id: string; data: UpdateGeolocationDto }) =>
|
||||||
|
geolocationApi.update(id, data),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: geolocationKeys.lists() });
|
||||||
|
queryClient.invalidateQueries({ queryKey: geolocationKeys.detail(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteGeolocation = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => geolocationApi.delete(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: geolocationKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useValidatePostalCode = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ postalCode, countryId }: { postalCode: string; countryId?: string }) =>
|
||||||
|
geolocationApi.validatePostalCode(postalCode, countryId),
|
||||||
|
});
|
||||||
|
};
|
||||||
277
src/features/mcp/api/mcp.api.ts
Normal file
277
src/features/mcp/api/mcp.api.ts
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
import { api } from '@services/api/axios-instance';
|
||||||
|
import type {
|
||||||
|
McpServer,
|
||||||
|
McpTool,
|
||||||
|
McpResource,
|
||||||
|
McpPrompt,
|
||||||
|
McpFilters,
|
||||||
|
McpServersResponse,
|
||||||
|
CreateMcpServerDto,
|
||||||
|
UpdateMcpServerDto,
|
||||||
|
McpServerStatus,
|
||||||
|
McpExecutionResult,
|
||||||
|
McpToolCall,
|
||||||
|
McpResourceAccess,
|
||||||
|
} from '../../shared/types/api.types';
|
||||||
|
|
||||||
|
const BASE_URL = '/api/v1/mcp';
|
||||||
|
|
||||||
|
export const mcpApi = {
|
||||||
|
// Get all MCP servers with filters
|
||||||
|
getAll: async (filters?: McpFilters): Promise<McpServersResponse> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.search) params.append('search', filters.search);
|
||||||
|
if (filters?.status) params.append('status', filters.status);
|
||||||
|
if (filters?.protocol) params.append('protocol', filters.protocol);
|
||||||
|
if (filters?.isConnected !== undefined) params.append('isConnected', String(filters.isConnected));
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
if (filters?.sortBy) params.append('sortBy', filters.sortBy);
|
||||||
|
if (filters?.sortOrder) params.append('sortOrder', filters.sortOrder);
|
||||||
|
|
||||||
|
const response = await api.get<McpServersResponse>(`${BASE_URL}?${params.toString()}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get MCP server by ID
|
||||||
|
getById: async (id: string): Promise<McpServer> => {
|
||||||
|
const response = await api.get<McpServer>(`${BASE_URL}/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Create MCP server
|
||||||
|
create: async (data: CreateMcpServerDto): Promise<McpServer> => {
|
||||||
|
const response = await api.post<McpServer>(BASE_URL, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update MCP server
|
||||||
|
update: async (id: string, data: UpdateMcpServerDto): Promise<McpServer> => {
|
||||||
|
const response = await api.patch<McpServer>(`${BASE_URL}/${id}`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Delete MCP server
|
||||||
|
delete: async (id: string): Promise<void> => {
|
||||||
|
await api.delete(`${BASE_URL}/${id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Connect to MCP server
|
||||||
|
connect: async (id: string): Promise<McpServer> => {
|
||||||
|
const response = await api.post<McpServer>(`${BASE_URL}/${id}/connect`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Disconnect from MCP server
|
||||||
|
disconnect: async (id: string): Promise<McpServer> => {
|
||||||
|
const response = await api.post<McpServer>(`${BASE_URL}/${id}/disconnect`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get server status
|
||||||
|
getStatus: async (id: string): Promise<McpServerStatus> => {
|
||||||
|
const response = await api.get<McpServerStatus>(`${BASE_URL}/${id}/status`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get available tools for server
|
||||||
|
getTools: async (serverId: string): Promise<McpTool[]> => {
|
||||||
|
const response = await api.get<McpTool[]>(`${BASE_URL}/${serverId}/tools`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get tool details
|
||||||
|
getTool: async (serverId: string, toolName: string): Promise<McpTool> => {
|
||||||
|
const response = await api.get<McpTool>(`${BASE_URL}/${serverId}/tools/${toolName}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Execute tool
|
||||||
|
executeTool: async (
|
||||||
|
serverId: string,
|
||||||
|
toolName: string,
|
||||||
|
args: Record<string, any>
|
||||||
|
): Promise<McpExecutionResult> => {
|
||||||
|
const response = await api.post<McpExecutionResult>(
|
||||||
|
`${BASE_URL}/${serverId}/tools/${toolName}/execute`,
|
||||||
|
{ args }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get available resources for server
|
||||||
|
getResources: async (serverId: string): Promise<McpResource[]> => {
|
||||||
|
const response = await api.get<McpResource[]>(`${BASE_URL}/${serverId}/resources`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get resource details
|
||||||
|
getResource: async (serverId: string, resourceName: string): Promise<McpResource> => {
|
||||||
|
const response = await api.get<McpResource>(`${BASE_URL}/${serverId}/resources/${resourceName}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Read resource content
|
||||||
|
readResource: async (
|
||||||
|
serverId: string,
|
||||||
|
resourceName: string,
|
||||||
|
uri?: string
|
||||||
|
): Promise<{ contents: any[] }> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (uri) params.append('uri', uri);
|
||||||
|
|
||||||
|
const response = await api.get<{ contents: any[] }>(
|
||||||
|
`${BASE_URL}/${serverId}/resources/${resourceName}/read?${params.toString()}`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get available prompts for server
|
||||||
|
getPrompts: async (serverId: string): Promise<McpPrompt[]> => {
|
||||||
|
const response = await api.get<McpPrompt[]>(`${BASE_URL}/${serverId}/prompts`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get prompt details
|
||||||
|
getPrompt: async (serverId: string, promptName: string): Promise<McpPrompt> => {
|
||||||
|
const response = await api.get<McpPrompt>(`${BASE_URL}/${serverId}/prompts/${promptName}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Execute prompt
|
||||||
|
executePrompt: async (
|
||||||
|
serverId: string,
|
||||||
|
promptName: string,
|
||||||
|
args?: Record<string, any>
|
||||||
|
): Promise<{ messages: any[] }> => {
|
||||||
|
const response = await api.post<{ messages: any[] }>(
|
||||||
|
`${BASE_URL}/${serverId}/prompts/${promptName}/execute`,
|
||||||
|
{ args }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get tool execution history
|
||||||
|
getToolHistory: async (
|
||||||
|
serverId: string,
|
||||||
|
filters?: {
|
||||||
|
toolName?: string;
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
status?: 'success' | 'error';
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
): Promise<{ executions: McpToolCall[]; total: number }> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.toolName) params.append('toolName', filters.toolName);
|
||||||
|
if (filters?.startDate) params.append('startDate', filters.startDate);
|
||||||
|
if (filters?.endDate) params.append('endDate', filters.endDate);
|
||||||
|
if (filters?.status) params.append('status', filters.status);
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
|
||||||
|
const response = await api.get<{ executions: McpToolCall[]; total: number }>(
|
||||||
|
`${BASE_URL}/${serverId}/tools/history?${params.toString()}`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get resource access history
|
||||||
|
getResourceHistory: async (
|
||||||
|
serverId: string,
|
||||||
|
filters?: {
|
||||||
|
resourceName?: string;
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
): Promise<{ accesses: McpResourceAccess[]; total: number }> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.resourceName) params.append('resourceName', filters.resourceName);
|
||||||
|
if (filters?.startDate) params.append('startDate', filters.startDate);
|
||||||
|
if (filters?.endDate) params.append('endDate', filters.endDate);
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
|
||||||
|
const response = await api.get<{ accesses: McpResourceAccess[]; total: number }>(
|
||||||
|
`${BASE_URL}/${serverId}/resources/history?${params.toString()}`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Test server connection
|
||||||
|
testConnection: async (serverConfig: CreateMcpServerDto): Promise<{ success: boolean; error?: string }> => {
|
||||||
|
const response = await api.post<{ success: boolean; error?: string }>(
|
||||||
|
`${BASE_URL}/test-connection`,
|
||||||
|
serverConfig
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get server logs
|
||||||
|
getLogs: async (
|
||||||
|
id: string,
|
||||||
|
filters?: {
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
level?: 'error' | 'warn' | 'info' | 'debug';
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
): Promise<{ logs: any[]; total: number }> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.startDate) params.append('startDate', filters.startDate);
|
||||||
|
if (filters?.endDate) params.append('endDate', filters.endDate);
|
||||||
|
if (filters?.level) params.append('level', filters.level);
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
|
||||||
|
const response = await api.get<{ logs: any[]; total: number }>(
|
||||||
|
`${BASE_URL}/${id}/logs?${params.toString()}`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Restart server
|
||||||
|
restart: async (id: string): Promise<McpServer> => {
|
||||||
|
const response = await api.post<McpServer>(`${BASE_URL}/${id}/restart`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get server metrics
|
||||||
|
getMetrics: async (id: string): Promise<{
|
||||||
|
uptime: number;
|
||||||
|
totalRequests: number;
|
||||||
|
successfulRequests: number;
|
||||||
|
failedRequests: number;
|
||||||
|
averageResponseTime: number;
|
||||||
|
memoryUsage: number;
|
||||||
|
cpuUsage: number;
|
||||||
|
}> => {
|
||||||
|
const response = await api.get<any>(`${BASE_URL}/${id}/metrics`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Export server configuration
|
||||||
|
exportConfig: async (id: string): Promise<Blob> => {
|
||||||
|
const response = await api.get(`${BASE_URL}/${id}/export`, {
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Import server configuration
|
||||||
|
importConfig: async (file: File): Promise<McpServer> => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
const response = await api.post<McpServer>(`${BASE_URL}/import`, formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
363
src/features/mcp/hooks/useMcp.ts
Normal file
363
src/features/mcp/hooks/useMcp.ts
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
import { useQuery, useMutation, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
|
||||||
|
import { mcpApi } from '../api/mcp.api';
|
||||||
|
import type {
|
||||||
|
McpServer,
|
||||||
|
McpTool,
|
||||||
|
McpResource,
|
||||||
|
McpPrompt,
|
||||||
|
McpFilters,
|
||||||
|
McpServersResponse,
|
||||||
|
CreateMcpServerDto,
|
||||||
|
UpdateMcpServerDto,
|
||||||
|
McpServerStatus,
|
||||||
|
McpExecutionResult,
|
||||||
|
McpToolCall,
|
||||||
|
McpResourceAccess,
|
||||||
|
} from '../../shared/types/api.types';
|
||||||
|
|
||||||
|
// Query Keys
|
||||||
|
export const mcpKeys = {
|
||||||
|
all: ['mcp'] as const,
|
||||||
|
lists: () => [...mcpKeys.all, 'list'] as const,
|
||||||
|
list: (filters: McpFilters) => [...mcpKeys.lists(), filters] as const,
|
||||||
|
details: () => [...mcpKeys.all, 'detail'] as const,
|
||||||
|
detail: (id: string) => [...mcpKeys.details(), id] as const,
|
||||||
|
status: (id: string) => [...mcpKeys.detail(id), 'status'] as const,
|
||||||
|
tools: (serverId: string) => [...mcpKeys.detail(serverId), 'tools'] as const,
|
||||||
|
tool: (serverId: string, toolName: string) =>
|
||||||
|
[...mcpKeys.tools(serverId), toolName] as const,
|
||||||
|
resources: (serverId: string) => [...mcpKeys.detail(serverId), 'resources'] as const,
|
||||||
|
resource: (serverId: string, resourceName: string) =>
|
||||||
|
[...mcpKeys.resources(serverId), resourceName] as const,
|
||||||
|
prompts: (serverId: string) => [...mcpKeys.detail(serverId), 'prompts'] as const,
|
||||||
|
prompt: (serverId: string, promptName: string) =>
|
||||||
|
[...mcpKeys.prompts(serverId), promptName] as const,
|
||||||
|
toolHistory: (serverId: string) => [...mcpKeys.detail(serverId), 'toolHistory'] as const,
|
||||||
|
resourceHistory: (serverId: string) => [...mcpKeys.detail(serverId), 'resourceHistory'] as const,
|
||||||
|
logs: (id: string) => [...mcpKeys.detail(id), 'logs'] as const,
|
||||||
|
metrics: (id: string) => [...mcpKeys.detail(id), 'metrics'] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Queries
|
||||||
|
export const useMcpServers = (
|
||||||
|
filters?: McpFilters,
|
||||||
|
options?: Omit<UseQueryOptions<McpServersResponse>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: mcpKeys.list(filters || {}),
|
||||||
|
queryFn: () => mcpApi.getAll(filters),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpServer = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<McpServer>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: mcpKeys.detail(id),
|
||||||
|
queryFn: () => mcpApi.getById(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpServerStatus = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<McpServerStatus>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: mcpKeys.status(id),
|
||||||
|
queryFn: () => mcpApi.getStatus(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpServerTools = (
|
||||||
|
serverId: string,
|
||||||
|
options?: Omit<UseQueryOptions<McpTool[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: mcpKeys.tools(serverId),
|
||||||
|
queryFn: () => mcpApi.getTools(serverId),
|
||||||
|
enabled: !!serverId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpServerTool = (
|
||||||
|
serverId: string,
|
||||||
|
toolName: string,
|
||||||
|
options?: Omit<UseQueryOptions<McpTool>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: mcpKeys.tool(serverId, toolName),
|
||||||
|
queryFn: () => mcpApi.getTool(serverId, toolName),
|
||||||
|
enabled: !!(serverId && toolName),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpServerResources = (
|
||||||
|
serverId: string,
|
||||||
|
options?: Omit<UseQueryOptions<McpResource[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: mcpKeys.resources(serverId),
|
||||||
|
queryFn: () => mcpApi.getResources(serverId),
|
||||||
|
enabled: !!serverId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpServerResource = (
|
||||||
|
serverId: string,
|
||||||
|
resourceName: string,
|
||||||
|
options?: Omit<UseQueryOptions<McpResource>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: mcpKeys.resource(serverId, resourceName),
|
||||||
|
queryFn: () => mcpApi.getResource(serverId, resourceName),
|
||||||
|
enabled: !!(serverId && resourceName),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpServerPrompts = (
|
||||||
|
serverId: string,
|
||||||
|
options?: Omit<UseQueryOptions<McpPrompt[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: mcpKeys.prompts(serverId),
|
||||||
|
queryFn: () => mcpApi.getPrompts(serverId),
|
||||||
|
enabled: !!serverId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpServerPrompt = (
|
||||||
|
serverId: string,
|
||||||
|
promptName: string,
|
||||||
|
options?: Omit<UseQueryOptions<McpPrompt>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: mcpKeys.prompt(serverId, promptName),
|
||||||
|
queryFn: () => mcpApi.getPrompt(serverId, promptName),
|
||||||
|
enabled: !!(serverId && promptName),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpToolHistory = (
|
||||||
|
serverId: string,
|
||||||
|
filters?: {
|
||||||
|
toolName?: string;
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
status?: 'success' | 'error';
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
},
|
||||||
|
options?: Omit<UseQueryOptions<{ executions: McpToolCall[]; total: number }>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...mcpKeys.toolHistory(serverId), filters],
|
||||||
|
queryFn: () => mcpApi.getToolHistory(serverId, filters),
|
||||||
|
enabled: !!serverId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpResourceHistory = (
|
||||||
|
serverId: string,
|
||||||
|
filters?: {
|
||||||
|
resourceName?: string;
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
},
|
||||||
|
options?: Omit<UseQueryOptions<{ accesses: McpResourceAccess[]; total: number }>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...mcpKeys.resourceHistory(serverId), filters],
|
||||||
|
queryFn: () => mcpApi.getResourceHistory(serverId, filters),
|
||||||
|
enabled: !!serverId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMcpServerLogs = (
|
||||||
|
id: string,
|
||||||
|
filters?: {
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
level?: 'error' | 'warn' | 'info' | 'debug';
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
},
|
||||||
|
options?: Omit<UseQueryOptions<{ logs: any[]; total: number }>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...mcpKeys.logs(id), filters],
|
||||||
|
queryFn: () => mcpApi.getLogs(id, filters),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mutations
|
||||||
|
export const useCreateMcpServer = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (data: CreateMcpServerDto) => mcpApi.create(data),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateMcpServer = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, data }: { id: string; data: UpdateMcpServerDto }) =>
|
||||||
|
mcpApi.update(id, data),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.lists() });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.detail(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteMcpServer = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => mcpApi.delete(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useConnectMcpServer = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => mcpApi.connect(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.status(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.tools(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.resources(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.prompts(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDisconnectMcpServer = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => mcpApi.disconnect(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.status(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.tools(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.resources(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.prompts(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useExecuteMcpTool = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({
|
||||||
|
serverId,
|
||||||
|
toolName,
|
||||||
|
args
|
||||||
|
}: {
|
||||||
|
serverId: string;
|
||||||
|
toolName: string;
|
||||||
|
args: Record<string, any>;
|
||||||
|
}) => mcpApi.executeTool(serverId, toolName, args),
|
||||||
|
onSuccess: (_, { serverId }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.toolHistory(serverId) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useReadMcpResource = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({
|
||||||
|
serverId,
|
||||||
|
resourceName,
|
||||||
|
uri
|
||||||
|
}: {
|
||||||
|
serverId: string;
|
||||||
|
resourceName: string;
|
||||||
|
uri?: string;
|
||||||
|
}) => mcpApi.readResource(serverId, resourceName, uri),
|
||||||
|
onSuccess: (_, { serverId }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.resourceHistory(serverId) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useExecuteMcpPrompt = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({
|
||||||
|
serverId,
|
||||||
|
promptName,
|
||||||
|
args
|
||||||
|
}: {
|
||||||
|
serverId: string;
|
||||||
|
promptName: string;
|
||||||
|
args?: Record<string, any>;
|
||||||
|
}) => mcpApi.executePrompt(serverId, promptName, args),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useTestMcpConnection = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (serverConfig: CreateMcpServerDto) => mcpApi.testConnection(serverConfig),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRestartMcpServer = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => mcpApi.restart(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.status(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useExportMcpConfig = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => mcpApi.exportConfig(id),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useImportMcpConfig = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (file: File) => mcpApi.importConfig(file),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: mcpKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
234
src/features/payment-terminals/api/payment-terminals.api.ts
Normal file
234
src/features/payment-terminals/api/payment-terminals.api.ts
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
import { api } from '@services/api/axios-instance';
|
||||||
|
import type {
|
||||||
|
PaymentTerminal,
|
||||||
|
PaymentTerminalTransaction,
|
||||||
|
PaymentTerminalFilters,
|
||||||
|
PaymentTerminalsResponse,
|
||||||
|
CreatePaymentTerminalDto,
|
||||||
|
UpdatePaymentTerminalDto,
|
||||||
|
TerminalStatus,
|
||||||
|
TransactionStatus,
|
||||||
|
PaymentMethod,
|
||||||
|
} from '../../shared/types/api.types';
|
||||||
|
|
||||||
|
const BASE_URL = '/api/v1/payment-terminals';
|
||||||
|
|
||||||
|
export const paymentTerminalsApi = {
|
||||||
|
// Get all payment terminals with filters
|
||||||
|
getAll: async (filters?: PaymentTerminalFilters): Promise<PaymentTerminalsResponse> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.search) params.append('search', filters.search);
|
||||||
|
if (filters?.storeId) params.append('storeId', filters.storeId);
|
||||||
|
if (filters?.status) params.append('status', filters.status);
|
||||||
|
if (filters?.terminalType) params.append('terminalType', filters.terminalType);
|
||||||
|
if (filters?.paymentMethod) params.append('paymentMethod', filters.paymentMethod);
|
||||||
|
if (filters?.isActive !== undefined) params.append('isActive', String(filters.isActive));
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
if (filters?.sortBy) params.append('sortBy', filters.sortBy);
|
||||||
|
if (filters?.sortOrder) params.append('sortOrder', filters.sortOrder);
|
||||||
|
|
||||||
|
const response = await api.get<PaymentTerminalsResponse>(`${BASE_URL}?${params.toString()}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get payment terminal by ID
|
||||||
|
getById: async (id: string): Promise<PaymentTerminal> => {
|
||||||
|
const response = await api.get<PaymentTerminal>(`${BASE_URL}/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Create payment terminal
|
||||||
|
create: async (data: CreatePaymentTerminalDto): Promise<PaymentTerminal> => {
|
||||||
|
const response = await api.post<PaymentTerminal>(BASE_URL, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update payment terminal
|
||||||
|
update: async (id: string, data: UpdatePaymentTerminalDto): Promise<PaymentTerminal> => {
|
||||||
|
const response = await api.patch<PaymentTerminal>(`${BASE_URL}/${id}`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Delete payment terminal
|
||||||
|
delete: async (id: string): Promise<void> => {
|
||||||
|
await api.delete(`${BASE_URL}/${id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Activate terminal
|
||||||
|
activate: async (id: string): Promise<PaymentTerminal> => {
|
||||||
|
const response = await api.post<PaymentTerminal>(`${BASE_URL}/${id}/activate`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Deactivate terminal
|
||||||
|
deactivate: async (id: string): Promise<PaymentTerminal> => {
|
||||||
|
const response = await api.post<PaymentTerminal>(`${BASE_URL}/${id}/deactivate`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get terminal status
|
||||||
|
getStatus: async (id: string): Promise<TerminalStatus> => {
|
||||||
|
const response = await api.get<TerminalStatus>(`${BASE_URL}/${id}/status`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get terminal transactions
|
||||||
|
getTransactions: async (
|
||||||
|
terminalId: string,
|
||||||
|
filters?: {
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
status?: TransactionStatus;
|
||||||
|
paymentMethod?: PaymentMethod;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
): Promise<{ transactions: PaymentTerminalTransaction[]; total: number }> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.startDate) params.append('startDate', filters.startDate);
|
||||||
|
if (filters?.endDate) params.append('endDate', filters.endDate);
|
||||||
|
if (filters?.status) params.append('status', filters.status);
|
||||||
|
if (filters?.paymentMethod) params.append('paymentMethod', filters.paymentMethod);
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
|
||||||
|
const response = await api.get<{ transactions: PaymentTerminalTransaction[]; total: number }>(
|
||||||
|
`${BASE_URL}/${terminalId}/transactions?${params.toString()}`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Process payment through terminal
|
||||||
|
processPayment: async (
|
||||||
|
terminalId: string,
|
||||||
|
paymentData: {
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
paymentMethod: PaymentMethod;
|
||||||
|
reference?: string;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
): Promise<PaymentTerminalTransaction> => {
|
||||||
|
const response = await api.post<PaymentTerminalTransaction>(
|
||||||
|
`${BASE_URL}/${terminalId}/process-payment`,
|
||||||
|
paymentData
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Refund transaction
|
||||||
|
refundTransaction: async (
|
||||||
|
terminalId: string,
|
||||||
|
transactionId: string,
|
||||||
|
amount?: number,
|
||||||
|
reason?: string
|
||||||
|
): Promise<PaymentTerminalTransaction> => {
|
||||||
|
const response = await api.post<PaymentTerminalTransaction>(
|
||||||
|
`${BASE_URL}/${terminalId}/transactions/${transactionId}/refund`,
|
||||||
|
{ amount, reason }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Void transaction
|
||||||
|
voidTransaction: async (
|
||||||
|
terminalId: string,
|
||||||
|
transactionId: string,
|
||||||
|
reason?: string
|
||||||
|
): Promise<PaymentTerminalTransaction> => {
|
||||||
|
const response = await api.post<PaymentTerminalTransaction>(
|
||||||
|
`${BASE_URL}/${terminalId}/transactions/${transactionId}/void`,
|
||||||
|
{ reason }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get transaction by ID
|
||||||
|
getTransaction: async (
|
||||||
|
terminalId: string,
|
||||||
|
transactionId: string
|
||||||
|
): Promise<PaymentTerminalTransaction> => {
|
||||||
|
const response = await api.get<PaymentTerminalTransaction>(
|
||||||
|
`${BASE_URL}/${terminalId}/transactions/${transactionId}`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Sync terminal with provider
|
||||||
|
sync: async (id: string): Promise<PaymentTerminal> => {
|
||||||
|
const response = await api.post<PaymentTerminal>(`${BASE_URL}/${id}/sync`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get terminal configuration
|
||||||
|
getConfig: async (id: string): Promise<any> => {
|
||||||
|
const response = await api.get<any>(`${BASE_URL}/${id}/config`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update terminal configuration
|
||||||
|
updateConfig: async (id: string, config: any): Promise<PaymentTerminal> => {
|
||||||
|
const response = await api.patch<PaymentTerminal>(`${BASE_URL}/${id}/config`, config);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get terminal health check
|
||||||
|
healthCheck: async (id: string): Promise<{ healthy: boolean; issues: string[] }> => {
|
||||||
|
const response = await api.get<{ healthy: boolean; issues: string[] }>(
|
||||||
|
`${BASE_URL}/${id}/health-check`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Reboot terminal
|
||||||
|
reboot: async (id: string): Promise<void> => {
|
||||||
|
await api.post(`${BASE_URL}/${id}/reboot`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get terminal logs
|
||||||
|
getLogs: async (
|
||||||
|
id: string,
|
||||||
|
filters?: {
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
level?: 'error' | 'warn' | 'info' | 'debug';
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
): Promise<{ logs: any[]; total: number }> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.startDate) params.append('startDate', filters.startDate);
|
||||||
|
if (filters?.endDate) params.append('endDate', filters.endDate);
|
||||||
|
if (filters?.level) params.append('level', filters.level);
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
|
||||||
|
const response = await api.get<{ logs: any[]; total: number }>(
|
||||||
|
`${BASE_URL}/${id}/logs?${params.toString()}`
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Export transactions
|
||||||
|
exportTransactions: async (
|
||||||
|
terminalId: string,
|
||||||
|
format: 'json' | 'csv' | 'pdf',
|
||||||
|
filters?: {
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
status?: TransactionStatus;
|
||||||
|
}
|
||||||
|
): Promise<Blob> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append('format', format);
|
||||||
|
if (filters?.startDate) params.append('startDate', filters.startDate);
|
||||||
|
if (filters?.endDate) params.append('endDate', filters.endDate);
|
||||||
|
if (filters?.status) params.append('status', filters.status);
|
||||||
|
|
||||||
|
const response = await api.get(`${BASE_URL}/${terminalId}/transactions/export?${params.toString()}`, {
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
331
src/features/payment-terminals/hooks/usePaymentTerminals.ts
Normal file
331
src/features/payment-terminals/hooks/usePaymentTerminals.ts
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
import { useQuery, useMutation, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
|
||||||
|
import { paymentTerminalsApi } from '../api/payment-terminals.api';
|
||||||
|
import type {
|
||||||
|
PaymentTerminal,
|
||||||
|
PaymentTerminalTransaction,
|
||||||
|
PaymentTerminalFilters,
|
||||||
|
PaymentTerminalsResponse,
|
||||||
|
CreatePaymentTerminalDto,
|
||||||
|
UpdatePaymentTerminalDto,
|
||||||
|
TerminalStatus,
|
||||||
|
TransactionStatus,
|
||||||
|
PaymentMethod,
|
||||||
|
} from '../../shared/types/api.types';
|
||||||
|
|
||||||
|
// Query Keys
|
||||||
|
export const paymentTerminalsKeys = {
|
||||||
|
all: ['payment-terminals'] as const,
|
||||||
|
lists: () => [...paymentTerminalsKeys.all, 'list'] as const,
|
||||||
|
list: (filters: PaymentTerminalFilters) => [...paymentTerminalsKeys.lists(), filters] as const,
|
||||||
|
details: () => [...paymentTerminalsKeys.all, 'detail'] as const,
|
||||||
|
detail: (id: string) => [...paymentTerminalsKeys.details(), id] as const,
|
||||||
|
transactions: (terminalId: string) => [...paymentTerminalsKeys.detail(terminalId), 'transactions'] as const,
|
||||||
|
transaction: (terminalId: string, transactionId: string) =>
|
||||||
|
[...paymentTerminalsKeys.transactions(terminalId), transactionId] as const,
|
||||||
|
status: (id: string) => [...paymentTerminalsKeys.detail(id), 'status'] as const,
|
||||||
|
config: (id: string) => [...paymentTerminalsKeys.detail(id), 'config'] as const,
|
||||||
|
logs: (id: string) => [...paymentTerminalsKeys.detail(id), 'logs'] as const,
|
||||||
|
metrics: (id: string) => [...paymentTerminalsKeys.detail(id), 'metrics'] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Queries
|
||||||
|
export const usePaymentTerminals = (
|
||||||
|
filters?: PaymentTerminalFilters,
|
||||||
|
options?: Omit<UseQueryOptions<PaymentTerminalsResponse>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: paymentTerminalsKeys.list(filters || {}),
|
||||||
|
queryFn: () => paymentTerminalsApi.getAll(filters),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentTerminal = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<PaymentTerminal>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: paymentTerminalsKeys.detail(id),
|
||||||
|
queryFn: () => paymentTerminalsApi.getById(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentTerminalTransactions = (
|
||||||
|
terminalId: string,
|
||||||
|
filters?: {
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
status?: TransactionStatus;
|
||||||
|
paymentMethod?: PaymentMethod;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
},
|
||||||
|
options?: Omit<UseQueryOptions<{ transactions: PaymentTerminalTransaction[]; total: number }>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...paymentTerminalsKeys.transactions(terminalId), filters],
|
||||||
|
queryFn: () => paymentTerminalsApi.getTransactions(terminalId, filters),
|
||||||
|
enabled: !!terminalId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentTerminalTransaction = (
|
||||||
|
terminalId: string,
|
||||||
|
transactionId: string,
|
||||||
|
options?: Omit<UseQueryOptions<PaymentTerminalTransaction>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: paymentTerminalsKeys.transaction(terminalId, transactionId),
|
||||||
|
queryFn: () => paymentTerminalsApi.getTransaction(terminalId, transactionId),
|
||||||
|
enabled: !!(terminalId && transactionId),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentTerminalStatus = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<TerminalStatus>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: paymentTerminalsKeys.status(id),
|
||||||
|
queryFn: () => paymentTerminalsApi.getStatus(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentTerminalConfig = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: paymentTerminalsKeys.config(id),
|
||||||
|
queryFn: () => paymentTerminalsApi.getConfig(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentTerminalHealthCheck = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<{ healthy: boolean; issues: string[] }>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...paymentTerminalsKeys.detail(id), 'health'],
|
||||||
|
queryFn: () => paymentTerminalsApi.healthCheck(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentTerminalLogs = (
|
||||||
|
id: string,
|
||||||
|
filters?: {
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
level?: 'error' | 'warn' | 'info' | 'debug';
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
},
|
||||||
|
options?: Omit<UseQueryOptions<{ logs: any[]; total: number }>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...paymentTerminalsKeys.logs(id), filters],
|
||||||
|
queryFn: () => paymentTerminalsApi.getLogs(id, filters),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePaymentTerminalMetrics = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: paymentTerminalsKeys.metrics(id),
|
||||||
|
queryFn: () => paymentTerminalsApi.getMetrics(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mutations
|
||||||
|
export const useCreatePaymentTerminal = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (data: CreatePaymentTerminalDto) => paymentTerminalsApi.create(data),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdatePaymentTerminal = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, data }: { id: string; data: UpdatePaymentTerminalDto }) =>
|
||||||
|
paymentTerminalsApi.update(id, data),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.lists() });
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.detail(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeletePaymentTerminal = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => paymentTerminalsApi.delete(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useActivatePaymentTerminal = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => paymentTerminalsApi.activate(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeactivatePaymentTerminal = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => paymentTerminalsApi.deactivate(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useProcessPayment = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({
|
||||||
|
terminalId,
|
||||||
|
paymentData
|
||||||
|
}: {
|
||||||
|
terminalId: string;
|
||||||
|
paymentData: {
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
paymentMethod: PaymentMethod;
|
||||||
|
reference?: string;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
};
|
||||||
|
}) => paymentTerminalsApi.processPayment(terminalId, paymentData),
|
||||||
|
onSuccess: (_, { terminalId }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.transactions(terminalId) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRefundTransaction = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({
|
||||||
|
terminalId,
|
||||||
|
transactionId,
|
||||||
|
amount,
|
||||||
|
reason
|
||||||
|
}: {
|
||||||
|
terminalId: string;
|
||||||
|
transactionId: string;
|
||||||
|
amount?: number;
|
||||||
|
reason?: string;
|
||||||
|
}) => paymentTerminalsApi.refundTransaction(terminalId, transactionId, amount, reason),
|
||||||
|
onSuccess: (_, { terminalId }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.transactions(terminalId) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useVoidTransaction = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({
|
||||||
|
terminalId,
|
||||||
|
transactionId,
|
||||||
|
reason
|
||||||
|
}: {
|
||||||
|
terminalId: string;
|
||||||
|
transactionId: string;
|
||||||
|
reason?: string;
|
||||||
|
}) => paymentTerminalsApi.voidTransaction(terminalId, transactionId, reason),
|
||||||
|
onSuccess: (_, { terminalId }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.transactions(terminalId) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSyncPaymentTerminal = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => paymentTerminalsApi.sync(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.status(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdatePaymentTerminalConfig = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, config }: { id: string; config: any }) =>
|
||||||
|
paymentTerminalsApi.updateConfig(id, config),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.config(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRebootPaymentTerminal = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => paymentTerminalsApi.reboot(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: paymentTerminalsKeys.status(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useExportTransactions = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({
|
||||||
|
terminalId,
|
||||||
|
format,
|
||||||
|
filters
|
||||||
|
}: {
|
||||||
|
terminalId: string;
|
||||||
|
format: 'json' | 'csv' | 'pdf';
|
||||||
|
filters?: {
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
status?: TransactionStatus;
|
||||||
|
};
|
||||||
|
}) => paymentTerminalsApi.exportTransactions(terminalId, format, filters),
|
||||||
|
});
|
||||||
|
};
|
||||||
188
src/features/scanning/api/scanning.api.ts
Normal file
188
src/features/scanning/api/scanning.api.ts
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
import { api } from '@services/api/axios-instance';
|
||||||
|
import type {
|
||||||
|
ScanningSession,
|
||||||
|
ScanningDevice,
|
||||||
|
ScanningResult,
|
||||||
|
ScanningFilters,
|
||||||
|
ScanningSessionsResponse,
|
||||||
|
CreateScanningSessionDto,
|
||||||
|
UpdateScanningSessionDto,
|
||||||
|
ScanningConfig,
|
||||||
|
ScanningTemplate,
|
||||||
|
} from '../../shared/types/api.types';
|
||||||
|
|
||||||
|
const BASE_URL = '/api/v1/scanning';
|
||||||
|
|
||||||
|
export const scanningApi = {
|
||||||
|
// Get all scanning sessions with filters
|
||||||
|
getAll: async (filters?: ScanningFilters): Promise<ScanningSessionsResponse> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (filters?.search) params.append('search', filters.search);
|
||||||
|
if (filters?.deviceId) params.append('deviceId', filters.deviceId);
|
||||||
|
if (filters?.status) params.append('status', filters.status);
|
||||||
|
if (filters?.userId) params.append('userId', filters.userId);
|
||||||
|
if (filters?.startDate) params.append('startDate', filters.startDate);
|
||||||
|
if (filters?.endDate) params.append('endDate', filters.endDate);
|
||||||
|
if (filters?.page) params.append('page', String(filters.page));
|
||||||
|
if (filters?.limit) params.append('limit', String(filters.limit));
|
||||||
|
if (filters?.sortBy) params.append('sortBy', filters.sortBy);
|
||||||
|
if (filters?.sortOrder) params.append('sortOrder', filters.sortOrder);
|
||||||
|
|
||||||
|
const response = await api.get<ScanningSessionsResponse>(`${BASE_URL}?${params.toString()}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get scanning session by ID
|
||||||
|
getById: async (id: string): Promise<ScanningSession> => {
|
||||||
|
const response = await api.get<ScanningSession>(`${BASE_URL}/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Create scanning session
|
||||||
|
create: async (data: CreateScanningSessionDto): Promise<ScanningSession> => {
|
||||||
|
const response = await api.post<ScanningSession>(BASE_URL, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update scanning session
|
||||||
|
update: async (id: string, data: UpdateScanningSessionDto): Promise<ScanningSession> => {
|
||||||
|
const response = await api.patch<ScanningSession>(`${BASE_URL}/${id}`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Delete scanning session
|
||||||
|
delete: async (id: string): Promise<void> => {
|
||||||
|
await api.delete(`${BASE_URL}/${id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Start scanning session
|
||||||
|
start: async (id: string): Promise<ScanningSession> => {
|
||||||
|
const response = await api.post<ScanningSession>(`${BASE_URL}/${id}/start`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Pause scanning session
|
||||||
|
pause: async (id: string): Promise<ScanningSession> => {
|
||||||
|
const response = await api.post<ScanningSession>(`${BASE_URL}/${id}/pause`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Resume scanning session
|
||||||
|
resume: async (id: string): Promise<ScanningSession> => {
|
||||||
|
const response = await api.post<ScanningSession>(`${BASE_URL}/${id}/resume`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Stop scanning session
|
||||||
|
stop: async (id: string): Promise<ScanningSession> => {
|
||||||
|
const response = await api.post<ScanningSession>(`${BASE_URL}/${id}/stop`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get scanning results for session
|
||||||
|
getResults: async (sessionId: string): Promise<ScanningResult[]> => {
|
||||||
|
const response = await api.get<ScanningResult[]>(`${BASE_URL}/${sessionId}/results`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get scanning devices
|
||||||
|
getDevices: async (): Promise<ScanningDevice[]> => {
|
||||||
|
const response = await api.get<ScanningDevice[]>(`${BASE_URL}/devices`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get device by ID
|
||||||
|
getDevice: async (id: string): Promise<ScanningDevice> => {
|
||||||
|
const response = await api.get<ScanningDevice>(`${BASE_URL}/devices/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Register scanning device
|
||||||
|
registerDevice: async (device: Partial<ScanningDevice>): Promise<ScanningDevice> => {
|
||||||
|
const response = await api.post<ScanningDevice>(`${BASE_URL}/devices`, device);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update device
|
||||||
|
updateDevice: async (id: string, device: Partial<ScanningDevice>): Promise<ScanningDevice> => {
|
||||||
|
const response = await api.patch<ScanningDevice>(`${BASE_URL}/devices/${id}`, device);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Remove device
|
||||||
|
removeDevice: async (id: string): Promise<void> => {
|
||||||
|
await api.delete(`${BASE_URL}/devices/${id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get scanning templates
|
||||||
|
getTemplates: async (): Promise<ScanningTemplate[]> => {
|
||||||
|
const response = await api.get<ScanningTemplate[]>(`${BASE_URL}/templates`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get template by ID
|
||||||
|
getTemplate: async (id: string): Promise<ScanningTemplate> => {
|
||||||
|
const response = await api.get<ScanningTemplate>(`${BASE_URL}/templates/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Create scanning template
|
||||||
|
createTemplate: async (template: Partial<ScanningTemplate>): Promise<ScanningTemplate> => {
|
||||||
|
const response = await api.post<ScanningTemplate>(`${BASE_URL}/templates`, template);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update template
|
||||||
|
updateTemplate: async (id: string, template: Partial<ScanningTemplate>): Promise<ScanningTemplate> => {
|
||||||
|
const response = await api.patch<ScanningTemplate>(`${BASE_URL}/templates/${id}`, template);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Delete template
|
||||||
|
deleteTemplate: async (id: string): Promise<void> => {
|
||||||
|
await api.delete(`${BASE_URL}/templates/${id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Get scanning configuration
|
||||||
|
getConfig: async (): Promise<ScanningConfig> => {
|
||||||
|
const response = await api.get<ScanningConfig>(`${BASE_URL}/config`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update scanning configuration
|
||||||
|
updateConfig: async (config: Partial<ScanningConfig>): Promise<ScanningConfig> => {
|
||||||
|
const response = await api.patch<ScanningConfig>(`${BASE_URL}/config`, config);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Export scanning results
|
||||||
|
exportResults: async (sessionId: string, format: 'json' | 'csv' | 'pdf'): Promise<Blob> => {
|
||||||
|
const response = await api.get(`${BASE_URL}/${sessionId}/export?format=${format}`, {
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Import scanning data
|
||||||
|
importData: async (file: File, sessionId?: string): Promise<ScanningResult[]> => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
if (sessionId) formData.append('sessionId', sessionId);
|
||||||
|
|
||||||
|
const response = await api.post<ScanningResult[]>(`${BASE_URL}/import`, formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Validate scanned data
|
||||||
|
validateData: async (data: any, templateId: string): Promise<{ valid: boolean; errors: string[] }> => {
|
||||||
|
const response = await api.post<{ valid: boolean; errors: string[] }>(
|
||||||
|
`${BASE_URL}/validate`,
|
||||||
|
{ data, templateId }
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
311
src/features/scanning/hooks/useScanning.ts
Normal file
311
src/features/scanning/hooks/useScanning.ts
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
import { useQuery, useMutation, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
|
||||||
|
import { scanningApi } from '../api/scanning.api';
|
||||||
|
import type {
|
||||||
|
ScanningSession,
|
||||||
|
ScanningDevice,
|
||||||
|
ScanningResult,
|
||||||
|
ScanningFilters,
|
||||||
|
ScanningSessionsResponse,
|
||||||
|
CreateScanningSessionDto,
|
||||||
|
UpdateScanningSessionDto,
|
||||||
|
ScanningConfig,
|
||||||
|
ScanningTemplate,
|
||||||
|
DeviceStatus,
|
||||||
|
ScanningStatus,
|
||||||
|
} from '../../shared/types/api.types';
|
||||||
|
|
||||||
|
// Query Keys
|
||||||
|
export const scanningKeys = {
|
||||||
|
all: ['scanning'] as const,
|
||||||
|
lists: () => [...scanningKeys.all, 'list'] as const,
|
||||||
|
list: (filters: ScanningFilters) => [...scanningKeys.lists(), filters] as const,
|
||||||
|
details: () => [...scanningKeys.all, 'detail'] as const,
|
||||||
|
detail: (id: string) => [...scanningKeys.details(), id] as const,
|
||||||
|
devices: () => [...scanningKeys.all, 'devices'] as const,
|
||||||
|
device: (id: string) => [...scanningKeys.devices(), id] as const,
|
||||||
|
templates: () => [...scanningKeys.all, 'templates'] as const,
|
||||||
|
template: (id: string) => [...scanningKeys.templates(), id] as const,
|
||||||
|
results: (sessionId: string) => [...scanningKeys.detail(sessionId), 'results'] as const,
|
||||||
|
config: () => [...scanningKeys.all, 'config'] as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Queries
|
||||||
|
export const useScanningSessions = (
|
||||||
|
filters?: ScanningFilters,
|
||||||
|
options?: Omit<UseQueryOptions<ScanningSessionsResponse>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: scanningKeys.list(filters || {}),
|
||||||
|
queryFn: () => scanningApi.getAll(filters),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useScanningSession = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<ScanningSession>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: scanningKeys.detail(id),
|
||||||
|
queryFn: () => scanningApi.getById(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useScanningDevices = (
|
||||||
|
options?: Omit<UseQueryOptions<ScanningDevice[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: scanningKeys.devices(),
|
||||||
|
queryFn: () => scanningApi.getDevices(),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useScanningDevice = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<ScanningDevice>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: scanningKeys.device(id),
|
||||||
|
queryFn: () => scanningApi.getDevice(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useScanningTemplates = (
|
||||||
|
options?: Omit<UseQueryOptions<ScanningTemplate[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: scanningKeys.templates(),
|
||||||
|
queryFn: () => scanningApi.getTemplates(),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useScanningTemplate = (
|
||||||
|
id: string,
|
||||||
|
options?: Omit<UseQueryOptions<ScanningTemplate>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: scanningKeys.template(id),
|
||||||
|
queryFn: () => scanningApi.getTemplate(id),
|
||||||
|
enabled: !!id,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useScanningResults = (
|
||||||
|
sessionId: string,
|
||||||
|
options?: Omit<UseQueryOptions<ScanningResult[]>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: scanningKeys.results(sessionId),
|
||||||
|
queryFn: () => scanningApi.getResults(sessionId),
|
||||||
|
enabled: !!sessionId,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useScanningConfig = (
|
||||||
|
options?: Omit<UseQueryOptions<ScanningConfig>, 'queryKey' | 'queryFn'>
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: scanningKeys.config(),
|
||||||
|
queryFn: () => scanningApi.getConfig(),
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mutations
|
||||||
|
export const useCreateScanningSession = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (data: CreateScanningSessionDto) => scanningApi.create(data),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateScanningSession = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, data }: { id: string; data: UpdateScanningSessionDto }) =>
|
||||||
|
scanningApi.update(id, data),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.lists() });
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.detail(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteScanningSession = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => scanningApi.delete(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useStartScanningSession = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => scanningApi.start(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.lists() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePauseScanningSession = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => scanningApi.pause(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.detail(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useResumeScanningSession = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => scanningApi.resume(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.detail(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useStopScanningSession = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => scanningApi.stop(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.detail(id) });
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.results(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRegisterScanningDevice = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (device: Partial<ScanningDevice>) => scanningApi.registerDevice(device),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.devices() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateScanningDevice = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, device }: { id: string; device: Partial<ScanningDevice> }) =>
|
||||||
|
scanningApi.updateDevice(id, device),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.devices() });
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.device(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRemoveScanningDevice = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => scanningApi.removeDevice(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.devices() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCreateScanningTemplate = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (template: Partial<ScanningTemplate>) => scanningApi.createTemplate(template),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.templates() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateScanningTemplate = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, template }: { id: string; template: Partial<ScanningTemplate> }) =>
|
||||||
|
scanningApi.updateTemplate(id, template),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.templates() });
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.template(id) });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteScanningTemplate = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => scanningApi.deleteTemplate(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.templates() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateScanningConfig = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (config: Partial<ScanningConfig>) => scanningApi.updateConfig(config),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.config() });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useExportScanningResults = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ sessionId, format }: { sessionId: string; format: 'json' | 'csv' | 'pdf' }) =>
|
||||||
|
scanningApi.exportResults(sessionId, format),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useImportScanningData = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ file, sessionId }: { file: File; sessionId?: string }) =>
|
||||||
|
scanningApi.importData(file, sessionId),
|
||||||
|
onSuccess: (_, { sessionId }) => {
|
||||||
|
if (sessionId) {
|
||||||
|
queryClient.invalidateQueries({ queryKey: scanningKeys.results(sessionId) });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useValidateScanningData = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ data, templateId }: { data: any; templateId: string }) =>
|
||||||
|
scanningApi.validateData(data, templateId),
|
||||||
|
});
|
||||||
|
};
|
||||||
561
src/features/shared/types/api.types.ts
Normal file
561
src/features/shared/types/api.types.ts
Normal file
@ -0,0 +1,561 @@
|
|||||||
|
// Geolocation Types
|
||||||
|
export interface Geolocation {
|
||||||
|
id: string;
|
||||||
|
country: string;
|
||||||
|
countryCode: string;
|
||||||
|
region?: string;
|
||||||
|
regionCode?: string;
|
||||||
|
city?: string;
|
||||||
|
postalCode?: string;
|
||||||
|
latitude?: number;
|
||||||
|
longitude?: number;
|
||||||
|
timezone?: string;
|
||||||
|
isActive: boolean;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeolocationFilters {
|
||||||
|
search?: string;
|
||||||
|
countryId?: string;
|
||||||
|
regionId?: string;
|
||||||
|
cityId?: string;
|
||||||
|
postalCode?: string;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
sortBy?: string;
|
||||||
|
sortOrder?: 'asc' | 'desc';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeolocationsResponse {
|
||||||
|
data: Geolocation[];
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateGeolocationDto {
|
||||||
|
country: string;
|
||||||
|
countryCode: string;
|
||||||
|
region?: string;
|
||||||
|
regionCode?: string;
|
||||||
|
city?: string;
|
||||||
|
postalCode?: string;
|
||||||
|
latitude?: number;
|
||||||
|
longitude?: number;
|
||||||
|
timezone?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateGeolocationDto {
|
||||||
|
country?: string;
|
||||||
|
countryCode?: string;
|
||||||
|
region?: string;
|
||||||
|
regionCode?: string;
|
||||||
|
city?: string;
|
||||||
|
postalCode?: string;
|
||||||
|
latitude?: number;
|
||||||
|
longitude?: number;
|
||||||
|
timezone?: string;
|
||||||
|
isActive?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeolocationQuery {
|
||||||
|
address?: string;
|
||||||
|
postalCode?: string;
|
||||||
|
city?: string;
|
||||||
|
country?: string;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dashboard Types
|
||||||
|
export interface Dashboard {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
userId: string;
|
||||||
|
isDefault: boolean;
|
||||||
|
isPublic: boolean;
|
||||||
|
layout: DashboardLayout;
|
||||||
|
widgets: DashboardWidget[];
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DashboardLayout {
|
||||||
|
columns: number;
|
||||||
|
gap: number;
|
||||||
|
breakpoints: {
|
||||||
|
lg: number;
|
||||||
|
md: number;
|
||||||
|
sm: number;
|
||||||
|
xs: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DashboardWidget {
|
||||||
|
id: string;
|
||||||
|
dashboardId: string;
|
||||||
|
type: WidgetType;
|
||||||
|
title: string;
|
||||||
|
config: WidgetConfig;
|
||||||
|
position: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
};
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type WidgetType =
|
||||||
|
| 'chart'
|
||||||
|
| 'metric'
|
||||||
|
| 'table'
|
||||||
|
| 'list'
|
||||||
|
| 'calendar'
|
||||||
|
| 'map'
|
||||||
|
| 'text'
|
||||||
|
| 'image'
|
||||||
|
| 'iframe';
|
||||||
|
|
||||||
|
export interface WidgetConfig {
|
||||||
|
[key: string]: any;
|
||||||
|
dataSource?: string;
|
||||||
|
refreshInterval?: number;
|
||||||
|
filters?: Record<string, any>;
|
||||||
|
chartType?: 'line' | 'bar' | 'pie' | 'area' | 'scatter';
|
||||||
|
metricConfig?: {
|
||||||
|
label: string;
|
||||||
|
format: string;
|
||||||
|
showTrend: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DashboardFilters {
|
||||||
|
search?: string;
|
||||||
|
userId?: string;
|
||||||
|
isDefault?: boolean;
|
||||||
|
isPublic?: boolean;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
sortBy?: string;
|
||||||
|
sortOrder?: 'asc' | 'desc';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DashboardsResponse {
|
||||||
|
data: Dashboard[];
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateDashboardDto {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
isDefault?: boolean;
|
||||||
|
isPublic?: boolean;
|
||||||
|
layout?: DashboardLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateDashboardDto {
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
isDefault?: boolean;
|
||||||
|
isPublic?: boolean;
|
||||||
|
layout?: DashboardLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DashboardMetrics {
|
||||||
|
totalWidgets: number;
|
||||||
|
activeWidgets: number;
|
||||||
|
lastUpdated: string;
|
||||||
|
refreshRate: number;
|
||||||
|
dataPoints: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scanning Types
|
||||||
|
export interface ScanningSession {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
deviceId: string;
|
||||||
|
userId: string;
|
||||||
|
status: ScanningStatus;
|
||||||
|
templateId?: string;
|
||||||
|
config: ScanningConfig;
|
||||||
|
results: ScanningResult[];
|
||||||
|
startedAt?: string;
|
||||||
|
pausedAt?: string;
|
||||||
|
stoppedAt?: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ScanningStatus =
|
||||||
|
| 'idle'
|
||||||
|
| 'scanning'
|
||||||
|
| 'paused'
|
||||||
|
| 'completed'
|
||||||
|
| 'error'
|
||||||
|
| 'cancelled';
|
||||||
|
|
||||||
|
export interface ScanningDevice {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
model: string;
|
||||||
|
serialNumber?: string;
|
||||||
|
ipAddress?: string;
|
||||||
|
port?: number;
|
||||||
|
protocol: string;
|
||||||
|
config: Record<string, any>;
|
||||||
|
status: DeviceStatus;
|
||||||
|
lastSeen?: string;
|
||||||
|
isActive: boolean;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DeviceStatus =
|
||||||
|
| 'online'
|
||||||
|
| 'offline'
|
||||||
|
| 'error'
|
||||||
|
| 'maintenance';
|
||||||
|
|
||||||
|
export interface ScanningResult {
|
||||||
|
id: string;
|
||||||
|
sessionId: string;
|
||||||
|
scanIndex: number;
|
||||||
|
data: Record<string, any>;
|
||||||
|
isValid: boolean;
|
||||||
|
errors?: string[];
|
||||||
|
warnings?: string[];
|
||||||
|
scannedAt: string;
|
||||||
|
processedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScanningFilters {
|
||||||
|
search?: string;
|
||||||
|
deviceId?: string;
|
||||||
|
status?: ScanningStatus;
|
||||||
|
userId?: string;
|
||||||
|
startDate?: string;
|
||||||
|
endDate?: string;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
sortBy?: string;
|
||||||
|
sortOrder?: 'asc' | 'desc';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScanningSessionsResponse {
|
||||||
|
data: ScanningSession[];
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateScanningSessionDto {
|
||||||
|
name: string;
|
||||||
|
deviceId: string;
|
||||||
|
templateId?: string;
|
||||||
|
config?: ScanningConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateScanningSessionDto {
|
||||||
|
name?: string;
|
||||||
|
deviceId?: string;
|
||||||
|
templateId?: string;
|
||||||
|
config?: ScanningConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScanningConfig {
|
||||||
|
scanInterval: number;
|
||||||
|
batchSize: number;
|
||||||
|
maxRetries: number;
|
||||||
|
timeout: number;
|
||||||
|
validationRules: ValidationRule[];
|
||||||
|
outputFormat: 'json' | 'xml' | 'csv';
|
||||||
|
compression: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ValidationRule {
|
||||||
|
field: string;
|
||||||
|
type: 'required' | 'format' | 'range' | 'custom';
|
||||||
|
value?: any;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScanningTemplate {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
fields: TemplateField[];
|
||||||
|
config: ScanningConfig;
|
||||||
|
isActive: boolean;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TemplateField {
|
||||||
|
name: string;
|
||||||
|
type: 'string' | 'number' | 'boolean' | 'date' | 'object' | 'array';
|
||||||
|
required: boolean;
|
||||||
|
validation?: ValidationRule[];
|
||||||
|
defaultValue?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payment Terminals Types
|
||||||
|
export interface PaymentTerminal {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
storeId: string;
|
||||||
|
terminalType: string;
|
||||||
|
serialNumber: string;
|
||||||
|
model: string;
|
||||||
|
manufacturer: string;
|
||||||
|
ipAddress?: string;
|
||||||
|
port?: number;
|
||||||
|
paymentMethods: PaymentMethod[];
|
||||||
|
status: TerminalStatus;
|
||||||
|
isActive: boolean;
|
||||||
|
config: PaymentTerminalConfig;
|
||||||
|
lastHeartbeat?: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TerminalStatus =
|
||||||
|
| 'online'
|
||||||
|
| 'offline'
|
||||||
|
| 'error'
|
||||||
|
| 'maintenance'
|
||||||
|
| 'initializing';
|
||||||
|
|
||||||
|
export type PaymentMethod =
|
||||||
|
| 'credit_card'
|
||||||
|
| 'debit_card'
|
||||||
|
| 'cash'
|
||||||
|
| 'mobile_payment'
|
||||||
|
| 'bank_transfer'
|
||||||
|
| 'check'
|
||||||
|
| 'cryptocurrency';
|
||||||
|
|
||||||
|
export interface PaymentTerminalTransaction {
|
||||||
|
id: string;
|
||||||
|
terminalId: string;
|
||||||
|
amount: number;
|
||||||
|
currency: string;
|
||||||
|
paymentMethod: PaymentMethod;
|
||||||
|
status: TransactionStatus;
|
||||||
|
reference?: string;
|
||||||
|
authorizationCode?: string;
|
||||||
|
errorCode?: string;
|
||||||
|
errorMessage?: string;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TransactionStatus =
|
||||||
|
| 'pending'
|
||||||
|
| 'approved'
|
||||||
|
| 'declined'
|
||||||
|
| 'cancelled'
|
||||||
|
| 'refunded'
|
||||||
|
| 'voided'
|
||||||
|
| 'error';
|
||||||
|
|
||||||
|
export interface PaymentTerminalFilters {
|
||||||
|
search?: string;
|
||||||
|
storeId?: string;
|
||||||
|
status?: TerminalStatus;
|
||||||
|
terminalType?: string;
|
||||||
|
paymentMethod?: PaymentMethod;
|
||||||
|
isActive?: boolean;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
sortBy?: string;
|
||||||
|
sortOrder?: 'asc' | 'desc';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaymentTerminalsResponse {
|
||||||
|
data: PaymentTerminal[];
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreatePaymentTerminalDto {
|
||||||
|
name: string;
|
||||||
|
storeId: string;
|
||||||
|
terminalType: string;
|
||||||
|
serialNumber: string;
|
||||||
|
model: string;
|
||||||
|
manufacturer: string;
|
||||||
|
ipAddress?: string;
|
||||||
|
port?: number;
|
||||||
|
paymentMethods: PaymentMethod[];
|
||||||
|
config?: PaymentTerminalConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdatePaymentTerminalDto {
|
||||||
|
name?: string;
|
||||||
|
storeId?: string;
|
||||||
|
terminalType?: string;
|
||||||
|
model?: string;
|
||||||
|
manufacturer?: string;
|
||||||
|
ipAddress?: string;
|
||||||
|
port?: number;
|
||||||
|
paymentMethods?: PaymentMethod[];
|
||||||
|
config?: PaymentTerminalConfig;
|
||||||
|
isActive?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaymentTerminalConfig {
|
||||||
|
connectionTimeout: number;
|
||||||
|
responseTimeout: number;
|
||||||
|
maxRetries: number;
|
||||||
|
retryDelay: number;
|
||||||
|
enableLogging: boolean;
|
||||||
|
logLevel: 'error' | 'warn' | 'info' | 'debug';
|
||||||
|
customSettings: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MCP (Model Context Protocol) Types
|
||||||
|
export interface McpServer {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
protocol: string;
|
||||||
|
version: string;
|
||||||
|
endpoint: string;
|
||||||
|
config: McpServerConfig;
|
||||||
|
status: McpServerStatus;
|
||||||
|
isConnected: boolean;
|
||||||
|
lastConnectedAt?: string;
|
||||||
|
tools: McpTool[];
|
||||||
|
resources: McpResource[];
|
||||||
|
prompts: McpPrompt[];
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpServerConfig {
|
||||||
|
timeout: number;
|
||||||
|
retries: number;
|
||||||
|
headers?: Record<string, string>;
|
||||||
|
auth?: {
|
||||||
|
type: 'bearer' | 'basic' | 'api_key';
|
||||||
|
token?: string;
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
|
apiKey?: string;
|
||||||
|
};
|
||||||
|
customSettings?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpServerStatus {
|
||||||
|
healthy: boolean;
|
||||||
|
uptime: number;
|
||||||
|
version: string;
|
||||||
|
capabilities: string[];
|
||||||
|
lastError?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpTool {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
inputSchema: Record<string, any>;
|
||||||
|
isAsync: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpResource {
|
||||||
|
uri: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
mimeType?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpPrompt {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
arguments?: McpPromptArgument[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpPromptArgument {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
required?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpFilters {
|
||||||
|
search?: string;
|
||||||
|
status?: string;
|
||||||
|
protocol?: string;
|
||||||
|
isConnected?: boolean;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
sortBy?: string;
|
||||||
|
sortOrder?: 'asc' | 'desc';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpServersResponse {
|
||||||
|
data: McpServer[];
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateMcpServerDto {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
protocol: string;
|
||||||
|
version: string;
|
||||||
|
endpoint: string;
|
||||||
|
config: McpServerConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateMcpServerDto {
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
protocol?: string;
|
||||||
|
version?: string;
|
||||||
|
endpoint?: string;
|
||||||
|
config?: McpServerConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpExecutionResult {
|
||||||
|
success: boolean;
|
||||||
|
result?: any;
|
||||||
|
error?: string;
|
||||||
|
executionTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpToolCall {
|
||||||
|
id: string;
|
||||||
|
serverId: string;
|
||||||
|
toolName: string;
|
||||||
|
args: Record<string, any>;
|
||||||
|
status: 'success' | 'error';
|
||||||
|
result?: any;
|
||||||
|
error?: string;
|
||||||
|
executionTime: number;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface McpResourceAccess {
|
||||||
|
id: string;
|
||||||
|
serverId: string;
|
||||||
|
resourceUri: string;
|
||||||
|
action: 'read' | 'write' | 'delete';
|
||||||
|
status: 'success' | 'error';
|
||||||
|
result?: any;
|
||||||
|
error?: string;
|
||||||
|
executionTime: number;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user