|
- "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;
|