What you are practising: everything at once. Callbacks as props, lifting state to a common parent, composition, and shipping a small working application: the travel bucket list.
DestinationList.tsx and AddDestinationForm.tsx ship as empty shells again, because the finished versions are Session 7's exercise answers. Paste in your Session 7 components, or rebuild them. The API client, the data, and the styling are all identical to Session 7.
Accept the assignment, clone your repository, then install once:
npm install# Terminal 1
npm run api
# Terminal 2
npm run devOffline fallback: set USE_MOCK = true at the top of src/api.ts. Reset your data: npm run reset-db.
src/api.tsanddb.json: identical to Session 7.src/components/Card.tsx: carried forward.src/components/DestinationList.tsxandAddDestinationForm.tsx: shells; bring your Session 7 work.src/components/FilterBar.tsxandDestinationDetail.tsx: new shells for the mini-project.src/App.tsx: the three regions of the app (filter, results, detail) scaffolded with TODOs. Keep thearia-labels on those<section>s — the grader uses them to find each region.src/index.css: the full baseline plus.filter-barand.detail.
An app that fetches the destinations, filters them by phase and name, shows a detail panel for the selected destination, and adds new destinations through a form. Work through the milestones in order; each leaves the app in a working state.
- Scaffold
<App>with filter, results, and detail regions (done for you). - Fetch destinations on mount through
api.listDestinations()with the discriminated-union state. - Render the list with correct keys and the
<Card>from earlier sessions. - Wire the filter bar (search + phase) with lifted state; filter results client-side.
- Selection: clicking a card sets the selected id; the detail panel renders the selected destination. Clicking the selected card again clears it.
- Add form: a controlled form that calls
api.addDestination(...)and inserts the new destination into the list without refetching. - Polish: disable the submit while the request is in flight, show a friendly error on failure, keep the form cleared on success.
Incomplete is fine. The point is an end-to-end working feature, not a finished product.
You have something you could show a friend: the list loads, the filters narrow it, selection drives the detail panel, and a new destination appears without a refetch. npm run typecheck passes and your work is committed and pushed.
Every push runs two GitHub Actions checks:
- Type check — runs
tsc -bon your project. - Autograding — renders your
<App />with a mocked network and checks the core pipeline: the destinations load and list, clicking a card shows it in the Detail region, clicking it again clears the detail, and the search box narrows the Results. Plus an automated code-quality review of the whole mini-project (including the add form). To let the grader drive it: keep thearia-label="Results"/aria-label="Detail"sections, render each card's name in an<h2>inside a.card, and give the search input an accessible name containing "search" (a label or placeholder).