Files
bakery-ia/frontend/src/components/domain/unified-wizard/UnifiedAddWizard.tsx

137 lines
4.6 KiB
TypeScript
Raw Normal View History

fix: CRITICAL ROOT CAUSE - Prevent wizard component recreation on every keystroke ROOT CAUSE ANALYSIS: The input focus loss bug was caused by the wizard steps being recreated on EVERY SINGLE RENDER of UnifiedAddWizard, which happened on EVERY KEYSTROKE. DETAILED PROBLEM FLOW: 1. User types in name field → handleDataChange called 2. handleDataChange calls setWizardData → UnifiedAddWizard re-renders 3. Line 127: steps={getWizardSteps()} called on every render 4. getWizardSteps() calls InventoryWizardSteps(wizardData, setWizardData) 5. Returns NEW array with NEW component function references: component: (props) => <InventoryDetailsStep {...props} data={data} onDataChange={setData} /> 6. React compares old component ref with new ref, sees they're different 7. React UNMOUNTS old component and MOUNTS new component 8. Input element is DESTROYED and RECREATED → LOSES FOCUS This happened on EVERY keystroke because: - wizardData updates on every keystroke - getWizardSteps() runs on every render - New component functions created every time - React sees different function reference = different component type SOLUTION: Used useMemo to memoize the wizardSteps array so it's only recreated when selectedItemType changes, NOT when wizardData changes. const wizardSteps = useMemo(() => { // ... generate steps }, [selectedItemType, handleItemTypeSelect]); Now the step component functions maintain the same reference across renders, so React keeps the same component instance mounted, preserving input focus. IMPACT: ✅ Inputs no longer lose focus while typing ✅ Component state is preserved between keystrokes ✅ No more unmount/remount cycles on every keystroke ✅ Dramatically improved performance (no unnecessary component recreation) This was the TRUE root cause - the previous fixes helped but didn't solve the fundamental architectural issue of recreating components on every render.
2025-11-10 10:19:54 +00:00
import React, { useState, useCallback, useMemo } from 'react';
feat: Add JTBD-driven Unified Add Wizard system Implemented a comprehensive unified wizard system to consolidate all "add new content" actions into a single, intuitive, step-by-step guided experience based on Jobs To Be Done (JTBD) methodology. ## What's New ### Core Components - **UnifiedAddWizard**: Main orchestrator component that routes to specific wizards - **ItemTypeSelector**: Beautiful visual card-based selection for 9 content types - **9 Individual Wizards**: Step-by-step flows for each content type ### Priority Implementations (P0) 1. **SalesEntryWizard** ⭐ (MOST CRITICAL) - Manual entry with dynamic product lists and auto-calculated totals - File upload placeholder for CSV/Excel bulk import - Critical for small bakeries without POS systems 2. **InventoryWizard** - Type selection (ingredient vs finished product) - Context-aware forms based on inventory type - Optional initial lot entry ### Placeholder Wizards (P1/P2) - Customer Order, Supplier, Recipe, Customer, Quality Template, Equipment, Team Member - Proper structure in place for incremental enhancement ### Dashboard Integration - Added prominent "Agregar" button in dashboard header - Opens wizard modal with visual type selection - Auto-refreshes dashboard after wizard completion ### Design Highlights - Mobile-first responsive design (full-screen on mobile, modal on desktop) - Touch-friendly with 44px+ touch targets - Follows existing color system and design tokens - Progressive disclosure to reduce cognitive load - Accessibility-compliant (WCAG AA) ## Documentation Created comprehensive documentation: - `JTBD_UNIFIED_ADD_WIZARD.md` - Full JTBD analysis and research - `WIZARD_ARCHITECTURE_DESIGN.md` - Technical design and specifications - `UNIFIED_WIZARD_IMPLEMENTATION_SUMMARY.md` - Implementation guide ## Files Changed - New: `frontend/src/components/domain/unified-wizard/` (15 new files) - Modified: `frontend/src/pages/app/DashboardPage.tsx` (added wizard integration) ## Next Steps - [ ] Connect wizards to real API endpoints (currently mock/placeholder) - [ ] Implement full CSV upload for sales entry - [ ] Add comprehensive form validation - [ ] Enhance P1 priority wizards based on user feedback ## JTBD Alignment Main Job: "When I need to expand or update my bakery operations, I want to quickly add new resources to my management system, so I can keep my business running smoothly." Key insights applied: - Prioritized sales entry (most bakeries lack POS) - Mobile-first (bakery owners are on their feet) - Progressive disclosure (reduce overwhelm) - Forgiving interactions (can go back, save drafts)
2025-11-09 08:40:01 +00:00
import { Sparkles } from 'lucide-react';
import { WizardModal, WizardStep } from '../../ui/WizardModal/WizardModal';
import { ItemTypeSelector, ItemType } from './ItemTypeSelector';
// Import specific wizards
import { InventoryWizardSteps } from './wizards/InventoryWizard';
import { SupplierWizardSteps } from './wizards/SupplierWizard';
import { RecipeWizardSteps } from './wizards/RecipeWizard';
import { EquipmentWizardSteps } from './wizards/EquipmentWizard';
import { QualityTemplateWizardSteps } from './wizards/QualityTemplateWizard';
import { CustomerOrderWizardSteps } from './wizards/CustomerOrderWizard';
import { CustomerWizardSteps } from './wizards/CustomerWizard';
import { TeamMemberWizardSteps } from './wizards/TeamMemberWizard';
import { SalesEntryWizardSteps } from './wizards/SalesEntryWizard';
interface UnifiedAddWizardProps {
isOpen: boolean;
onClose: () => void;
onComplete?: (itemType: ItemType, data?: any) => void;
// Optional: Start with a specific item type (when opened from individual page buttons)
initialItemType?: ItemType;
}
export const UnifiedAddWizard: React.FC<UnifiedAddWizardProps> = ({
isOpen,
onClose,
onComplete,
initialItemType,
}) => {
const [selectedItemType, setSelectedItemType] = useState<ItemType | null>(
initialItemType || null
);
const [wizardData, setWizardData] = useState<Record<string, any>>({});
// Reset state when modal closes
const handleClose = useCallback(() => {
setSelectedItemType(initialItemType || null);
setWizardData({});
onClose();
}, [onClose, initialItemType]);
// Handle item type selection from step 0
const handleItemTypeSelect = useCallback((itemType: ItemType) => {
setSelectedItemType(itemType);
}, []);
// Handle wizard completion
const handleWizardComplete = useCallback(
(data?: any) => {
if (selectedItemType) {
onComplete?.(selectedItemType, data);
}
handleClose();
},
[selectedItemType, onComplete, handleClose]
);
// Get wizard steps based on selected item type
fix: CRITICAL ROOT CAUSE - Prevent wizard component recreation on every keystroke ROOT CAUSE ANALYSIS: The input focus loss bug was caused by the wizard steps being recreated on EVERY SINGLE RENDER of UnifiedAddWizard, which happened on EVERY KEYSTROKE. DETAILED PROBLEM FLOW: 1. User types in name field → handleDataChange called 2. handleDataChange calls setWizardData → UnifiedAddWizard re-renders 3. Line 127: steps={getWizardSteps()} called on every render 4. getWizardSteps() calls InventoryWizardSteps(wizardData, setWizardData) 5. Returns NEW array with NEW component function references: component: (props) => <InventoryDetailsStep {...props} data={data} onDataChange={setData} /> 6. React compares old component ref with new ref, sees they're different 7. React UNMOUNTS old component and MOUNTS new component 8. Input element is DESTROYED and RECREATED → LOSES FOCUS This happened on EVERY keystroke because: - wizardData updates on every keystroke - getWizardSteps() runs on every render - New component functions created every time - React sees different function reference = different component type SOLUTION: Used useMemo to memoize the wizardSteps array so it's only recreated when selectedItemType changes, NOT when wizardData changes. const wizardSteps = useMemo(() => { // ... generate steps }, [selectedItemType, handleItemTypeSelect]); Now the step component functions maintain the same reference across renders, so React keeps the same component instance mounted, preserving input focus. IMPACT: ✅ Inputs no longer lose focus while typing ✅ Component state is preserved between keystrokes ✅ No more unmount/remount cycles on every keystroke ✅ Dramatically improved performance (no unnecessary component recreation) This was the TRUE root cause - the previous fixes helped but didn't solve the fundamental architectural issue of recreating components on every render.
2025-11-10 10:19:54 +00:00
// CRITICAL: Memoize the steps to prevent component recreation on every render
// Without this, every keystroke causes the component to unmount/remount, losing focus
const wizardSteps = useMemo((): WizardStep[] => {
feat: Add JTBD-driven Unified Add Wizard system Implemented a comprehensive unified wizard system to consolidate all "add new content" actions into a single, intuitive, step-by-step guided experience based on Jobs To Be Done (JTBD) methodology. ## What's New ### Core Components - **UnifiedAddWizard**: Main orchestrator component that routes to specific wizards - **ItemTypeSelector**: Beautiful visual card-based selection for 9 content types - **9 Individual Wizards**: Step-by-step flows for each content type ### Priority Implementations (P0) 1. **SalesEntryWizard** ⭐ (MOST CRITICAL) - Manual entry with dynamic product lists and auto-calculated totals - File upload placeholder for CSV/Excel bulk import - Critical for small bakeries without POS systems 2. **InventoryWizard** - Type selection (ingredient vs finished product) - Context-aware forms based on inventory type - Optional initial lot entry ### Placeholder Wizards (P1/P2) - Customer Order, Supplier, Recipe, Customer, Quality Template, Equipment, Team Member - Proper structure in place for incremental enhancement ### Dashboard Integration - Added prominent "Agregar" button in dashboard header - Opens wizard modal with visual type selection - Auto-refreshes dashboard after wizard completion ### Design Highlights - Mobile-first responsive design (full-screen on mobile, modal on desktop) - Touch-friendly with 44px+ touch targets - Follows existing color system and design tokens - Progressive disclosure to reduce cognitive load - Accessibility-compliant (WCAG AA) ## Documentation Created comprehensive documentation: - `JTBD_UNIFIED_ADD_WIZARD.md` - Full JTBD analysis and research - `WIZARD_ARCHITECTURE_DESIGN.md` - Technical design and specifications - `UNIFIED_WIZARD_IMPLEMENTATION_SUMMARY.md` - Implementation guide ## Files Changed - New: `frontend/src/components/domain/unified-wizard/` (15 new files) - Modified: `frontend/src/pages/app/DashboardPage.tsx` (added wizard integration) ## Next Steps - [ ] Connect wizards to real API endpoints (currently mock/placeholder) - [ ] Implement full CSV upload for sales entry - [ ] Add comprehensive form validation - [ ] Enhance P1 priority wizards based on user feedback ## JTBD Alignment Main Job: "When I need to expand or update my bakery operations, I want to quickly add new resources to my management system, so I can keep my business running smoothly." Key insights applied: - Prioritized sales entry (most bakeries lack POS) - Mobile-first (bakery owners are on their feet) - Progressive disclosure (reduce overwhelm) - Forgiving interactions (can go back, save drafts)
2025-11-09 08:40:01 +00:00
if (!selectedItemType) {
// Step 0: Item Type Selection
return [
{
id: 'item-type-selection',
title: 'Seleccionar tipo',
description: 'Elige qué deseas agregar',
component: (props) => (
<ItemTypeSelector onSelect={handleItemTypeSelect} />
),
},
];
}
// Return specific wizard steps based on selected type
switch (selectedItemType) {
case 'inventory':
return InventoryWizardSteps(wizardData, setWizardData);
case 'supplier':
return SupplierWizardSteps(wizardData, setWizardData);
case 'recipe':
return RecipeWizardSteps(wizardData, setWizardData);
case 'equipment':
return EquipmentWizardSteps(wizardData, setWizardData);
case 'quality-template':
return QualityTemplateWizardSteps(wizardData, setWizardData);
case 'customer-order':
return CustomerOrderWizardSteps(wizardData, setWizardData);
case 'customer':
return CustomerWizardSteps(wizardData, setWizardData);
case 'team-member':
return TeamMemberWizardSteps(wizardData, setWizardData);
case 'sales-entry':
return SalesEntryWizardSteps(wizardData, setWizardData);
default:
return [];
}
fix: CRITICAL ROOT CAUSE - Prevent wizard component recreation on every keystroke ROOT CAUSE ANALYSIS: The input focus loss bug was caused by the wizard steps being recreated on EVERY SINGLE RENDER of UnifiedAddWizard, which happened on EVERY KEYSTROKE. DETAILED PROBLEM FLOW: 1. User types in name field → handleDataChange called 2. handleDataChange calls setWizardData → UnifiedAddWizard re-renders 3. Line 127: steps={getWizardSteps()} called on every render 4. getWizardSteps() calls InventoryWizardSteps(wizardData, setWizardData) 5. Returns NEW array with NEW component function references: component: (props) => <InventoryDetailsStep {...props} data={data} onDataChange={setData} /> 6. React compares old component ref with new ref, sees they're different 7. React UNMOUNTS old component and MOUNTS new component 8. Input element is DESTROYED and RECREATED → LOSES FOCUS This happened on EVERY keystroke because: - wizardData updates on every keystroke - getWizardSteps() runs on every render - New component functions created every time - React sees different function reference = different component type SOLUTION: Used useMemo to memoize the wizardSteps array so it's only recreated when selectedItemType changes, NOT when wizardData changes. const wizardSteps = useMemo(() => { // ... generate steps }, [selectedItemType, handleItemTypeSelect]); Now the step component functions maintain the same reference across renders, so React keeps the same component instance mounted, preserving input focus. IMPACT: ✅ Inputs no longer lose focus while typing ✅ Component state is preserved between keystrokes ✅ No more unmount/remount cycles on every keystroke ✅ Dramatically improved performance (no unnecessary component recreation) This was the TRUE root cause - the previous fixes helped but didn't solve the fundamental architectural issue of recreating components on every render.
2025-11-10 10:19:54 +00:00
}, [selectedItemType, handleItemTypeSelect]); // Only recreate when item type changes, NOT when wizardData changes
feat: Add JTBD-driven Unified Add Wizard system Implemented a comprehensive unified wizard system to consolidate all "add new content" actions into a single, intuitive, step-by-step guided experience based on Jobs To Be Done (JTBD) methodology. ## What's New ### Core Components - **UnifiedAddWizard**: Main orchestrator component that routes to specific wizards - **ItemTypeSelector**: Beautiful visual card-based selection for 9 content types - **9 Individual Wizards**: Step-by-step flows for each content type ### Priority Implementations (P0) 1. **SalesEntryWizard** ⭐ (MOST CRITICAL) - Manual entry with dynamic product lists and auto-calculated totals - File upload placeholder for CSV/Excel bulk import - Critical for small bakeries without POS systems 2. **InventoryWizard** - Type selection (ingredient vs finished product) - Context-aware forms based on inventory type - Optional initial lot entry ### Placeholder Wizards (P1/P2) - Customer Order, Supplier, Recipe, Customer, Quality Template, Equipment, Team Member - Proper structure in place for incremental enhancement ### Dashboard Integration - Added prominent "Agregar" button in dashboard header - Opens wizard modal with visual type selection - Auto-refreshes dashboard after wizard completion ### Design Highlights - Mobile-first responsive design (full-screen on mobile, modal on desktop) - Touch-friendly with 44px+ touch targets - Follows existing color system and design tokens - Progressive disclosure to reduce cognitive load - Accessibility-compliant (WCAG AA) ## Documentation Created comprehensive documentation: - `JTBD_UNIFIED_ADD_WIZARD.md` - Full JTBD analysis and research - `WIZARD_ARCHITECTURE_DESIGN.md` - Technical design and specifications - `UNIFIED_WIZARD_IMPLEMENTATION_SUMMARY.md` - Implementation guide ## Files Changed - New: `frontend/src/components/domain/unified-wizard/` (15 new files) - Modified: `frontend/src/pages/app/DashboardPage.tsx` (added wizard integration) ## Next Steps - [ ] Connect wizards to real API endpoints (currently mock/placeholder) - [ ] Implement full CSV upload for sales entry - [ ] Add comprehensive form validation - [ ] Enhance P1 priority wizards based on user feedback ## JTBD Alignment Main Job: "When I need to expand or update my bakery operations, I want to quickly add new resources to my management system, so I can keep my business running smoothly." Key insights applied: - Prioritized sales entry (most bakeries lack POS) - Mobile-first (bakery owners are on their feet) - Progressive disclosure (reduce overwhelm) - Forgiving interactions (can go back, save drafts)
2025-11-09 08:40:01 +00:00
// Get wizard title based on selected item type
const getWizardTitle = (): string => {
if (!selectedItemType) {
return 'Agregar Contenido';
}
const titleMap: Record<ItemType, string> = {
'inventory': 'Agregar Inventario',
'supplier': 'Agregar Proveedor',
'recipe': 'Agregar Receta',
'equipment': 'Agregar Equipo',
'quality-template': 'Agregar Plantilla de Calidad',
'customer-order': 'Agregar Pedido',
'customer': 'Agregar Cliente',
'team-member': 'Agregar Miembro del Equipo',
'sales-entry': 'Registrar Ventas',
};
return titleMap[selectedItemType] || 'Agregar Contenido';
};
return (
<WizardModal
isOpen={isOpen}
onClose={handleClose}
onComplete={handleWizardComplete}
title={getWizardTitle()}
fix: CRITICAL ROOT CAUSE - Prevent wizard component recreation on every keystroke ROOT CAUSE ANALYSIS: The input focus loss bug was caused by the wizard steps being recreated on EVERY SINGLE RENDER of UnifiedAddWizard, which happened on EVERY KEYSTROKE. DETAILED PROBLEM FLOW: 1. User types in name field → handleDataChange called 2. handleDataChange calls setWizardData → UnifiedAddWizard re-renders 3. Line 127: steps={getWizardSteps()} called on every render 4. getWizardSteps() calls InventoryWizardSteps(wizardData, setWizardData) 5. Returns NEW array with NEW component function references: component: (props) => <InventoryDetailsStep {...props} data={data} onDataChange={setData} /> 6. React compares old component ref with new ref, sees they're different 7. React UNMOUNTS old component and MOUNTS new component 8. Input element is DESTROYED and RECREATED → LOSES FOCUS This happened on EVERY keystroke because: - wizardData updates on every keystroke - getWizardSteps() runs on every render - New component functions created every time - React sees different function reference = different component type SOLUTION: Used useMemo to memoize the wizardSteps array so it's only recreated when selectedItemType changes, NOT when wizardData changes. const wizardSteps = useMemo(() => { // ... generate steps }, [selectedItemType, handleItemTypeSelect]); Now the step component functions maintain the same reference across renders, so React keeps the same component instance mounted, preserving input focus. IMPACT: ✅ Inputs no longer lose focus while typing ✅ Component state is preserved between keystrokes ✅ No more unmount/remount cycles on every keystroke ✅ Dramatically improved performance (no unnecessary component recreation) This was the TRUE root cause - the previous fixes helped but didn't solve the fundamental architectural issue of recreating components on every render.
2025-11-10 10:19:54 +00:00
steps={wizardSteps}
feat: Add JTBD-driven Unified Add Wizard system Implemented a comprehensive unified wizard system to consolidate all "add new content" actions into a single, intuitive, step-by-step guided experience based on Jobs To Be Done (JTBD) methodology. ## What's New ### Core Components - **UnifiedAddWizard**: Main orchestrator component that routes to specific wizards - **ItemTypeSelector**: Beautiful visual card-based selection for 9 content types - **9 Individual Wizards**: Step-by-step flows for each content type ### Priority Implementations (P0) 1. **SalesEntryWizard** ⭐ (MOST CRITICAL) - Manual entry with dynamic product lists and auto-calculated totals - File upload placeholder for CSV/Excel bulk import - Critical for small bakeries without POS systems 2. **InventoryWizard** - Type selection (ingredient vs finished product) - Context-aware forms based on inventory type - Optional initial lot entry ### Placeholder Wizards (P1/P2) - Customer Order, Supplier, Recipe, Customer, Quality Template, Equipment, Team Member - Proper structure in place for incremental enhancement ### Dashboard Integration - Added prominent "Agregar" button in dashboard header - Opens wizard modal with visual type selection - Auto-refreshes dashboard after wizard completion ### Design Highlights - Mobile-first responsive design (full-screen on mobile, modal on desktop) - Touch-friendly with 44px+ touch targets - Follows existing color system and design tokens - Progressive disclosure to reduce cognitive load - Accessibility-compliant (WCAG AA) ## Documentation Created comprehensive documentation: - `JTBD_UNIFIED_ADD_WIZARD.md` - Full JTBD analysis and research - `WIZARD_ARCHITECTURE_DESIGN.md` - Technical design and specifications - `UNIFIED_WIZARD_IMPLEMENTATION_SUMMARY.md` - Implementation guide ## Files Changed - New: `frontend/src/components/domain/unified-wizard/` (15 new files) - Modified: `frontend/src/pages/app/DashboardPage.tsx` (added wizard integration) ## Next Steps - [ ] Connect wizards to real API endpoints (currently mock/placeholder) - [ ] Implement full CSV upload for sales entry - [ ] Add comprehensive form validation - [ ] Enhance P1 priority wizards based on user feedback ## JTBD Alignment Main Job: "When I need to expand or update my bakery operations, I want to quickly add new resources to my management system, so I can keep my business running smoothly." Key insights applied: - Prioritized sales entry (most bakeries lack POS) - Mobile-first (bakery owners are on their feet) - Progressive disclosure (reduce overwhelm) - Forgiving interactions (can go back, save drafts)
2025-11-09 08:40:01 +00:00
icon={<Sparkles className="w-6 h-6" />}
size="xl"
/>
);
};
export default UnifiedAddWizard;