Deduplicate prefilled pick list products

This commit is contained in:
beatz174-bit committed 2025-11-23 15:49:08 +10:00
1 parent 1efa5a161d
commit b9ca6f7e31
3 files changed
+278 -21

No files matched your search

+99 -8
View File
@@ -1,25 +1,98 @@
import { Button, Container, MenuItem, Stack, TextField, Typography } from '@mui/material';
import { useState } from 'react';
import {
Button,
Checkbox,
Container,
FormControlLabel,
FormGroup,
MenuItem,
Stack,
TextField,
Typography,
} from '@mui/material';
import { useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { v4 as uuidv4 } from 'uuid';
import { useAreas } from '../hooks/dataHooks';
import { useAreas, useCategories } from '../hooks/dataHooks';
import { useDatabase } from '../context/DBProvider';
export const StartPickListScreen = () => {
const areas = useAreas();
const categories = useCategories();
const db = useDatabase();
const navigate = useNavigate();
const [areaId, setAreaId] = useState('');
const [notes, setNotes] = useState('');
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
const sortedCategories = useMemo(
() =>
[...categories].sort((a, b) =>
a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }),
),
[categories],
);
const handleToggleCategory = (categoryId: string) => {
setSelectedCategories((current) =>
current.includes(categoryId)
? current.filter((id) => id !== categoryId)
: [...current, categoryId],
);
};
const start = async () => {
if (!areaId) return;
const pickListId = uuidv4();
await db.pickLists.add({
id: pickListId,
area_id: areaId,
created_at: Date.now(),
notes: notes.trim() || undefined,
const timestamp = Date.now();
const selectedCategoryNames = categories
.filter((category) => selectedCategories.includes(category.id))
.map((category) => category.name);
await db.transaction('rw', db.pickLists, db.pickItems, db.products, async () => {
await db.pickLists.add({
id: pickListId,
area_id: areaId,
created_at: timestamp,
notes: notes.trim() || undefined,
});
if (selectedCategoryNames.length === 0) {
return;
}
const products = await db.products.toArray();
const productsInCategories = products.filter(
(product) => selectedCategoryNames.includes(product.category) && !product.archived,
);
const uniqueProducts: typeof productsInCategories = [];
const seenNames = new Set<string>();
productsInCategories.forEach((product) => {
const nameKey = product.name.toLowerCase();
if (!seenNames.has(nameKey)) {
seenNames.add(nameKey);
uniqueProducts.push(product);
}
});
if (productsInCategories.length === 0) {
return;
}
await db.pickItems.bulkAdd(
uniqueProducts.map((product) => ({
id: uuidv4(),
pick_list_id: pickListId,
product_id: product.id,
quantity: 1,
is_carton: false,
status: 'pending',
created_at: timestamp,
updated_at: timestamp,
})),
);
});
navigate(`/pick-lists/${pickListId}`);
};
@@ -47,12 +120,30 @@ export const StartPickListScreen = () => {
))}
</TextField>
<TextField
fullWidth
label="Notes (optional)"
value={notes}
onChange={(event) => setNotes(event.target.value)}
multiline
minRows={2}
/>
<Stack spacing={1}>
<Typography variant="subtitle2">Add categories to prefill products</Typography>
<FormGroup>
{sortedCategories.map((category) => (
<FormControlLabel
key={category.id}
control={
<Checkbox
checked={selectedCategories.includes(category.id)}
onChange={() => handleToggleCategory(category.id)}
/>
}
label={category.name}
/>
))}
</FormGroup>
</Stack>
<Button variant="contained" disabled={!areaId} onClick={start}>
Save Pick List
</Button>