[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