Component Inventory — Frontend
The frontend is built with Leptos 0.8 (CSR + nightly). Components fall into two layers:
-
Primitives in
frontend/src/ui/— copied (with attribution + license preserved atfrontend/src/ui/LICENSE.rust-ui) from the rust-ui MIT-licensed component library plus our own additions. -
Feature components in
frontend/src/{admin,employee,customer}/— page-level Leptos components for each surface.
Primitives — frontend/src/ui/
| File | Component | Status |
|---|---|---|
|
|
Inline, signals only |
|
|
⚠️ Needs JS shim (Dialog overlay) |
|
|
Inline |
|
|
Inline |
|
|
Inline |
|
|
Inline |
|
|
Inline (used as toast replacement until Sonner shim lands) |
|
|
Inline |
|
|
Inline; exposes |
|
|
⚠️ Compiles + renders, throws at runtime when opened (needs |
|
|
⚠️ Same JS-shim issue as Dialog |
|
|
Inline |
|
|
Inline |
|
|
⚠️ Same JS-shim issue |
|
|
Inline |
|
|
Hand-rolled (not from rust-ui). Icon-free; |
|
|
⚠️ Markup-only — toast logic lives in upstream JS we didn’t pull |
|
|
Internal-state only; no |
|
|
Inline |
|
|
Inline |
|
|
Inline |
|
rust-ui hooks |
One hook (see source) |
⚠️ items are tracked in docs/follow-ups.md under "Frontend — UI follow-ups".
Surface 1 — Admin (frontend/src/admin/)
10 routed pages under /admin/*, all wrapped by AdminShell (sidebar + header).
| Route | Component | File |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/admin/ redirects to /admin/dashboard. Shell provides the navigation chrome via Sidebar.
Surface 2 — Employee (frontend/src/employee/)
5 routed pages under /app/*, wrapped by EmployeeShell.
| Route | Component | File |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
/app/ redirects to /app/schedule.
Surface 3 — Customer (frontend/src/customer/)
Single route /f/:slug, no shell — the page is the form.
-
form_page.rs→CustomerFormPage— fetches the form by slug, renders viaform_renderer.rs. -
form_renderer.rs→FormRenderer— drives the field render loop. -
fields/— per-field-type components:-
text.rs—TextField -
number.rs—NumberField -
date_field.rs—DateField -
select.rs—SelectField(pre-selected option not yet visually reflected — see follow-up) -
location.rs—LocationField(usesdefault_location_idas initial value; cleared selection sticks — see follow-up)
-
Cross-cutting modules
-
frontend/src/api/— backend client.client.rsexposesapi_get,api_post,api_patch,api_delete, all attaching the JWT from local storage.types.rsmirrors backend DTOs.mod.rsre-exports. -
frontend/src/auth/—provide_auth_contextputs aResource<Option<MeResponse>>into Leptos context.get_tokenreadsshiftit_tokenfrom local storage viagloo-storage. -
frontend/src/app.rs—Appcomponent: provides auth context, declares the router. The router lives entirely in this one file (~60 lines). -
frontend/src/main.rs/lib.rs— wasm-bindgen entry points.
Patterns the next session should know
-
Fetching:
LocalResource::new(fetcher).gloo-netfutures are!Sendon wasm32 so the local variant is mandatory. -
Mutating:
Action::new_local. Same!Sendreason. -
Refetch after mutate:
versionsignal incremented in anEffect, used in theLocalResource's key. Already used byEmployeeDetailandShiftDetail(Phase 2).Roles,Locations,FormListstill need this — see follow-up "Optimistic UI / refetch after mutation". -
Iteration in views:
<For each=… key=… children=…>(theview=prop was renamed in 0.8). -
Anchor classes:
<A attr:class="…">(notclass=). -
view!macro limits: does not accept turbofish or tuple destructuring in closure args.