Improve the UI add button
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react';
|
||||
import { Sparkles } from 'lucide-react';
|
||||
import { WizardModal, WizardStep } from '../../ui/WizardModal/WizardModal';
|
||||
import { ItemTypeSelector, ItemType } from './ItemTypeSelector';
|
||||
import { AnyWizardData } from './types';
|
||||
|
||||
// Import specific wizards
|
||||
import { InventoryWizardSteps } from './wizards/InventoryWizard';
|
||||
import { InventoryWizardSteps, ProductTypeStep, BasicInfoStep, StockConfigStep } from './wizards/InventoryWizard';
|
||||
import { SupplierWizardSteps } from './wizards/SupplierWizard';
|
||||
import { RecipeWizardSteps } from './wizards/RecipeWizard';
|
||||
import { EquipmentWizardSteps } from './wizards/EquipmentWizard';
|
||||
@@ -31,12 +32,22 @@ export const UnifiedAddWizard: React.FC<UnifiedAddWizardProps> = ({
|
||||
const [selectedItemType, setSelectedItemType] = useState<ItemType | null>(
|
||||
initialItemType || null
|
||||
);
|
||||
const [wizardData, setWizardData] = useState<Record<string, any>>({});
|
||||
const [wizardData, setWizardData] = useState<AnyWizardData>({});
|
||||
|
||||
// Use a ref to store the current data - this allows step components
|
||||
// to always access the latest data without causing the steps array to be recreated
|
||||
const dataRef = useRef<AnyWizardData>({});
|
||||
|
||||
// Update ref whenever data changes
|
||||
useEffect(() => {
|
||||
dataRef.current = wizardData;
|
||||
}, [wizardData]);
|
||||
|
||||
// Reset state when modal closes
|
||||
const handleClose = useCallback(() => {
|
||||
setSelectedItemType(initialItemType || null);
|
||||
setWizardData({});
|
||||
dataRef.current = {};
|
||||
onClose();
|
||||
}, [onClose, initialItemType]);
|
||||
|
||||
@@ -45,11 +56,23 @@ export const UnifiedAddWizard: React.FC<UnifiedAddWizardProps> = ({
|
||||
setSelectedItemType(itemType);
|
||||
}, []);
|
||||
|
||||
// CRITICAL FIX: Update both ref AND state, but wizardSteps won't recreate
|
||||
// The step component needs to re-render to show typed text (controlled inputs)
|
||||
// But wizardSteps useMemo ensures steps array doesn't recreate, so no component recreation
|
||||
const handleDataChange = useCallback((newData: AnyWizardData) => {
|
||||
// Update ref first for immediate access
|
||||
dataRef.current = newData;
|
||||
// Update state to trigger re-render (controlled inputs need this)
|
||||
setWizardData(newData);
|
||||
}, []);
|
||||
|
||||
// Handle wizard completion
|
||||
const handleWizardComplete = useCallback(
|
||||
(data?: any) => {
|
||||
if (selectedItemType) {
|
||||
onComplete?.(selectedItemType, data);
|
||||
// On completion, sync the ref to state for submission
|
||||
setWizardData(dataRef.current);
|
||||
onComplete?.(selectedItemType, dataRef.current);
|
||||
}
|
||||
handleClose();
|
||||
},
|
||||
@@ -57,10 +80,10 @@ export const UnifiedAddWizard: React.FC<UnifiedAddWizardProps> = ({
|
||||
);
|
||||
|
||||
// Get wizard steps based on selected item type
|
||||
// CRITICAL: Memoize the steps to prevent component recreation on every render
|
||||
// Without this, every keystroke causes the component to unmount/remount, losing focus
|
||||
// IMPORTANT: For dynamic wizards (like sales-entry), we need to include the entryMethod
|
||||
// in the dependency array so steps update when the user selects manual vs upload
|
||||
// ARCHITECTURAL SOLUTION: We pass dataRef and setWizardData to wizard step functions.
|
||||
// The wizard steps use these in their component wrappers, which creates a closure
|
||||
// that always accesses the CURRENT data from dataRef.current, without needing
|
||||
// to recreate the steps array on every data change.
|
||||
const wizardSteps = useMemo((): WizardStep[] => {
|
||||
if (!selectedItemType) {
|
||||
// Step 0: Item Type Selection
|
||||
@@ -76,30 +99,31 @@ export const UnifiedAddWizard: React.FC<UnifiedAddWizardProps> = ({
|
||||
];
|
||||
}
|
||||
|
||||
// Return specific wizard steps based on selected type
|
||||
// Pass dataRef and setWizardData - the wizard step functions will use
|
||||
// dataRef.current to always access fresh data without recreating steps
|
||||
switch (selectedItemType) {
|
||||
case 'inventory':
|
||||
return InventoryWizardSteps(wizardData, setWizardData);
|
||||
return InventoryWizardSteps(dataRef, setWizardData);
|
||||
case 'supplier':
|
||||
return SupplierWizardSteps(wizardData, setWizardData);
|
||||
return SupplierWizardSteps(dataRef, setWizardData);
|
||||
case 'recipe':
|
||||
return RecipeWizardSteps(wizardData, setWizardData);
|
||||
return RecipeWizardSteps(dataRef, setWizardData);
|
||||
case 'equipment':
|
||||
return EquipmentWizardSteps(wizardData, setWizardData);
|
||||
return EquipmentWizardSteps(dataRef, setWizardData);
|
||||
case 'quality-template':
|
||||
return QualityTemplateWizardSteps(wizardData, setWizardData);
|
||||
return QualityTemplateWizardSteps(dataRef, setWizardData);
|
||||
case 'customer-order':
|
||||
return CustomerOrderWizardSteps(wizardData, setWizardData);
|
||||
return CustomerOrderWizardSteps(dataRef, setWizardData);
|
||||
case 'customer':
|
||||
return CustomerWizardSteps(wizardData, setWizardData);
|
||||
return CustomerWizardSteps(dataRef, setWizardData);
|
||||
case 'team-member':
|
||||
return TeamMemberWizardSteps(wizardData, setWizardData);
|
||||
return TeamMemberWizardSteps(dataRef, setWizardData);
|
||||
case 'sales-entry':
|
||||
return SalesEntryWizardSteps(wizardData, setWizardData);
|
||||
return SalesEntryWizardSteps(dataRef, setWizardData);
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}, [selectedItemType, handleItemTypeSelect, wizardData.entryMethod]); // Include only critical fields for dynamic step generation
|
||||
}, [selectedItemType, handleItemTypeSelect, wizardData.entryMethod]); // Add entryMethod for dynamic sales-entry steps
|
||||
|
||||
// Get wizard title based on selected item type
|
||||
const getWizardTitle = (): string => {
|
||||
@@ -131,6 +155,8 @@ export const UnifiedAddWizard: React.FC<UnifiedAddWizardProps> = ({
|
||||
steps={wizardSteps}
|
||||
icon={<Sparkles className="w-6 h-6" />}
|
||||
size="xl"
|
||||
dataRef={dataRef}
|
||||
onDataChange={handleDataChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user