ADD new frontend
This commit is contained in:
650
frontend/src/hooks/api/useProduction.ts
Normal file
650
frontend/src/hooks/api/useProduction.ts
Normal file
@@ -0,0 +1,650 @@
|
||||
/**
|
||||
* Production hook for managing production batches, recipes, and scheduling
|
||||
*/
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { ProductionService } from '../../services/api/production.service';
|
||||
import {
|
||||
ProductionBatch,
|
||||
ProductionBatchCreate,
|
||||
ProductionBatchUpdate,
|
||||
Recipe,
|
||||
RecipeCreate,
|
||||
RecipeUpdate,
|
||||
ProductionSchedule,
|
||||
ProductionScheduleCreate,
|
||||
QualityControl,
|
||||
QualityControlCreate
|
||||
} from '../../types/production.types';
|
||||
import { ApiResponse, PaginatedResponse, QueryParams } from '../../types/api.types';
|
||||
|
||||
interface ProductionState {
|
||||
batches: ProductionBatch[];
|
||||
recipes: Recipe[];
|
||||
schedules: ProductionSchedule[];
|
||||
qualityControls: QualityControl[];
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
pagination: {
|
||||
total: number;
|
||||
page: number;
|
||||
pages: number;
|
||||
limit: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface ProductionActions {
|
||||
// Production Batches
|
||||
fetchBatches: (params?: QueryParams) => Promise<void>;
|
||||
createBatch: (data: ProductionBatchCreate) => Promise<boolean>;
|
||||
updateBatch: (id: string, data: ProductionBatchUpdate) => Promise<boolean>;
|
||||
deleteBatch: (id: string) => Promise<boolean>;
|
||||
getBatch: (id: string) => Promise<ProductionBatch | null>;
|
||||
startBatch: (id: string) => Promise<boolean>;
|
||||
completeBatch: (id: string) => Promise<boolean>;
|
||||
cancelBatch: (id: string, reason: string) => Promise<boolean>;
|
||||
|
||||
// Recipes
|
||||
fetchRecipes: (params?: QueryParams) => Promise<void>;
|
||||
createRecipe: (data: RecipeCreate) => Promise<boolean>;
|
||||
updateRecipe: (id: string, data: RecipeUpdate) => Promise<boolean>;
|
||||
deleteRecipe: (id: string) => Promise<boolean>;
|
||||
getRecipe: (id: string) => Promise<Recipe | null>;
|
||||
duplicateRecipe: (id: string, name: string) => Promise<boolean>;
|
||||
|
||||
// Production Scheduling
|
||||
fetchSchedules: (params?: QueryParams) => Promise<void>;
|
||||
createSchedule: (data: ProductionScheduleCreate) => Promise<boolean>;
|
||||
updateSchedule: (id: string, data: Partial<ProductionScheduleCreate>) => Promise<boolean>;
|
||||
deleteSchedule: (id: string) => Promise<boolean>;
|
||||
getCapacityAnalysis: (date: string) => Promise<any>;
|
||||
|
||||
// Quality Control
|
||||
fetchQualityControls: (params?: QueryParams) => Promise<void>;
|
||||
createQualityControl: (data: QualityControlCreate) => Promise<boolean>;
|
||||
updateQualityControl: (id: string, data: Partial<QualityControlCreate>) => Promise<boolean>;
|
||||
|
||||
// Analytics
|
||||
getProductionAnalytics: (startDate?: string, endDate?: string) => Promise<any>;
|
||||
getEfficiencyReport: (period: string) => Promise<any>;
|
||||
getRecipePerformance: (recipeId?: string) => Promise<any>;
|
||||
|
||||
// Utilities
|
||||
clearError: () => void;
|
||||
refresh: () => Promise<void>;
|
||||
}
|
||||
|
||||
export const useProduction = (): ProductionState & ProductionActions => {
|
||||
const [state, setState] = useState<ProductionState>({
|
||||
batches: [],
|
||||
recipes: [],
|
||||
schedules: [],
|
||||
qualityControls: [],
|
||||
isLoading: false,
|
||||
error: null,
|
||||
pagination: {
|
||||
total: 0,
|
||||
page: 1,
|
||||
pages: 1,
|
||||
limit: 20,
|
||||
},
|
||||
});
|
||||
|
||||
const productionService = new ProductionService();
|
||||
|
||||
// Fetch production batches
|
||||
const fetchBatches = useCallback(async (params?: QueryParams) => {
|
||||
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.getBatches(params);
|
||||
|
||||
if (response.success && response.data) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
batches: Array.isArray(response.data) ? response.data : response.data.items || [],
|
||||
pagination: response.data.pagination || prev.pagination,
|
||||
isLoading: false,
|
||||
}));
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
isLoading: false,
|
||||
error: response.error || 'Error al cargar lotes de producción',
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
isLoading: false,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Create production batch
|
||||
const createBatch = useCallback(async (data: ProductionBatchCreate): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.createBatch(data);
|
||||
|
||||
if (response.success) {
|
||||
await fetchBatches();
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al crear lote de producción',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchBatches]);
|
||||
|
||||
// Update production batch
|
||||
const updateBatch = useCallback(async (id: string, data: ProductionBatchUpdate): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.updateBatch(id, data);
|
||||
|
||||
if (response.success) {
|
||||
await fetchBatches();
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al actualizar lote de producción',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchBatches]);
|
||||
|
||||
// Delete production batch
|
||||
const deleteBatch = useCallback(async (id: string): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.deleteBatch(id);
|
||||
|
||||
if (response.success) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
batches: prev.batches.filter(batch => batch.id !== id),
|
||||
}));
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al eliminar lote de producción',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Get single production batch
|
||||
const getBatch = useCallback(async (id: string): Promise<ProductionBatch | null> => {
|
||||
try {
|
||||
const response = await productionService.getBatch(id);
|
||||
return response.success ? response.data : null;
|
||||
} catch (error) {
|
||||
console.error('Error fetching batch:', error);
|
||||
return null;
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Start production batch
|
||||
const startBatch = useCallback(async (id: string): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.startBatch(id);
|
||||
|
||||
if (response.success) {
|
||||
await fetchBatches();
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al iniciar lote de producción',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchBatches]);
|
||||
|
||||
// Complete production batch
|
||||
const completeBatch = useCallback(async (id: string): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.completeBatch(id);
|
||||
|
||||
if (response.success) {
|
||||
await fetchBatches();
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al completar lote de producción',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchBatches]);
|
||||
|
||||
// Cancel production batch
|
||||
const cancelBatch = useCallback(async (id: string, reason: string): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.cancelBatch(id, reason);
|
||||
|
||||
if (response.success) {
|
||||
await fetchBatches();
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al cancelar lote de producción',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchBatches]);
|
||||
|
||||
// Fetch recipes
|
||||
const fetchRecipes = useCallback(async (params?: QueryParams) => {
|
||||
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.getRecipes(params);
|
||||
|
||||
if (response.success && response.data) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
recipes: Array.isArray(response.data) ? response.data : response.data.items || [],
|
||||
isLoading: false,
|
||||
}));
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
isLoading: false,
|
||||
error: response.error || 'Error al cargar recetas',
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
isLoading: false,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Create recipe
|
||||
const createRecipe = useCallback(async (data: RecipeCreate): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.createRecipe(data);
|
||||
|
||||
if (response.success) {
|
||||
await fetchRecipes();
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al crear receta',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchRecipes]);
|
||||
|
||||
// Update recipe
|
||||
const updateRecipe = useCallback(async (id: string, data: RecipeUpdate): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.updateRecipe(id, data);
|
||||
|
||||
if (response.success) {
|
||||
await fetchRecipes();
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al actualizar receta',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchRecipes]);
|
||||
|
||||
// Delete recipe
|
||||
const deleteRecipe = useCallback(async (id: string): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.deleteRecipe(id);
|
||||
|
||||
if (response.success) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
recipes: prev.recipes.filter(recipe => recipe.id !== id),
|
||||
}));
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al eliminar receta',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Get single recipe
|
||||
const getRecipe = useCallback(async (id: string): Promise<Recipe | null> => {
|
||||
try {
|
||||
const response = await productionService.getRecipe(id);
|
||||
return response.success ? response.data : null;
|
||||
} catch (error) {
|
||||
console.error('Error fetching recipe:', error);
|
||||
return null;
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Duplicate recipe
|
||||
const duplicateRecipe = useCallback(async (id: string, name: string): Promise<boolean> => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
|
||||
try {
|
||||
const response = await productionService.duplicateRecipe(id, name);
|
||||
|
||||
if (response.success) {
|
||||
await fetchRecipes();
|
||||
return true;
|
||||
} else {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: response.error || 'Error al duplicar receta',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: 'Error de conexión al servidor',
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchRecipes]);
|
||||
|
||||
// Fetch production schedules
|
||||
const fetchSchedules = useCallback(async (params?: QueryParams) => {
|
||||
try {
|
||||
const response = await productionService.getSchedules(params);
|
||||
|
||||
if (response.success && response.data) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
schedules: Array.isArray(response.data) ? response.data : response.data.items || [],
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching schedules:', error);
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Create production schedule
|
||||
const createSchedule = useCallback(async (data: ProductionScheduleCreate): Promise<boolean> => {
|
||||
try {
|
||||
const response = await productionService.createSchedule(data);
|
||||
|
||||
if (response.success) {
|
||||
await fetchSchedules();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error('Error creating schedule:', error);
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchSchedules]);
|
||||
|
||||
// Update production schedule
|
||||
const updateSchedule = useCallback(async (id: string, data: Partial<ProductionScheduleCreate>): Promise<boolean> => {
|
||||
try {
|
||||
const response = await productionService.updateSchedule(id, data);
|
||||
|
||||
if (response.success) {
|
||||
await fetchSchedules();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error('Error updating schedule:', error);
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchSchedules]);
|
||||
|
||||
// Delete production schedule
|
||||
const deleteSchedule = useCallback(async (id: string): Promise<boolean> => {
|
||||
try {
|
||||
const response = await productionService.deleteSchedule(id);
|
||||
|
||||
if (response.success) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
schedules: prev.schedules.filter(schedule => schedule.id !== id),
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error('Error deleting schedule:', error);
|
||||
return false;
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Get capacity analysis
|
||||
const getCapacityAnalysis = useCallback(async (date: string) => {
|
||||
try {
|
||||
const response = await productionService.getCapacityAnalysis(date);
|
||||
return response.success ? response.data : null;
|
||||
} catch (error) {
|
||||
console.error('Error fetching capacity analysis:', error);
|
||||
return null;
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Fetch quality controls
|
||||
const fetchQualityControls = useCallback(async (params?: QueryParams) => {
|
||||
try {
|
||||
const response = await productionService.getQualityControls(params);
|
||||
|
||||
if (response.success && response.data) {
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
qualityControls: Array.isArray(response.data) ? response.data : response.data.items || [],
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching quality controls:', error);
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Create quality control
|
||||
const createQualityControl = useCallback(async (data: QualityControlCreate): Promise<boolean> => {
|
||||
try {
|
||||
const response = await productionService.createQualityControl(data);
|
||||
|
||||
if (response.success) {
|
||||
await fetchQualityControls();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error('Error creating quality control:', error);
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchQualityControls]);
|
||||
|
||||
// Update quality control
|
||||
const updateQualityControl = useCallback(async (id: string, data: Partial<QualityControlCreate>): Promise<boolean> => {
|
||||
try {
|
||||
const response = await productionService.updateQualityControl(id, data);
|
||||
|
||||
if (response.success) {
|
||||
await fetchQualityControls();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error('Error updating quality control:', error);
|
||||
return false;
|
||||
}
|
||||
}, [productionService, fetchQualityControls]);
|
||||
|
||||
// Get production analytics
|
||||
const getProductionAnalytics = useCallback(async (startDate?: string, endDate?: string) => {
|
||||
try {
|
||||
const response = await productionService.getAnalytics(startDate, endDate);
|
||||
return response.success ? response.data : null;
|
||||
} catch (error) {
|
||||
console.error('Error fetching production analytics:', error);
|
||||
return null;
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Get efficiency report
|
||||
const getEfficiencyReport = useCallback(async (period: string) => {
|
||||
try {
|
||||
const response = await productionService.getEfficiencyReport(period);
|
||||
return response.success ? response.data : null;
|
||||
} catch (error) {
|
||||
console.error('Error fetching efficiency report:', error);
|
||||
return null;
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Get recipe performance
|
||||
const getRecipePerformance = useCallback(async (recipeId?: string) => {
|
||||
try {
|
||||
const response = await productionService.getRecipePerformance(recipeId);
|
||||
return response.success ? response.data : null;
|
||||
} catch (error) {
|
||||
console.error('Error fetching recipe performance:', error);
|
||||
return null;
|
||||
}
|
||||
}, [productionService]);
|
||||
|
||||
// Clear error
|
||||
const clearError = useCallback(() => {
|
||||
setState(prev => ({ ...prev, error: null }));
|
||||
}, []);
|
||||
|
||||
// Refresh all data
|
||||
const refresh = useCallback(async () => {
|
||||
await Promise.all([
|
||||
fetchBatches(),
|
||||
fetchRecipes(),
|
||||
fetchSchedules(),
|
||||
]);
|
||||
}, [fetchBatches, fetchRecipes, fetchSchedules]);
|
||||
|
||||
// Initialize data on mount
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
}, []);
|
||||
|
||||
return {
|
||||
...state,
|
||||
fetchBatches,
|
||||
createBatch,
|
||||
updateBatch,
|
||||
deleteBatch,
|
||||
getBatch,
|
||||
startBatch,
|
||||
completeBatch,
|
||||
cancelBatch,
|
||||
fetchRecipes,
|
||||
createRecipe,
|
||||
updateRecipe,
|
||||
deleteRecipe,
|
||||
getRecipe,
|
||||
duplicateRecipe,
|
||||
fetchSchedules,
|
||||
createSchedule,
|
||||
updateSchedule,
|
||||
deleteSchedule,
|
||||
getCapacityAnalysis,
|
||||
fetchQualityControls,
|
||||
createQualityControl,
|
||||
updateQualityControl,
|
||||
getProductionAnalytics,
|
||||
getEfficiencyReport,
|
||||
getRecipePerformance,
|
||||
clearError,
|
||||
refresh,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user