Fix pick item controls responsiveness

This commit is contained in:
beatz174-bit
2025-11-24 09:24:17 +10:00
parent 8c80c14f3b
commit 3eef44ca0f
+163 -72
View File
@@ -10,8 +10,10 @@ import {
IconButton, IconButton,
Stack, Stack,
Typography, Typography,
useMediaQuery,
} from '@mui/material'; } from '@mui/material';
import { alpha } from '@mui/material/styles'; import { alpha, useTheme } from '@mui/material/styles';
import type React from 'react';
import { useState } from 'react'; import { useState } from 'react';
import { PickItem } from '../models/PickItem'; import { PickItem } from '../models/PickItem';
import { Product } from '../models/Product'; import { Product } from '../models/Product';
@@ -35,8 +37,10 @@ export const PickItemRow = ({
onStatusChange, onStatusChange,
onDelete, onDelete,
}: PickItemRowProps) => { }: PickItemRowProps) => {
const theme = useTheme();
const [isConfirmOpen, setIsConfirmOpen] = useState(false); const [isConfirmOpen, setIsConfirmOpen] = useState(false);
const [isControlsOpen, setIsControlsOpen] = useState(false); const [isControlsOpen, setIsControlsOpen] = useState(false);
const isNarrowScreen = useMediaQuery(theme.breakpoints.down('sm'));
const packagingLabel = item.is_carton const packagingLabel = item.is_carton
? product?.bulk_name ?? 'Carton' ? product?.bulk_name ?? 'Carton'
: product?.unit_type ?? 'Unit'; : product?.unit_type ?? 'Unit';
@@ -50,6 +54,25 @@ export const PickItemRow = ({
setIsConfirmOpen(false); setIsConfirmOpen(false);
}; };
const handleRowClick = () => {
if (isNarrowScreen) {
setIsControlsOpen(true);
}
};
const handleRowKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (!isNarrowScreen) return;
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
setIsControlsOpen(true);
}
};
const stopPropagation = (event: React.SyntheticEvent) => {
event.stopPropagation();
};
return ( return (
<Stack <Stack
direction="row" direction="row"
@@ -61,17 +84,12 @@ export const PickItemRow = ({
borderRadius: 1, borderRadius: 1,
bgcolor: 'background.paper', bgcolor: 'background.paper',
boxShadow: 1, boxShadow: 1,
cursor: 'pointer', cursor: isNarrowScreen ? 'pointer' : 'default',
}}
onClick={() => setIsControlsOpen(true)}
role="button"
tabIndex={0}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
setIsControlsOpen(true);
}
}} }}
onClick={handleRowClick}
role={isNarrowScreen ? 'button' : undefined}
tabIndex={isNarrowScreen ? 0 : undefined}
onKeyDown={handleRowKeyDown}
> >
<Stack direction="row" spacing={1} alignItems="center" flex={1} minWidth={0}> <Stack direction="row" spacing={1} alignItems="center" flex={1} minWidth={0}>
<Checkbox <Checkbox
@@ -103,73 +121,145 @@ export const PickItemRow = ({
{item.quantity} {packagingLabel} {item.quantity} {packagingLabel}
</Typography> </Typography>
</Typography> </Typography>
<Typography variant="caption" color="text.secondary" noWrap> {isNarrowScreen && (
Tap to adjust quantity and packaging <Typography variant="caption" color="text.secondary" noWrap>
</Typography> Tap to adjust quantity and packaging
</Typography>
)}
</Stack> </Stack>
</Stack> </Stack>
<Dialog {!isNarrowScreen && (
open={isControlsOpen} <Stack direction="row" spacing={1} alignItems="center">
onClose={() => setIsControlsOpen(false)} <IconButton
fullWidth aria-label={`Switch to ${item.is_carton ? 'unit' : 'carton'} packaging`}
maxWidth="xs" color={item.is_carton ? 'primary' : 'default'}
aria-labelledby="item-controls-title" onClick={(event) => {
> stopPropagation(event);
<DialogTitle onToggleCarton();
id="item-controls-title" }}
sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }} sx={{
> boxShadow: item.is_carton
<Typography variant="h6" noWrap sx={{ minWidth: 0, flex: 1 }}> ? (theme) => `0 0 0 8px ${alpha(theme.palette.primary.main, 0.15)}`
{product?.name ?? 'Unknown product'} : 'none',
</Typography> }}
<IconButton aria-label="Close controls" onClick={() => setIsControlsOpen(false)}> >
<Close /> <Inventory2 />
</IconButton> </IconButton>
</DialogTitle> <IconButton
<DialogContent> aria-label="Decrease quantity"
<Stack spacing={2} alignItems="stretch"> color="primary"
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}> onClick={(event) => {
Quantity: {item.quantity} {packagingLabel} stopPropagation(event);
onDecrementQuantity();
}}
>
<Remove />
</IconButton>
<IconButton
aria-label="Increase quantity"
color="primary"
onClick={(event) => {
stopPropagation(event);
onIncrementQuantity();
}}
>
<Add />
</IconButton>
<IconButton
color="error"
onClick={(event) => {
stopPropagation(event);
setIsConfirmOpen(true);
}}
aria-label="Delete item"
>
<Delete />
</IconButton>
</Stack>
)}
{isNarrowScreen && (
<Dialog
open={isControlsOpen}
onClose={() => setIsControlsOpen(false)}
fullWidth
maxWidth="xs"
aria-labelledby="item-controls-title"
>
<DialogTitle
id="item-controls-title"
sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}
>
<Typography variant="h6" noWrap sx={{ minWidth: 0, flex: 1 }}>
{product?.name ?? 'Unknown product'}
</Typography> </Typography>
<Stack direction="row" spacing={1} justifyContent="center" flexWrap="wrap"> <IconButton
<IconButton aria-label="Close controls"
aria-label={`Switch to ${item.is_carton ? 'unit' : 'carton'} packaging`} onClick={(event) => {
color={item.is_carton ? 'primary' : 'default'} stopPropagation(event);
onClick={onToggleCarton} setIsControlsOpen(false);
sx={{ }}
boxShadow: item.is_carton >
? (theme) => `0 0 0 8px ${alpha(theme.palette.primary.main, 0.15)}` <Close />
: 'none', </IconButton>
}} </DialogTitle>
> <DialogContent>
<Inventory2 /> <Stack spacing={2} alignItems="stretch">
</IconButton> <Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
<IconButton Quantity: {item.quantity} {packagingLabel}
aria-label="Decrease quantity" </Typography>
color="primary" <Stack direction="row" spacing={1} justifyContent="center" flexWrap="wrap">
onClick={onDecrementQuantity} <IconButton
> aria-label={`Switch to ${item.is_carton ? 'unit' : 'carton'} packaging`}
<Remove /> color={item.is_carton ? 'primary' : 'default'}
</IconButton> onClick={(event) => {
<IconButton stopPropagation(event);
aria-label="Increase quantity" onToggleCarton();
color="primary" }}
onClick={onIncrementQuantity} sx={{
> boxShadow: item.is_carton
<Add /> ? (theme) => `0 0 0 8px ${alpha(theme.palette.primary.main, 0.15)}`
</IconButton> : 'none',
<IconButton }}
color="error" >
onClick={() => setIsConfirmOpen(true)} <Inventory2 />
aria-label="Delete item" </IconButton>
> <IconButton
<Delete /> aria-label="Decrease quantity"
</IconButton> color="primary"
onClick={(event) => {
stopPropagation(event);
onDecrementQuantity();
}}
>
<Remove />
</IconButton>
<IconButton
aria-label="Increase quantity"
color="primary"
onClick={(event) => {
stopPropagation(event);
onIncrementQuantity();
}}
>
<Add />
</IconButton>
<IconButton
color="error"
onClick={(event) => {
stopPropagation(event);
setIsConfirmOpen(true);
}}
aria-label="Delete item"
>
<Delete />
</IconButton>
</Stack>
</Stack> </Stack>
</Stack> </DialogContent>
</DialogContent> </Dialog>
</Dialog> )}
<Dialog <Dialog
open={isConfirmOpen} open={isConfirmOpen}
@@ -191,6 +281,7 @@ export const PickItemRow = ({
color="error" color="error"
variant="contained" variant="contained"
onClick={handleConfirmDelete} onClick={handleConfirmDelete}
aria-label="Confirm delete"
> >
Delete Delete
</Button> </Button>