Personal Catalogue: React, Express & MongoDB — Chapter 4, Exercise 1 ===================================================================== TASK Build the full AddItemForm component with FIELD_CONFIG covering all four types, wire it into App.jsx, and create one real item of each type through the actual UI, confirming each one via GET /api/items. SOLUTION src/fieldConfig.js: export const ITEM_TYPES = ['Book', 'Cd', 'Dvd', 'Bluray']; export const FIELD_CONFIG = { Book: [ { name: 'author', label: 'Author', required: true }, { name: 'isbn', label: 'ISBN' }, { name: 'publisher', label: 'Publisher' }, { name: 'tags', label: 'Tags (comma-separated)', isArray: true }, ], Cd: [ { name: 'artist', label: 'Artist', required: true }, { name: 'tracklist', label: 'Tracklist (comma-separated)', isArray: true }, ], Dvd: [ { name: 'director', label: 'Director' }, { name: 'runtimeMinutes', label: 'Runtime (minutes)', type: 'number' }, { name: 'regionCode', label: 'Region Code' }, ], Bluray: [ { name: 'director', label: 'Director' }, { name: 'runtimeMinutes', label: 'Runtime (minutes)', type: 'number' }, { name: 'resolution', label: 'Resolution', options: ['1080p', '4K'] }, ], }; src/components/AddItemForm.jsx (full component): import { useState } from 'react'; import { ITEM_TYPES, FIELD_CONFIG } from '../fieldConfig'; export default function AddItemForm({ onCreated }) { const [itemType, setItemType] = useState('Book'); const [shared, setShared] = useState({ title: '', releaseYear: '', notes: '' }); const [typeFields, setTypeFields] = useState({}); function handleTypeChange(e) { setItemType(e.target.value); setTypeFields({}); } function handleTypeFieldChange(name, value) { setTypeFields((prev) => ({ ...prev, [name]: value })); } async function handleSubmit(e) { e.preventDefault(); const payload = { itemType, title: shared.title, releaseYear: shared.releaseYear ? Number(shared.releaseYear) : undefined, notes: shared.notes || undefined, ...typeFields, }; for (const field of FIELD_CONFIG[itemType]) { if (field.isArray && typeof payload[field.name] === 'string') { payload[field.name] = payload[field.name].split(',').map((s) => s.trim()).filter(Boolean); } } const res = await fetch('http://localhost:4000/api/items', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (!res.ok) { const { error } = await res.json(); alert(error); return; } const created = await res.json(); onCreated(created); setShared({ title: '', releaseYear: '', notes: '' }); setTypeFields({}); } return (
); } src/App.jsx: import AddItemForm from './components/AddItemForm'; export default function App() { return (