|
- "use client";
- import React, { useState, useRef, useEffect } from "react";
- import { Material, MaterialDatabase } from "./types";
- import {
- Box,
- Typography,
- TextField,
- Paper,
- Stack,
- Button,
- IconButton,
- Chip,
- } from "@mui/material";
- import CheckIcon from "@mui/icons-material/Check";
- import CloseIcon from "@mui/icons-material/Close";
-
- interface MaterialLotScannerProps {
- materials: Material[];
- onMaterialsChange: (materials: Material[]) => void;
- error?: string;
- }
-
- const MaterialLotScanner: React.FC<MaterialLotScannerProps> = ({
- materials,
- onMaterialsChange,
- error,
- }) => {
- const [materialScanInput, setMaterialScanInput] = useState<string>("");
- const materialScanRef = useRef<HTMLInputElement>(null);
-
- useEffect(() => {
- if (materialScanRef.current) {
- materialScanRef.current.focus();
- }
- }, []);
-
- const handleMaterialInputChange = (
- e: React.ChangeEvent<HTMLInputElement>,
- ) => {
- setMaterialScanInput(e.target.value.trim());
- };
-
- const handleMaterialInputKeyPress = async (
- e: React.KeyboardEvent<HTMLInputElement>,
- ) => {
- if (e.key === "Enter") {
- const target = e.target as HTMLInputElement;
- const scannedLot = target.value.trim();
- if (scannedLot) {
- const response = await fetch(
- "http://your-backend-url.com/validateLot",
- {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ lot: scannedLot }),
- },
- );
- const data = await response.json();
- if (data.suggestedLot) {
- const updatedMaterials = materials.map((material) => {
- if (material.name === data.matchedMaterial.name) {
- const isAlreadyAdded = material.lotNumbers.includes(scannedLot);
- if (!isAlreadyAdded) {
- return {
- ...material,
- isUsed: true,
- lotNumbers: [...material.lotNumbers, scannedLot],
- };
- }
- }
- return material;
- });
- onMaterialsChange(updatedMaterials);
- setMaterialScanInput("");
- } else if (data.matchedMaterial) {
- setMaterialScanInput(
- scannedLot +
- " (Invalid lot number format. Suggested lot number: " +
- data.suggestedLot +
- ")",
- );
- } else {
- setMaterialScanInput(
- scannedLot +
- " (Invalid lot number format or material not recognized.)",
- );
- }
- }
- }
- };
-
- const removeLotNumber = (materialName: string, lotNumber: string): void => {
- const updatedMaterials = materials.map((material) => {
- if (material.name === materialName) {
- const updatedLotNumbers = material.lotNumbers.filter(
- (lot) => lot !== lotNumber,
- );
- return {
- ...material,
- lotNumbers: updatedLotNumbers,
- isUsed: updatedLotNumbers.length > 0,
- };
- }
- return material;
- });
- onMaterialsChange(updatedMaterials);
- };
-
- const requiredMaterials = materials.filter((m) => m.required);
- const optionalMaterials = materials.filter((m) => !m.required);
-
- return (
- <Box>
- <Typography variant="h6" fontWeight={600} mb={2}>
- Material Lot Numbers
- </Typography>
- <Paper
- elevation={2}
- sx={{
- mb: 2,
- p: 2,
- bgcolor: "yellow.50",
- border: "1px solid",
- borderColor: "yellow.200",
- }}
- >
- <TextField
- inputRef={materialScanRef}
- type="text"
- value={materialScanInput}
- onChange={handleMaterialInputChange}
- onKeyPress={handleMaterialInputKeyPress}
- fullWidth
- label="Scan or enter material lot number (e.g., SS-240616-001)"
- variant="outlined"
- size="small"
- sx={{ bgcolor: "white" }}
- />
- <Box mt={2}>
- <Typography variant="body2" color="warning.main">
- <strong>Lot Number Formats:</strong>
- </Typography>
- <Typography variant="body2" color="warning.main">
- Steel Sheet: SS-YYMMDD-XXX | Aluminum: AL-YYMMDD-XXX | Plastic:
- PP-YYMMDD-XXX
- </Typography>
- <Typography variant="body2" color="warning.main">
- Copper Wire: CW-YYMMDD-XXX | Rubber: RG-YYMMDD-XXX | Glass:
- GP-YYMMDD-XXX
- </Typography>
- </Box>
- </Paper>
- {error && (
- <Typography color="error" variant="body2" mb={2}>
- {error}
- </Typography>
- )}
- <Stack spacing={3}>
- {/* Required Materials */}
- <Box>
- <Stack direction="row" alignItems="center" spacing={1} mb={1}>
- <Typography variant="subtitle1" fontWeight={600} color="error.main">
- Required Materials
- </Typography>
- <Chip label="Must scan lot numbers" color="error" size="small" />
- </Stack>
- <Stack spacing={1}>
- {requiredMaterials.map((material) => (
- <Paper
- key={material.id}
- sx={{
- p: 2,
- bgcolor: "red.50",
- border: "1px solid",
- borderColor: "red.200",
- }}
- >
- <Stack
- direction="row"
- alignItems="center"
- justifyContent="space-between"
- mb={1}
- >
- <Stack direction="row" alignItems="center" spacing={1}>
- {material.isUsed && (
- <CheckIcon fontSize="small" color="success" />
- )}
- <Typography fontWeight={500}>{material.name}</Typography>
- </Stack>
- <Typography variant="body2" color="text.secondary">
- {material.lotNumbers.length} lot(s)
- </Typography>
- </Stack>
- {material.lotNumbers.length > 0 && (
- <Stack spacing={1}>
- {material.lotNumbers.map((lotNumber, index) => (
- <Paper
- key={index}
- sx={{
- p: 1,
- display: "flex",
- alignItems: "center",
- justifyContent: "space-between",
- bgcolor: "white",
- border: "1px solid",
- borderColor: "grey.200",
- }}
- >
- <Typography variant="body2" fontFamily="monospace">
- {lotNumber}
- </Typography>
- <IconButton
- onClick={() =>
- removeLotNumber(material.name, lotNumber)
- }
- color="error"
- size="small"
- >
- <CloseIcon fontSize="small" />
- </IconButton>
- </Paper>
- ))}
- </Stack>
- )}
- </Paper>
- ))}
- </Stack>
- </Box>
- {/* Optional Materials */}
- <Box>
- <Stack direction="row" alignItems="center" spacing={1} mb={1}>
- <Typography
- variant="subtitle1"
- fontWeight={600}
- color="primary.main"
- >
- Optional Materials
- </Typography>
- <Chip
- label="Lot numbers recommended"
- color="primary"
- size="small"
- />
- </Stack>
- <Stack spacing={1}>
- {optionalMaterials.map((material) => (
- <Paper
- key={material.id}
- sx={{
- p: 2,
- bgcolor: "blue.50",
- border: "1px solid",
- borderColor: "blue.200",
- }}
- >
- <Stack
- direction="row"
- alignItems="center"
- justifyContent="space-between"
- mb={1}
- >
- <Stack direction="row" alignItems="center" spacing={1}>
- {material.isUsed && (
- <CheckIcon fontSize="small" color="success" />
- )}
- <Typography fontWeight={500}>{material.name}</Typography>
- </Stack>
- <Typography variant="body2" color="text.secondary">
- {material.lotNumbers.length} lot(s)
- </Typography>
- </Stack>
- {material.lotNumbers.length > 0 && (
- <Stack spacing={1}>
- {material.lotNumbers.map((lotNumber, index) => (
- <Paper
- key={index}
- sx={{
- p: 1,
- display: "flex",
- alignItems: "center",
- justifyContent: "space-between",
- bgcolor: "white",
- border: "1px solid",
- borderColor: "grey.200",
- }}
- >
- <Typography variant="body2" fontFamily="monospace">
- {lotNumber}
- </Typography>
- <IconButton
- onClick={() =>
- removeLotNumber(material.name, lotNumber)
- }
- color="error"
- size="small"
- >
- <CloseIcon fontSize="small" />
- </IconButton>
- </Paper>
- ))}
- </Stack>
- )}
- </Paper>
- ))}
- </Stack>
- </Box>
- </Stack>
- </Box>
- );
- };
-
- export default MaterialLotScanner;
|