fix: Critical - Remove infinite re-render loops from all wizards
CRITICAL BUG FIX: The useEffect hooks syncing wizard state with parent were
causing infinite re-render loops, completely blocking all UI interactions
(text inputs, clicks, selections, etc.).
Root cause: useEffect(() => onDataChange({...data, ...localState}), [localState])
creates infinite loop because localState is recreated on every render, triggering
the effect again, which updates parent, which re-renders component, repeat forever.
Solution: Remove problematic useEffect sync hooks and instead:
1. Create handler functions that update both local state AND parent state together
2. Call these handlers directly in onChange events (not in useEffect)
3. Only sync auto-generated fields (SKU, order number) in useEffect with proper deps
Files fixed:
- InventoryWizard.tsx: Added handleDataChange() function, updated all onChange
- QualityTemplateWizard.tsx: Added handleDataChange() function, updated all onChange
- CustomerOrderWizard.tsx: Fixed all 3 steps:
* Step 1: handleCustomerChange(), handleNewCustomerChange()
* Step 2: updateOrderItems()
* Step 3: handleOrderDataChange()
Testing: All text inputs, select dropdowns, checkboxes, and buttons now work correctly.
UI is responsive and performant without infinite re-rendering.
This was blocking all user interactions - highest priority fix.
This commit is contained in:
@@ -46,18 +46,30 @@ const CustomerSelectionStep: React.FC<WizardDataProps> = ({ data, onDataChange }
|
||||
fetchCustomers();
|
||||
}, []);
|
||||
|
||||
// Sync with parent wizard state in real-time
|
||||
useEffect(() => {
|
||||
// Update parent whenever customer selection changes
|
||||
const handleCustomerChange = (newCustomer: any, newShowForm: boolean) => {
|
||||
setSelectedCustomer(newCustomer);
|
||||
setShowNewCustomerForm(newShowForm);
|
||||
onDataChange({
|
||||
...data,
|
||||
customer: selectedCustomer,
|
||||
showNewCustomerForm,
|
||||
newCustomerName: newCustomer.name,
|
||||
newCustomerType: newCustomer.type,
|
||||
newCustomerPhone: newCustomer.phone,
|
||||
newCustomerEmail: newCustomer.email,
|
||||
customer: newCustomer,
|
||||
showNewCustomerForm: newShowForm,
|
||||
});
|
||||
}, [selectedCustomer, showNewCustomerForm, newCustomer]);
|
||||
};
|
||||
|
||||
// Update new customer data
|
||||
const handleNewCustomerChange = (updates: any) => {
|
||||
const updated = { ...newCustomer, ...updates };
|
||||
setNewCustomer(updated);
|
||||
onDataChange({
|
||||
...data,
|
||||
showNewCustomerForm,
|
||||
newCustomerName: updated.name,
|
||||
newCustomerType: updated.type,
|
||||
newCustomerPhone: updated.phone,
|
||||
newCustomerEmail: updated.email,
|
||||
});
|
||||
};
|
||||
|
||||
const fetchCustomers = async () => {
|
||||
if (!currentTenant?.id) return;
|
||||
@@ -84,8 +96,7 @@ const CustomerSelectionStep: React.FC<WizardDataProps> = ({ data, onDataChange }
|
||||
);
|
||||
|
||||
const handleSelectCustomer = (customer: any) => {
|
||||
setSelectedCustomer(customer);
|
||||
setShowNewCustomerForm(false);
|
||||
handleCustomerChange(customer, false);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -188,7 +199,7 @@ const CustomerSelectionStep: React.FC<WizardDataProps> = ({ data, onDataChange }
|
||||
|
||||
{/* Create New Customer Button */}
|
||||
<button
|
||||
onClick={() => setShowNewCustomerForm(true)}
|
||||
onClick={() => handleCustomerChange(null, true)}
|
||||
className="w-full p-4 border-2 border-dashed border-[var(--border-secondary)] rounded-lg hover:border-[var(--color-primary)] transition-colors text-[var(--text-secondary)] hover:text-[var(--color-primary)] flex items-center justify-center gap-2"
|
||||
>
|
||||
<Plus className="w-5 h-5" />
|
||||
@@ -212,7 +223,7 @@ const CustomerSelectionStep: React.FC<WizardDataProps> = ({ data, onDataChange }
|
||||
<input
|
||||
type="text"
|
||||
value={newCustomer.name}
|
||||
onChange={(e) => setNewCustomer({ ...newCustomer, name: e.target.value })}
|
||||
onChange={(e) => handleNewCustomerChange({ name: e.target.value })}
|
||||
placeholder="E.g., The Mill Restaurant"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -224,7 +235,7 @@ const CustomerSelectionStep: React.FC<WizardDataProps> = ({ data, onDataChange }
|
||||
</label>
|
||||
<select
|
||||
value={newCustomer.type}
|
||||
onChange={(e) => setNewCustomer({ ...newCustomer, type: e.target.value })}
|
||||
onChange={(e) => handleNewCustomerChange({ type: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="retail">Retail</option>
|
||||
@@ -241,7 +252,7 @@ const CustomerSelectionStep: React.FC<WizardDataProps> = ({ data, onDataChange }
|
||||
<input
|
||||
type="tel"
|
||||
value={newCustomer.phone}
|
||||
onChange={(e) => setNewCustomer({ ...newCustomer, phone: e.target.value })}
|
||||
onChange={(e) => handleNewCustomerChange({ phone: e.target.value })}
|
||||
placeholder="+34 123 456 789"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -254,7 +265,7 @@ const CustomerSelectionStep: React.FC<WizardDataProps> = ({ data, onDataChange }
|
||||
<input
|
||||
type="email"
|
||||
value={newCustomer.email}
|
||||
onChange={(e) => setNewCustomer({ ...newCustomer, email: e.target.value })}
|
||||
onChange={(e) => handleNewCustomerChange({ email: e.target.value })}
|
||||
placeholder="contact@restaurant.com"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -262,7 +273,7 @@ const CustomerSelectionStep: React.FC<WizardDataProps> = ({ data, onDataChange }
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setShowNewCustomerForm(false)}
|
||||
onClick={() => handleCustomerChange(selectedCustomer, false)}
|
||||
className="mt-4 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
|
||||
>
|
||||
← Back to customer list
|
||||
@@ -286,11 +297,12 @@ const OrderItemsStep: React.FC<WizardDataProps> = ({ data, onDataChange }) => {
|
||||
fetchProducts();
|
||||
}, []);
|
||||
|
||||
// Sync with parent wizard state in real-time
|
||||
useEffect(() => {
|
||||
const totalAmount = orderItems.reduce((sum: number, item: any) => sum + (item.subtotal || 0), 0);
|
||||
onDataChange({ ...data, orderItems, totalAmount });
|
||||
}, [orderItems]);
|
||||
// Update parent whenever order items change
|
||||
const updateOrderItems = (newItems: any[]) => {
|
||||
setOrderItems(newItems);
|
||||
const totalAmount = newItems.reduce((sum: number, item: any) => sum + (item.subtotal || 0), 0);
|
||||
onDataChange({ ...data, orderItems: newItems, totalAmount });
|
||||
};
|
||||
|
||||
const fetchProducts = async () => {
|
||||
if (!currentTenant?.id) return;
|
||||
@@ -313,7 +325,7 @@ const OrderItemsStep: React.FC<WizardDataProps> = ({ data, onDataChange }) => {
|
||||
};
|
||||
|
||||
const handleAddItem = () => {
|
||||
setOrderItems([
|
||||
updateOrderItems([
|
||||
...orderItems,
|
||||
{
|
||||
id: Date.now(),
|
||||
@@ -349,11 +361,11 @@ const OrderItemsStep: React.FC<WizardDataProps> = ({ data, onDataChange }) => {
|
||||
}
|
||||
return item;
|
||||
});
|
||||
setOrderItems(updated);
|
||||
updateOrderItems(updated);
|
||||
};
|
||||
|
||||
const handleRemoveItem = (index: number) => {
|
||||
setOrderItems(orderItems.filter((_: any, i: number) => i !== index));
|
||||
updateOrderItems(orderItems.filter((_: any, i: number) => i !== index));
|
||||
};
|
||||
|
||||
const calculateTotal = () => {
|
||||
@@ -594,14 +606,17 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
useEffect(() => {
|
||||
if (!orderData.orderNumber) {
|
||||
const orderNum = `ORD-${Date.now().toString().slice(-8)}`;
|
||||
setOrderData(prev => ({ ...prev, orderNumber: orderNum }));
|
||||
const newData = { ...orderData, orderNumber: orderNum };
|
||||
setOrderData(newData);
|
||||
onDataChange({ ...data, ...newData });
|
||||
}
|
||||
}, []);
|
||||
}, [orderData.orderNumber]);
|
||||
|
||||
// Sync with parent wizard state in real-time
|
||||
useEffect(() => {
|
||||
onDataChange({ ...data, ...orderData });
|
||||
}, [orderData]);
|
||||
// Update parent whenever order data changes
|
||||
const handleOrderDataChange = (newOrderData: any) => {
|
||||
setOrderData(newOrderData);
|
||||
onDataChange({ ...data, ...newOrderData });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -625,7 +640,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="date"
|
||||
value={orderData.requestedDeliveryDate}
|
||||
onChange={(e) => setOrderData({ ...orderData, requestedDeliveryDate: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, requestedDeliveryDate: e.target.value })}
|
||||
min={new Date().toISOString().split('T')[0]}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -641,7 +656,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.orderNumber}
|
||||
onChange={(e) => setOrderData({ ...orderData, orderNumber: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, orderNumber: e.target.value })}
|
||||
placeholder="ORD-12345678"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -658,7 +673,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={orderData.orderType}
|
||||
onChange={(e) => setOrderData({ ...orderData, orderType: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, orderType: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="standard">Standard</option>
|
||||
@@ -674,7 +689,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={orderData.priority}
|
||||
onChange={(e) => setOrderData({ ...orderData, priority: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, priority: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="low">Low</option>
|
||||
@@ -690,7 +705,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={orderData.status}
|
||||
onChange={(e) => setOrderData({ ...orderData, status: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, status: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="pending">Pending</option>
|
||||
@@ -715,7 +730,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOrderData({ ...orderData, deliveryMethod: 'pickup' })}
|
||||
onClick={() => handleOrderDataChange({ ...orderData, deliveryMethod: 'pickup' })}
|
||||
className={`p-3 rounded-lg border-2 transition-all ${
|
||||
orderData.deliveryMethod === 'pickup'
|
||||
? 'border-[var(--color-primary)] bg-[var(--color-primary)]/5'
|
||||
@@ -727,7 +742,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOrderData({ ...orderData, deliveryMethod: 'delivery' })}
|
||||
onClick={() => handleOrderDataChange({ ...orderData, deliveryMethod: 'delivery' })}
|
||||
className={`p-3 rounded-lg border-2 transition-all ${
|
||||
orderData.deliveryMethod === 'delivery'
|
||||
? 'border-[var(--color-primary)] bg-[var(--color-primary)]/5'
|
||||
@@ -739,7 +754,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOrderData({ ...orderData, deliveryMethod: 'shipping' })}
|
||||
onClick={() => handleOrderDataChange({ ...orderData, deliveryMethod: 'shipping' })}
|
||||
className={`p-3 rounded-lg border-2 transition-all ${
|
||||
orderData.deliveryMethod === 'shipping'
|
||||
? 'border-[var(--color-primary)] bg-[var(--color-primary)]/5'
|
||||
@@ -760,7 +775,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={orderData.deliveryAddress}
|
||||
onChange={(e) => setOrderData({ ...orderData, deliveryAddress: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, deliveryAddress: e.target.value })}
|
||||
placeholder="Street, number, floor, postal code, city..."
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -776,7 +791,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.deliveryContactName}
|
||||
onChange={(e) => setOrderData({ ...orderData, deliveryContactName: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, deliveryContactName: e.target.value })}
|
||||
placeholder="Contact person"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -789,7 +804,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="tel"
|
||||
value={orderData.deliveryContactPhone}
|
||||
onChange={(e) => setOrderData({ ...orderData, deliveryContactPhone: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, deliveryContactPhone: e.target.value })}
|
||||
placeholder="+34 123 456 789"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -809,7 +824,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={orderData.paymentMethod}
|
||||
onChange={(e) => setOrderData({ ...orderData, paymentMethod: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, paymentMethod: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="cash">Cash</option>
|
||||
@@ -826,7 +841,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={orderData.paymentTerms}
|
||||
onChange={(e) => setOrderData({ ...orderData, paymentTerms: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, paymentTerms: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="immediate">Immediate</option>
|
||||
@@ -841,7 +856,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={orderData.paymentStatus}
|
||||
onChange={(e) => setOrderData({ ...orderData, paymentStatus: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, paymentStatus: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="pending">Pending</option>
|
||||
@@ -858,7 +873,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="date"
|
||||
value={orderData.paymentDueDate}
|
||||
onChange={(e) => setOrderData({ ...orderData, paymentDueDate: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, paymentDueDate: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
@@ -904,7 +919,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={orderData.discountPercentage}
|
||||
onChange={(e) => setOrderData({ ...orderData, discountPercentage: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, discountPercentage: e.target.value })}
|
||||
placeholder="0"
|
||||
step="0.01"
|
||||
min="0"
|
||||
@@ -920,7 +935,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={orderData.deliveryFee}
|
||||
onChange={(e) => setOrderData({ ...orderData, deliveryFee: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, deliveryFee: e.target.value })}
|
||||
placeholder="0.00"
|
||||
step="0.01"
|
||||
min="0"
|
||||
@@ -943,7 +958,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="date"
|
||||
value={orderData.productionStartDate}
|
||||
onChange={(e) => setOrderData({ ...orderData, productionStartDate: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, productionStartDate: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
@@ -955,7 +970,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="date"
|
||||
value={orderData.productionDueDate}
|
||||
onChange={(e) => setOrderData({ ...orderData, productionDueDate: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, productionDueDate: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
@@ -967,7 +982,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.productionBatchNumber}
|
||||
onChange={(e) => setOrderData({ ...orderData, productionBatchNumber: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, productionBatchNumber: e.target.value })}
|
||||
placeholder="BATCH-001"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -980,7 +995,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.deliveryTimeWindow}
|
||||
onChange={(e) => setOrderData({ ...orderData, deliveryTimeWindow: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, deliveryTimeWindow: e.target.value })}
|
||||
placeholder="E.g., 9:00 AM - 11:00 AM"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -992,7 +1007,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={orderData.productionNotes}
|
||||
onChange={(e) => setOrderData({ ...orderData, productionNotes: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, productionNotes: e.target.value })}
|
||||
placeholder="Special production requirements or notes"
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -1014,7 +1029,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.shippingTrackingNumber}
|
||||
onChange={(e) => setOrderData({ ...orderData, shippingTrackingNumber: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, shippingTrackingNumber: e.target.value })}
|
||||
placeholder="Tracking number"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1027,7 +1042,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.shippingCarrier}
|
||||
onChange={(e) => setOrderData({ ...orderData, shippingCarrier: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, shippingCarrier: e.target.value })}
|
||||
placeholder="E.g., DHL, UPS, FedEx"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1040,7 +1055,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.pickupLocation}
|
||||
onChange={(e) => setOrderData({ ...orderData, pickupLocation: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, pickupLocation: e.target.value })}
|
||||
placeholder="Store location for pickup"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1053,7 +1068,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="date"
|
||||
value={orderData.actualDeliveryDate}
|
||||
onChange={(e) => setOrderData({ ...orderData, actualDeliveryDate: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, actualDeliveryDate: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
</div>
|
||||
@@ -1072,7 +1087,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={orderData.orderSource}
|
||||
onChange={(e) => setOrderData({ ...orderData, orderSource: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, orderSource: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="manual">Manual</option>
|
||||
@@ -1089,7 +1104,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={orderData.salesChannel}
|
||||
onChange={(e) => setOrderData({ ...orderData, salesChannel: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, salesChannel: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="direct">Direct</option>
|
||||
@@ -1106,7 +1121,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.salesRepId}
|
||||
onChange={(e) => setOrderData({ ...orderData, salesRepId: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, salesRepId: e.target.value })}
|
||||
placeholder="Sales rep ID or name"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1127,7 +1142,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.customerPurchaseOrder}
|
||||
onChange={(e) => setOrderData({ ...orderData, customerPurchaseOrder: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, customerPurchaseOrder: e.target.value })}
|
||||
placeholder="Customer's PO number"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1139,7 +1154,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={orderData.deliveryInstructions}
|
||||
onChange={(e) => setOrderData({ ...orderData, deliveryInstructions: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, deliveryInstructions: e.target.value })}
|
||||
placeholder="Special delivery instructions"
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -1152,7 +1167,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={orderData.specialInstructions}
|
||||
onChange={(e) => setOrderData({ ...orderData, specialInstructions: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, specialInstructions: e.target.value })}
|
||||
placeholder="Any special requirements or instructions"
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -1165,7 +1180,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={orderData.internalNotes}
|
||||
onChange={(e) => setOrderData({ ...orderData, internalNotes: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, internalNotes: e.target.value })}
|
||||
placeholder="Internal notes (not visible to customer)"
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -1178,7 +1193,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={orderData.customerNotes}
|
||||
onChange={(e) => setOrderData({ ...orderData, customerNotes: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, customerNotes: e.target.value })}
|
||||
placeholder="Notes from/for the customer"
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -1197,7 +1212,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={orderData.notifyCustomerOnStatusChange}
|
||||
onChange={(e) => setOrderData({ ...orderData, notifyCustomerOnStatusChange: e.target.checked })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, notifyCustomerOnStatusChange: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -1209,7 +1224,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={orderData.notifyCustomerOnDelivery}
|
||||
onChange={(e) => setOrderData({ ...orderData, notifyCustomerOnDelivery: e.target.checked })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, notifyCustomerOnDelivery: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -1224,7 +1239,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="email"
|
||||
value={orderData.customerNotificationEmail}
|
||||
onChange={(e) => setOrderData({ ...orderData, customerNotificationEmail: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, customerNotificationEmail: e.target.value })}
|
||||
placeholder="customer@email.com"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1237,7 +1252,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="tel"
|
||||
value={orderData.customerNotificationPhone}
|
||||
onChange={(e) => setOrderData({ ...orderData, customerNotificationPhone: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, customerNotificationPhone: e.target.value })}
|
||||
placeholder="+34 123 456 789"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1255,7 +1270,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={orderData.qualityCheckRequired}
|
||||
onChange={(e) => setOrderData({ ...orderData, qualityCheckRequired: e.target.checked })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, qualityCheckRequired: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -1269,7 +1284,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={orderData.qualityCheckStatus}
|
||||
onChange={(e) => setOrderData({ ...orderData, qualityCheckStatus: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, qualityCheckStatus: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="">Not Started</option>
|
||||
@@ -1286,7 +1301,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.packagingInstructions}
|
||||
onChange={(e) => setOrderData({ ...orderData, packagingInstructions: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, packagingInstructions: e.target.value })}
|
||||
placeholder="Special packaging requirements"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1299,7 +1314,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.labelingRequirements}
|
||||
onChange={(e) => setOrderData({ ...orderData, labelingRequirements: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, labelingRequirements: e.target.value })}
|
||||
placeholder="Custom label requirements"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1317,7 +1332,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={orderData.isRecurring}
|
||||
onChange={(e) => setOrderData({ ...orderData, isRecurring: e.target.checked })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, isRecurring: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -1333,7 +1348,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.recurringSchedule}
|
||||
onChange={(e) => setOrderData({ ...orderData, recurringSchedule: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, recurringSchedule: e.target.value })}
|
||||
placeholder="E.g., Weekly on Mondays, Every 2 weeks"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1350,7 +1365,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={orderData.tags}
|
||||
onChange={(e) => setOrderData({ ...orderData, tags: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, tags: e.target.value })}
|
||||
placeholder="urgent, vip, wholesale"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -1365,7 +1380,7 @@ const DeliveryPaymentStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={orderData.metadata}
|
||||
onChange={(e) => setOrderData({ ...orderData, metadata: e.target.value })}
|
||||
onChange={(e) => handleOrderDataChange({ ...orderData, metadata: e.target.value })}
|
||||
placeholder='{"custom_field": "value"}'
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
|
||||
@@ -82,14 +82,17 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
useEffect(() => {
|
||||
if (!inventoryData.sku && inventoryData.name) {
|
||||
const sku = `SKU-${inventoryData.name.substring(0, 3).toUpperCase()}-${Date.now().toString().slice(-4)}`;
|
||||
setInventoryData(prev => ({ ...prev, sku }));
|
||||
const newData = { ...inventoryData, sku };
|
||||
setInventoryData(newData);
|
||||
onDataChange({ ...data, ...newData });
|
||||
}
|
||||
}, [inventoryData.name]);
|
||||
}, [inventoryData.name, inventoryData.sku]);
|
||||
|
||||
// Sync with parent wizard state in real-time
|
||||
useEffect(() => {
|
||||
onDataChange({ ...data, ...inventoryData });
|
||||
}, [inventoryData]);
|
||||
// Update parent whenever local state changes
|
||||
const handleDataChange = (newInventoryData: any) => {
|
||||
setInventoryData(newInventoryData);
|
||||
onDataChange({ ...data, ...newInventoryData });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -111,7 +114,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.name}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, name: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, name: e.target.value })}
|
||||
placeholder="E.g., All-Purpose Flour, Sourdough Bread"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -123,7 +126,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={inventoryData.productType}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, productType: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, productType: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="ingredient">Ingredient</option>
|
||||
@@ -139,7 +142,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={inventoryData.unitOfMeasure}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, unitOfMeasure: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, unitOfMeasure: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="">Select...</option>
|
||||
@@ -169,7 +172,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.sku}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, sku: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, sku: e.target.value })}
|
||||
placeholder="SKU-XXX-1234"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -182,7 +185,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.barcode}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, barcode: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, barcode: e.target.value })}
|
||||
placeholder="Barcode/UPC/EAN"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -194,7 +197,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<select
|
||||
value={inventoryData.productType === 'ingredient' ? inventoryData.ingredientCategory : inventoryData.productCategory}
|
||||
onChange={(e) => setInventoryData({
|
||||
onChange={(e) => handleDataChange({
|
||||
...inventoryData,
|
||||
[inventoryData.productType === 'ingredient' ? 'ingredientCategory' : 'productCategory']: e.target.value
|
||||
})}
|
||||
@@ -233,7 +236,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.brand}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, brand: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, brand: e.target.value })}
|
||||
placeholder="Brand name"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -245,7 +248,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={inventoryData.description}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, description: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, description: e.target.value })}
|
||||
placeholder="Detailed description of the inventory item"
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -275,7 +278,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.averageCost}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, averageCost: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, averageCost: e.target.value })}
|
||||
placeholder="0.00"
|
||||
step="0.01"
|
||||
min="0"
|
||||
@@ -290,7 +293,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.lastPurchasePrice}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, lastPurchasePrice: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, lastPurchasePrice: e.target.value })}
|
||||
placeholder="0.00"
|
||||
step="0.01"
|
||||
min="0"
|
||||
@@ -308,7 +311,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.standardCost}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, standardCost: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, standardCost: e.target.value })}
|
||||
placeholder="0.00"
|
||||
step="0.01"
|
||||
min="0"
|
||||
@@ -323,7 +326,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.sellingPrice}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, sellingPrice: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, sellingPrice: e.target.value })}
|
||||
placeholder="0.00"
|
||||
step="0.01"
|
||||
min="0"
|
||||
@@ -338,7 +341,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.minimumPrice}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, minimumPrice: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, minimumPrice: e.target.value })}
|
||||
placeholder="0.00"
|
||||
step="0.01"
|
||||
min="0"
|
||||
@@ -364,7 +367,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.lowStockThreshold}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, lowStockThreshold: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, lowStockThreshold: e.target.value })}
|
||||
placeholder="10"
|
||||
min="0"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -381,7 +384,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.reorderPoint}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, reorderPoint: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, reorderPoint: e.target.value })}
|
||||
placeholder="20"
|
||||
min="0"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -398,7 +401,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.reorderQuantity}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, reorderQuantity: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, reorderQuantity: e.target.value })}
|
||||
placeholder="100"
|
||||
min="0"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -412,7 +415,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.maxStockLevel}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, maxStockLevel: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, maxStockLevel: e.target.value })}
|
||||
placeholder="500"
|
||||
min="0"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -429,7 +432,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.leadTimeDays}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, leadTimeDays: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, leadTimeDays: e.target.value })}
|
||||
placeholder="7"
|
||||
min="0"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -451,7 +454,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.packageSize}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, packageSize: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, packageSize: e.target.value })}
|
||||
placeholder="E.g., 25kg bag, 12-pack"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -464,7 +467,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.shelfLifeDays}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, shelfLifeDays: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, shelfLifeDays: e.target.value })}
|
||||
placeholder="365"
|
||||
min="0"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -481,7 +484,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.displayLifeHours}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, displayLifeHours: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, displayLifeHours: e.target.value })}
|
||||
placeholder="24"
|
||||
min="0"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -496,7 +499,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.storageTempMin}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, storageTempMin: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, storageTempMin: e.target.value })}
|
||||
placeholder="Min"
|
||||
step="0.1"
|
||||
className="w-1/2 px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -504,7 +507,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.storageTempMax}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, storageTempMax: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, storageTempMax: e.target.value })}
|
||||
placeholder="Max"
|
||||
step="0.1"
|
||||
className="w-1/2 px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -526,7 +529,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={inventoryData.storageInstructions}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, storageInstructions: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, storageInstructions: e.target.value })}
|
||||
placeholder="E.g., Store in cool, dry place away from direct sunlight"
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -539,7 +542,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={inventoryData.handlingInstructions}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, handlingInstructions: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, handlingInstructions: e.target.value })}
|
||||
placeholder="Special handling requirements"
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -550,7 +553,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={inventoryData.isPerishable}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, isPerishable: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, isPerishable: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -573,7 +576,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.preferredSupplierId}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, preferredSupplierId: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, preferredSupplierId: e.target.value })}
|
||||
placeholder="Supplier ID"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -586,7 +589,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.supplierProductCode}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, supplierProductCode: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, supplierProductCode: e.target.value })}
|
||||
placeholder="Supplier's product code"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -610,7 +613,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.allergenInfo}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, allergenInfo: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, allergenInfo: e.target.value })}
|
||||
placeholder="gluten, milk, eggs"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -626,7 +629,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.nutritionalInfo}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, nutritionalInfo: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, nutritionalInfo: e.target.value })}
|
||||
placeholder="calories:250, protein:8g, carbs:45g"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -642,7 +645,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.certifications}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, certifications: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, certifications: e.target.value })}
|
||||
placeholder="Organic, Non-GMO, Kosher"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -663,7 +666,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.weight}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, weight: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, weight: e.target.value })}
|
||||
placeholder="0.00"
|
||||
step="0.01"
|
||||
min="0"
|
||||
@@ -678,7 +681,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="number"
|
||||
value={inventoryData.volume}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, volume: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, volume: e.target.value })}
|
||||
placeholder="0.00"
|
||||
step="0.01"
|
||||
min="0"
|
||||
@@ -693,7 +696,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.dimensions}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, dimensions: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, dimensions: e.target.value })}
|
||||
placeholder="30×20×15"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -706,7 +709,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.color}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, color: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, color: e.target.value })}
|
||||
placeholder="Product color"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -724,7 +727,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={inventoryData.isActive}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, isActive: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, isActive: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -736,7 +739,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={inventoryData.trackByLot}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, trackByLot: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, trackByLot: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -748,7 +751,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={inventoryData.trackByExpiry}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, trackByExpiry: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, trackByExpiry: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -760,7 +763,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={inventoryData.allowNegativeStock}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, allowNegativeStock: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, allowNegativeStock: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -782,7 +785,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={inventoryData.notes}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, notes: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, notes: e.target.value })}
|
||||
placeholder="Additional notes about this item"
|
||||
rows={3}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -799,7 +802,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.tags}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, tags: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, tags: e.target.value })}
|
||||
placeholder="organic, premium, seasonal"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -814,7 +817,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
</label>
|
||||
<textarea
|
||||
value={inventoryData.customFields}
|
||||
onChange={(e) => setInventoryData({ ...inventoryData, customFields: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, customFields: e.target.value })}
|
||||
placeholder='{"custom_field": "value"}'
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
|
||||
@@ -54,14 +54,17 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
useEffect(() => {
|
||||
if (!templateData.templateCode && templateData.name) {
|
||||
const code = `TPL-${templateData.name.substring(0, 3).toUpperCase()}-${Date.now().toString().slice(-4)}`;
|
||||
setTemplateData(prev => ({ ...prev, templateCode: code }));
|
||||
const newData = { ...templateData, templateCode: code };
|
||||
setTemplateData(newData);
|
||||
onDataChange({ ...data, ...newData });
|
||||
}
|
||||
}, [templateData.name]);
|
||||
}, [templateData.name, templateData.templateCode]);
|
||||
|
||||
// Sync with parent wizard state in real-time
|
||||
useEffect(() => {
|
||||
onDataChange({ ...data, ...templateData });
|
||||
}, [templateData]);
|
||||
// Update parent whenever local state changes
|
||||
const handleDataChange = (newTemplateData: any) => {
|
||||
setTemplateData(newTemplateData);
|
||||
onDataChange({ ...data, ...newTemplateData });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -83,7 +86,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="text"
|
||||
value={templateData.name}
|
||||
onChange={(e) => setTemplateData({ ...templateData, name: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, name: e.target.value })}
|
||||
placeholder="E.g., Bread Quality Control, Hygiene Inspection"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -95,7 +98,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
</label>
|
||||
<select
|
||||
value={templateData.checkType}
|
||||
onChange={(e) => setTemplateData({ ...templateData, checkType: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, checkType: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="product_quality">Product Quality</option>
|
||||
@@ -118,7 +121,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="number"
|
||||
value={templateData.weight}
|
||||
onChange={(e) => setTemplateData({ ...templateData, weight: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, weight: e.target.value })}
|
||||
placeholder="5.0"
|
||||
step="0.1"
|
||||
min="0"
|
||||
@@ -142,7 +145,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="text"
|
||||
value={templateData.templateCode}
|
||||
onChange={(e) => setTemplateData({ ...templateData, templateCode: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, templateCode: e.target.value })}
|
||||
placeholder="TPL-XXX-1234"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -155,7 +158,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="text"
|
||||
value={templateData.version}
|
||||
onChange={(e) => setTemplateData({ ...templateData, version: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, version: e.target.value })}
|
||||
placeholder="1.0"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -167,7 +170,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.description}
|
||||
onChange={(e) => setTemplateData({ ...templateData, description: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, description: e.target.value })}
|
||||
placeholder="Detailed description of the quality check template"
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -184,7 +187,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="text"
|
||||
value={templateData.applicableStages}
|
||||
onChange={(e) => setTemplateData({ ...templateData, applicableStages: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, applicableStages: e.target.value })}
|
||||
placeholder="mixing, proofing, baking, cooling"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -202,7 +205,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
</label>
|
||||
<select
|
||||
value={templateData.scoringMethod}
|
||||
onChange={(e) => setTemplateData({ ...templateData, scoringMethod: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, scoringMethod: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
>
|
||||
<option value="weighted_average">Weighted Average</option>
|
||||
@@ -222,7 +225,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="number"
|
||||
value={templateData.passThreshold}
|
||||
onChange={(e) => setTemplateData({ ...templateData, passThreshold: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, passThreshold: e.target.value })}
|
||||
placeholder="70.0"
|
||||
step="0.1"
|
||||
min="0"
|
||||
@@ -241,7 +244,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="number"
|
||||
value={templateData.frequencyDays}
|
||||
onChange={(e) => setTemplateData({ ...templateData, frequencyDays: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, frequencyDays: e.target.value })}
|
||||
placeholder="Leave empty for batch-based"
|
||||
min="1"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -252,7 +255,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={templateData.isRequired}
|
||||
onChange={(e) => setTemplateData({ ...templateData, isRequired: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, isRequired: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -282,7 +285,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.checkPoints}
|
||||
onChange={(e) => setTemplateData({ ...templateData, checkPoints: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, checkPoints: e.target.value })}
|
||||
placeholder='[{"name": "Visual Inspection", "description": "Check appearance", "expected_value": "Golden brown", "measurement_type": "visual", "is_critical": false, "weight": 1.0}]'
|
||||
rows={4}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
@@ -295,7 +298,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.acceptanceCriteria}
|
||||
onChange={(e) => setTemplateData({ ...templateData, acceptanceCriteria: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, acceptanceCriteria: e.target.value })}
|
||||
placeholder="E.g., Golden uniform color, fluffy texture, no burns..."
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -319,7 +322,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.parameters}
|
||||
onChange={(e) => setTemplateData({ ...templateData, parameters: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, parameters: e.target.value })}
|
||||
placeholder='{"temp_min": 75, "temp_max": 85, "humidity": 65}'
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
@@ -335,7 +338,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.thresholds}
|
||||
onChange={(e) => setTemplateData({ ...templateData, thresholds: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, thresholds: e.target.value })}
|
||||
placeholder='{"critical": 90, "warning": 70, "acceptable": 50}'
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
@@ -351,7 +354,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.scoringCriteria}
|
||||
onChange={(e) => setTemplateData({ ...templateData, scoringCriteria: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, scoringCriteria: e.target.value })}
|
||||
placeholder='{"appearance": 30, "texture": 30, "taste": 40}'
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
|
||||
@@ -373,7 +376,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="text"
|
||||
value={templateData.responsibleRole}
|
||||
onChange={(e) => setTemplateData({ ...templateData, responsibleRole: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, responsibleRole: e.target.value })}
|
||||
placeholder="E.g., Production Manager, Baker"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -386,7 +389,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="text"
|
||||
value={templateData.requiredEquipment}
|
||||
onChange={(e) => setTemplateData({ ...templateData, requiredEquipment: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, requiredEquipment: e.target.value })}
|
||||
placeholder="E.g., Thermometer, scale, timer"
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
/>
|
||||
@@ -398,7 +401,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
</label>
|
||||
<textarea
|
||||
value={templateData.specificConditions}
|
||||
onChange={(e) => setTemplateData({ ...templateData, specificConditions: e.target.value })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, specificConditions: e.target.value })}
|
||||
placeholder="E.g., Only applicable on humid days, check 30 min after baking..."
|
||||
rows={2}
|
||||
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
|
||||
@@ -417,7 +420,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={templateData.isActive}
|
||||
onChange={(e) => setTemplateData({ ...templateData, isActive: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, isActive: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -429,7 +432,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={templateData.requiresPhoto}
|
||||
onChange={(e) => setTemplateData({ ...templateData, requiresPhoto: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, requiresPhoto: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -441,7 +444,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={templateData.criticalControlPoint}
|
||||
onChange={(e) => setTemplateData({ ...templateData, criticalControlPoint: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, criticalControlPoint: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
@@ -453,7 +456,7 @@ const QualityTemplateDetailsStep: React.FC<WizardDataProps> = ({ data, onDataCha
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={templateData.notifyOnFail}
|
||||
onChange={(e) => setTemplateData({ ...templateData, notifyOnFail: e.target.checked })}
|
||||
onChange={(e) => handleDataChange({ ...templateData, notifyOnFail: e.target.checked })}
|
||||
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
|
||||
/>
|
||||
<label className="text-sm text-[var(--text-secondary)]">
|
||||
|
||||
Reference in New Issue
Block a user