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:
@@ -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
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -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} />
|
||||||
|
<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>
|
||||||
<Typography variant="caption" color="text.secondary">
|
<Typography variant="caption" color="text.secondary">
|
||||||
{item.quantity_units} units / {item.quantity_bulk} bulk
|
{item.quantity_units} units / {item.quantity_bulk} bulk
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</Stack>
|
||||||
<Chip label={item.status} color={statusColor[item.status]} size="small" />
|
</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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user