Improve onboarding flow
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Package, Salad, AlertCircle, ArrowRight, ArrowLeft, CheckCircle } from 'lucide-react';
|
||||
import Button from '../../../ui/Button/Button';
|
||||
@@ -6,8 +6,11 @@ import Card from '../../../ui/Card/Card';
|
||||
import Input from '../../../ui/Input/Input';
|
||||
import { useCurrentTenant } from '../../../../stores/tenant.store';
|
||||
import { useAddStock, useStock } from '../../../../api/hooks/inventory';
|
||||
import { useAutoSaveDraft, useStepDraft, useDeleteStepDraft } from '../../../../api/hooks/onboarding';
|
||||
import InfoCard from '../../../ui/InfoCard';
|
||||
|
||||
const STEP_NAME = 'initial-stock-entry';
|
||||
|
||||
export interface ProductWithStock {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -55,6 +58,49 @@ export const InitialStockEntryStep: React.FC<InitialStockEntryStepProps> = ({
|
||||
}));
|
||||
});
|
||||
|
||||
// Draft auto-save hooks
|
||||
const { data: draftData, isLoading: isLoadingDraft } = useStepDraft(STEP_NAME);
|
||||
const { saveDraft, cancelPendingSave } = useAutoSaveDraft(STEP_NAME, 2000);
|
||||
const deleteStepDraft = useDeleteStepDraft();
|
||||
const initializedRef = useRef(false);
|
||||
const draftCheckedRef = useRef(false);
|
||||
const stepCompletedRef = useRef(false); // Track if step has been completed to prevent draft saves after completion
|
||||
|
||||
// Restore draft data on mount (only once)
|
||||
useEffect(() => {
|
||||
if (isLoadingDraft || initializedRef.current) return;
|
||||
|
||||
initializedRef.current = true;
|
||||
draftCheckedRef.current = true;
|
||||
|
||||
if (draftData?.draft_data?.products && Array.isArray(draftData.draft_data.products)) {
|
||||
// Restore products with stock values from draft
|
||||
setProducts(draftData.draft_data.products);
|
||||
console.log('✅ Restored initial-stock-entry draft:', draftData.draft_data.products.length, 'products');
|
||||
}
|
||||
}, [isLoadingDraft, draftData]);
|
||||
|
||||
// Auto-save draft when products change
|
||||
useEffect(() => {
|
||||
// CRITICAL: Do not save drafts after the step has been completed
|
||||
// This prevents overwriting completed status with draft data
|
||||
if (stepCompletedRef.current) {
|
||||
console.log('⏸️ Skipping draft save - step already completed');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!draftCheckedRef.current) return;
|
||||
// Only save if we have products with stock values
|
||||
const productsWithValues = products.filter(p => p.initialStock !== undefined);
|
||||
if (productsWithValues.length === 0) return;
|
||||
|
||||
const draftPayload = {
|
||||
products,
|
||||
};
|
||||
|
||||
saveDraft(draftPayload);
|
||||
}, [products, saveDraft]);
|
||||
|
||||
// Merge existing stock from backend on mount
|
||||
useEffect(() => {
|
||||
if (!stockData?.items || products.length === 0) return;
|
||||
@@ -138,7 +184,7 @@ export const InitialStockEntryStep: React.FC<InitialStockEntryStepProps> = ({
|
||||
|
||||
if (stockEntriesToSync.length > 0) {
|
||||
// Create or update stock entries
|
||||
// Note: useAddStock currently handles creation/initial set.
|
||||
// Note: useAddStock currently handles creation/initial set.
|
||||
// If the backend requires a different endpoint for updates, this might need adjustment.
|
||||
// For onboarding, we assume addStock is a "set-and-forget" for initial levels.
|
||||
const stockPromises = stockEntriesToSync.map(product =>
|
||||
@@ -156,6 +202,19 @@ export const InitialStockEntryStep: React.FC<InitialStockEntryStepProps> = ({
|
||||
console.log(`✅ Synced ${stockEntriesToSync.length} stock entries successfully`);
|
||||
}
|
||||
|
||||
// CRITICAL: Mark step as completed BEFORE canceling auto-save
|
||||
// This prevents any pending auto-save from overwriting the completion
|
||||
stepCompletedRef.current = true;
|
||||
|
||||
// Cancel any pending auto-save and delete draft on successful completion
|
||||
cancelPendingSave();
|
||||
try {
|
||||
await deleteStepDraft.mutateAsync(STEP_NAME);
|
||||
console.log('✅ Deleted initial-stock-entry draft after successful completion');
|
||||
} catch {
|
||||
// Ignore errors when deleting draft
|
||||
}
|
||||
|
||||
onComplete?.();
|
||||
} catch (error) {
|
||||
console.error('Error syncing stock entries:', error);
|
||||
@@ -255,7 +314,7 @@ export const InitialStockEntryStep: React.FC<InitialStockEntryStepProps> = ({
|
||||
{hasStock && <CheckCircle className="w-4 h-4 text-[var(--color-success)]" />}
|
||||
</div>
|
||||
{product.category && (
|
||||
<div className="text-xs text-[var(--text-secondary)]">{product.category}</div>
|
||||
<div className="text-xs text-[var(--text-secondary)] uppercase">{t(`inventory:enums.ingredient_category.${product.category}`, product.category)}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -269,7 +328,7 @@ export const InitialStockEntryStep: React.FC<InitialStockEntryStepProps> = ({
|
||||
className="w-20 sm:w-24 text-right min-h-[44px]"
|
||||
/>
|
||||
<span className="text-sm text-[var(--text-secondary)] whitespace-nowrap">
|
||||
{product.unit || 'kg'}
|
||||
{t(`inventory:enums.unit_of_measure.${product.unit}`, product.unit || 'kg')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -306,7 +365,7 @@ export const InitialStockEntryStep: React.FC<InitialStockEntryStepProps> = ({
|
||||
{hasStock && <CheckCircle className="w-4 h-4 text-[var(--color-info)]" />}
|
||||
</div>
|
||||
{product.category && (
|
||||
<div className="text-xs text-[var(--text-secondary)]">{product.category}</div>
|
||||
<div className="text-xs text-[var(--text-secondary)] uppercase">{t(`inventory:enums.ingredient_category.${product.category}`, product.category)}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -320,7 +379,7 @@ export const InitialStockEntryStep: React.FC<InitialStockEntryStepProps> = ({
|
||||
className="w-24 text-right"
|
||||
/>
|
||||
<span className="text-sm text-[var(--text-secondary)] whitespace-nowrap">
|
||||
{product.unit || t('common:units', 'unidades')}
|
||||
{t(`inventory:enums.unit_of_measure.${product.unit}`, product.unit || t('common:units', 'unidades'))}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user