From 8be364ef816a637a83a1a0904d873d82332eeed6 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 6 Nov 2025 15:01:24 +0000 Subject: [PATCH] Fix recipes step next button & start AI inventory redesign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔧 Recipes Step Fix: - Add onComplete prop handling to RecipesSetupStep - Add "Next" button when minimum requirement met (recipes.length >= 1) - Show success indicator with recipe count - Button only visible when not in adding mode 🚧 AI Inventory Step Redesign (In Progress): - Updated InventoryItem interface to support both AI suggestions and manual entries - Added new fields: id, isSuggested, isExpanded, low_stock_threshold, reorder_point - Modified AI suggestion mapper to calculate inventory management defaults - Next: Need to redesign UI from checkbox-grid to expandable-card list - Next: Add manual ingredient addition form - Next: Move inventory creation from button to onComplete/onNext handler This is work in progress - UI redesign not yet complete. --- .../onboarding/steps/UploadSalesDataStep.tsx | 42 ++++++++++++------- .../setup-wizard/steps/RecipesSetupStep.tsx | 22 +++++++++- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/domain/onboarding/steps/UploadSalesDataStep.tsx b/frontend/src/components/domain/onboarding/steps/UploadSalesDataStep.tsx index e69ab371..3f124826 100644 --- a/frontend/src/components/domain/onboarding/steps/UploadSalesDataStep.tsx +++ b/frontend/src/components/domain/onboarding/steps/UploadSalesDataStep.tsx @@ -24,14 +24,15 @@ interface ProgressState { } interface InventoryItem { - suggestion_id: string; - original_name: string; - suggested_name: string; + id: string; // Unique ID for UI tracking + suggestion_id?: string; // Only for AI suggestions + original_name?: string; // Only for AI suggestions + suggested_name: string; // The actual ingredient name product_type: string; category: string; unit_of_measure: string; - confidence_score: number; - estimated_shelf_life_days?: number; + confidence_score?: number; // Only for AI suggestions + estimated_shelf_life_days: number; requires_refrigeration: boolean; requires_freezing: boolean; is_seasonal: boolean; @@ -44,9 +45,12 @@ interface InventoryItem { frequency: number; }; // UI-specific fields - selected: boolean; + isSuggested: boolean; // true for AI, false for manual + isExpanded: boolean; // for expand/collapse UI stock_quantity: number; cost_per_unit: number; + low_stock_threshold: number; + reorder_point: number; } export const UploadSalesDataStep: React.FC = ({ @@ -170,20 +174,27 @@ export const UploadSalesDataStep: React.FC = ({ setProgressState({ stage: 'preparing', progress: 90, message: 'Preparando sugerencias de inventario...' }); // Convert API response to InventoryItem format - use exact backend structure plus UI fields - const items: InventoryItem[] = classificationResponse.suggestions.map((suggestion: ProductSuggestionResponse) => { + const items: InventoryItem[] = classificationResponse.suggestions.map((suggestion: ProductSuggestionResponse, index: number) => { // Calculate default stock quantity based on sales data const defaultStock = Math.max( Math.ceil((suggestion.sales_data?.average_daily_sales || 1) * 7), // 1 week supply 1 ); - + // Estimate cost per unit based on category - const estimatedCost = suggestion.category === 'Dairy' ? 5.0 : - suggestion.category === 'Baking Ingredients' ? 2.0 : + const estimatedCost = suggestion.category === 'Dairy' ? 5.0 : + suggestion.category === 'Baking Ingredients' ? 2.0 : 3.0; + // Calculate inventory management defaults + const minimumStock = Math.max(1, Math.ceil(defaultStock * 0.2)); + const calculatedReorderPoint = Math.ceil(defaultStock * 0.3); + const reorderPoint = Math.max(minimumStock + 2, calculatedReorderPoint, minimumStock + 1); + return { - // Exact backend fields + // UI tracking + id: `ai-${index}-${Date.now()}`, + // AI suggestion fields suggestion_id: suggestion.suggestion_id, original_name: suggestion.original_name, suggested_name: suggestion.suggested_name, @@ -191,7 +202,7 @@ export const UploadSalesDataStep: React.FC = ({ category: suggestion.category, unit_of_measure: suggestion.unit_of_measure, confidence_score: suggestion.confidence_score, - estimated_shelf_life_days: suggestion.estimated_shelf_life_days, + estimated_shelf_life_days: suggestion.estimated_shelf_life_days || 30, requires_refrigeration: suggestion.requires_refrigeration, requires_freezing: suggestion.requires_freezing, is_seasonal: suggestion.is_seasonal, @@ -199,9 +210,12 @@ export const UploadSalesDataStep: React.FC = ({ notes: suggestion.notes, sales_data: suggestion.sales_data, // UI-specific fields - selected: suggestion.confidence_score > 0.7, // Auto-select high confidence items + isSuggested: true, + isExpanded: false, // Start collapsed stock_quantity: defaultStock, - cost_per_unit: estimatedCost + cost_per_unit: estimatedCost, + low_stock_threshold: minimumStock, + reorder_point: reorderPoint }; }); diff --git a/frontend/src/components/domain/setup-wizard/steps/RecipesSetupStep.tsx b/frontend/src/components/domain/setup-wizard/steps/RecipesSetupStep.tsx index aa63fba5..643f720c 100644 --- a/frontend/src/components/domain/setup-wizard/steps/RecipesSetupStep.tsx +++ b/frontend/src/components/domain/setup-wizard/steps/RecipesSetupStep.tsx @@ -16,7 +16,7 @@ interface RecipeIngredientForm { ingredient_order: number; } -export const RecipesSetupStep: React.FC = ({ onUpdate }) => { +export const RecipesSetupStep: React.FC = ({ onUpdate, onComplete }) => { const { t } = useTranslation(); // Get tenant ID @@ -714,6 +714,26 @@ export const RecipesSetupStep: React.FC = ({ onUpdate }) => {

)} + + {/* Navigation - Show Next button when minimum requirement met */} + {recipes.length >= 1 && !isAdding && ( +
+
+ + + + + {t('setup_wizard:recipes.minimum_met', '{{count}} recipe(s) added - Ready to continue!', { count: recipes.length })} + +
+ +
+ )} ); };