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 }}>
{blocking ? (
<>
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 You are downgrading to the {targetTier} tier, which allows {maxSelections} vehicle
{maxSelections > 1 ? 's' : ''}. Select which vehicles you want to keep active. Unselected {maxSelections > 1 ? 's' : ''}. Select which vehicles you want to keep active.
vehicles will be hidden but not deleted, and you can unlock them by upgrading later. 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>