Restructure project to root layout

This commit is contained in:
beatz174-bit committed 2025-11-21 16:10:41 +10:00
1 parent e0e26a34ab
commit 3ffe9bbf99
51 files changed
+16 -12

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
import { Alert, Card, CardContent, Typography } from '@mui/material';
import { useBarcodeScanner } from '../hooks/useBarcodeScanner';
interface BarcodeScannerViewProps {
onDetected?: (code: string) => void;
}
export const BarcodeScannerView = ({ onDetected }: BarcodeScannerViewProps) => {
const { videoRef, result } = useBarcodeScanner();
if (result.code && onDetected) {
onDetected(result.code);
}
return (
<Card variant="outlined">
<CardContent>
<Typography variant="subtitle1" gutterBottom>
Scan Barcode
</Typography>
<video ref={videoRef} style={{ width: '100%', borderRadius: 8 }} />
{result.code ? <Alert severity="success">Detected {result.code}</Alert> : null}
{result.error ? <Alert severity="error">{result.error}</Alert> : null}
</CardContent>
</Card>
);
};
+20
View File
@@ -0,0 +1,20 @@
import { Button, ButtonProps } from '@mui/material';
import React from 'react';
import { useLongPress } from '../hooks/useLongPress';
interface LongPressButtonProps extends ButtonProps {
onLongPress: () => void;
}
export const LongPressButton = ({ onLongPress, onClick, children, ...rest }: LongPressButtonProps) => {
const gestureHandlers = useLongPress({
onLongPress,
onClick: onClick ? () => onClick({} as React.MouseEvent<HTMLButtonElement>) : undefined,
});
return (
<Button {...rest} {...gestureHandlers} onClick={undefined}>
{children}
</Button>
);
};
+34
View File
@@ -0,0 +1,34 @@
import { IconButton, Stack, TextField } from '@mui/material';
import RemoveIcon from '@mui/icons-material/Remove';
import AddIcon from '@mui/icons-material/Add';
interface NumericStepperProps {
label?: string;
value: number;
onChange: (value: number) => void;
min?: number;
}
export const NumericStepper = ({ label, value, onChange, min = 0 }: NumericStepperProps) => (
<Stack direction="row" alignItems="center" spacing={1}>
<IconButton
aria-label={`decrease ${label ?? 'value'}`}
onClick={() => onChange(Math.max(min, value - 1))}
size="small"
>
<RemoveIcon />
</IconButton>
<TextField
size="small"
type="number"
label={label}
value={value}
onChange={(event) => onChange(Number(event.target.value))}
inputProps={{ min }}
sx={{ width: 120 }}
/>
<IconButton aria-label={`increase ${label ?? 'value'}`} onClick={() => onChange(value + 1)} size="small">
<AddIcon />
</IconButton>
</Stack>
);
+52
View File
@@ -0,0 +1,52 @@
import { Chip, Stack, Typography } from '@mui/material';
import { PickItem, PickItemStatus } 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;
onIncrementUnit: () => void;
onIncrementBulk: () => void;
onSwipeLeft: () => void;
onSwipeRight: () => void;
}
const statusColor: Record<PickItemStatus, 'default' | 'success' | 'warning'> = {
pending: 'default',
picked: 'success',
skipped: 'warning',
};
export const PickItemRow = ({
item,
product,
onIncrementUnit,
onIncrementBulk,
onSwipeLeft,
onSwipeRight,
}: PickItemRowProps) => {
const longPressHandlers = useLongPress({ onLongPress: onIncrementBulk, onClick: onIncrementUnit });
const swipeHandlers = useSwipe({ onSwipeLeft, onSwipeRight });
return (
<Stack
direction="row"
alignItems="center"
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_units} units / {item.quantity_bulk} bulk
</Typography>
</div>
<Chip label={item.status} color={statusColor[item.status]} size="small" />
</Stack>
);
};
+26
View File
@@ -0,0 +1,26 @@
import { Card, CardContent, Stack, Typography } from '@mui/material';
import { Product } from '../models/Product';
interface ProductRowProps {
product: Product;
}
export const ProductRow = ({ product }: ProductRowProps) => (
<Card variant="outlined" sx={{ mb: 1 }}>
<CardContent>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<div>
<Typography variant="subtitle1">{product.name}</Typography>
<Typography variant="caption" color="text.secondary">
{product.category} • {product.unit_type}
</Typography>
</div>
{product.bulk_name && product.units_per_bulk ? (
<Typography variant="caption" color="text.secondary">
{product.units_per_bulk} per {product.bulk_name}
</Typography>
) : null}
</Stack>
</CardContent>
</Card>
);
+18
View File
@@ -0,0 +1,18 @@
import { Box, Paper } from '@mui/material';
import { PropsWithChildren } from 'react';
import { useSwipe } from '../hooks/useSwipe';
interface SwipeableRowProps extends PropsWithChildren {
onSwipeLeft?: () => void;
onSwipeRight?: () => void;
}
export const SwipeableRow = ({ children, onSwipeLeft, onSwipeRight }: SwipeableRowProps) => {
const gestureHandlers = useSwipe({ onSwipeLeft, onSwipeRight });
return (
<Paper sx={{ p: 1, mb: 1 }} {...gestureHandlers}>
<Box>{children}</Box>
</Paper>
);
};