feat: add blocking mode to VehicleSelectionDialog (refs #60)

- Add blocking prop to prevent dismissal
- Disable backdrop click and escape key when blocking
- Hide Cancel button in blocking mode
- Update messaging for auto-downgrade scenario

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Eric Gullickson
2026-01-24 11:28:02 -06:00
parent baf576f5cb
commit de7aa8c13c

View File

@@ -29,6 +29,8 @@ interface VehicleSelectionDialogProps {
vehicles: Vehicle[]; vehicles: Vehicle[];
maxSelections: number; maxSelections: number;
targetTier: SubscriptionTier; targetTier: SubscriptionTier;
/** When true, dialog cannot be dismissed - user must make a selection */
blocking?: boolean;
} }
export const VehicleSelectionDialog = ({ export const VehicleSelectionDialog = ({
@@ -38,6 +40,7 @@ export const VehicleSelectionDialog = ({
vehicles, vehicles,
maxSelections, maxSelections,
targetTier, targetTier,
blocking = false,
}: VehicleSelectionDialogProps) => { }: VehicleSelectionDialogProps) => {
const [selectedVehicleIds, setSelectedVehicleIds] = useState<string[]>([]); const [selectedVehicleIds, setSelectedVehicleIds] = useState<string[]>([]);
@@ -77,14 +80,42 @@ export const VehicleSelectionDialog = ({
const canConfirm = selectedVehicleIds.length > 0 && selectedVehicleIds.length <= maxSelections; const canConfirm = selectedVehicleIds.length > 0 && selectedVehicleIds.length <= maxSelections;
// Handle dialog close - prevent if blocking
const handleClose = (_event: object, reason: string) => {
if (blocking && (reason === 'backdropClick' || reason === 'escapeKeyDown')) {
return;
}
onClose();
};
return ( return (
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth> <Dialog
<DialogTitle>Select Vehicles to Keep</DialogTitle> open={open}
onClose={handleClose}
maxWidth="sm"
fullWidth
disableEscapeKeyDown={blocking}
>
<DialogTitle>
{blocking ? 'Vehicle Selection Required' : 'Select Vehicles to Keep'}
</DialogTitle>
<DialogContent> <DialogContent>
<Alert severity="warning" sx={{ mb: 2 }}> <Alert severity={blocking ? 'info' : 'warning'} sx={{ mb: 2 }}>
You are downgrading to the {targetTier} tier, which allows {maxSelections} vehicle {blocking ? (
{maxSelections > 1 ? 's' : ''}. Select which vehicles you want to keep active. Unselected <>
vehicles will be hidden but not deleted, and you can unlock them by upgrading later. Your subscription has been downgraded to the {targetTier} tier, which allows{' '}
{maxSelections} vehicle{maxSelections > 1 ? 's' : ''}. Please select which vehicles
you want to keep active to continue using the app. Unselected vehicles will be hidden
but not deleted, and you can unlock them by upgrading later.
</>
) : (
<>
You are downgrading to the {targetTier} tier, which allows {maxSelections} vehicle
{maxSelections > 1 ? 's' : ''}. Select which vehicles you want to keep active.
Unselected vehicles will be hidden but not deleted, and you can unlock them by
upgrading later.
</>
)}
</Alert> </Alert>
<Box sx={{ mb: 2 }}> <Box sx={{ mb: 2 }}>
@@ -125,9 +156,9 @@ export const VehicleSelectionDialog = ({
)} )}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}>Cancel</Button> {!blocking && <Button onClick={onClose}>Cancel</Button>}
<Button onClick={handleConfirm} variant="contained" disabled={!canConfirm}> <Button onClick={handleConfirm} variant="contained" disabled={!canConfirm}>
Confirm Downgrade {blocking ? 'Confirm Selection' : 'Confirm Downgrade'}
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>