Skip to content

[Enhancement] Migrate create/auth forms to react-hook-form + zod and fix broken label associations #83

Description

@zeemscript

What's Happening

The project ships react-hook-form, zod, and @hookform/resolvers in package.json — and none of the app's forms use them. Creation and auth forms are hand-rolled useState + bare required attributes, with several concrete defects verified in the source:

components/organisms/create/book-create-form.jsx:

  • Every <Label> says htmlFor="title" — the description, category, and price labels all point at the (nonexistent) title id, and the inputs themselves have name but no id, so no label is programmatically associated with its field (clicking a label focuses nothing; screen readers announce unlabeled inputs). The file upload labels use id="thumbail" (typo) / id="file" on the <Label> itself instead of htmlFor.
  • Errors surface via alert(data.message || 'Book creation failed') and alert('Something went wrong!').
  • The price placeholder is "Price (₦)" (naira) while the platform sells in USDC (PaymentModal renders ${item?.price} USDC) — no min/step constraints, so negative prices pass client-side.

components/organisms/create/course-create-form.jsx: same duplicated htmlFor="title" on all four labels, same Label id= misuse.

components/organisms/create/space-create-form.jsx: correct htmlFors but fields lack matching ids, and failure is alert('Something went wrong!').

components/organisms/auth/signup-form.jsx / login-form.jsx: manual useState handling, no inline validation messages (only toasts after submit).

No numeric coercion is done on price (it stays a string from the input), and no file-type/size validation runs before upload even though lib/utils/cloudinaryUpload.js exports a ready-made validateFile helper.

Where to Find This

  • components/organisms/create/book-create-form.jsx, course-create-form.jsx, space-create-form.jsx
  • components/organisms/auth/signup-form.jsx, login-form.jsx
  • components/ui/form.jsx — the shadcn Form wrapper for react-hook-form already exists in the repo, unused
  • lib/utils/cloudinaryUpload.jsvalidateFile

What We Want

  1. Migrate the three create forms to react-hook-form + zodResolver with zod schemas (title/description lengths, category required, price coerced to a number >= 0 with a sensible max, required files with type/size checks via validateFile).
  2. Render field-level error messages inline (use the existing components/ui/form.jsx primitives); remove every alert() in these forms in favor of inline errors + sonner toasts for submit-level failures.
  3. Fix all label/input associations: unique id per input, matching htmlFor per label (this alone fixes a WCAG 1.3.1/4.1.2 failure).
  4. Correct the currency affordance: label/prefix the price field as USD/USDC to match the Stellar checkout.
  5. Migrate signup/login to the same pattern (email format, min password length consistent with hooks/passwordChecker.js if applicable) — inline errors before submit.

Technical Context

  • zod@^3.24, react-hook-form@^7.56, @hookform/resolvers@^5 are already installed — no new dependencies.
  • Keep the existing submit actions (createBook, createCourse, create-space actions in lib/actions/) and their FormData shapes; only the client-side layer changes.
  • The forms render inside the custom Modal — check that error text doesn't overflow the modal's max-h scroll container.
  • Button here is the custom components/atoms/form/Button (has loading prop) — keep it.

Acceptance Criteria

  • All five forms validate with zod before submit and show inline, per-field error messages; no alert() calls remain in them.
  • Clicking any label focuses its input; an axe/Lighthouse pass reports no missing-label violations on these forms.
  • price reaches the API as a non-negative number and the UI presents it as USDC/USD, not ₦.
  • Selecting an oversized or wrong-type file is rejected client-side with a clear message before any upload starts.
  • Existing happy paths (create book/course/space, login, signup) still work end-to-end.
  • npm run lint and npm run build pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    complexity:highMaps to Drips Wave High tier (200 pts)enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions