Merge pull request #23 from beatz174-bit/codex/fix-search-feature-on-pick-lists

Improve pick list product search UX
This commit is contained in:
beatz174-bit
2025-11-23 10:04:37 +10:00
committed by GitHub
2 changed files with 46 additions and 27 deletions
+1 -2
View File
@@ -55,9 +55,8 @@ describe('AddItemScreen product search', () => {
); );
await user.type(screen.getByPlaceholderText(/search products/i), 'cola'); await user.type(screen.getByPlaceholderText(/search products/i), 'cola');
await user.click(screen.getByLabelText(/product/i));
expect(screen.getByRole('option', { name: /cola \(drinks\)/i })).toBeVisible(); expect(await screen.findByRole('option', { name: /cola \(drinks\)/i })).toBeVisible();
expect(screen.queryByRole('option', { name: /chips \(snacks\)/i })).not.toBeInTheDocument(); expect(screen.queryByRole('option', { name: /chips \(snacks\)/i })).not.toBeInTheDocument();
}); });
}); });
+45 -25
View File
@@ -1,7 +1,7 @@
import { import {
Autocomplete,
Button, Button,
Container, Container,
MenuItem,
Stack, Stack,
TextField, TextField,
Typography, Typography,
@@ -20,7 +20,7 @@ export const AddItemScreen = () => {
const db = useDatabase(); const db = useDatabase();
const items = usePickItems(id); const items = usePickItems(id);
const products = useProducts(); const products = useProducts();
const [productId, setProductId] = useState(''); const [selectedProduct, setSelectedProduct] = useState<typeof products[number] | null>(null);
const [query, setQuery] = useState(''); const [query, setQuery] = useState('');
const [units, setUnits] = useState(1); const [units, setUnits] = useState(1);
const [bulk, setBulk] = useState(0); const [bulk, setBulk] = useState(0);
@@ -47,13 +47,15 @@ export const AddItemScreen = () => {
}, [availableProducts, query]); }, [availableProducts, query]);
useEffect(() => { useEffect(() => {
if (!productId) return; if (!selectedProduct) return;
if (!filteredProducts.some((product) => product.id === productId)) { if (!filteredProducts.some((product) => product.id === selectedProduct.id)) {
setProductId(''); setSelectedProduct(null);
} }
}, [filteredProducts, productId]); }, [filteredProducts, selectedProduct]);
const addItem = async () => { const addItem = async () => {
const productId = selectedProduct?.id;
if (!id || !productId || existingProductIds.has(productId)) return; if (!id || !productId || existingProductIds.has(productId)) return;
await db.pickItems.add({ await db.pickItems.add({
id: uuidv4(), id: uuidv4(),
@@ -74,28 +76,46 @@ export const AddItemScreen = () => {
Add Item Add Item
</Typography> </Typography>
<Stack spacing={2}> <Stack spacing={2}>
<TextField <Autocomplete
placeholder="Search products" options={filteredProducts}
value={query} getOptionLabel={(option) => `${option.name} (${option.category})`}
onChange={(event) => setQuery(event.target.value)} isOptionEqualToValue={(option, value) => option.id === value.id}
InputProps={{ startAdornment: <InputAdornment position="start">{<SearchIcon />}</InputAdornment> }} value={selectedProduct}
/> onChange={(_, value) => setSelectedProduct(value)}
<TextField inputValue={query}
select onInputChange={(_, value, reason) => {
label="Product" if (reason === 'input') {
setQuery(value);
}
if (reason === 'clear') {
setQuery('');
}
}}
filterOptions={(options) => options}
noOptionsText={query.trim() ? 'No matching products' : 'No products available'}
fullWidth fullWidth
value={productId} renderInput={(params) => (
onChange={(event) => setProductId(event.target.value)} <TextField
> {...params}
{filteredProducts.map((product) => ( placeholder="Search products"
<MenuItem key={product.id} value={product.id}> InputProps={{
{product.name} ({product.category}) ...params.InputProps,
</MenuItem> startAdornment: (
))} <>
</TextField> <InputAdornment position="start">
<SearchIcon />
</InputAdornment>
{params.InputProps.startAdornment}
</>
),
}}
/>
)}
/>
<NumericStepper label="Units" value={units} onChange={setUnits} /> <NumericStepper label="Units" value={units} onChange={setUnits} />
<NumericStepper label="Bulk" value={bulk} onChange={setBulk} /> <NumericStepper label="Bulk" value={bulk} onChange={setBulk} />
<Button variant="contained" disabled={!productId} onClick={addItem}> <Button variant="contained" disabled={!selectedProduct} onClick={addItem}>
Add to List Add to List
</Button> </Button>
</Stack> </Stack>