import React, { useState, useMemo } from 'react'; import { ChefHat } from 'lucide-react'; import { WizardModal, WizardStep } from '../../../ui/WizardModal/WizardModal'; import { RecipeProductStep } from './RecipeProductStep'; import { RecipeIngredientsStep } from './RecipeIngredientsStep'; import { RecipeProductionStep } from './RecipeProductionStep'; import { RecipeReviewStep } from './RecipeReviewStep'; import type { RecipeCreate, RecipeIngredientCreate, MeasurementUnit } from '../../../../api/types/recipes'; import { useIngredients } from '../../../../api/hooks/inventory'; import { useCurrentTenant } from '../../../../stores/tenant.store'; interface RecipeWizardModalProps { isOpen: boolean; onClose: () => void; onCreateRecipe: (recipeData: RecipeCreate) => Promise; } export const RecipeWizardModal: React.FC = ({ isOpen, onClose, onCreateRecipe }) => { // Recipe state const [recipeData, setRecipeData] = useState>({ difficulty_level: 1, yield_quantity: 1, yield_unit: 'units' as MeasurementUnit, serves_count: 1, prep_time_minutes: 0, cook_time_minutes: 0, rest_time_minutes: 0, target_margin_percentage: 30, batch_size_multiplier: 1.0, is_seasonal: false, is_signature_item: false, ingredients: [{ ingredient_id: '', quantity: 1, unit: 'grams' as MeasurementUnit, ingredient_order: 1, is_optional: false }] }); // Get tenant and fetch data const currentTenant = useCurrentTenant(); const tenantId = currentTenant?.id || ''; const { data: inventoryItems = [], isLoading: inventoryLoading } = useIngredients(tenantId, {}); // Separate finished products and ingredients const finishedProducts = useMemo(() => (inventoryItems || []) .filter(item => item.product_type === 'finished_product') .map(product => ({ value: product.id, label: `${product.name} (${product.category || 'Sin categoría'})` })), [inventoryItems] ); const availableIngredients = useMemo(() => (inventoryItems || []) .filter(item => item.product_type !== 'finished_product') .map(ingredient => ({ value: ingredient.id, label: `${ingredient.name} (${ingredient.category || 'Sin categoría'})` })), [inventoryItems] ); // Create map of ingredient IDs to names for display const ingredientNames = useMemo(() => { const map = new Map(); inventoryItems.forEach(item => { map.set(item.id, item.name); }); return map; }, [inventoryItems]); // Options const categoryOptions = [ { value: 'bread', label: 'Pan' }, { value: 'pastry', label: 'Bollería' }, { value: 'cake', label: 'Tarta' }, { value: 'cookie', label: 'Galleta' }, { value: 'muffin', label: 'Muffin' }, { value: 'savory', label: 'Salado' }, { value: 'desserts', label: 'Postres' }, { value: 'specialty', label: 'Especialidad' }, { value: 'other', label: 'Otro' } ]; const cuisineTypeOptions = [ { value: 'french', label: 'Francés' }, { value: 'spanish', label: 'Español' }, { value: 'italian', label: 'Italiano' }, { value: 'german', label: 'Alemán' }, { value: 'american', label: 'Americano' }, { value: 'artisanal', label: 'Artesanal' }, { value: 'traditional', label: 'Tradicional' }, { value: 'modern', label: 'Moderno' } ]; const unitOptions = [ { value: 'units' as MeasurementUnit, label: 'Unidades' }, { value: 'pieces' as MeasurementUnit, label: 'Piezas' }, { value: 'grams' as MeasurementUnit, label: 'Gramos' }, { value: 'kilograms' as MeasurementUnit, label: 'Kilogramos' }, { value: 'milliliters' as MeasurementUnit, label: 'Mililitros' }, { value: 'liters' as MeasurementUnit, label: 'Litros' } ]; const handleUpdate = (data: Partial) => { setRecipeData(data); }; const handleComplete = async () => { try { // Generate recipe code if not provided const recipeCode = recipeData.recipe_code || (recipeData.name?.substring(0, 3).toUpperCase() || 'RCP') + String(Date.now()).slice(-3); // Calculate total time const totalTime = (recipeData.prep_time_minutes || 0) + (recipeData.cook_time_minutes || 0) + (recipeData.rest_time_minutes || 0); // Filter and validate ingredients const validIngredients = (recipeData.ingredients || []) .filter((ing: RecipeIngredientCreate) => ing.ingredient_id && ing.ingredient_id.trim() !== '') .map((ing: RecipeIngredientCreate, index: number) => ({ ...ing, ingredient_order: index + 1 })); if (validIngredients.length === 0) { throw new Error('Debe agregar al menos un ingrediente válido'); } // Build final recipe data const finalRecipeData: RecipeCreate = { name: recipeData.name!, recipe_code: recipeCode, version: recipeData.version || '1.0', finished_product_id: recipeData.finished_product_id!, description: recipeData.description || '', category: recipeData.category!, cuisine_type: recipeData.cuisine_type || '', difficulty_level: recipeData.difficulty_level!, yield_quantity: recipeData.yield_quantity!, yield_unit: recipeData.yield_unit!, prep_time_minutes: recipeData.prep_time_minutes || 0, cook_time_minutes: recipeData.cook_time_minutes || 0, total_time_minutes: totalTime, rest_time_minutes: recipeData.rest_time_minutes || 0, target_margin_percentage: recipeData.target_margin_percentage || 30, instructions: null, preparation_notes: recipeData.preparation_notes || '', storage_instructions: recipeData.storage_instructions || '', quality_check_configuration: null, serves_count: recipeData.serves_count || 1, is_seasonal: recipeData.is_seasonal || false, season_start_month: recipeData.is_seasonal ? recipeData.season_start_month : undefined, season_end_month: recipeData.is_seasonal ? recipeData.season_end_month : undefined, is_signature_item: recipeData.is_signature_item || false, batch_size_multiplier: recipeData.batch_size_multiplier || 1.0, minimum_batch_size: recipeData.minimum_batch_size, maximum_batch_size: recipeData.maximum_batch_size, optimal_production_temperature: recipeData.optimal_production_temperature, optimal_humidity: recipeData.optimal_humidity, allergen_info: recipeData.allergen_info || null, dietary_tags: recipeData.dietary_tags || null, nutritional_info: recipeData.nutritional_info || null, ingredients: validIngredients }; await onCreateRecipe(finalRecipeData); // Reset state setRecipeData({ difficulty_level: 1, yield_quantity: 1, yield_unit: 'units' as MeasurementUnit, serves_count: 1, prep_time_minutes: 0, cook_time_minutes: 0, rest_time_minutes: 0, target_margin_percentage: 30, batch_size_multiplier: 1.0, is_seasonal: false, is_signature_item: false, ingredients: [{ ingredient_id: '', quantity: 1, unit: 'grams' as MeasurementUnit, ingredient_order: 1, is_optional: false }] }); } catch (error) { console.error('Error creating recipe:', error); throw error; } }; // Define wizard steps const steps: WizardStep[] = [ { id: 'product', title: 'Información del Producto', description: 'Configura los datos básicos de la receta', component: (props) => ( ), validate: () => { return !!( recipeData.name && recipeData.name.trim().length >= 2 && recipeData.finished_product_id && recipeData.category ); } }, { id: 'ingredients', title: 'Ingredientes', description: 'Agrega los ingredientes necesarios', component: (props) => ( ), validate: () => { const ingredients = recipeData.ingredients || []; return ingredients.length > 0 && ingredients.some(ing => ing.ingredient_id && ing.ingredient_id.trim() !== '' && ing.quantity > 0); } }, { id: 'production', title: 'Detalles de Producción', description: 'Define tiempos y parámetros', component: (props) => ( ), validate: () => { return !!(recipeData.yield_quantity && Number(recipeData.yield_quantity) > 0 && recipeData.yield_unit); } }, { id: 'review', title: 'Instrucciones y Revisión', description: 'Completa las instrucciones y revisa', component: (props) => ( ) } ]; return ( } size="2xl" /> ); };