# Frontend / UI / UX Audit — WFDASH **Date:** 2026-08-28 **Scope:** `src/app/(app)/**/page.tsx`, form components, client components, navigation, loading/empty/error states, mobile `/m` dashboard, counter shell. **Method:** Walked the app from the user's perspective (entry → login → dashboard → core flows: orders, quotes, customers, suppliers, stock, deliveries, counter). Read every primary page + form + the sidebar/nav + key modals. Did **not** fix anything — this is a categorised findings list. ## Severity legend - **Critical** — broken flows, data loss, security hole, anything that blocks production rollout - **Major** — visible UX failure, confusing default, accessibility blocker, fragile pattern that will bite later - **Minor** — polish, consistency, hardening --- ## Executive summary The app has a thoughtful information architecture, real-time updates via PocketBase subscriptions, a cohesive brand language (tri-colour stripe, themed WFDASH palette, themed login) and a lot of detailed care (per-row expansion on the orders list, deterministic accent colours for approval cards, etc). The big remaining issues are: 1. **No `loading.tsx` / `error.tsx` / `not-found.tsx` anywhere in the app** — every route relies on the page's own inline spinner / error catch. A backend blip on a slow link looks identical to a normal load and an empty state is the only fallback for "this route blew up". 2. **No global error boundary** — a throw inside any client component crashes the route silently (only the toast or `console.error` surfaces it). 3. **Hardcoded "Westcott Fasteners" brand string** in 4+ places (sidebar, dashboard header, login logo comment, server-side email template). 4. **Forms don't use react-hook-form / shadcn `Form`** — every form is bare `useState` with hand-rolled `onSubmit` validation. Inline error messages are inconsistent (some use `toast.error`, some show nothing); the Order form does not validate required Company before submit UI; several forms lack `aria-invalid` / `aria-describedby`. 5. **Mobile `/m` dashboard** does a hard `document.location.href = "/login"` on 401 (loses state, no retry). It also uses native `` with a hand-rolled backdrop click handler that double-fires in some browsers. 6. **Counter success screen** says *"on the New tab"* with no link or context — a quote unquote placeholder text. 7. **Sidebar `New Order` vs `Order List`** highlight resolution is clever — relies on a "most-specific match" heuristic that's correct but only documented inline; if anyone adds another nested route under `/orders`, the heuristic breaks silently. The remainder of this doc walks the app section by section. --- ## 1. Auth & shell ### 1.1 Login screen — `src/app/(auth)/login/page.tsx` **Strengths** - The branded login is genuinely nice — tri-colour stripe, brand-correct dot grid mask, three-radial wash behind the card, three tabs (Login / Register / Reset). - Tabs use a scoped `