From d099951883f2a602f1facf5ef6d13e5e05882449 Mon Sep 17 00:00:00 2001 From: beatz174-bit Date: Fri, 21 Nov 2025 18:20:26 +1000 Subject: [PATCH] Enhance barcode scanner lookup --- src/screens/BarcodeScannerScreen.tsx | 127 +++++++++++++++++++++++++-- 1 file changed, 120 insertions(+), 7 deletions(-) diff --git a/src/screens/BarcodeScannerScreen.tsx b/src/screens/BarcodeScannerScreen.tsx index 1f5aedc..2d7c056 100644 --- a/src/screens/BarcodeScannerScreen.tsx +++ b/src/screens/BarcodeScannerScreen.tsx @@ -1,9 +1,58 @@ -import { Container, Typography } from '@mui/material'; -import { useState } from 'react'; +import { Alert, Card, CardContent, Chip, Container, Divider, Stack, Typography } from '@mui/material'; +import { liveQuery } from 'dexie'; +import { useEffect, useMemo, useState } from 'react'; import { BarcodeScannerView } from '../components/BarcodeScannerView'; +import { useDatabase } from '../context/DBProvider'; +import { Area } from '../models/Area'; +import { PickList } from '../models/PickList'; +import { Product } from '../models/Product'; + +interface ProductLookup { + product?: Product | null; + pickLists: { list: PickList; area?: Area }[]; +} export const BarcodeScannerScreen = () => { + const db = useDatabase(); const [lastCode, setLastCode] = useState(''); + const [lookup, setLookup] = useState({ pickLists: [] }); + + useEffect(() => { + if (!lastCode) { + setLookup({ pickLists: [] }); + return undefined; + } + + const subscription = liveQuery(async () => { + const product = await db.products.where('barcode').equals(lastCode).first(); + + if (!product) { + return { product: null, pickLists: [] } satisfies ProductLookup; + } + + const pickItems = await db.pickItems.where('product_id').equals(product.id).toArray(); + const pickListIds = Array.from(new Set(pickItems.map((item) => item.pick_list_id))); + const pickLists = (await db.pickLists.bulkGet(pickListIds)).filter( + (list): list is PickList => Boolean(list), + ); + const areas = await db.areas.bulkGet(pickLists.map((list) => list.area_id)); + const areaMap = new Map(); + areas.forEach((area) => { + if (area) areaMap.set(area.id, area); + }); + + return { + product, + pickLists: pickLists.map((list) => ({ list, area: areaMap.get(list.area_id) })), + } satisfies ProductLookup; + }).subscribe({ + next: setLookup, + }); + + return () => subscription.unsubscribe(); + }, [db, lastCode]); + + const hasProduct = useMemo(() => lookup.product && lookup.product !== null, [lookup.product]); return ( @@ -11,11 +60,75 @@ export const BarcodeScannerScreen = () => { Barcode Scanner setLastCode(code)} /> - {lastCode ? ( - - Last detected: {lastCode} - - ) : null} + + {lastCode ? ( + + + + Last detected + + + + {lastCode} + + {lookup.product === null ? ( + + This barcode is not present in the product list. + + ) : null} + + + ) : null} + + {lookup.product ? ( + + + + Product + + {lookup.product.name} + + Category: {lookup.product.category} + + {lookup.product.barcode ? ( + + Barcode: {lookup.product.barcode} + + ) : null} + + + ) : null} + + {hasProduct ? ( + + + + Pick lists containing this product + + {lookup.pickLists.length === 0 ? ( + + This product is not in any pick lists yet. + + ) : ( + } spacing={1}> + {lookup.pickLists.map(({ list, area }) => ( + + Pick List #{list.id.slice(0, 8)} + + Area: {area?.name ?? 'Unknown area'} + + + ))} + + )} + + + ) : null} + ); };