+ {/* Header */}
+
+
+
+ {t('scanner.title')}
+
+
+
+
+ {/* Camera View */}
+
+
+ {!cameraActive && scanState.type !== 'scanning' && scanState.type !== 'loading' && (
+
+
+
+ )}
+ {cameraActive && (
+
+ )}
+
+
+ {/* Scan controls & status */}
+ {scanState.type === 'idle' && (
+
+ )}
+
+ {scanState.type === 'scanning' && (
+
+
+ {t('scanner.searching')}
+
+
+ )}
+
+ {scanState.type === 'loading' && (
+
+
+ {t('scanner.loadingProduct', { barcode: scanState.barcode })}
+
+ )}
+
+ {scanState.type === 'success' && (
+
+
+
{scanState.name || scanState.barcode}
+
+
+ )}
+
+ {/* Duplicate found */}
+ {scanState.type === 'duplicate' && (
+
+
+
+
{t('scanner.duplicateFound')}
+
+
+ Barcode: {scanState.barcode}{scanState.apiName ? ` ยท ${scanState.apiName}` : ''}
+
+
+ {scanState.existing.map((product) => {
+ const status = getExpiryStatus(product.expiryDate);
+ const daysLeft = getDaysUntilExpiry(product.expiryDate);
+ return (
+
+
+
{product.name}
+
+ {t(`status.${status}`)}
+
+
+
+
{product.storageLocation}
+
{product.quantity} {product.unit}
+
{formatDate(product.expiryDate, product.expiryPrecision)}
+
{formatDaysUntil(daysLeft)}
+
+
+ );
+ })}
+
+
+
+
+
+
+ )}
+
+ {scanState.type === 'error' && (
+
+
+
+
{scanState.message}
+
+
+
+ )}
+
+ );
+}
+
export function ProductForm() {
const { editingProductId, setPage, setEditingProductId, scannedData, setScannedData } = useAppStore();
const locations = useLiveQuery(() => db.storageLocations.toArray()) ?? [];
@@ -119,7 +416,6 @@ export function ProductForm() {
populatedRef.current = false;
if (!editingProductId) {
setForm((prev) => {
- // Only reset if the form was populated with editing data
if (prev.name && !restoredRef.current) {
return { ...defaultForm, storageLocation: prev.storageLocation || '' };
}
@@ -151,6 +447,19 @@ export function ProductForm() {
setForm((prev) => ({ ...prev, [key]: value }));
}
+ const handleScanned = useCallback((data: { barcode: string; name?: string; imageUrl?: string }) => {
+ setForm((prev) => ({
+ ...prev,
+ barcode: data.barcode || prev.barcode,
+ name: data.name || prev.name,
+ }));
+ if (data.imageUrl) {
+ fetchAndCompressImage(data.imageUrl).then((base64) => {
+ if (base64) setForm((prev) => ({ ...prev, photo: base64 }));
+ });
+ }
+ }, []);
+
function handleCameraClick() {
saveFormDraft(form, editingProductId);
cameraInputRef.current?.click();
@@ -214,6 +523,11 @@ export function ProductForm() {