Files
Thinh Lam 688fac73e9
CI/CD / backend (push) Failing after 2m8s
CI/CD / frontend (push) Failing after 1m40s
CI/CD / deploy (push) Has been skipped
sciagent code + Gitea Actions CI/CD
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 09:38:30 +07:00

5.8 KiB
Raw Permalink Blame History

Phase 1 Signup page — how it works

This document describes Signup.tsx: a standalone registration screen for the fe01 “phase1” demo flow. Use it as a spec when re-implementing the same behavior elsewhere.

Where it lives in the app

  • Component: fe01/src/phase1/pages/Signup.tsx (default export Signup)
  • Route: /phase1/signup (see fe01/src/App.tsx)

This is not the same as the main apps tabbed login/signup at /signup, which uses SignupForm (fe01/src/components/auth/SignupForm.tsx) with extra fields and optional OTP. The phase1 page is intentionally simpler.

Dependencies

Area What
Router react-router-dom: Link, useNavigate — success screen uses navigate('/login') (root login, not phase1). Link at bottom goes to /phase1/login.
API authService from @/phase1/lib/auth-serviceregister() and resendVerify().
UI shadcn-style: Button, Input, Label, Card*, Alert, Select; icons from lucide-react.

Base URL: authService uses import.meta.env.VITE_API_URL or falls back to http://localhost:3000 (see auth-service.ts). Ensure your re-implementation uses the same env variable or your chosen API base.

User-facing flow (two screens)

  1. Form screen — collect name, school email, password, role → submit.
  2. Success screen — shown when registration succeeds: explains that a verification email was sent, offers resend verification and back to login.

There is no auto-redirect after signup; the user must verify email via the link in mail (handled by backend + a separate verify route elsewhere, e.g. /verify-email?userId=...&token=...).

State model

State Type Role
email, password, fullName string Controlled form fields
role 'Admin' | 'Editor' | 'Viewer' Default 'Viewer'
error string Inline validation / API error message
loading boolean Disables inputs and shows spinner on submit/resend
successMsg string | null Message from API after successful register or resend
registeredEmail string | null Email used for resend; together with successMsg gates the success UI

Success UI condition: successMsg && registeredEmail — both must be set after a successful register().

Role picker

  • Canonical values sent to API: Admin, Editor, Viewer (must match backend).
  • Display: Vietnamese labels + icons + a one-line description under the select (ROLE_OPTIONS array in the component).

Re-implementing: keep the API values exactly as the backend expects; only labels/descriptions are presentation.

Client-side validation (before register)

Order in handleSubmit:

  1. Clear error.
  2. fullName — non-empty after trim.
  3. email — non-empty after trim.
  4. Domain checkvalidateDomain():
    • Must contain @.
    • Part after @ (lower case, trimmed) must equal one of ump.edu.vn or umc.edu.vn (hardcoded hint list ALLOWED_DOMAINS_HINT).
  5. password — length ≥ 8.

Important: This list is a UX hint. The file comment states the server re-validates using SystemSettings / Auth.AllowedEmailDomains. Your copy can change the hint list, but must stay aligned with server policy.

On submit: email is sent as email.trim().toLowerCase(); fullName is fullName.trim().

API: register

Call: authService.register({ email, password, fullName, role })

HTTP: POST {API_URL}/auth/register

Headers: Content-Type: application/json, X-Client-Origin: window.location.origin

Body: JSON { email, password, fullName, role } with role one of Admin | Editor | Viewer.

On failure (!res.ok): authService returns { success: false, error: string } — page sets error and stops.

On success: { success: true, userId, email, role, emailSent, message } — page sets registeredEmail from res.email, successMsg from res.message, does not set tokens (registration does not log the user in).

API: resend verification

When: User is on success screen and clicks “Gửi lại email xác nhận”.

Call: authService.resendVerify(registeredEmail)

HTTP: POST {API_URL}/auth/resend-verify with JSON { email }, same X-Client-Origin pattern.

On response: Page updates successMsg with res.message (does not clear the success layout).

Error display

  • Errors render in a destructive Alert above the submit button.
  • Success screen uses a non-destructive Alert for successMsg.

Styling / layout notes

  • Form: centered card on bg-muted/20, max width max-w-md.
  • Success: full-height centered layout with gradient background and slightly richer card styling (backdrop blur, green mail icon).
  • Accessibility: labels use htmlFor matching input id; password field has minLength={8} and required in addition to JS checks.

Checklist for a faithful re-implementation

  • Same route or intentionally different — document if you move it.
  • register + resendVerify endpoints, payloads, and headers (X-Client-Origin, credentials: 'include' if cookies matter for your stack).
  • Two-step UI: form → “check your email” with resend + login navigation.
  • Client validation order and domain hint list (or replace hint with server-driven list if you add an endpoint).
  • Role enum matches backend; Vietnamese copy optional.
  • Distinguish this simple flow from SignupForm (OTP/extra fields) if both exist in the product.
  • fe01/src/phase1/lib/auth-service.tsregister, resendVerify, verifyEmail
  • fe01/src/App.tsx — route wiring
  • fe01/src/components/auth/SignupForm.tsx — richer signup used on main /login + /signup (different product path)