Create the frontend receipes page to use real API
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Recipes React Query hooks
|
||||
* Data fetching and caching layer for recipe management
|
||||
* All hooks properly handle tenant-dependent operations
|
||||
*/
|
||||
|
||||
import {
|
||||
@@ -23,31 +24,19 @@ import type {
|
||||
RecipeFeasibilityResponse,
|
||||
RecipeStatisticsResponse,
|
||||
RecipeCategoriesResponse,
|
||||
ProductionBatchResponse,
|
||||
ProductionBatchCreate,
|
||||
ProductionBatchUpdate,
|
||||
} from '../types/recipes';
|
||||
|
||||
// Query Keys Factory
|
||||
export const recipesKeys = {
|
||||
all: ['recipes'] as const,
|
||||
lists: () => [...recipesKeys.all, 'list'] as const,
|
||||
list: (filters: RecipeSearchParams) => [...recipesKeys.lists(), { filters }] as const,
|
||||
details: () => [...recipesKeys.all, 'detail'] as const,
|
||||
detail: (id: string) => [...recipesKeys.details(), id] as const,
|
||||
statistics: () => [...recipesKeys.all, 'statistics'] as const,
|
||||
categories: () => [...recipesKeys.all, 'categories'] as const,
|
||||
feasibility: (id: string, batchMultiplier: number) => [...recipesKeys.all, 'feasibility', id, batchMultiplier] as const,
|
||||
|
||||
// Production batch keys
|
||||
productionBatches: {
|
||||
all: ['production-batches'] as const,
|
||||
lists: () => [...recipesKeys.productionBatches.all, 'list'] as const,
|
||||
list: (filters: any) => [...recipesKeys.productionBatches.lists(), { filters }] as const,
|
||||
details: () => [...recipesKeys.productionBatches.all, 'detail'] as const,
|
||||
detail: (id: string) => [...recipesKeys.productionBatches.details(), id] as const,
|
||||
byRecipe: (recipeId: string) => [...recipesKeys.productionBatches.all, 'recipe', recipeId] as const,
|
||||
}
|
||||
tenant: (tenantId: string) => [...recipesKeys.all, 'tenant', tenantId] as const,
|
||||
lists: (tenantId: string) => [...recipesKeys.tenant(tenantId), 'list'] as const,
|
||||
list: (tenantId: string, filters: RecipeSearchParams) => [...recipesKeys.lists(tenantId), { filters }] as const,
|
||||
details: (tenantId: string) => [...recipesKeys.tenant(tenantId), 'detail'] as const,
|
||||
detail: (tenantId: string, id: string) => [...recipesKeys.details(tenantId), id] as const,
|
||||
statistics: (tenantId: string) => [...recipesKeys.tenant(tenantId), 'statistics'] as const,
|
||||
categories: (tenantId: string) => [...recipesKeys.tenant(tenantId), 'categories'] as const,
|
||||
feasibility: (tenantId: string, id: string, batchMultiplier: number) => [...recipesKeys.tenant(tenantId), 'feasibility', id, batchMultiplier] as const,
|
||||
} as const;
|
||||
|
||||
// Recipe Queries
|
||||
@@ -56,13 +45,14 @@ export const recipesKeys = {
|
||||
* Fetch a single recipe by ID
|
||||
*/
|
||||
export const useRecipe = (
|
||||
tenantId: string,
|
||||
recipeId: string,
|
||||
options?: Omit<UseQueryOptions<RecipeResponse, ApiError>, 'queryKey' | 'queryFn'>
|
||||
) => {
|
||||
return useQuery<RecipeResponse, ApiError>({
|
||||
queryKey: recipesKeys.detail(recipeId),
|
||||
queryFn: () => recipesService.getRecipe(recipeId),
|
||||
enabled: !!recipeId,
|
||||
queryKey: recipesKeys.detail(tenantId, recipeId),
|
||||
queryFn: () => recipesService.getRecipe(tenantId, recipeId),
|
||||
enabled: !!(tenantId && recipeId),
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
...options,
|
||||
});
|
||||
@@ -72,13 +62,15 @@ export const useRecipe = (
|
||||
* Search/list recipes with filters
|
||||
*/
|
||||
export const useRecipes = (
|
||||
tenantId: string,
|
||||
filters: RecipeSearchParams = {},
|
||||
options?: Omit<UseQueryOptions<RecipeResponse[], ApiError>, 'queryKey' | 'queryFn'>
|
||||
) => {
|
||||
return useQuery<RecipeResponse[], ApiError>({
|
||||
queryKey: recipesKeys.list(filters),
|
||||
queryFn: () => recipesService.searchRecipes(filters),
|
||||
queryKey: recipesKeys.list(tenantId, filters),
|
||||
queryFn: () => recipesService.searchRecipes(tenantId, filters),
|
||||
staleTime: 2 * 60 * 1000, // 2 minutes
|
||||
enabled: !!tenantId,
|
||||
...options,
|
||||
});
|
||||
};
|
||||
@@ -87,18 +79,20 @@ export const useRecipes = (
|
||||
* Infinite query for recipes (pagination)
|
||||
*/
|
||||
export const useInfiniteRecipes = (
|
||||
tenantId: string,
|
||||
filters: Omit<RecipeSearchParams, 'offset'> = {},
|
||||
options?: Omit<UseInfiniteQueryOptions<RecipeResponse[], ApiError>, 'queryKey' | 'queryFn' | 'getNextPageParam'>
|
||||
) => {
|
||||
return useInfiniteQuery<RecipeResponse[], ApiError>({
|
||||
queryKey: recipesKeys.list(filters),
|
||||
queryKey: recipesKeys.list(tenantId, filters),
|
||||
queryFn: ({ pageParam = 0 }) =>
|
||||
recipesService.searchRecipes({ ...filters, offset: pageParam }),
|
||||
recipesService.searchRecipes(tenantId, { ...filters, offset: pageParam }),
|
||||
getNextPageParam: (lastPage, allPages) => {
|
||||
const limit = filters.limit || 100;
|
||||
if (lastPage.length < limit) return undefined;
|
||||
return allPages.length * limit;
|
||||
},
|
||||
enabled: !!tenantId,
|
||||
staleTime: 2 * 60 * 1000, // 2 minutes
|
||||
...options,
|
||||
});
|
||||
@@ -108,12 +102,14 @@ export const useInfiniteRecipes = (
|
||||
* Get recipe statistics
|
||||
*/
|
||||
export const useRecipeStatistics = (
|
||||
tenantId: string,
|
||||
options?: Omit<UseQueryOptions<RecipeStatisticsResponse, ApiError>, 'queryKey' | 'queryFn'>
|
||||
) => {
|
||||
return useQuery<RecipeStatisticsResponse, ApiError>({
|
||||
queryKey: recipesKeys.statistics(),
|
||||
queryFn: () => recipesService.getRecipeStatistics(),
|
||||
queryKey: recipesKeys.statistics(tenantId),
|
||||
queryFn: () => recipesService.getRecipeStatistics(tenantId),
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
enabled: !!tenantId,
|
||||
...options,
|
||||
});
|
||||
};
|
||||
@@ -122,12 +118,14 @@ export const useRecipeStatistics = (
|
||||
* Get recipe categories
|
||||
*/
|
||||
export const useRecipeCategories = (
|
||||
tenantId: string,
|
||||
options?: Omit<UseQueryOptions<RecipeCategoriesResponse, ApiError>, 'queryKey' | 'queryFn'>
|
||||
) => {
|
||||
return useQuery<RecipeCategoriesResponse, ApiError>({
|
||||
queryKey: recipesKeys.categories(),
|
||||
queryFn: () => recipesService.getRecipeCategories(),
|
||||
queryKey: recipesKeys.categories(tenantId),
|
||||
queryFn: () => recipesService.getRecipeCategories(tenantId),
|
||||
staleTime: 10 * 60 * 1000, // 10 minutes
|
||||
enabled: !!tenantId,
|
||||
...options,
|
||||
});
|
||||
};
|
||||
@@ -136,14 +134,15 @@ export const useRecipeCategories = (
|
||||
* Check recipe feasibility
|
||||
*/
|
||||
export const useRecipeFeasibility = (
|
||||
tenantId: string,
|
||||
recipeId: string,
|
||||
batchMultiplier: number = 1.0,
|
||||
options?: Omit<UseQueryOptions<RecipeFeasibilityResponse, ApiError>, 'queryKey' | 'queryFn'>
|
||||
) => {
|
||||
return useQuery<RecipeFeasibilityResponse, ApiError>({
|
||||
queryKey: recipesKeys.feasibility(recipeId, batchMultiplier),
|
||||
queryFn: () => recipesService.checkRecipeFeasibility(recipeId, batchMultiplier),
|
||||
enabled: !!recipeId,
|
||||
queryKey: recipesKeys.feasibility(tenantId, recipeId, batchMultiplier),
|
||||
queryFn: () => recipesService.checkRecipeFeasibility(tenantId, recipeId, batchMultiplier),
|
||||
enabled: !!(tenantId && recipeId),
|
||||
staleTime: 1 * 60 * 1000, // 1 minute (fresher data for inventory checks)
|
||||
...options,
|
||||
});
|
||||
@@ -155,21 +154,22 @@ export const useRecipeFeasibility = (
|
||||
* Create a new recipe
|
||||
*/
|
||||
export const useCreateRecipe = (
|
||||
tenantId: string,
|
||||
options?: UseMutationOptions<RecipeResponse, ApiError, RecipeCreate>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<RecipeResponse, ApiError, RecipeCreate>({
|
||||
mutationFn: (recipeData: RecipeCreate) => recipesService.createRecipe(recipeData),
|
||||
mutationFn: (recipeData: RecipeCreate) => recipesService.createRecipe(tenantId, recipeData),
|
||||
onSuccess: (data) => {
|
||||
// Add to lists cache
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists(tenantId) });
|
||||
// Set individual recipe cache
|
||||
queryClient.setQueryData(recipesKeys.detail(data.id), data);
|
||||
queryClient.setQueryData(recipesKeys.detail(tenantId, data.id), data);
|
||||
// Invalidate statistics
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics(tenantId) });
|
||||
// Invalidate categories (new category might be added)
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.categories() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.categories(tenantId) });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
@@ -179,21 +179,22 @@ export const useCreateRecipe = (
|
||||
* Update an existing recipe
|
||||
*/
|
||||
export const useUpdateRecipe = (
|
||||
tenantId: string,
|
||||
options?: UseMutationOptions<RecipeResponse, ApiError, { id: string; data: RecipeUpdate }>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<RecipeResponse, ApiError, { id: string; data: RecipeUpdate }>({
|
||||
mutationFn: ({ id, data }) => recipesService.updateRecipe(id, data),
|
||||
mutationFn: ({ id, data }) => recipesService.updateRecipe(tenantId, id, data),
|
||||
onSuccess: (data) => {
|
||||
// Update individual recipe cache
|
||||
queryClient.setQueryData(recipesKeys.detail(data.id), data);
|
||||
queryClient.setQueryData(recipesKeys.detail(tenantId, data.id), data);
|
||||
// Invalidate lists (recipe might move in search results)
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists(tenantId) });
|
||||
// Invalidate statistics
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics(tenantId) });
|
||||
// Invalidate categories
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.categories() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.categories(tenantId) });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
@@ -203,23 +204,22 @@ export const useUpdateRecipe = (
|
||||
* Delete a recipe
|
||||
*/
|
||||
export const useDeleteRecipe = (
|
||||
tenantId: string,
|
||||
options?: UseMutationOptions<{ message: string }, ApiError, string>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<{ message: string }, ApiError, string>({
|
||||
mutationFn: (recipeId: string) => recipesService.deleteRecipe(recipeId),
|
||||
mutationFn: (recipeId: string) => recipesService.deleteRecipe(tenantId, recipeId),
|
||||
onSuccess: (_, recipeId) => {
|
||||
// Remove from individual cache
|
||||
queryClient.removeQueries({ queryKey: recipesKeys.detail(recipeId) });
|
||||
queryClient.removeQueries({ queryKey: recipesKeys.detail(tenantId, recipeId) });
|
||||
// Invalidate lists
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists(tenantId) });
|
||||
// Invalidate statistics
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics(tenantId) });
|
||||
// Invalidate categories
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.categories() });
|
||||
// Invalidate production batches for this recipe
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.byRecipe(recipeId) });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.categories(tenantId) });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
@@ -229,19 +229,20 @@ export const useDeleteRecipe = (
|
||||
* Duplicate a recipe
|
||||
*/
|
||||
export const useDuplicateRecipe = (
|
||||
tenantId: string,
|
||||
options?: UseMutationOptions<RecipeResponse, ApiError, { id: string; data: RecipeDuplicateRequest }>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<RecipeResponse, ApiError, { id: string; data: RecipeDuplicateRequest }>({
|
||||
mutationFn: ({ id, data }) => recipesService.duplicateRecipe(id, data),
|
||||
mutationFn: ({ id, data }) => recipesService.duplicateRecipe(tenantId, id, data),
|
||||
onSuccess: (data) => {
|
||||
// Add to lists cache
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists(tenantId) });
|
||||
// Set individual recipe cache
|
||||
queryClient.setQueryData(recipesKeys.detail(data.id), data);
|
||||
queryClient.setQueryData(recipesKeys.detail(tenantId, data.id), data);
|
||||
// Invalidate statistics
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics(tenantId) });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
@@ -251,227 +252,20 @@ export const useDuplicateRecipe = (
|
||||
* Activate a recipe
|
||||
*/
|
||||
export const useActivateRecipe = (
|
||||
tenantId: string,
|
||||
options?: UseMutationOptions<RecipeResponse, ApiError, string>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<RecipeResponse, ApiError, string>({
|
||||
mutationFn: (recipeId: string) => recipesService.activateRecipe(recipeId),
|
||||
mutationFn: (recipeId: string) => recipesService.activateRecipe(tenantId, recipeId),
|
||||
onSuccess: (data) => {
|
||||
// Update individual recipe cache
|
||||
queryClient.setQueryData(recipesKeys.detail(data.id), data);
|
||||
queryClient.setQueryData(recipesKeys.detail(tenantId, data.id), data);
|
||||
// Invalidate lists
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists() });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.lists(tenantId) });
|
||||
// Invalidate statistics
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics() });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
// Production Batch Queries
|
||||
|
||||
/**
|
||||
* Get production batch by ID (recipe-specific)
|
||||
*/
|
||||
export const useRecipeProductionBatch = (
|
||||
batchId: string,
|
||||
options?: Omit<UseQueryOptions<ProductionBatchResponse, ApiError>, 'queryKey' | 'queryFn'>
|
||||
) => {
|
||||
return useQuery<ProductionBatchResponse, ApiError>({
|
||||
queryKey: recipesKeys.productionBatches.detail(batchId),
|
||||
queryFn: () => recipesService.getProductionBatch(batchId),
|
||||
enabled: !!batchId,
|
||||
staleTime: 2 * 60 * 1000, // 2 minutes
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get production batches with filters (recipe-specific)
|
||||
*/
|
||||
export const useRecipeProductionBatches = (
|
||||
filters: {
|
||||
recipe_id?: string;
|
||||
status?: string;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
} = {},
|
||||
options?: Omit<UseQueryOptions<ProductionBatchResponse[], ApiError>, 'queryKey' | 'queryFn'>
|
||||
) => {
|
||||
return useQuery<ProductionBatchResponse[], ApiError>({
|
||||
queryKey: recipesKeys.productionBatches.list(filters),
|
||||
queryFn: () => recipesService.getProductionBatches(filters),
|
||||
staleTime: 1 * 60 * 1000, // 1 minute
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get production batches for a specific recipe
|
||||
*/
|
||||
export const useRecipeProductionBatchesByRecipe = (
|
||||
recipeId: string,
|
||||
options?: Omit<UseQueryOptions<ProductionBatchResponse[], ApiError>, 'queryKey' | 'queryFn'>
|
||||
) => {
|
||||
return useQuery<ProductionBatchResponse[], ApiError>({
|
||||
queryKey: recipesKeys.productionBatches.byRecipe(recipeId),
|
||||
queryFn: () => recipesService.getRecipeProductionBatches(recipeId),
|
||||
enabled: !!recipeId,
|
||||
staleTime: 1 * 60 * 1000, // 1 minute
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
// Production Batch Mutations
|
||||
|
||||
/**
|
||||
* Create a production batch for recipe
|
||||
*/
|
||||
export const useCreateRecipeProductionBatch = (
|
||||
options?: UseMutationOptions<ProductionBatchResponse, ApiError, ProductionBatchCreate>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<ProductionBatchResponse, ApiError, ProductionBatchCreate>({
|
||||
mutationFn: (batchData: ProductionBatchCreate) => recipesService.createProductionBatch(batchData),
|
||||
onSuccess: (data) => {
|
||||
// Set individual batch cache
|
||||
queryClient.setQueryData(recipesKeys.productionBatches.detail(data.id), data);
|
||||
// Invalidate batch lists
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.lists() });
|
||||
// Invalidate recipe-specific batches
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.byRecipe(data.recipe_id) });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update a production batch for recipe
|
||||
*/
|
||||
export const useUpdateRecipeProductionBatch = (
|
||||
options?: UseMutationOptions<ProductionBatchResponse, ApiError, { id: string; data: ProductionBatchUpdate }>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<ProductionBatchResponse, ApiError, { id: string; data: ProductionBatchUpdate }>({
|
||||
mutationFn: ({ id, data }) => recipesService.updateProductionBatch(id, data),
|
||||
onSuccess: (data) => {
|
||||
// Update individual batch cache
|
||||
queryClient.setQueryData(recipesKeys.productionBatches.detail(data.id), data);
|
||||
// Invalidate batch lists
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.lists() });
|
||||
// Invalidate recipe-specific batches
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.byRecipe(data.recipe_id) });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a production batch for recipe
|
||||
*/
|
||||
export const useDeleteRecipeProductionBatch = (
|
||||
options?: UseMutationOptions<{ message: string }, ApiError, string>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<{ message: string }, ApiError, string>({
|
||||
mutationFn: (batchId: string) => recipesService.deleteProductionBatch(batchId),
|
||||
onSuccess: (_, batchId) => {
|
||||
// Remove from individual cache
|
||||
queryClient.removeQueries({ queryKey: recipesKeys.productionBatches.detail(batchId) });
|
||||
// Invalidate batch lists
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.lists() });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Start a production batch for recipe
|
||||
*/
|
||||
export const useStartRecipeProductionBatch = (
|
||||
options?: UseMutationOptions<ProductionBatchResponse, ApiError, string>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<ProductionBatchResponse, ApiError, string>({
|
||||
mutationFn: (batchId: string) => recipesService.startProductionBatch(batchId),
|
||||
onSuccess: (data) => {
|
||||
// Update individual batch cache
|
||||
queryClient.setQueryData(recipesKeys.productionBatches.detail(data.id), data);
|
||||
// Invalidate batch lists
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.lists() });
|
||||
// Invalidate recipe-specific batches
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.byRecipe(data.recipe_id) });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Complete a production batch for recipe
|
||||
*/
|
||||
export const useCompleteRecipeProductionBatch = (
|
||||
options?: UseMutationOptions<ProductionBatchResponse, ApiError, {
|
||||
id: string;
|
||||
data: {
|
||||
actual_quantity?: number;
|
||||
quality_score?: number;
|
||||
quality_notes?: string;
|
||||
waste_quantity?: number;
|
||||
waste_reason?: string;
|
||||
}
|
||||
}>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<ProductionBatchResponse, ApiError, {
|
||||
id: string;
|
||||
data: {
|
||||
actual_quantity?: number;
|
||||
quality_score?: number;
|
||||
quality_notes?: string;
|
||||
waste_quantity?: number;
|
||||
waste_reason?: string;
|
||||
}
|
||||
}>({
|
||||
mutationFn: ({ id, data }) => recipesService.completeProductionBatch(id, data),
|
||||
onSuccess: (data) => {
|
||||
// Update individual batch cache
|
||||
queryClient.setQueryData(recipesKeys.productionBatches.detail(data.id), data);
|
||||
// Invalidate batch lists
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.lists() });
|
||||
// Invalidate recipe-specific batches
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.byRecipe(data.recipe_id) });
|
||||
// Invalidate inventory queries (production affects inventory)
|
||||
queryClient.invalidateQueries({ queryKey: ['inventory'] });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel a production batch for recipe
|
||||
*/
|
||||
export const useCancelRecipeProductionBatch = (
|
||||
options?: UseMutationOptions<ProductionBatchResponse, ApiError, { id: string; reason?: string }>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<ProductionBatchResponse, ApiError, { id: string; reason?: string }>({
|
||||
mutationFn: ({ id, reason }) => recipesService.cancelProductionBatch(id, reason),
|
||||
onSuccess: (data) => {
|
||||
// Update individual batch cache
|
||||
queryClient.setQueryData(recipesKeys.productionBatches.detail(data.id), data);
|
||||
// Invalidate batch lists
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.lists() });
|
||||
// Invalidate recipe-specific batches
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.productionBatches.byRecipe(data.recipe_id) });
|
||||
queryClient.invalidateQueries({ queryKey: recipesKeys.statistics(tenantId) });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user