@@ -65,6 +65,7 @@ const RideActions: React.FC<RideActionsProps> = ({
6565 const [ contactAdminOpen , setContactAdminOpen ] = useState ( false ) ;
6666 const [ updating , setUpdating ] = useState ( false ) ;
6767 const [ saving , setSaving ] = useState ( false ) ;
68+ const [ scopeDialogMode , setScopeDialogMode ] = useState < 'save' | 'cancel' | null > ( null ) ;
6869
6970 const ride = editedRide ! ; // We know this exists from the context
7071 const rideCompleted = ride . status === Status . COMPLETED ;
@@ -91,32 +92,26 @@ const RideActions: React.FC<RideActionsProps> = ({
9192 } ;
9293
9394 const handleCancel = ( ) => {
94- setCancelConfirmOpen ( true ) ;
95- } ;
96-
97- const handleCancelConfirm = async ( ) => {
98- // Check for recurring rides (not supported yet)
99- if ( ride . isRecurring ) {
100- showToast ( 'Recurring ride deletion not supported yet' , ToastStatus . ERROR ) ;
101- return ;
95+ // Recurring rides need scope selection before cancelling
96+ if ( ride . recurrenceId ) {
97+ setScopeDialogMode ( 'cancel' ) ;
98+ } else {
99+ setCancelConfirmOpen ( true ) ;
102100 }
101+ } ;
103102
103+ const handleCancelConfirm = async ( scope ?: 'single' | 'future' ) => {
104104 try {
105- // Call the DELETE endpoint like DeleteOrEditTypeModal does
106- await axios . delete ( `/api/rides/${ ride . id } ` ) ;
105+ const url = scope
106+ ? `/api/rides/${ ride . id } ?scope=${ scope } `
107+ : `/api/rides/${ ride . id } ` ;
108+ await axios . delete ( url ) ;
107109
108- // Close the cancel confirmation modal
109110 setCancelConfirmOpen ( false ) ;
111+ setScopeDialogMode ( null ) ;
110112
111- // Close the main ride details dialog since the ride no longer exists
112- if ( onClose ) {
113- onClose ( ) ;
114- }
115-
116- // Refresh the rides data
113+ if ( onClose ) onClose ( ) ;
117114 refreshRides ( ) ;
118-
119- // Show success message
120115 showToast ( 'Ride Cancelled' , ToastStatus . SUCCESS ) ;
121116 } catch ( error ) {
122117 console . error ( 'Failed to cancel ride:' , error ) ;
@@ -126,34 +121,35 @@ const RideActions: React.FC<RideActionsProps> = ({
126121
127122 const handleEdit = ( ) => {
128123 if ( isEditing ) {
129- // Save changes
130124 handleSave ( ) ;
131125 } else {
132- // Start editing
133126 startEditing ( ) ;
134127 }
135128 } ;
136129
137- const handleSave = async ( ) => {
130+ const handleSave = async ( scope ?: 'single' | 'future' ) => {
131+ // If ride is recurring and no scope decided yet, show scope dialog
132+ if ( ride . recurrenceId && scope === undefined ) {
133+ setScopeDialogMode ( 'save' ) ;
134+ return ;
135+ }
136+
138137 setSaving ( true ) ;
139138 try {
140- const success = await saveChanges ( ) ;
139+ const success = await saveChanges ( scope ) ;
141140 if ( success ) {
142141 const message = isNewRide ( ride )
143142 ? 'Ride created successfully'
144143 : 'Ride saved successfully' ;
145144 showToast ( message , ToastStatus . SUCCESS ) ;
146145
147- // Only refresh rides if the ride is on the current date being displayed in the context
148146 const rideDate = new Date ( ride . startTime ) . toDateString ( ) ;
149147 const contextDate = curDate . toDateString ( ) ;
150148 if ( rideDate === contextDate ) {
151149 refreshRides ( ) ;
152150 }
153151
154- if ( onClose ) {
155- onClose ( ) ; // Close modal after creating new ride
156- }
152+ if ( onClose ) onClose ( ) ;
157153 } else {
158154 const message = isNewRide ( ride )
159155 ? 'Failed to create ride'
@@ -168,6 +164,7 @@ const RideActions: React.FC<RideActionsProps> = ({
168164 showToast ( message , ToastStatus . ERROR ) ;
169165 } finally {
170166 setSaving ( false ) ;
167+ setScopeDialogMode ( null ) ;
171168 }
172169 } ;
173170
@@ -422,7 +419,7 @@ const RideActions: React.FC<RideActionsProps> = ({
422419 < DialogActions >
423420 < Button onClick = { ( ) => setCancelConfirmOpen ( false ) } > Keep Ride</ Button >
424421 < Button
425- onClick = { handleCancelConfirm }
422+ onClick = { ( ) => handleCancelConfirm ( ) }
426423 variant = "contained"
427424 color = "error"
428425 >
@@ -431,6 +428,49 @@ const RideActions: React.FC<RideActionsProps> = ({
431428 </ DialogActions >
432429 </ Dialog >
433430
431+ { /* Recurring Scope Dialog — shown when editing or cancelling a recurring ride */ }
432+ < Dialog
433+ open = { scopeDialogMode !== null }
434+ onClose = { ( ) => setScopeDialogMode ( null ) }
435+ maxWidth = "xs"
436+ fullWidth
437+ >
438+ < DialogTitle >
439+ { scopeDialogMode === 'save' ? 'Edit Recurring Ride' : 'Cancel Recurring Ride' }
440+ </ DialogTitle >
441+ < DialogContent >
442+ < Typography >
443+ { scopeDialogMode === 'save'
444+ ? 'Do you want to edit just this ride, or this and all future rides in the series?'
445+ : 'Do you want to cancel just this ride, or this and all future rides in the series?' }
446+ </ Typography >
447+ </ DialogContent >
448+ < DialogActions >
449+ < Button onClick = { ( ) => setScopeDialogMode ( null ) } > Back</ Button >
450+ < Button
451+ variant = "outlined"
452+ onClick = { ( ) =>
453+ scopeDialogMode === 'save'
454+ ? handleSave ( 'single' )
455+ : handleCancelConfirm ( 'single' )
456+ }
457+ >
458+ Just this ride
459+ </ Button >
460+ < Button
461+ variant = "contained"
462+ color = { scopeDialogMode === 'cancel' ? 'error' : 'primary' }
463+ onClick = { ( ) =>
464+ scopeDialogMode === 'save'
465+ ? handleSave ( 'future' )
466+ : handleCancelConfirm ( 'future' )
467+ }
468+ >
469+ This and all future rides
470+ </ Button >
471+ </ DialogActions >
472+ </ Dialog >
473+
434474 { /* Contact Admin Modal */ }
435475 < Dialog
436476 open = { contactAdminOpen }
0 commit comments