|
- "use client";
- import React from "react";
- import { X, Save } from "@mui/icons-material";
- import { useTranslation } from "react-i18next";
- import { useState } from "react";
- import {
- Dialog,
- DialogTitle,
- DialogContent,
- DialogActions,
- IconButton,
- Typography,
- TextField,
- Stack,
- Box,
- Button,
- } from "@mui/material";
- import { useForm, Controller } from "react-hook-form";
- import { Material, FormData, ProductionRecord, ProcessData } from "./types";
- import { Operator, Machine } from "@/app/api/jo";
- import OperatorScanner from "./OperatorScanner";
- import MachineScanner from "./MachineScanner";
- import MaterialLotScanner from "./MaterialLotScanner";
- import dayjs from 'dayjs';
- import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
-
- interface ProductionRecordingModalProps {
- isOpen: boolean;
- onClose: () => void;
- jobProcess: ProcessData;
- onDataRecorded?: (processId: string, data: any) => void;
- }
-
- const ProductionRecordingModal: React.FC<ProductionRecordingModalProps> = ({
- isOpen,
- onClose,
- jobProcess,
- }) => {
- const { t } = useTranslation("common");
- const {
- control,
- handleSubmit,
- reset,
- watch,
- setValue,
- setError,
- clearErrors,
- formState: { errors },
- } = useForm<FormData>({
- defaultValues: {
- productionDate: dayjs().format(INPUT_DATE_FORMAT),
- notes: "",
- operators: [],
- machines: [],
- materials: jobProcess.materials || [],
- },
- });
-
- const watchedOperators = watch("operators");
- const watchedMachines = watch("machines");
- const watchedMaterials = watch("materials");
- const [activeScannerType, setActiveScannerType] = useState<'operator' | 'machine' | 'material' | null>(null);
-
-
- const handleScannerActivate = (scannerType: 'operator' | 'machine' | 'material') => {
- setActiveScannerType(scannerType);
- };
-
- const handleScannerDeactivate = () => {
- setActiveScannerType(null);
- };
-
- const validateForm = (): boolean => {
- let isValid = true;
-
- // Clear previous errors
- clearErrors();
-
- // Validate operators
- if (!watchedOperators || watchedOperators.length === 0) {
- setError("operators", {
- type: "required",
- message: "At least one operator is required",
- });
- isValid = false;
- }
-
- // Validate machines
- if (!watchedMachines || watchedMachines.length === 0) {
- setError("machines", {
- type: "required",
- message: "At least one machine is required",
- });
- isValid = false;
- }
-
- // Validate materials
- console.log(watchedMaterials);
- if (watchedMaterials) {
- const missingLotNumbers = watchedMaterials.filter(
- (m) =>
- m.required &&
- m.isUsed &&
- (!m.lotNumbers || m.lotNumbers.length === 0),
- ).length;
-
- if (missingLotNumbers > 0) {
- setError("materials", {
- type: "custom",
- message: `${missingLotNumbers} required material(s) missing lot numbers`,
- });
- isValid = false;
- }
- }
-
- return isValid;
- };
-
- const onSubmit = (data: FormData) => {
- if (!validateForm()) {
- return;
- }
-
- const usedMaterials = data.materials
- .filter((material) => material.isUsed)
- .map((material) => ({
- id: material.id,
- name: material.name,
- lotNumbers: material.lotNumbers,
- required: material.required,
- isUsed: false,
- }));
-
- const recordData: ProductionRecord = {
- ...data,
- materials: usedMaterials,
- timestamp: new Date().toISOString(),
- };
-
- console.log("Production record saved:", recordData);
- handleClose();
- };
-
- const handleClose = (): void => {
- reset({
- productionDate: dayjs().format(INPUT_DATE_FORMAT),
- notes: "",
- operators: [],
- machines: [],
- materials: jobProcess.materials.map((material) => ({
- ...material,
- isUsed: false,
- lotNumbers: [],
- })),
- });
- onClose();
- };
-
- const getUsedMaterialsCount = (): number =>
- watchedMaterials?.filter((m) => m.isUsed).length || 0;
-
- if (!isOpen) return null;
-
- return (
- <Dialog open={isOpen} onClose={handleClose} maxWidth="xl" fullWidth>
- <DialogTitle
- sx={{
- display: "flex",
- alignItems: "center",
- justifyContent: "space-between",
- }}
- >
- <Box>
- <Typography variant="h5" fontWeight={700}>
- Production Recording
- </Typography>
- <Typography variant="body2" color="text.secondary" mt={0.5}>
- {watchedOperators?.length || 0} operator(s),{" "}
- {watchedMachines?.length || 0} machine(s), {getUsedMaterialsCount()}{" "}
- materials
- </Typography>
- </Box>
- <IconButton onClick={handleClose} size="large">
- <X />
- </IconButton>
- </DialogTitle>
- <DialogContent dividers sx={{ p: 3 }}>
- <Stack spacing={4}>
- {/* Basic Information */}
- <Stack direction={{ xs: "column", md: "row" }} spacing={2}>
- <Controller
- name="productionDate"
- control={control}
- rules={{
- required: "Production date is required",
- }}
- render={({ field }) => (
- <TextField
- {...field}
- type="date"
- label="Production Date"
- InputLabelProps={{ shrink: true }}
- fullWidth
- size="small"
- error={!!errors.productionDate}
- helperText={errors.productionDate?.message}
- />
- )}
- />
- </Stack>
-
- {/* Operator Scanner */}
- <OperatorScanner
- operators={watchedOperators || []}
- onOperatorsChange={(operators) => {
- setValue("operators", operators);
- if (operators.length > 0) {
- clearErrors("operators");
- }
- }}
- error={errors.operators?.message}
- isActive={activeScannerType === 'operator'}
- onActivate={() => handleScannerActivate('operator')}
- onDeactivate={handleScannerDeactivate}
- />
-
- {/* Machine Scanner */}
- <MachineScanner
- machines={watchedMachines || []}
- onMachinesChange={(machines) => {
- setValue("machines", machines);
- if (machines.length > 0) {
- clearErrors("machines");
- }
- }}
- error={errors.machines?.message}
- isActive={activeScannerType === 'machine'}
- onActivate={() => handleScannerActivate('machine')}
- onDeactivate={handleScannerDeactivate}
- />
-
- {/* Material Lot Scanner */}
- <MaterialLotScanner
- materials={watchedMaterials || []}
- onMaterialsChange={(materials) => {
- setValue("materials", materials);
- clearErrors("materials");
- }}
- error={errors.materials?.message}
- />
-
- {/* Additional Notes */}
- <Controller
- name="notes"
- control={control}
- render={({ field }) => (
- <TextField
- {...field}
- label="Additional Notes"
- multiline
- minRows={3}
- fullWidth
- size="small"
- placeholder={t("Enter any additional production notes...")}
- error={!!errors.notes}
- helperText={errors.notes?.message}
- />
- )}
- />
- </Stack>
- </DialogContent>
- <DialogActions sx={{ p: 3 }}>
- <Button variant="outlined" color="inherit" onClick={handleClose}>
- Cancel
- </Button>
- <Button
- variant="contained"
- color="primary"
- onClick={handleSubmit(onSubmit)}
- startIcon={<Save />}
- >
- Save Record
- </Button>
- </DialogActions>
- </Dialog>
- );
- };
-
- export default ProductionRecordingModal;
|