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 })}
+
+
+
+
+ )}
);
};