Fix pick item controls responsiveness
This commit is contained in:
+163
-72
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user