Redesign pick lists for reuse

This commit is contained in:
beatz174-bit
2025-11-21 18:49:35 +10:00
parent 7f24948317
commit 858c1559d7
4 changed files with 163 additions and 24 deletions
+9 -10
View File
@@ -1,6 +1,6 @@
import { Button, Container, Stack, Typography } from '@mui/material'; import { Button, Container, Stack, Typography } from '@mui/material';
import { useParams, useNavigate, Link as RouterLink } from 'react-router-dom'; import { useParams, useNavigate, Link as RouterLink } from 'react-router-dom';
import { useEffect, useMemo } from 'react'; import { useMemo } from 'react';
import { useAreas, usePickItems, usePickList, useProducts } from '../hooks/dataHooks'; import { useAreas, usePickItems, usePickList, useProducts } from '../hooks/dataHooks';
import { useDatabase } from '../context/DBProvider'; import { useDatabase } from '../context/DBProvider';
import { PickItemRow } from '../components/PickItemRow'; import { PickItemRow } from '../components/PickItemRow';
@@ -14,10 +14,6 @@ export const ActivePickListScreen = () => {
const db = useDatabase(); const db = useDatabase();
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => {
if (!id || !pickList) return;
}, [id, pickList]);
const areaName = useMemo( const areaName = useMemo(
() => areas.find((area) => area.id === pickList?.area_id)?.name ?? 'Area', () => areas.find((area) => area.id === pickList?.area_id)?.name ?? 'Area',
[areas, pickList?.area_id], [areas, pickList?.area_id],
@@ -49,9 +45,7 @@ export const ActivePickListScreen = () => {
await db.pickItems.delete(itemId); await db.pickItems.delete(itemId);
}; };
const completeList = async () => { const returnToLists = () => {
if (!id) return;
await db.pickLists.update(id, { completed_at: Date.now() });
navigate('/pick-lists'); navigate('/pick-lists');
}; };
@@ -63,6 +57,11 @@ export const ActivePickListScreen = () => {
Add Item Add Item
</Button> </Button>
</Stack> </Stack>
{pickList?.notes ? (
<Typography variant="body2" color="text.secondary" mb={2}>
{pickList.notes}
</Typography>
) : null}
<Stack spacing={1}> <Stack spacing={1}>
{items.map((item) => ( {items.map((item) => (
<PickItemRow <PickItemRow
@@ -76,8 +75,8 @@ export const ActivePickListScreen = () => {
/> />
))} ))}
</Stack> </Stack>
<Button fullWidth sx={{ mt: 3 }} variant="outlined" onClick={completeList}> <Button fullWidth sx={{ mt: 3 }} variant="outlined" onClick={returnToLists}>
Complete List Save and Return
</Button> </Button>
</Container> </Container>
); );
+2 -2
View File
@@ -8,10 +8,10 @@ export const HomeScreen = () => (
</Typography> </Typography>
<Stack spacing={2}> <Stack spacing={2}>
<Button component={RouterLink} to="/start" variant="contained"> <Button component={RouterLink} to="/start" variant="contained">
Start New Pick List Create Pick List
</Button> </Button>
<Button component={RouterLink} to="/pick-lists" variant="outlined"> <Button component={RouterLink} to="/pick-lists" variant="outlined">
View Pick Lists View & Edit Pick Lists
</Button> </Button>
<Button component={RouterLink} to="/products" variant="outlined"> <Button component={RouterLink} to="/products" variant="outlined">
Manage Products Manage Products
+129 -5
View File
@@ -1,32 +1,156 @@
import { Button, Container, List, ListItemButton, ListItemText, Typography } from '@mui/material'; import {
Button,
Container,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
IconButton,
List,
ListItem,
ListItemButton,
ListItemText,
MenuItem,
Stack,
TextField,
Typography,
} from '@mui/material';
import { Delete, Edit } from '@mui/icons-material';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { useMemo, useState } from 'react';
import { Link as RouterLink } from 'react-router-dom'; import { Link as RouterLink } from 'react-router-dom';
import { usePickLists, useAreas } from '../hooks/dataHooks'; import { usePickLists, useAreas } from '../hooks/dataHooks';
import { useDatabase } from '../context/DBProvider';
import { PickList } from '../models/PickList';
export const PickListsScreen = () => { export const PickListsScreen = () => {
const lists = usePickLists(); const lists = usePickLists();
const areas = useAreas(); const areas = useAreas();
const db = useDatabase();
const [editingList, setEditingList] = useState<PickList | null>(null);
const [areaId, setAreaId] = useState('');
const [notes, setNotes] = useState('');
const sortedLists = useMemo(() => {
return [...lists].sort((a, b) => a.created_at - b.created_at);
}, [lists]);
const getAreaName = (areaId: string) => areas.find((a) => a.id === areaId)?.name ?? 'Unknown area'; const getAreaName = (areaId: string) => areas.find((a) => a.id === areaId)?.name ?? 'Unknown area';
const openEdit = (list: PickList) => {
setEditingList(list);
setAreaId(list.area_id);
setNotes(list.notes ?? '');
};
const closeEdit = () => {
setEditingList(null);
setAreaId('');
setNotes('');
};
const saveEdit = async () => {
if (!editingList || !areaId) return;
await db.pickLists.update(editingList.id, {
area_id: areaId,
notes: notes.trim() || undefined,
});
closeEdit();
};
const deleteList = async (list: PickList) => {
const confirmed = window.confirm('Remove this pick list and its items?');
if (!confirmed) return;
await db.pickItems.where('pick_list_id').equals(list.id).delete();
await db.pickLists.delete(list.id);
};
return ( return (
<Container sx={{ py: 4 }}> <Container sx={{ py: 4 }}>
<Typography variant="h5" gutterBottom> <Typography variant="h5" gutterBottom>
Pick Lists Pick Lists
</Typography> </Typography>
<Button component={RouterLink} to="/start" variant="contained" sx={{ mb: 2 }}> <Button component={RouterLink} to="/start" variant="contained" sx={{ mb: 2 }}>
Start New Add Pick List
</Button> </Button>
<List> <List>
{lists.map((list) => ( {sortedLists.map((list) => (
<ListItemButton key={list.id} component={RouterLink} to={`/pick-lists/${list.id}`} divider> <ListItem key={list.id} divider secondaryAction={
<Stack direction="row" spacing={1}>
<IconButton
edge="end"
aria-label="Edit"
onClick={(event) => {
event.stopPropagation();
event.preventDefault();
openEdit(list);
}}
>
<Edit />
</IconButton>
<IconButton
edge="end"
aria-label="Delete"
onClick={(event) => {
event.stopPropagation();
event.preventDefault();
deleteList(list);
}}
>
<Delete />
</IconButton>
</Stack>
}>
<ListItemButton component={RouterLink} to={`/pick-lists/${list.id}`}>
<ListItemText <ListItemText
primary={getAreaName(list.area_id)} primary={getAreaName(list.area_id)}
secondary={format(list.created_at, 'PPpp')} secondary={
<Stack spacing={0.5}>
{list.notes ? <span>{list.notes}</span> : null}
<Typography variant="caption" color="text.secondary">
Created {format(list.created_at, 'PPpp')}
</Typography>
</Stack>
}
/> />
</ListItemButton> </ListItemButton>
</ListItem>
))} ))}
</List> </List>
<Dialog open={Boolean(editingList)} onClose={closeEdit} fullWidth>
<DialogTitle>Edit Pick List</DialogTitle>
<DialogContent sx={{ pt: 1 }}>
<Stack spacing={2} mt={1}>
<TextField
select
fullWidth
label="Area"
value={areaId}
onChange={(event) => setAreaId(event.target.value)}
>
{areas.map((area) => (
<MenuItem key={area.id} value={area.id}>
{area.name}
</MenuItem>
))}
</TextField>
<TextField
label="Notes"
value={notes}
onChange={(event) => setNotes(event.target.value)}
multiline
minRows={2}
/>
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={closeEdit}>Cancel</Button>
<Button variant="contained" onClick={saveEdit} disabled={!areaId}>
Save Changes
</Button>
</DialogActions>
</Dialog>
</Container> </Container>
); );
}; };
+19 -3
View File
@@ -10,18 +10,27 @@ export const StartPickListScreen = () => {
const db = useDatabase(); const db = useDatabase();
const navigate = useNavigate(); const navigate = useNavigate();
const [areaId, setAreaId] = useState(''); const [areaId, setAreaId] = useState('');
const [notes, setNotes] = useState('');
const start = async () => { const start = async () => {
if (!areaId) return; if (!areaId) return;
const pickListId = uuidv4(); const pickListId = uuidv4();
await db.pickLists.add({ id: pickListId, area_id: areaId, created_at: Date.now() }); await db.pickLists.add({
id: pickListId,
area_id: areaId,
created_at: Date.now(),
notes: notes.trim() || undefined,
});
navigate(`/pick-lists/${pickListId}`); navigate(`/pick-lists/${pickListId}`);
}; };
return ( return (
<Container sx={{ py: 4 }}> <Container sx={{ py: 4 }}>
<Typography variant="h5" gutterBottom> <Typography variant="h5" gutterBottom>
Start Pick List Create Pick List
</Typography>
<Typography variant="body2" color="text.secondary" gutterBottom>
Pick lists are reusable. Create one for each store area and update it anytime you restock.
</Typography> </Typography>
<Stack spacing={2}> <Stack spacing={2}>
<TextField <TextField
@@ -37,8 +46,15 @@ export const StartPickListScreen = () => {
</MenuItem> </MenuItem>
))} ))}
</TextField> </TextField>
<TextField
label="Notes (optional)"
value={notes}
onChange={(event) => setNotes(event.target.value)}
multiline
minRows={2}
/>
<Button variant="contained" disabled={!areaId} onClick={start}> <Button variant="contained" disabled={!areaId} onClick={start}>
Start Save Pick List
</Button> </Button>
</Stack> </Stack>
</Container> </Container>