All files / src/pages/inventory/dialogs/ItemFormDialog ItemFormDialog.tsx

100% Statements 135/135
100% Branches 14/14
80% Functions 4/5
100% Lines 135/135

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 1361x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 2x 3x 5x 5x 5x 2x 3x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 2x 2x 2x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 1x 1x 1x 5x 5x 5x 5x 5x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 5x  
/**
 * ItemFormDialog - Main dialog container for item creation/editing
 * 
 * @module dialogs/ItemFormDialog/ItemFormDialog
 * @description
 * Manages dialog lifecycle (title, open/close, actions).
 * Delegates all form logic to useItemForm hook.
 * 
 * @enterprise
 * - Thin container following separation of concerns
 * - Dialog title changes: "Create Item" for new / "Edit Item" for existing
 * - Help button links to appropriate documentation section
 * - Cancel button dismisses without changes
 * - Save/Create button triggers submission with loading state
 */
 
import {
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
  Button,
  Box,
  CircularProgress,
  Tooltip,
  IconButton,
} from '@mui/material';
import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
import { useTranslation } from 'react-i18next';
import { useRef } from 'react';
import { ItemForm } from './ItemForm';
import { useItemForm } from './useItemForm';
import type { ItemFormDialogProps } from './ItemFormDialog.types';
 
/**
 * ItemFormDialog - Main dialog component
 * 
 * Opens when isOpen is true. Renders ItemForm and manages dialog actions.
 * All form state/queries/validation delegated to useItemForm hook.
 * 
 * @param isOpen - Whether dialog is visible
 * @param onClose - Called on cancel or successful save
 * @param initial - Initial item data (undefined for create mode)
 */
export function ItemFormDialog({
  isOpen,
  onClose,
  initial,
  onSaved,
}: ItemFormDialogProps) {
  const { t } = useTranslation(['common', 'inventory']);
  const dialogRef = useRef<HTMLDivElement>(null);
 
  // All form state and handlers delegated to hook
  const state = useItemForm({ isOpen, onClose, initial, onSaved });
 
  // Dialog title reflects create vs edit mode
  const dialogTitle = initial?.id
    ? t('inventory:dialogs.editItem', 'Edit Item')
    : t('inventory:dialogs.createItem', 'Create Item');
 
  // Button label also changes based on mode
  const submitLabel = initial?.id
    ? t('common:actions.save', 'Save')
    : t('common:actions.create', 'Create');
 
  return (
    <Dialog
      ref={dialogRef}
      open={isOpen}
      onClose={() => state.handleClose()}
      maxWidth="sm"
      fullWidth
    >
      {/* Title with help icon */}
      <DialogTitle
        sx={{
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
        }}
      >
        <span>{dialogTitle}</span>
        <Tooltip title={t('common:help', 'Help')}>
          <IconButton
            size="small"
            onClick={() => {
              const section = initial?.id ? 'edit_item' : 'create_item';
              window.open(`#/help?section=${section}`, '_blank');
            }}
            aria-label="help"
          >
            <HelpOutlineIcon fontSize="small" />
          </IconButton>
        </Tooltip>
      </DialogTitle>
 
      {/* Form content */}
      <DialogContent>
        <ItemForm state={state} initial={initial} />
      </DialogContent>
 
      {/* Dialog actions */}
      <DialogActions>
        <Button onClick={() => state.handleClose()} disabled={state.formState.isSubmitting}>
          {t('common:actions.cancel', 'Cancel')}
        </Button>
        <Box sx={{ position: 'relative', display: 'inline-block' }}>
          <Button
            variant="contained"
            onClick={(e) => {
              e.preventDefault();
              state.handleSubmit(state.onSubmit)(e);
            }}
            disabled={state.formState.isSubmitting}
          >
            {submitLabel}
          </Button>
          {state.formState.isSubmitting && (
            <CircularProgress
              size={24}
              sx={{
                position: 'absolute',
                top: '50%',
                left: '50%',
                marginTop: '-12px',
                marginLeft: '-12px',
              }}
            />
          )}
        </Box>
      </DialogActions>
    </Dialog>
  );
}