|
- "use client";
- import React from "react";
- import { X, Save } from "@mui/icons-material";
- import {
- Dialog,
- DialogTitle,
- DialogContent,
- DialogActions,
- IconButton,
- Typography,
- Button,
- Box,
- Stack,
- } from "@mui/material";
- import { useForm, Controller } from "react-hook-form";
- import {
- QualityCheckModalProps,
- QualityCheckData,
- QualityCheckRecord,
- QualityCheckItem,
- } from "./types";
- import { getStatusIcon, getStatusColor } from "./utils/QualityCheckHelper";
- import DefectsSection from "./DefectsSection";
- import OperatorScanner from "./OperatorScanner";
-
- const QualityCheckModal: React.FC<QualityCheckModalProps> = ({
- isOpen,
- onClose,
- item = null,
- }) => {
- const {
- control,
- handleSubmit,
- reset,
- watch,
- setValue,
- setError,
- clearErrors,
- formState: { errors, isValid },
- } = useForm<QualityCheckData>({
- defaultValues: {
- inspectors: [],
- checkDate: new Date().toISOString().split("T")[0],
- status: "pending",
- notes: "",
- defects: [],
- },
- mode: "onChange",
- });
-
- const watchedDefects = watch("defects");
- const watchedInspectors = watch("inspectors");
-
- const validateForm = (): boolean => {
- let isValid = true;
-
- // Clear previous errors
- clearErrors();
-
- // Validate inspectors
- if (!watchedInspectors || watchedInspectors.length === 0) {
- setError("inspectors", {
- type: "required",
- message: "At least one inspector is required",
- });
- isValid = false;
- }
-
- return isValid;
- };
-
- const onSubmit = (data: QualityCheckData): void => {
- if (!validateForm()) {
- return;
- }
-
- console.log(data);
- const qualityRecord: QualityCheckRecord = {
- ...data,
- itemId: item?.id?.toString(),
- itemName: item?.name,
- timestamp: new Date().toISOString(),
- };
-
- // Save to localStorage or your preferred storage method
- // const existingRecords = JSON.parse(localStorage.getItem('qualityCheckRecords') || '[]');
- // const updatedRecords = [...existingRecords, qualityRecord];
- // localStorage.setItem('qualityCheckRecords', JSON.stringify(updatedRecords));
-
- // Close modal and reset form
- handleClose();
- };
-
- const handleClose = (): void => {
- reset({
- inspectors: [],
- checkDate: new Date().toISOString().split("T")[0],
- status: "pending",
- notes: "",
- defects: [],
- });
- onClose();
- };
-
- const statusOptions: Array<"pending" | "passed" | "failed"> = [
- "pending",
- "passed",
- "failed",
- ];
-
- if (!isOpen) return null;
-
- return (
- <Dialog open={isOpen} onClose={handleClose} maxWidth="md" fullWidth>
- <DialogTitle
- sx={{
- display: "flex",
- alignItems: "center",
- justifyContent: "space-between",
- }}
- >
- <Box>
- <Typography variant="h5" fontWeight={700}>
- Quality Check
- </Typography>
- {item && (
- <Typography variant="body2" color="text.secondary" mt={0.5}>
- Item: {item.name} (ID: {item.id})
- </Typography>
- )}
- </Box>
- <IconButton onClick={handleClose} size="large">
- <X />
- </IconButton>
- </DialogTitle>
- <DialogContent dividers sx={{ p: 3 }}>
- <Stack spacing={4}>
- {/* Inspector and Date */}
- <Stack direction={{ xs: "column", md: "row" }} spacing={2}>
- <Box sx={{ flex: 1 }}>
- <Typography variant="body2" fontWeight={600} mb={1}>
- Inspector *
- </Typography>
- <OperatorScanner
- operators={watchedInspectors || []}
- onOperatorsChange={(operators) => {
- setValue("inspectors", operators);
- if (operators.length > 0) {
- clearErrors("inspectors");
- }
- }}
- error={errors.inspectors?.message}
- />
- </Box>
- </Stack>
- <Stack direction={{ xs: "column", md: "row" }} spacing={2}>
- <Box sx={{ flex: 1 }}>
- <Typography variant="body2" fontWeight={600} mb={1}>
- Check Date *
- </Typography>
- <Controller
- name="checkDate"
- control={control}
- rules={{ required: "Check date is required" }}
- render={({ field }) => (
- <input
- {...field}
- type="date"
- style={{
- width: "100%",
- padding: "8px 12px",
- border: errors.checkDate
- ? "1px solid #f44336"
- : "1px solid #ccc",
- borderRadius: "4px",
- fontSize: "14px",
- outline: "none",
- }}
- />
- )}
- />
- {errors.checkDate && (
- <Typography variant="caption" color="error" sx={{ mt: 0.5 }}>
- {errors.checkDate.message}
- </Typography>
- )}
- </Box>
- </Stack>
-
- {/* Quality Status */}
- <Box>
- <Typography variant="body2" fontWeight={600} mb={2}>
- Quality Status *
- </Typography>
- <Controller
- name="status"
- control={control}
- rules={{ required: "Please select a quality status" }}
- render={({ field }) => (
- <Stack direction="row" spacing={2}>
- {statusOptions.map((statusOption) => {
- const IconComponent = getStatusIcon(statusOption);
- const isSelected = field.value === statusOption;
-
- return (
- <Button
- key={statusOption}
- variant={isSelected ? "contained" : "outlined"}
- onClick={() => field.onChange(statusOption)}
- startIcon={
- <IconComponent
- sx={{
- fontSize: 20,
- color:
- statusOption === "passed"
- ? "success.main"
- : statusOption === "failed"
- ? "error.main"
- : "warning.main",
- }}
- />
- }
- sx={{
- flex: 1,
- textTransform: "capitalize",
- py: 1.5,
- backgroundColor: isSelected
- ? statusOption === "passed"
- ? "success.main"
- : statusOption === "failed"
- ? "error.main"
- : "warning.main"
- : "transparent",
- borderColor:
- statusOption === "passed"
- ? "success.main"
- : statusOption === "failed"
- ? "error.main"
- : "warning.main",
- color: isSelected
- ? "white"
- : statusOption === "passed"
- ? "success.main"
- : statusOption === "failed"
- ? "error.main"
- : "warning.main",
- "&:hover": {
- backgroundColor: isSelected
- ? statusOption === "passed"
- ? "success.dark"
- : statusOption === "failed"
- ? "error.dark"
- : "warning.dark"
- : statusOption === "passed"
- ? "success.light"
- : statusOption === "failed"
- ? "error.light"
- : "warning.light",
- },
- }}
- >
- {statusOption}
- </Button>
- );
- })}
- </Stack>
- )}
- />
- {errors.status && (
- <Typography variant="caption" color="error" sx={{ mt: 0.5 }}>
- {errors.status.message}
- </Typography>
- )}
- </Box>
-
- {/* Defects Section */}
- <DefectsSection
- defects={watchedDefects || []}
- onDefectsChange={(defects) => {
- setValue("defects", defects);
- clearErrors("defects");
- }}
- error={errors.defects?.message}
- />
-
- {/* Additional Notes */}
- <Controller
- name="notes"
- control={control}
- render={({ field }) => (
- <Box>
- <Typography variant="body2" fontWeight={600} mb={1}>
- Additional Notes
- </Typography>
- <textarea
- {...field}
- rows={4}
- style={{
- width: "100%",
- padding: "12px",
- border: "1px solid #ccc",
- borderRadius: "4px",
- fontSize: "14px",
- fontFamily: "inherit",
- outline: "none",
- resize: "vertical",
- }}
- placeholder="Enter any additional observations or notes..."
- />
- </Box>
- )}
- />
- </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 />}
- disabled={!isValid}
- >
- Save Quality Check
- </Button>
- </DialogActions>
- </Dialog>
- );
- };
-
- export default QualityCheckModal;
|