# Error Fix: "Objects are not valid as a React child" ## Problem When creating a custom request through the NewRequestWizard, the application threw an error: ``` Error: Objects are not valid as a React child (found: object with keys {email, name, level, tat, tatType}) ``` ## Root Cause The NewRequestWizard stores approvers, spectators, ccList, and invitedUsers as arrays of objects with the structure: ```typescript { email: string, name: string, level: number, tat: number, tatType: 'hours' | 'days' } ``` When these objects were passed to `handleNewRequestSubmit` in App.tsx, they were being mapped to the request structure, but the mapping wasn't properly extracting the string values from the objects. Instead, entire objects were being assigned to fields that should contain strings. ## Solution ### 1. Enhanced Approver Mapping Updated the `approvalFlow` mapping in `handleNewRequestSubmit` to properly extract values: ```typescript approvalFlow: (requestData.approvers || []) .filter((a: any) => a) // Filter out null/undefined .map((approver: any, index: number) => { // Extract name from email if name is not available const approverName = approver?.name || approver?.email?.split('@')[0] || `Approver ${index + 1}`; const approverEmail = approver?.email || ''; return { step: index + 1, approver: `${approverName}${approverEmail ? ` (${approverEmail})` : ''}`, // STRING, not object role: approver?.role || `Level ${approver?.level || index + 1} Approver`, status: index === 0 ? 'pending' : 'waiting', tatHours: approver?.tat ? (typeof approver.tat === 'string' ? parseInt(approver.tat) : approver.tat) : 48, elapsedHours: index === 0 ? 0 : 0, assignedAt: index === 0 ? new Date().toISOString() : null, comment: null, timestamp: null }; }) ``` **Key changes:** - Added `.filter((a: any) => a)` to remove null/undefined entries - Properly extract `approverName` from `name` or `email` - Build a display string combining name and email - Convert TAT to number (handles both string and number inputs) ### 2. Enhanced Spectator Mapping Updated spectators mapping to properly extract values: ```typescript spectators: (requestData.spectators || []) .filter((s: any) => s && (s.name || s.email)) // Filter invalid entries .map((spectator: any) => { const name = spectator?.name || spectator?.email?.split('@')[0] || 'Observer'; return { name: name, // STRING, not object role: spectator?.role || spectator?.department || 'Observer', avatar: name.split(' ').map((n: string) => n[0]).join('').toUpperCase().slice(0, 2) || 'OB' }; }) ``` **Key changes:** - Filter out entries without name or email - Extract name from email if needed - Safe avatar generation with fallback ### 3. Added Missing Fields Added fields required by MyRequests component: ```typescript currentApprover: requestData.approvers?.[0]?.name || requestData.approvers?.[0]?.email?.split('@')[0] || 'Pending Assignment', approverLevel: `1 of ${requestData.approvers?.length || 1}`, submittedDate: new Date().toISOString(), estimatedCompletion: new Date(Date.now() + 5 * 24 * 60 * 60 * 1000).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) ``` ### 4. Fixed Audit Trail Message Updated audit trail to safely extract approver name: ```typescript details: `Request assigned to ${requestData.approvers?.[0]?.name || requestData.approvers?.[0]?.email || 'first approver'}` ``` ## Testing Checklist ✅ **Create Custom Request** - [ ] Fill out NewRequestWizard with title, description - [ ] Add 2-3 approvers with emails - [ ] Add spectators (optional) - [ ] Submit request ✅ **Verify No Errors** - [ ] No console errors about "Objects are not valid as React child" - [ ] Request appears in My Requests - [ ] Can click on request ✅ **Verify Detail Page** - [ ] Request detail page loads - [ ] Approver names display correctly (not [object Object]) - [ ] Workflow tab shows all approvers - [ ] Spectators display correctly (if added) ✅ **Verify My Requests Display** - [ ] Request shows in list - [ ] Current approver displays as string - [ ] Approver level shows correctly (e.g., "1 of 3") ## Common Patterns to Avoid ### ❌ Bad: Rendering Objects Directly ```typescript {approver} // If approver is {email: "...", name: "..."} ``` ### ✅ Good: Extract String First ```typescript {approver.name || approver.email} ``` ### ❌ Bad: Assigning Object to String Field ```typescript { approver: approverObject // {email: "...", name: "..."} } ``` ### ✅ Good: Extract String Value ```typescript { approver: approverObject.name || approverObject.email } ``` ## Related Files Modified 1. **App.tsx** - `handleNewRequestSubmit` function - Enhanced approver mapping - Enhanced spectator mapping - Added missing fields for MyRequests compatibility - Fixed audit trail messages ## Data Flow ``` NewRequestWizard (formData) ├── approvers: [{email, name, level, tat, tatType}, ...] ├── spectators: [{email, name, role, department}, ...] └── ...other fields ↓ handleNewRequestSubmit (App.tsx) ├── Maps approvers → approvalFlow with STRING values ├── Maps spectators → spectators with STRING values └── Creates complete request object ↓ dynamicRequests state (App.tsx) ├── Stored in memory └── Passed to components ↓ RequestDetail / MyRequests ├── Receives proper data structure └── Renders strings (no object errors) ``` ## Prevention Tips 1. **Always validate data types** when mapping from wizard to database 2. **Extract primitive values** from objects before assigning to display fields 3. **Add TypeScript interfaces** to catch type mismatches early 4. **Test with console.log** before rendering to verify data structure 5. **Use optional chaining** (`?.`) to safely access nested properties ## Future Improvements 1. Add TypeScript interfaces for wizard form data 2. Add TypeScript interfaces for request objects 3. Create validation functions for data transformation 4. Add unit tests for data mapping functions 5. Create reusable mapping utilities