Lesson 7 Lab — The Staff Create/Edit Form¶
Build the shared Staff form — one component for create and edit, with
react-hook-form — following the Menu Item form from the guide. Staff has no FK
dropdown; instead it has role checkboxes. Refer back to the guide for register,
the rule vocabulary, defaultValues, and the create-vs-edit switch.
Prerequisite: your API is running on the HTTP profile (
http, nothttps) with Staff seed data loaded. You're extending theStaffPagefrom earlier lessons.
The Staff form fields¶
First Name (required), Last Name (required), Email (optional, with a format pattern),
Phone (optional), Username (required, maxLength 50), Password (required, maxLength 60),
and two role checkboxes — isManager and isAdmin.
Steps¶
Same arc as the guide: API calls → the form (fields + validation) → save → thin pages + routes.
- Add
find(id),post(staff), andput(staff)toStaffAPI.ts. - Build
StaffFormwithuseForm<IStaff>; read:idwithuseParams. IndefaultValues(async), return anemptyStaffblank when there's no:id, elsestaffAPI.find(Number(id)). - Register each field with validation (
is-invalid+invalid-feedback, like the guide): firstName,lastName—required.username—required+maxLength: { value: 50, message: "Username is too long" }.password—required+maxLength: { value: 60, message: "Password is too long" }.email— optional, but add apatternrule that still allows empty:(The{...register("email", { pattern: { value: /^$|^\S+@\S+\.\S+$/, message: "Enter a valid email" }, })}^$|lets an empty email pass; a malformed one shows the message. This is the one new client rule from the guide — email is otherwise unvalidated under react-hook-form.)phone— optional, no rules.- Role checkboxes — register as plain checkboxes (no rules); react-hook-form binds the
boolean automatically:
(and the same for
<div className="form-check form-check-inline"> <input {...register("isManager")} type="checkbox" className="form-check-input" /> <label className="form-check-label">Manager</label> </div>isAdmin). - Write
save(handleSubmit): POST when!staff.idelse PUT; on successnavigate("/staff"). - Create thin
StaffCreatePage/StaffEditPageand add routesstaff/createandstaff/edit/:idunderLayout. ✅ Checkpoint: Add Staff opens an empty form; Save-empty shows inline errors; a valid save returns to the list (201), and ⋮ → Edit pre-fills the form (200 on save).
No FK dropdown, no
valueAsNumber, no nested-object delete — Staff has no foreign key, so its form is plain inputs plus checkboxes. Simpler than the Menu Item form. On PRS this is exactly the Users form (also no FK, also role flags, alsomaxLengthrules).
Verify in the browser¶
Browser checks are covered in the guide — section 6. With your API running and
npm run dev up:
- Add Staff →
/staff/create: empty fields, unchecked role boxes. Save with First Name empty → red field + "First name is required" (no network call). Fill it in, Save → back to the list, new card present. Network shows a 201POST. - ⋮ → Edit on a card →
/staff/edit/{id}: fields pre-filled, the right role boxeschecked. Toggle a role, Save → 200PUT, card updates. - Type a malformed email (e.g.
nope) and Save → the email field shows its error; clear it (empty) and it passes. - Confirm create and edit are the same form — only the URL's
:iddiffers. Console clean.
Same shared-form + react-hook-form pattern, checkboxes instead of an FK dropdown — exactly how you'll build the PRS Users form in the capstone.
Stretch challenges¶
Optional — for when you finish early. Not needed for the capstone. [Reinforce] builds on what you just did; [Reach] goes past the guide and needs some research.
- Watch the paste-bypass — [Reinforce] — paste a 70-character string into Password and
Save; the
maxLength: { value: 60 }rule fires its message (a nativemaxlengthattribute would have silently truncated the paste instead — that's why the app uses the rule). - Disable Save while submitting — [Reinforce] — pull
formState.isSubmittingfromuseFormand setdisabled={isSubmitting}on the Save button so a slow POST can't be double-submitted. - Watch a field live — [Reach] — use react-hook-form's
watch("firstName")to show a live "Hello, {firstName}" preview above the form as the user types.watchis the hook Lesson 10 leans on for derived fields — a gentle first look. Reference: react-hook-formwatch.
Finished these and want more? See stretch-react-challenges.md for bigger challenges that span the whole React pass.