Lesson 9 Lab — The Categories List¶
Categories is the last entity in TableServe without a screen. You've now built two card
grids from scratch — Menu Items (in the guides) and Staff (in the labs) — so build the
Categories list the same way, mostly from memory. This lab is deliberately light on code:
your MenuItemsPage / StaffPage and MenuItemCard / StaffCard are your templates — keep
them open beside this.
Prerequisite: your API is running on the HTTP profile (
http, nothttps) with Categories seed data loaded.
The entity (already created in Lesson 7)¶
You made ICategory in Lesson 7 for the Menu Item dropdown — here it is for reference:
export interface ICategory {
id: number | undefined;
name: string;
sortOrder: number;
}
The whole model — no FK, no nested collections (the simplest entity in the app).
Steps¶
Same arc as every list page you've built: API module → card → page → route + nav.
CategoryAPI.ts— adddelete(id)(your module already haslistfrom Lesson 7 andfindfrom the Lesson 8 lab), plainfetch; Lesson 12 hardens every module later.CategoryCard— a card showing name and sort order, with the same ⋮DropdownasStaffCard: an Edit link (→/categories/edit/:id) and a Delete-with-confirmthat callscategoryAPI.deletethen theonRemoveprop. (Edit 404s until the Lesson 10 lab builds the form.) If you built the Category detail page in the Lesson 8 lab, add a View item (→/categories/detail/:id) as the first dropdown entry.CategoriesPage— fetch into state in auseEffect,.map()the cards, show skeletons while loading (CategoryCardSkeleton, a card copy withskeleton skeleton-textbars), aremoveCategorythat filters state after a delete, and an Add Category button (→/categories/create). Model it onMenuItemsPage.- Route + nav — register
categoriesunderLayoutinmain.tsx, and add the Categories item toAppNav(the{/* Categories … */}slot you left in Lesson 5 — copy the Menu / OrdersNav.Linkshape; use an icon like#tags). - ✅ Checkpoint:
/categoriesshows one card per seeded category (skeletons first on a slow network); the ⋮ → Delete confirms and removes a card; the Categories nav pill works.
Verify in the browser¶
Browser checks work the same as your other list pages. With your API running and
npm run dev up:
- Click the Categories nav item → the card grid renders, name + sort order per card.
- Throttle to Slow 3G (DevTools → Network) and reload — skeleton cards show, then the real cards.
- ⋮ → Delete → confirm → the card disappears; Network shows a
DELETE. - Console clean.
Same fetch + card-grid + dropdown + skeleton patterns you've done twice now, on the last entity. On PRS this is Vendors — the simple no-FK reference entity.
Stretch challenges¶
Optional — for when you finish early. Not needed for the capstone. [Reinforce] builds on what you've done; [Reach] goes past it and needs some research.
- Sort by sort order — [Reinforce] — sort the fetched categories by
sortOrderbeforesetCategoriesso they render in menu order. - Count in the heading — [Reinforce] — show
Categories ({categories.length})and watch it fill in after the fetch. - A reusable confirm modal — [Reach] — replace the
window.confirmdelete with a react-bootstrapModal(the state-driven pattern from Lesson 9's guide). Reference: react-bootstrap Modal.
Finished these and want more? See stretch-react-challenges.md for bigger challenges that span the whole React pass.