Add POS service

This commit is contained in:
Urtzi Alfaro
2025-08-16 15:00:36 +02:00
parent 995a51e285
commit 23c5f50111
34 changed files with 6086 additions and 0 deletions

View File

@@ -0,0 +1,337 @@
// frontend/src/api/hooks/usePOS.ts
/**
* React hooks for POS Integration functionality
*/
import { useState, useEffect } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import {
posService,
POSConfiguration,
CreatePOSConfigurationRequest,
UpdatePOSConfigurationRequest,
POSTransaction,
POSSyncLog,
POSAnalytics,
SyncRequest
} from '../services/pos.service';
import { useTenantId } from './useTenant';
// ============================================================================
// CONFIGURATION HOOKS
// ============================================================================
export const usePOSConfigurations = (params?: {
pos_system?: string;
is_active?: boolean;
limit?: number;
offset?: number;
}) => {
const tenantId = useTenantId();
return useQuery({
queryKey: ['pos-configurations', tenantId, params],
queryFn: () => posService.getConfigurations(tenantId, params),
enabled: !!tenantId,
staleTime: 5 * 60 * 1000, // 5 minutes
});
};
export const usePOSConfiguration = (configId?: string) => {
const tenantId = useTenantId();
return useQuery({
queryKey: ['pos-configuration', tenantId, configId],
queryFn: () => posService.getConfiguration(tenantId, configId!),
enabled: !!tenantId && !!configId,
staleTime: 5 * 60 * 1000,
});
};
export const useCreatePOSConfiguration = () => {
const queryClient = useQueryClient();
const tenantId = useTenantId();
return useMutation({
mutationFn: (data: CreatePOSConfigurationRequest) =>
posService.createConfiguration(tenantId, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['pos-configurations', tenantId] });
},
});
};
export const useUpdatePOSConfiguration = () => {
const queryClient = useQueryClient();
const tenantId = useTenantId();
return useMutation({
mutationFn: ({ configId, data }: { configId: string; data: UpdatePOSConfigurationRequest }) =>
posService.updateConfiguration(tenantId, configId, data),
onSuccess: (_, { configId }) => {
queryClient.invalidateQueries({ queryKey: ['pos-configurations', tenantId] });
queryClient.invalidateQueries({ queryKey: ['pos-configuration', tenantId, configId] });
},
});
};
export const useDeletePOSConfiguration = () => {
const queryClient = useQueryClient();
const tenantId = useTenantId();
return useMutation({
mutationFn: (configId: string) =>
posService.deleteConfiguration(tenantId, configId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['pos-configurations', tenantId] });
},
});
};
export const useTestPOSConnection = () => {
const tenantId = useTenantId();
return useMutation({
mutationFn: (configId: string) =>
posService.testConnection(tenantId, configId),
});
};
// ============================================================================
// SYNCHRONIZATION HOOKS
// ============================================================================
export const useTriggerPOSSync = () => {
const queryClient = useQueryClient();
const tenantId = useTenantId();
return useMutation({
mutationFn: ({ configId, syncRequest }: { configId: string; syncRequest: SyncRequest }) =>
posService.triggerSync(tenantId, configId, syncRequest),
onSuccess: (_, { configId }) => {
queryClient.invalidateQueries({ queryKey: ['pos-sync-status', tenantId, configId] });
queryClient.invalidateQueries({ queryKey: ['pos-sync-logs', tenantId, configId] });
},
});
};
export const usePOSSyncStatus = (configId?: string, pollingInterval?: number) => {
const tenantId = useTenantId();
return useQuery({
queryKey: ['pos-sync-status', tenantId, configId],
queryFn: () => posService.getSyncStatus(tenantId, configId!),
enabled: !!tenantId && !!configId,
refetchInterval: pollingInterval || 30000, // Poll every 30 seconds by default
staleTime: 10 * 1000, // 10 seconds
});
};
export const usePOSSyncLogs = (configId?: string, params?: {
limit?: number;
offset?: number;
status?: string;
sync_type?: string;
data_type?: string;
}) => {
const tenantId = useTenantId();
return useQuery({
queryKey: ['pos-sync-logs', tenantId, configId, params],
queryFn: () => posService.getSyncLogs(tenantId, configId!, params),
enabled: !!tenantId && !!configId,
staleTime: 2 * 60 * 1000, // 2 minutes
});
};
// ============================================================================
// TRANSACTION HOOKS
// ============================================================================
export const usePOSTransactions = (params?: {
pos_system?: string;
start_date?: string;
end_date?: string;
status?: string;
is_synced?: boolean;
limit?: number;
offset?: number;
}) => {
const tenantId = useTenantId();
return useQuery({
queryKey: ['pos-transactions', tenantId, params],
queryFn: () => posService.getTransactions(tenantId, params),
enabled: !!tenantId,
staleTime: 2 * 60 * 1000, // 2 minutes
});
};
export const useSyncSingleTransaction = () => {
const queryClient = useQueryClient();
const tenantId = useTenantId();
return useMutation({
mutationFn: ({ transactionId, force }: { transactionId: string; force?: boolean }) =>
posService.syncSingleTransaction(tenantId, transactionId, force),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['pos-transactions', tenantId] });
},
});
};
export const useResyncFailedTransactions = () => {
const queryClient = useQueryClient();
const tenantId = useTenantId();
return useMutation({
mutationFn: (daysBack: number) =>
posService.resyncFailedTransactions(tenantId, daysBack),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['pos-transactions', tenantId] });
},
});
};
// ============================================================================
// ANALYTICS HOOKS
// ============================================================================
export const usePOSAnalytics = (days: number = 30) => {
const tenantId = useTenantId();
return useQuery({
queryKey: ['pos-analytics', tenantId, days],
queryFn: () => posService.getSyncAnalytics(tenantId, days),
enabled: !!tenantId,
staleTime: 10 * 60 * 1000, // 10 minutes
});
};
// ============================================================================
// SYSTEM INFO HOOKS
// ============================================================================
export const useSupportedPOSSystems = () => {
return useQuery({
queryKey: ['supported-pos-systems'],
queryFn: () => posService.getSupportedSystems(),
staleTime: 60 * 60 * 1000, // 1 hour
});
};
export const useWebhookStatus = (posSystem?: string) => {
return useQuery({
queryKey: ['webhook-status', posSystem],
queryFn: () => posService.getWebhookStatus(posSystem!),
enabled: !!posSystem,
staleTime: 5 * 60 * 1000, // 5 minutes
});
};
// ============================================================================
// COMPOSITE HOOKS
// ============================================================================
export const usePOSDashboard = () => {
const tenantId = useTenantId();
// Get configurations
const { data: configurationsData, isLoading: configurationsLoading } = usePOSConfigurations();
// Get recent transactions
const { data: transactionsData, isLoading: transactionsLoading } = usePOSTransactions({
limit: 10
});
// Get analytics for last 7 days
const { data: analyticsData, isLoading: analyticsLoading } = usePOSAnalytics(7);
const isLoading = configurationsLoading || transactionsLoading || analyticsLoading;
return {
configurations: configurationsData?.configurations || [],
transactions: transactionsData?.transactions || [],
analytics: analyticsData,
isLoading,
summary: {
total_configurations: configurationsData?.total || 0,
active_configurations: configurationsData?.configurations?.filter(c => c.is_active).length || 0,
connected_configurations: configurationsData?.configurations?.filter(c => c.is_connected).length || 0,
total_transactions: transactionsData?.total || 0,
total_revenue: transactionsData?.summary?.total_amount || 0,
sync_health: analyticsData?.success_rate || 0,
}
};
};
export const usePOSConfigurationManagement = () => {
const createMutation = useCreatePOSConfiguration();
const updateMutation = useUpdatePOSConfiguration();
const deleteMutation = useDeletePOSConfiguration();
const testConnectionMutation = useTestPOSConnection();
const [selectedConfiguration, setSelectedConfiguration] = useState<POSConfiguration | null>(null);
const [isFormOpen, setIsFormOpen] = useState(false);
const handleCreate = async (data: CreatePOSConfigurationRequest) => {
await createMutation.mutateAsync(data);
setIsFormOpen(false);
};
const handleUpdate = async (configId: string, data: UpdatePOSConfigurationRequest) => {
await updateMutation.mutateAsync({ configId, data });
setIsFormOpen(false);
setSelectedConfiguration(null);
};
const handleDelete = async (configId: string) => {
await deleteMutation.mutateAsync(configId);
};
const handleTestConnection = async (configId: string) => {
return await testConnectionMutation.mutateAsync(configId);
};
const openCreateForm = () => {
setSelectedConfiguration(null);
setIsFormOpen(true);
};
const openEditForm = (configuration: POSConfiguration) => {
setSelectedConfiguration(configuration);
setIsFormOpen(true);
};
const closeForm = () => {
setIsFormOpen(false);
setSelectedConfiguration(null);
};
return {
// State
selectedConfiguration,
isFormOpen,
// Actions
handleCreate,
handleUpdate,
handleDelete,
handleTestConnection,
openCreateForm,
openEditForm,
closeForm,
// Loading states
isCreating: createMutation.isPending,
isUpdating: updateMutation.isPending,
isDeleting: deleteMutation.isPending,
isTesting: testConnectionMutation.isPending,
// Errors
createError: createMutation.error,
updateError: updateMutation.error,
deleteError: deleteMutation.error,
testError: testConnectionMutation.error,
};
};