Merge branch 'main' into codex/add-quantity-and-is_carton-fields-to-pickitem

This commit is contained in:
beatz174-bit
2025-11-23 12:07:03 +10:00
committed by GitHub
3 changed files with 55 additions and 51 deletions
+8 -17
View File
@@ -157,10 +157,8 @@ quantities remain distinct.
### ActivePickListScreen
- List of PickItems\
- Tap = +1 of the item's unit type\
- Long-press = +1 of the item's unit type\
- Swipe left = mark picked\
- Swipe right = delete\
- Use the checkbox in each row to toggle between pending and picked without removing the item\
- Row controls provide explicit +1 unit and +1 bulk actions (no long-press or swipe)\
- Add Item button\
- Complete List button
@@ -193,23 +191,15 @@ quantities remain distinct.
------------------------------------------------------------------------
## 6. Gestures & Interaction Rules
## 6. Interaction Rules
### Tap
### Checkbox Toggle
Increase `quantity` by **1** for the tapped item's unit type.
Use a checkbox in each pick item row to switch between `"pending"` and `"picked"` without removing the item from the list. Picked rows must remain visible with clear status cues (e.g., checkmarks/strikethrough).
### Long Press
### Increment Controls
Increase `quantity` by **1** using a shared `useLongPress()` hook.
### Swipe Left
Mark item as `"picked"`.
### Swipe Right
Delete item.
Provide explicit controls to increase `quantity_units` and `quantity_bulk` (no long-press). Avoid swipe gestures for status changes or deletion on pick item rows.
### Barcode Scanning
@@ -323,6 +313,7 @@ Expose port 8080:
- Product creation must be minimal friction\
- Auto-save pick lists\
- Smooth animations on long press
- Pick list rows use checkboxes to toggle items between pending and picked; no swipe or long-press gestures should be required to update status, and picked rows stay visible with clear status cues
------------------------------------------------------------------------
+36 -27
View File
@@ -1,33 +1,26 @@
import { Chip, Stack, Typography } from '@mui/material';
import { PickItem, PickItemStatus } from '../models/PickItem';
import { Add, Delete } from '@mui/icons-material';
import { Button, Checkbox, Stack, Typography } from '@mui/material';
import { PickItem } from '../models/PickItem';
import { Product } from '../models/Product';
import { useLongPress } from '../hooks/useLongPress';
import { useSwipe } from '../hooks/useSwipe';
interface PickItemRowProps {
item: PickItem;
product?: Product | null;
onIncrement: () => void;
onSwipeLeft: () => void;
onSwipeRight: () => void;
onIncrementUnit: () => void;
onIncrementBulk: () => void;
onToggleStatus: () => void;
onDelete: () => void;
}
const statusColor: Record<PickItemStatus, 'default' | 'success' | 'warning'> = {
pending: 'default',
picked: 'success',
skipped: 'warning',
};
export const PickItemRow = ({
item,
product,
onIncrement,
onSwipeLeft,
onSwipeRight,
onIncrementUnit,
onIncrementBulk,
onToggleStatus,
onDelete,
}: PickItemRowProps) => {
const longPressHandlers = useLongPress({ onLongPress: onIncrement, onClick: onIncrement });
const swipeHandlers = useSwipe({ onSwipeLeft, onSwipeRight });
const unitLabel = item.is_carton ? product?.bulk_name ?? 'cartons' : product?.unit_type ?? 'units';
const isPicked = item.status === 'picked';
return (
<Stack
@@ -36,16 +29,32 @@ export const PickItemRow = ({
justifyContent="space-between"
spacing={1}
sx={{ p: 1, borderRadius: 1, bgcolor: 'background.paper', boxShadow: 1 }}
{...longPressHandlers}
{...swipeHandlers}
>
<div>
<Typography variant="subtitle1">{product?.name ?? 'Unknown product'}</Typography>
<Typography variant="caption" color="text.secondary">
{item.quantity} {unitLabel}
<Stack direction="row" alignItems="center" spacing={1} flex={1}>
<Checkbox color="success" checked={isPicked} onChange={onToggleStatus} />
<Stack spacing={0.5} flex={1}>
<Typography
variant="subtitle1"
sx={{ textDecoration: isPicked ? 'line-through' : 'none', display: 'flex', gap: 0.5, alignItems: 'center' }}
>
{isPicked ? '✔️' : null} {product?.name ?? 'Unknown product'}
</Typography>
</div>
<Chip label={item.status} color={statusColor[item.status]} size="small" />
<Typography variant="caption" color="text.secondary">
{item.quantity_units} units / {item.quantity_bulk} bulk
</Typography>
</Stack>
</Stack>
<Stack direction="row" spacing={1} alignItems="center">
<Button variant="outlined" size="small" startIcon={<Add />} onClick={onIncrementUnit}>
Unit
</Button>
<Button variant="outlined" size="small" startIcon={<Add />} onClick={onIncrementBulk}>
Bulk
</Button>
<Button variant="text" color="error" size="small" startIcon={<Delete />} onClick={onDelete}>
Delete
</Button>
</Stack>
</Stack>
);
};
+10 -6
View File
@@ -28,11 +28,14 @@ export const ActivePickListScreen = () => {
});
};
const handleSwipeLeft = async (itemId: string) => {
await db.pickItems.update(itemId, { status: 'picked', updated_at: Date.now() });
const handleToggleStatus = async (itemId: string) => {
const existing = await db.pickItems.get(itemId);
if (!existing) return;
const nextStatus = existing.status === 'picked' ? 'pending' : 'picked';
await db.pickItems.update(itemId, { status: nextStatus, updated_at: Date.now() });
};
const handleSwipeRight = async (itemId: string) => {
const handleDeleteItem = async (itemId: string) => {
await db.pickItems.delete(itemId);
};
@@ -59,9 +62,10 @@ export const ActivePickListScreen = () => {
key={item.id}
item={item}
product={products.find((p) => p.id === item.product_id)}
onIncrement={() => handleIncrement(item.id)}
onSwipeLeft={() => handleSwipeLeft(item.id)}
onSwipeRight={() => handleSwipeRight(item.id)}
onIncrementUnit={() => handleIncrementUnit(item.id)}
onIncrementBulk={() => handleIncrementBulk(item.id)}
onToggleStatus={() => handleToggleStatus(item.id)}
onDelete={() => handleDeleteItem(item.id)}
/>
))}
</Stack>