mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 08:51:13 -05:00
Fix error propagation in forms
This commit is contained in:
@@ -122,6 +122,9 @@ export function EntityForm({ onSubmit, onCancel, initialData }: EntityFormProps)
|
||||
action: initialData?.id ? 'Update Entity' : 'Create Entity',
|
||||
metadata: { entityName: data.name }
|
||||
});
|
||||
|
||||
// ⚠️ CRITICAL: Re-throw so parent can handle modal state
|
||||
throw error;
|
||||
}
|
||||
})}>
|
||||
{/* Form fields */}
|
||||
@@ -177,33 +180,64 @@ export function EntityListPage() {
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Form-Level Errors
|
||||
Forms use `handleError` utility for errors:
|
||||
### ⚠️ CRITICAL: Error Propagation Pattern
|
||||
|
||||
Forms MUST re-throw errors after logging them so parent components can respond appropriately (keep modals open, show additional context, etc.).
|
||||
|
||||
**Forms MUST re-throw errors:**
|
||||
```typescript
|
||||
try {
|
||||
await onSubmit(data);
|
||||
} catch (error: unknown) {
|
||||
// Log error for debugging and show toast to user
|
||||
handleError(error, {
|
||||
action: 'Create Park',
|
||||
action: 'Submit Park',
|
||||
userId: user?.id,
|
||||
metadata: { parkName: data.name }
|
||||
});
|
||||
|
||||
// ⚠️ CRITICAL: Re-throw so parent can handle modal state
|
||||
throw error;
|
||||
}
|
||||
```
|
||||
|
||||
### Parent-Level Errors
|
||||
Parent pages can catch errors for additional handling:
|
||||
**Why Re-throw?**
|
||||
- Parent needs to know submission failed
|
||||
- Modal should stay open so user can retry
|
||||
- User can fix validation issues and resubmit
|
||||
- Prevents "success" behavior on failures
|
||||
- Maintains proper error flow through the app
|
||||
|
||||
### Parent-Level Error Handling
|
||||
|
||||
```typescript
|
||||
try {
|
||||
await submitEntityCreation(data, user.id);
|
||||
toast({ title: "Success" });
|
||||
setIsModalOpen(false);
|
||||
} catch (error) {
|
||||
// Form already showed error toast
|
||||
// Parent can log or handle specific cases
|
||||
if (error.code === 'DUPLICATE_SLUG') {
|
||||
// Handle specific error
|
||||
const handleParkSubmit = async (data: FormData) => {
|
||||
try {
|
||||
await submitParkCreation(data, user.id);
|
||||
toast.success('Park submitted for review');
|
||||
setIsModalOpen(false); // Only close on success
|
||||
} catch (error) {
|
||||
// Error already toasted by form via handleError()
|
||||
// Modal stays open automatically because we don't close it
|
||||
// User can fix issues and retry
|
||||
console.error('Submission failed:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Expected Error Flow:**
|
||||
1. User submits form → `onSubmit()` called
|
||||
2. Submission fails → Form catches error
|
||||
3. Form shows error toast via `handleError()`
|
||||
4. Form re-throws error to parent
|
||||
5. Parent's catch block executes
|
||||
6. Modal stays open (no `setIsModalOpen(false)`)
|
||||
7. User fixes issue and tries again
|
||||
|
||||
**Common Mistake:**
|
||||
```typescript
|
||||
// ❌ WRONG - Error not re-thrown, parent never knows
|
||||
} catch (error: unknown) {
|
||||
handleError(error, { action: 'Submit' });
|
||||
// Missing: throw error;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -94,6 +94,9 @@ export function DesignerForm({ onSubmit, onCancel, initialData }: DesignerFormPr
|
||||
action: initialData?.id ? 'Update Designer' : 'Create Designer',
|
||||
metadata: { companyName: data.name }
|
||||
});
|
||||
|
||||
// Re-throw so parent can handle modal closing
|
||||
throw error;
|
||||
}
|
||||
})} className="space-y-6">
|
||||
{/* Basic Information */}
|
||||
|
||||
@@ -98,6 +98,9 @@ export function ManufacturerForm({ onSubmit, onCancel, initialData }: Manufactur
|
||||
action: initialData?.id ? 'Update Manufacturer' : 'Create Manufacturer',
|
||||
metadata: { companyName: data.name }
|
||||
});
|
||||
|
||||
// Re-throw so parent can handle modal closing
|
||||
throw error;
|
||||
}
|
||||
})} className="space-y-6">
|
||||
{/* Basic Information */}
|
||||
|
||||
@@ -94,6 +94,9 @@ export function OperatorForm({ onSubmit, onCancel, initialData }: OperatorFormPr
|
||||
action: initialData?.id ? 'Update Operator' : 'Create Operator',
|
||||
metadata: { companyName: data.name }
|
||||
});
|
||||
|
||||
// Re-throw so parent can handle modal closing
|
||||
throw error;
|
||||
}
|
||||
})} className="space-y-6">
|
||||
{/* Basic Information */}
|
||||
|
||||
@@ -274,6 +274,9 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
||||
hasNewOwner: !!tempNewPropertyOwner
|
||||
}
|
||||
});
|
||||
|
||||
// Re-throw so parent can handle modal closing
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -94,6 +94,9 @@ export function PropertyOwnerForm({ onSubmit, onCancel, initialData }: PropertyO
|
||||
action: initialData?.id ? 'Update Property Owner' : 'Create Property Owner',
|
||||
metadata: { companyName: data.name }
|
||||
});
|
||||
|
||||
// Re-throw so parent can handle modal closing
|
||||
throw error;
|
||||
}
|
||||
})} className="space-y-6">
|
||||
{/* Basic Information */}
|
||||
|
||||
@@ -352,6 +352,9 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
||||
hasNewModel: !!tempNewRideModel
|
||||
}
|
||||
});
|
||||
|
||||
// Re-throw so parent can handle modal closing
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -113,6 +113,9 @@ export function RideModelForm({
|
||||
handleError(error, {
|
||||
action: initialData?.id ? 'Update Ride Model' : 'Create Ride Model'
|
||||
});
|
||||
|
||||
// Re-throw so parent can handle modal closing
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user