fix: show item save confirmation with image before closing

- Add savingIndex state to track saving operation
- Display success overlay with saved image for 1.5 seconds
- Show item name in confirmation message
- Prevents modal from closing immediately after save

Fixes user complaint about image disappearing too quickly without confirmation
This commit is contained in:
2026-04-22 09:07:44 +03:00
parent e5615826d6
commit 99a4cae572
2 changed files with 40 additions and 9 deletions

View File

@@ -29,6 +29,7 @@ export default function AIOnboarding({ onCancel, onComplete, categories, invento
fileInputRef, fileInputRef,
existingTypes, existingTypes,
existingBoxes, existingBoxes,
savingIndex,
startLiveCamera, startLiveCamera,
stopLiveCamera, stopLiveCamera,
captureSnapshot, captureSnapshot,
@@ -483,6 +484,27 @@ export default function AIOnboarding({ onCancel, onComplete, categories, invento
</div> </div>
</div> </div>
)} )}
{/* Success confirmation overlay */}
{savingIndex !== null && image && (
<div className="fixed inset-0 bg-black/70 flex items-center justify-center z-50 animate-in fade-in duration-200">
<div className="flex flex-col items-center gap-4">
<div className="w-48 h-48 rounded-3xl overflow-hidden border-4 border-green-500 shadow-2xl">
<img
src={image}
alt="Saved item photo"
className="w-full h-full object-contain bg-black"
/>
</div>
<div className="text-center">
<p className="text-white text-lg font-normal mb-2">Item saved!</p>
<p className="text-secondary text-xs font-normal">
{extractedItems[savingIndex]?.Item || extractedItems[savingIndex]?.name || "New item"} added to catalog
</p>
</div>
</div>
</div>
)}
</div> </div>
); );
} }

View File

@@ -11,6 +11,7 @@ export function useAIExtraction(inventory: Item[], onComplete: (itemData: any) =
const [mode, setMode] = useState<'item' | 'box'>('item'); const [mode, setMode] = useState<'item' | 'box'>('item');
const [isLive, setIsLive] = useState(false); const [isLive, setIsLive] = useState(false);
const [extractedImageBlob, setExtractedImageBlob] = useState<Blob | null>(null); const [extractedImageBlob, setExtractedImageBlob] = useState<Blob | null>(null);
const [savingIndex, setSavingIndex] = useState<number | null>(null);
const videoRef = useRef<HTMLVideoElement>(null); const videoRef = useRef<HTMLVideoElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null); const canvasRef = useRef<HTMLCanvasElement>(null);
@@ -157,17 +158,24 @@ export function useAIExtraction(inventory: Item[], onComplete: (itemData: any) =
imageProcessing: data.image_processing imageProcessing: data.image_processing
}) })
}; };
// Show success briefly before closing
setSavingIndex(index);
onComplete(newItem); onComplete(newItem);
if (extractedItems.length > 1) { // Reset UI after brief delay so user sees the success
const remaining = [...extractedItems]; setTimeout(() => {
remaining.splice(index, 1); if (extractedItems.length > 1) {
setExtractedItems(remaining); const remaining = [...extractedItems];
setEditingIndex(null); remaining.splice(index, 1);
} else { setExtractedItems(remaining);
setExtractedItems([]); setEditingIndex(null);
setEditingIndex(null); } else {
} setExtractedItems([]);
setEditingIndex(null);
}
setSavingIndex(null);
}, 1500);
}; };
const confirmAllItems = async () => { const confirmAllItems = async () => {
@@ -255,6 +263,7 @@ export function useAIExtraction(inventory: Item[], onComplete: (itemData: any) =
existingBoxes, existingBoxes,
extractedImageBlob, extractedImageBlob,
setExtractedImageBlob, setExtractedImageBlob,
savingIndex,
startLiveCamera, startLiveCamera,
stopLiveCamera, stopLiveCamera,
captureSnapshot, captureSnapshot,