Redesign pick lists for reuse
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Button, Container, Stack, Typography } from '@mui/material';
|
||||
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 { useDatabase } from '../context/DBProvider';
|
||||
import { PickItemRow } from '../components/PickItemRow';
|
||||
@@ -14,10 +14,6 @@ export const ActivePickListScreen = () => {
|
||||
const db = useDatabase();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
if (!id || !pickList) return;
|
||||
}, [id, pickList]);
|
||||
|
||||
const areaName = useMemo(
|
||||
() => areas.find((area) => area.id === pickList?.area_id)?.name ?? 'Area',
|
||||
[areas, pickList?.area_id],
|
||||
@@ -49,9 +45,7 @@ export const ActivePickListScreen = () => {
|
||||
await db.pickItems.delete(itemId);
|
||||
};
|
||||
|
||||
const completeList = async () => {
|
||||
if (!id) return;
|
||||
await db.pickLists.update(id, { completed_at: Date.now() });
|
||||
const returnToLists = () => {
|
||||
navigate('/pick-lists');
|
||||
};
|
||||
|
||||
@@ -63,6 +57,11 @@ export const ActivePickListScreen = () => {
|
||||
Add Item
|
||||
</Button>
|
||||
</Stack>
|
||||
{pickList?.notes ? (
|
||||
<Typography variant="body2" color="text.secondary" mb={2}>
|
||||
{pickList.notes}
|
||||
</Typography>
|
||||
) : null}
|
||||
<Stack spacing={1}>
|
||||
{items.map((item) => (
|
||||
<PickItemRow
|
||||
@@ -76,8 +75,8 @@ export const ActivePickListScreen = () => {
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
<Button fullWidth sx={{ mt: 3 }} variant="outlined" onClick={completeList}>
|
||||
Complete List
|
||||
<Button fullWidth sx={{ mt: 3 }} variant="outlined" onClick={returnToLists}>
|
||||
Save and Return
|
||||
</Button>
|
||||
</Container>
|
||||
);
|
||||
|
||||
@@ -8,10 +8,10 @@ export const HomeScreen = () => (
|
||||
</Typography>
|
||||
<Stack spacing={2}>
|
||||
<Button component={RouterLink} to="/start" variant="contained">
|
||||
Start New Pick List
|
||||
Create Pick List
|
||||
</Button>
|
||||
<Button component={RouterLink} to="/pick-lists" variant="outlined">
|
||||
View Pick Lists
|
||||
View & Edit Pick Lists
|
||||
</Button>
|
||||
<Button component={RouterLink} to="/products" variant="outlined">
|
||||
Manage Products
|
||||
|
||||
@@ -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 { useMemo, useState } from 'react';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { usePickLists, useAreas } from '../hooks/dataHooks';
|
||||
import { useDatabase } from '../context/DBProvider';
|
||||
import { PickList } from '../models/PickList';
|
||||
|
||||
export const PickListsScreen = () => {
|
||||
const lists = usePickLists();
|
||||
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 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 (
|
||||
<Container sx={{ py: 4 }}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
Pick Lists
|
||||
</Typography>
|
||||
<Button component={RouterLink} to="/start" variant="contained" sx={{ mb: 2 }}>
|
||||
Start New
|
||||
Add Pick List
|
||||
</Button>
|
||||
<List>
|
||||
{lists.map((list) => (
|
||||
<ListItemButton key={list.id} component={RouterLink} to={`/pick-lists/${list.id}`} divider>
|
||||
<ListItemText
|
||||
primary={getAreaName(list.area_id)}
|
||||
secondary={format(list.created_at, 'PPpp')}
|
||||
/>
|
||||
</ListItemButton>
|
||||
{sortedLists.map((list) => (
|
||||
<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
|
||||
primary={getAreaName(list.area_id)}
|
||||
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>
|
||||
</ListItem>
|
||||
))}
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,18 +10,27 @@ export const StartPickListScreen = () => {
|
||||
const db = useDatabase();
|
||||
const navigate = useNavigate();
|
||||
const [areaId, setAreaId] = useState('');
|
||||
const [notes, setNotes] = useState('');
|
||||
|
||||
const start = async () => {
|
||||
if (!areaId) return;
|
||||
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}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<Container sx={{ py: 4 }}>
|
||||
<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>
|
||||
<Stack spacing={2}>
|
||||
<TextField
|
||||
@@ -37,8 +46,15 @@ export const StartPickListScreen = () => {
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
<TextField
|
||||
label="Notes (optional)"
|
||||
value={notes}
|
||||
onChange={(event) => setNotes(event.target.value)}
|
||||
multiline
|
||||
minRows={2}
|
||||
/>
|
||||
<Button variant="contained" disabled={!areaId} onClick={start}>
|
||||
Start
|
||||
Save Pick List
|
||||
</Button>
|
||||
</Stack>
|
||||
</Container>
|
||||
|
||||
Reference in New Issue
Block a user