# Epic 5.S3 Implementation: Error States **Story**: E5.S3 - Error states **Date**: 2025-12-27 **Status**: βœ… Complete **Story Points**: 2 SP --- ## 🎯 Objective Add user-friendly error states to agenda functionality with fallback links to `/epd/agenda` and proper error messaging in Dutch. --- ## πŸ“ Implementation Summary ### New Component Created **`components/swift/artifacts/blocks/agenda-error-state.tsx`** Created two reusable error components for consistent error handling across all agenda views: 1. **AgendaErrorState** - Full-page error state with retry button 2. **AgendaErrorAlert** - Inline error alert for forms ### Updated Components **`components/swift/artifacts/blocks/agenda-create-form.tsx`** - Replaced basic error display with `AgendaErrorAlert` - Added fallback link to full agenda - Added dismiss functionality --- ## πŸ”‘ Key Features ### 1. User-Friendly Error Messages The `getUserFriendlyMessage()` function maps technical errors to Dutch user-facing messages: | Error Type | Technical | User Message | |------------|-----------|--------------| | **Auth (401)** | "401 Unauthorized" | "Je sessie is verlopen. Log opnieuw in." | | **Not Found (404)** | "404 Not Found" | "De gevraagde afspraak kon niet worden gevonden." | | **Forbidden (403)** | "403 Forbidden" | "Je hebt geen toegang tot deze afspraak." | | **Server (500)** | "500 Internal Server Error" | "Er ging iets mis op de server. Probeer het opnieuw." | | **Network** | "Failed to fetch" | "Geen internetverbinding. Controleer je netwerkverbinding." | | **Timeout** | "Request timeout" | "De aanvraag duurde te lang. Probeer het opnieuw." | ### 2. Context-Aware Messages Different default messages based on operation context: ```typescript context: 'query' β†’ "Er ging iets mis bij het ophalen van je afspraken." context: 'create' β†’ "Er ging iets mis bij het aanmaken van de afspraak." context: 'cancel' β†’ "Er ging iets mis bij het annuleren van de afspraak." context: 'reschedule' β†’ "Er ging iets mis bij het verzetten van de afspraak." ``` ### 3. Fallback Link to Full Agenda All error states include a prominent link to `/epd/agenda`: ```tsx ``` ### 4. Automatic Auth Redirect Auth errors (401) automatically redirect to `/login`: ```typescript if (isAuthError) { window.location.href = '/login'; return null; } ``` ### 5. Retry Functionality Optional retry button for recoverable errors: ```tsx fetchAppointments()} showFallbackLink={true} context="query" /> ``` ### 6. Dev-Only Technical Details In development mode, shows collapsible technical details: ```tsx {process.env.NODE_ENV === 'development' && (
Technische details (dev only)
{error.stack}
)} ``` --- ## πŸ“ Component API ### AgendaErrorState (Full-Page Error) ```typescript interface AgendaErrorStateProps { error: string | Error; // Error to display onRetry?: () => void; // Optional retry function showFallbackLink?: boolean; // Show link to /epd/agenda (default: true) context?: 'query' | 'create' | 'cancel' | 'reschedule'; } ``` **Usage Example**: ```tsx refetch()} context="query" /> ``` ### AgendaErrorAlert (Inline Alert) ```typescript interface AgendaErrorAlertProps { error: string | Error; // Error to display onDismiss?: () => void; // Optional dismiss function showFallbackLink?: boolean; // Show link to /epd/agenda (default: false) } ``` **Usage Example**: ```tsx {error && ( setError(null)} showFallbackLink={true} /> )} ``` --- ## βœ… Acceptance Criteria | Criterion | Status | Implementation | |-----------|--------|----------------| | User-friendly error messages | βœ… | `getUserFriendlyMessage()` function | | Dutch language errors | βœ… | All messages in Dutch | | Fallback link to /epd/agenda | βœ… | "Open volledige agenda" button | | Auth error redirect | βœ… | Automatic redirect to /login | | Retry functionality | βœ… | Optional `onRetry` prop | | Context-aware messages | βœ… | Different messages per operation type | | Network error handling | βœ… | "Geen internetverbinding" message | | Server error handling | βœ… | "Er ging iets mis op de server" message | | TypeScript type safety | βœ… | Full type definitions | | Consistent styling | βœ… | Matches existing UI patterns | --- ## 🎨 UI Design ### Full-Page Error State ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ πŸ”΄ (AlertCircle Icon) β”‚ β”‚ β”‚ β”‚ Er ging iets mis β”‚ β”‚ β”‚ β”‚ Er ging iets mis bij het β”‚ β”‚ ophalen van je afspraken. β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ πŸ”„ Probeer β”‚ β”‚ πŸ”— Open β”‚ β”‚ β”‚ β”‚ opnieuw β”‚ β”‚ volledige β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ agenda β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Inline Error Alert ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ⚠️ Er ging iets mis bij het β”‚ β”‚ aanmaken van de afspraak. β”‚ β”‚ Open volledige agenda β†’ [Γ—] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ§ͺ Testing Scenarios ### Scenario 1: Network Error **Trigger**: Disconnect internet, try to create appointment **Expected**: - Message: "Geen internetverbinding. Controleer je netwerkverbinding." - Retry button enabled - Fallback link visible ### Scenario 2: Auth Error (401) **Trigger**: Expired session token **Expected**: - Automatic redirect to `/login` - No error component shown ### Scenario 3: Server Error (500) **Trigger**: Backend returns 500 **Expected**: - Message: "Er ging iets mis op de server. Probeer het opnieuw." - Retry button enabled - Fallback link visible ### Scenario 4: Not Found (404) **Trigger**: Try to cancel non-existent appointment **Expected**: - Message: "De gevraagde afspraak kon niet worden gevonden." - Fallback link visible ### Scenario 5: Validation Error **Trigger**: Submit form with invalid data **Expected**: - Inline alert with specific validation message - Fallback link visible - Dismiss button works ### Scenario 6: Retry Success **Trigger**: Network error β†’ reconnect β†’ click retry **Expected**: - Retry function called - Error cleared on success - Content loads normally --- ## πŸ’‘ Design Decisions ### Why Two Components? 1. **AgendaErrorState**: For full-page failures (query, list loading) 2. **AgendaErrorAlert**: For form-level errors (create, cancel, reschedule) Different UI patterns for different contexts. ### Why Auto-Redirect for Auth Errors? Auth errors (401) are not user-recoverable in the UI. User must log in again, so immediate redirect provides better UX than showing an error message. ### Why Show Fallback Link? If Swift fails, users can always fall back to the classic agenda UI at `/epd/agenda`. This provides a safety net and reduces frustration. ### Why Context Parameter? Different operations have different error messages. Context makes messages more specific and actionable: - Query failure β†’ "bij het ophalen" - Create failure β†’ "bij het aanmaken" - etc. ### Why Dev-Only Technical Details? Technical stack traces are only useful for developers debugging issues. Production users should see user-friendly messages only. --- ## πŸš€ Error Handling Best Practices ### 1. Always Use getUserFriendlyMessage() ```typescript // ❌ Bad - Technical error exposed to user setError(error.message); // βœ… Good - User-friendly Dutch message const friendlyMessage = getUserFriendlyMessage(error, 'create'); setError(friendlyMessage); ``` ### 2. Provide Context ```typescript // ❌ Bad - Generic error // βœ… Good - Context-specific error ``` ### 3. Offer Retry When Possible ```typescript // ❌ Bad - No recovery path // βœ… Good - User can retry refetchAppointments()} /> ``` ### 4. Use Inline Alerts for Forms ```typescript // ❌ Bad - Full-page error for form validation // βœ… Good - Inline alert in form setError(null)} /> ``` --- ## πŸ“Š Error Message Coverage Covered error types: - βœ… Authentication (401) - βœ… Authorization (403) - βœ… Not Found (404) - βœ… Server Error (500) - βœ… Network/Offline - βœ… Timeout - βœ… Validation - βœ… Generic/Unknown All with Dutch user-friendly messages. --- ## πŸ“ Files Modified/Created ``` βœ… components/swift/artifacts/blocks/agenda-error-state.tsx (NEW - 225 lines) β”œβ”€β”€ AgendaErrorState component β”œβ”€β”€ AgendaErrorAlert component └── getUserFriendlyMessage() utility βœ… components/swift/artifacts/blocks/agenda-create-form.tsx (UPDATED) └── Replaced basic error with AgendaErrorAlert βœ… docs/swift/bouwplan-swift-agenda-planning.md (UPDATED) └── E5.S3 β†’ Done, Epic 5 β†’ Done βœ… docs/swift/implementation-e5-s3-error-states.md (NEW) └── This documentation ``` --- ## 🎯 Impact ### Before E5.S3 - ❌ Technical error messages exposed to users - ❌ No fallback when errors occur - ❌ No retry functionality - ❌ Inconsistent error handling ### After E5.S3 - βœ… User-friendly Dutch error messages - βœ… Always provide fallback link to full agenda - βœ… Retry button for recoverable errors - βœ… Consistent error handling across all views - βœ… Auto-redirect for auth errors - βœ… Context-aware messaging --- ## πŸš€ Next Steps **Epic 6 - QA & Docs** - E6.S1: Manual test checklist (20 scenarios from build plan) - E6.S2: Docs update (bouwplan + release note) - E6.S3: Regression checks (Swift + klassieke agenda) --- **Implementation Status**: βœ… Complete **Epic 5 Status**: βœ… Complete (All 3 stories done) **Ready for**: Epic 6 (QA & Documentation)