- Created DeleteDocumentConfirmDialog with context-aware messaging: - Primary vehicle with no shares: Full delete - Shared vehicle: Remove association only - Primary vehicle with shares: Full delete (affects all) - Integrated documents display in VehicleDetailPage records table - Added delete button per document with 44px touch target - Document deletion uses appropriate backend calls based on context - Mobile-friendly dialog with responsive design Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
138 lines
4.2 KiB
TypeScript
138 lines
4.2 KiB
TypeScript
/**
|
|
* @ai-summary Context-aware document delete confirmation dialog
|
|
* Shows different messages based on whether document is being removed from vehicle or fully deleted
|
|
*/
|
|
|
|
import React from 'react';
|
|
import {
|
|
Dialog,
|
|
DialogTitle,
|
|
DialogContent,
|
|
DialogActions,
|
|
Button,
|
|
Typography,
|
|
Box,
|
|
useMediaQuery,
|
|
useTheme,
|
|
} from '@mui/material';
|
|
import WarningAmberIcon from '@mui/icons-material/WarningAmber';
|
|
import type { DocumentRecord } from '../types/documents.types';
|
|
|
|
export interface DeleteDocumentConfirmDialogProps {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
onConfirm: (fullDelete: boolean) => void;
|
|
document: DocumentRecord | null;
|
|
vehicleId: string | null;
|
|
}
|
|
|
|
export const DeleteDocumentConfirmDialog: React.FC<DeleteDocumentConfirmDialogProps> = ({
|
|
open,
|
|
onClose,
|
|
onConfirm,
|
|
document,
|
|
vehicleId,
|
|
}) => {
|
|
const theme = useTheme();
|
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
|
|
|
if (!document || !vehicleId) {
|
|
return null;
|
|
}
|
|
|
|
// Determine delete context
|
|
const isPrimaryVehicle = document.vehicleId === vehicleId;
|
|
const isSharedVehicle = document.sharedVehicleIds.includes(vehicleId);
|
|
const sharedCount = document.sharedVehicleIds.length;
|
|
|
|
let title: string;
|
|
let message: string;
|
|
let fullDelete: boolean;
|
|
let actionText: string;
|
|
|
|
if (isPrimaryVehicle && sharedCount === 0) {
|
|
// Primary vehicle with no shares: Full delete
|
|
title = 'Delete Document?';
|
|
message = 'This will permanently delete this document. This action cannot be undone.';
|
|
fullDelete = true;
|
|
actionText = 'Delete';
|
|
} else if (isSharedVehicle) {
|
|
// Shared vehicle: Remove association only
|
|
title = 'Remove Document from Vehicle?';
|
|
message = `This will remove the document from this vehicle. The document will remain shared with ${sharedCount - 1 === 1 ? '1 other vehicle' : `${sharedCount - 1} other vehicles`}.`;
|
|
fullDelete = false;
|
|
actionText = 'Remove';
|
|
} else if (isPrimaryVehicle && sharedCount > 0) {
|
|
// Primary vehicle with shares: Full delete (affects all)
|
|
title = 'Delete Document?';
|
|
message = `This document is shared with ${sharedCount === 1 ? '1 other vehicle' : `${sharedCount} other vehicles`}. Deleting it will remove it from all vehicles. This action cannot be undone.`;
|
|
fullDelete = true;
|
|
actionText = 'Delete';
|
|
} else {
|
|
// Fallback case (should not happen)
|
|
title = 'Delete Document?';
|
|
message = 'This will delete this document. This action cannot be undone.';
|
|
fullDelete = true;
|
|
actionText = 'Delete';
|
|
}
|
|
|
|
const handleConfirm = () => {
|
|
onConfirm(fullDelete);
|
|
};
|
|
|
|
return (
|
|
<Dialog
|
|
open={open}
|
|
onClose={onClose}
|
|
maxWidth="sm"
|
|
fullWidth
|
|
fullScreen={isSmallScreen}
|
|
PaperProps={{
|
|
sx: {
|
|
borderRadius: isSmallScreen ? 0 : 2,
|
|
},
|
|
}}
|
|
>
|
|
<DialogTitle sx={{ pb: 1 }}>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
<WarningAmberIcon color="warning" />
|
|
<Typography variant="h6" component="span" sx={{ fontWeight: 600 }}>
|
|
{title}
|
|
</Typography>
|
|
</Box>
|
|
</DialogTitle>
|
|
<DialogContent>
|
|
<Typography variant="body1" sx={{ color: 'text.secondary', mt: 1 }}>
|
|
{message}
|
|
</Typography>
|
|
<Box sx={{ mt: 2, p: 2, bgcolor: 'grey.100', borderRadius: 1 }}>
|
|
<Typography variant="body2" sx={{ fontWeight: 600, mb: 0.5 }}>
|
|
{document.title}
|
|
</Typography>
|
|
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
{document.documentType.charAt(0).toUpperCase() + document.documentType.slice(1)}
|
|
{document.expirationDate && ` • Expires: ${new Date(document.expirationDate).toLocaleDateString()}`}
|
|
</Typography>
|
|
</Box>
|
|
</DialogContent>
|
|
<DialogActions sx={{ px: 3, pb: 2 }}>
|
|
<Button
|
|
onClick={onClose}
|
|
variant="outlined"
|
|
sx={{ minWidth: 100, minHeight: 44 }}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
onClick={handleConfirm}
|
|
variant="contained"
|
|
color={fullDelete ? 'error' : 'primary'}
|
|
sx={{ minWidth: 100, minHeight: 44 }}
|
|
>
|
|
{actionText}
|
|
</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
);
|
|
};
|