Merge pull request #30 from beatz174-bit/codex/replace-swipe-handlers-with-checkbox-interaction

Add checkbox toggle for pick list items
This commit is contained in:
beatz174-bit
2025-11-23 12:04:50 +10:00
committed by GitHub
3 changed files with 49 additions and 47 deletions
+8 -17
View File
@@ -152,10 +152,8 @@ Dexie tables must be implemented exactly as follows:
### ActivePickListScreen ### ActivePickListScreen
- List of PickItems\ - List of PickItems\
- Tap = +1 unit\ - Use the checkbox in each row to toggle between pending and picked without removing the item\
- Long-press = +1 bulk\ - Row controls provide explicit +1 unit and +1 bulk actions (no long-press or swipe)\
- Swipe left = mark picked\
- Swipe right = delete\
- Add Item button\ - Add Item button\
- Complete List button - Complete List button
@@ -188,23 +186,15 @@ Dexie tables must be implemented exactly as follows:
------------------------------------------------------------------------ ------------------------------------------------------------------------
## 6. Gestures & Interaction Rules ## 6. Interaction Rules
### Tap ### Checkbox Toggle
Increase `quantity_units` by **1**. 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_bulk` by **1** using a shared `useLongPress()` hook. 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.
### Swipe Left
Mark item as `"picked"`.
### Swipe Right
Delete item.
### Barcode Scanning ### Barcode Scanning
@@ -318,6 +308,7 @@ Expose port 8080:
- Product creation must be minimal friction\ - Product creation must be minimal friction\
- Auto-save pick lists\ - Auto-save pick lists\
- Smooth animations on long press - 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
------------------------------------------------------------------------ ------------------------------------------------------------------------
+33 -25
View File
@@ -1,34 +1,26 @@
import { Chip, Stack, Typography } from '@mui/material'; import { Add, Delete } from '@mui/icons-material';
import { PickItem, PickItemStatus } from '../models/PickItem'; import { Button, Checkbox, Stack, Typography } from '@mui/material';
import { PickItem } from '../models/PickItem';
import { Product } from '../models/Product'; import { Product } from '../models/Product';
import { useLongPress } from '../hooks/useLongPress';
import { useSwipe } from '../hooks/useSwipe';
interface PickItemRowProps { interface PickItemRowProps {
item: PickItem; item: PickItem;
product?: Product | null; product?: Product | null;
onIncrementUnit: () => void; onIncrementUnit: () => void;
onIncrementBulk: () => void; onIncrementBulk: () => void;
onSwipeLeft: () => void; onToggleStatus: () => void;
onSwipeRight: () => void; onDelete: () => void;
} }
const statusColor: Record<PickItemStatus, 'default' | 'success' | 'warning'> = {
pending: 'default',
picked: 'success',
skipped: 'warning',
};
export const PickItemRow = ({ export const PickItemRow = ({
item, item,
product, product,
onIncrementUnit, onIncrementUnit,
onIncrementBulk, onIncrementBulk,
onSwipeLeft, onToggleStatus,
onSwipeRight, onDelete,
}: PickItemRowProps) => { }: PickItemRowProps) => {
const longPressHandlers = useLongPress({ onLongPress: onIncrementBulk, onClick: onIncrementUnit }); const isPicked = item.status === 'picked';
const swipeHandlers = useSwipe({ onSwipeLeft, onSwipeRight });
return ( return (
<Stack <Stack
@@ -37,16 +29,32 @@ export const PickItemRow = ({
justifyContent="space-between" justifyContent="space-between"
spacing={1} spacing={1}
sx={{ p: 1, borderRadius: 1, bgcolor: 'background.paper', boxShadow: 1 }} sx={{ p: 1, borderRadius: 1, bgcolor: 'background.paper', boxShadow: 1 }}
{...longPressHandlers}
{...swipeHandlers}
> >
<div> <Stack direction="row" alignItems="center" spacing={1} flex={1}>
<Typography variant="subtitle1">{product?.name ?? 'Unknown product'}</Typography> <Checkbox color="success" checked={isPicked} onChange={onToggleStatus} />
<Typography variant="caption" color="text.secondary"> <Stack spacing={0.5} flex={1}>
{item.quantity_units} units / {item.quantity_bulk} bulk <Typography
</Typography> variant="subtitle1"
</div> sx={{ textDecoration: isPicked ? 'line-through' : 'none', display: 'flex', gap: 0.5, alignItems: 'center' }}
<Chip label={item.status} color={statusColor[item.status]} size="small" /> >
{isPicked ? '✔️' : null} {product?.name ?? 'Unknown product'}
</Typography>
<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> </Stack>
); );
}; };
+8 -5
View File
@@ -37,11 +37,14 @@ export const ActivePickListScreen = () => {
}); });
}; };
const handleSwipeLeft = async (itemId: string) => { const handleToggleStatus = async (itemId: string) => {
await db.pickItems.update(itemId, { status: 'picked', updated_at: Date.now() }); 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); await db.pickItems.delete(itemId);
}; };
@@ -70,8 +73,8 @@ export const ActivePickListScreen = () => {
product={products.find((p) => p.id === item.product_id)} product={products.find((p) => p.id === item.product_id)}
onIncrementUnit={() => handleIncrementUnit(item.id)} onIncrementUnit={() => handleIncrementUnit(item.id)}
onIncrementBulk={() => handleIncrementBulk(item.id)} onIncrementBulk={() => handleIncrementBulk(item.id)}
onSwipeLeft={() => handleSwipeLeft(item.id)} onToggleStatus={() => handleToggleStatus(item.id)}
onSwipeRight={() => handleSwipeRight(item.id)} onDelete={() => handleDeleteItem(item.id)}
/> />
))} ))}
</Stack> </Stack>