18 KiB
Phase 4 - UI/UX & Design System Audit
Executive Summary
The dashboard already has a usable shared UI foundation through PageContainer, shadcn primitives, shared table utilities, and consistent card-based page composition. Responsive handling is generally better than average for an admin system because many key layouts already use min-w-0, wrapping button groups, and scoped table overflow.
The largest UI/UX problem is not layout instability but system inconsistency. Several feature areas still diverge from the intended design system, especially reports tables, file-upload flows, heading structure, and copy quality. The most visible issue across the entire UI is widespread Thai text encoding corruption, which materially harms readability, trust, and learnability.
Screen Inventory
Primary screens reviewed:
- Dashboard shell and sidebar
- Organization switcher and user menu
- Employee directory list
- Training records form and review-oriented detail states
- Announcements form and detail view
- Online lessons form
- Reports page
- Notifications page
- Audit logs table
- Shared page header, heading, data table, toolbar, pagination, notification card
Layout Assessment
Strengths:
src/components/layout/page-container.tsxgives pages a stable shell with responsive spacing and full-width containment.- Shared tables correctly scope horizontal overflow inside the table shell instead of the full page.
- Header actions commonly wrap well on small screens.
Weaknesses:
- Header patterns are inconsistent. Some pages use
PageContainerheader only, while others inject another local hero/header block inside the page body, creating double-header behavior. - Reports stack multiple large cards and wide tables vertically, which is workable but visually heavy and cognitively dense.
- Access fallback inside
PageContaineris centered plain text rather than a full empty/error-state pattern.
Typography Assessment
Strengths:
- Core sizes are mostly sensible: large page titles, smaller descriptions, readable card body text.
- Tables generally keep compact admin-dashboard typography.
Weaknesses:
- Typography hierarchy is semantically inconsistent because
Headingrendersh2while feature pages often behave like top-level page titles. - Some screens add their own
h1underPageContainer, producing mixed heading structures across modules. - Thai text corruption appears in navigation, headers, descriptions, pagination labels, and empty states across many files, which is the most serious typography/content issue in the system.
- Copy style mixes Thai and English unevenly, for example
PageContaineraccess fallback remains English while most feature UI is Thai.
Color & Status Assessment
Strengths:
- Shared
Badgeusage is established for workflow and report states. - Content approval states appear to reuse shared variants through
content-approvalhelpers.
Weaknesses:
- Status language is not fully standardized across features. Similar states use different wording such as archive/hide/remove-publish semantics depending on module.
- Some feedback and button copy rely on variant differences only, without additional structural separation for risky actions.
Button Standard Assessment
Strengths:
- Most primary/secondary actions use shared
Buttonvariants. - Mobile width handling is good in many forms and headers through
w-full sm:w-auto. - Action ordering is usually reasonable: cancel/back separated from primary submit action.
Weaknesses:
- Workflow buttons are not standardized across content modules. Announcements and online lessons use similar but not fully shared action group patterns.
- Some significant actions such as publish/archive are triggered directly from detail views without explicit confirmation, which weakens safety and workflow clarity.
- Loading labels are inconsistent and often use
...instead of a consistent loading copy pattern.
Table Standard Assessment
Strengths:
- Shared
DataTable, toolbar, and pagination are good system-level primitives. - Canonical table modules like employee directory and audit logs follow the shared pattern well.
- Action columns are generally handled in a stable way with pinning and reusable menus.
Weaknesses:
- Reports bypass the shared DataTable stack entirely and use manual
Tablecards, so sorting, pagination, column management, and interaction patterns differ from the rest of the app. - Manual report tables rely on horizontal scrolling only and do not offer the stronger affordances already available in the shared table system.
- Table empty/loading states are reasonably present, but wording and visual treatment vary by module.
Form Standard Assessment
Strengths:
- Major forms use TanStack Form wrappers and shared field primitives.
- Validation errors are shown inline and
scrollToFirstError()is used in important flows. - Training records form handles employee vs HRD mode clearly.
Weaknesses:
- Required mark style is inconsistent. Some screens use literal
*, some use styled destructive spans, and some rely on validation only. - Placeholder and helper-text patterns vary widely between modules.
- Inputs often omit
nameandautocompleteattributes, which is a lower-level accessibility and usability gap against modern form guidelines. - Feature forms mix shared field wrappers with raw HTML elements such as custom
textarea, creating slightly different spacing and behavior.
File Attachment UX Assessment
Strengths:
- Training records use a shared
FileUploaderand attachment list, which gives a clearer system pattern. - Content forms usually show current file, replace/remove flows, and post-save expectations.
Weaknesses:
- Attachment UX is fragmented across modules:
- Training records use shared uploader + attachment list
- Announcements use a raw file input
- Online lessons use custom
AssetPickersections
- This creates different expectations for drag-and-drop, file preview, replacement, and removal across similar content workflows.
- View-mode attachment presentation is not standardized across modules.
Feedback State Assessment
Strengths:
- Most reviewed modules include loading, error, and empty states.
- Toasts are used consistently for mutation feedback.
- Audit logs and notifications have decent empty-state handling.
Weaknesses:
- Loading states are inconsistent between skeleton-style, spinner-in-card, and plain text messaging.
PageContaineraccess denial uses a plain centered sentence rather than a richer restricted-state pattern.- Success and error messaging quality varies and is harder to read because of copy encoding issues.
Dialog / Sheet / Drawer Assessment
Observed strengths:
- Shared dialog/sheet primitives are clearly part of the system.
- Content review uses a shared action dialog component rather than ad hoc per-page modal markup.
Observed gaps:
- This audit did not fully validate focus trap, escape handling, and mobile height behavior for every dialog/sheet implementation.
- Action-safety patterns are not uniform; some important transitions use dialogs while other significant actions run immediately.
Workflow UX Assessment
Strengths:
- Training records and content modules expose state-aware actions instead of showing every action at once.
- Review notes and current status are surfaced in key detail/form views.
Weaknesses:
- Reports page is functionally useful but visually dense; it reads like stacked exports rather than a guided reporting workspace.
- Content modules blur the line between draft editing, review transition, publish, and archive actions because button patterns are similar but not always grouped by risk or workflow stage.
- Employee directory uses an extra local page hero inside
PageContainer, which makes it feel visually different from other management screens.
Responsive Assessment
Strengths:
- Shared layouts use
min-w-0, wrapped actions, and scoped overflow correctly. - Employee directory and shared tables are intentionally built for horizontal table scroll on smaller screens.
- Forms generally collapse to a single column well.
Weaknesses:
- Reports is the most likely responsive pain point because of multiple wide manual tables on one page.
- Some custom card headers and action groups depend on wrapping rather than a stronger mobile-specific layout hierarchy.
- Sidebar behavior was not visually runtime-tested in browser during this audit.
Accessibility Assessment
Positive observations:
- Many interactive controls use semantic elements such as
button,Link, and form labels. - Some icon-only actions already have
aria-label, for example notification mark-as-read and table pagination buttons. - Inline validation patterns exist in major forms.
Key gaps:
- No verified skip-link pattern was found for the dashboard shell.
- Decorative icons are widely rendered without explicit
aria-hidden, which can add noise for assistive tech depending on the icon implementation. - Heading hierarchy is inconsistent at the page level because of mixed
h1/h2usage. - Native form enhancements such as
autocomplete, input naming consistency, and copy punctuation are not standardized. - Notifications pagination uses
href='#'plus click interception, which is weaker semantically than true navigation controls.
Design System Inconsistencies
Most important system drifts:
- Copy quality and encoding
- Thai labels are corrupted across multiple feature surfaces.
- Page header structure
- Shared page shell exists, but some modules duplicate internal hero headers.
- Table architecture
- Canonical modules use shared DataTable; reports does not.
- File upload pattern
- Different modules use different uploader UX for similar tasks.
- Form semantics
- Required markers, placeholders, descriptions, and input metadata are inconsistent.
- Workflow action treatment
- Some risky actions confirm through dialogs; others execute directly.
Findings by Severity
[High] Thai UI copy is encoding-corrupted across major navigation, form, table, and feedback surfaces
Module:
Cross-cutting UI copy
Location Found:
src/config/nav-config.tssrc/components/layout/page-container.tsxsrc/components/ui/table/data-table.tsxsrc/components/ui/table/data-table-pagination.tsxsrc/features/employee-directory/components/employee-directory-header.tsxsrc/features/reports/components/reports-page-content.tsxsrc/features/notifications/components/notifications-page.tsxsrc/features/announcements/components/announcement-form.tsxsrc/features/announcements/components/announcement-view-page.tsxsrc/features/training-records/components/training-record-form.tsxsrc/features/online-lessons/components/online-lesson-form.tsx
Details:
Large portions of user-facing Thai text render as mojibake-like corrupted strings instead of readable Thai copy.
Impact:
- Severely damages readability and trust.
- Makes workflows harder to learn.
- Reduces accessibility because labels and feedback become harder to interpret.
Evidence from Code:
Corrupted Thai strings appear in page titles, descriptions, nav items, buttons, empty states, and pagination labels.
Example Scenario:
A user opening navigation, forms, or reports sees broken Thai labels in core actions and status descriptions, making the system feel unreliable even when the workflow itself works.
Recommendation:
Normalize file encoding and re-validate every user-facing Thai string before expanding UI work.
Must Fix Before Production: Yes
[Medium] Heading and page-header patterns are semantically and visually inconsistent across modules
Module:
Shared layout and page composition
Location Found:
src/components/ui/heading.tsxsrc/components/layout/page-container.tsxsrc/features/employee-directory/components/employee-directory-header.tsx
Details:
Heading renders h2, while some screens also introduce their own h1 inside the page body. Other screens rely entirely on the shared heading component.
Impact:
- Inconsistent visual rhythm across pages.
- Weaker accessibility and document structure.
- Makes it harder to standardize page templates.
Recommendation:
Define one canonical page-title pattern for dashboard screens and apply it uniformly.
Must Fix Before Production: Consider
[Medium] Reports UI diverges from the shared table system and creates a noticeably different interaction model
Module:
Reports
Location Found:
src/features/reports/components/reports-page-content.tsxsrc/features/reports/components/report-table-card.tsx
Details:
Reports use manual tables instead of the shared DataTable stack used elsewhere in the dashboard.
Impact:
- Table behavior differs from the rest of the product.
- Large report cards become dense and harder to scan.
- Users lose familiar controls such as unified table toolbars and standardized interaction patterns.
Recommendation:
Either formally designate reports as a separate reporting presentation pattern, or migrate the module toward shared table conventions where practical.
Must Fix Before Production: Consider
[Medium] File attachment UX is fragmented across modules instead of following one reusable pattern
Module:
Training Records, Announcements, Online Lessons
Location Found:
src/features/training-records/components/training-record-form.tsxsrc/features/announcements/components/announcement-form.tsxsrc/features/online-lessons/components/online-lesson-form.tsx
Details:
Comparable upload tasks use different components and different interaction rules.
Impact:
- Increases cognitive load when users move between modules.
- Makes future improvements and accessibility hardening harder to apply consistently.
Recommendation:
Standardize a single attachment/upload UX contract for content and training modules, even if internal storage logic remains feature-specific.
Must Fix Before Production: Consider
[Low] Form and pagination semantics miss several modern UX/a11y conventions
Module:
Shared forms and notifications
Location Found:
src/features/training-records/components/training-record-form.tsxsrc/features/announcements/components/announcement-form.tsxsrc/features/online-lessons/components/online-lesson-form.tsxsrc/features/notifications/components/notifications-page.tsx
Details:
Common gaps include missing autocomplete conventions, inconsistent input metadata, and pagination links implemented with href='#' plus click interception.
Impact:
- Mostly incremental usability and accessibility debt rather than immediate blockers.
Recommendation:
Add a lightweight shared checklist for form semantics, link semantics, and icon accessibility before future UI expansion.
Must Fix Before Production: No
Recommended UI Standard
Suggested system rules for this repo:
- One dashboard page header pattern
- Top-level page title, description, optional info button, optional right-side action area.
- One table family
- Use shared DataTable unless a page is intentionally a reporting surface with documented exceptions.
- One attachment pattern
- Shared file state, current file preview, replace/remove actions, and empty state wording.
- One required-field style
- Same marker, same placement, same helper/error rhythm.
- One workflow action grouping rule
- Primary action, secondary action, destructive action, and confirmation behavior defined centrally.
- One language-quality rule
- All user-facing Thai strings must be UTF-safe, readable, and consistently localized.
Recommended Remediation Order
- Fix Thai text encoding across all user-facing surfaces.
- Standardize heading semantics and page-header composition.
- Decide whether reports is an intentional exception or should move closer to the shared table pattern.
- Unify attachment UX across training records, announcements, and online lessons.
- Add a small accessibility/design checklist for forms, icon buttons, and navigation semantics.
Files Reviewed
plans/tms-system-full-audit-prompts.mddocs/AI_DEVELOPMENT_GUIDE.mddocs/PROJECT_ARCHITECTURE.mdsrc/components/layout/page-container.tsxsrc/components/layout/app-sidebar.tsxsrc/components/layout/user-nav.tsxsrc/components/org-switcher.tsxsrc/components/ui/heading.tsxsrc/components/ui/notification-card.tsxsrc/components/ui/table/data-table.tsxsrc/components/ui/table/data-table-toolbar.tsxsrc/components/ui/table/data-table-pagination.tsxsrc/config/nav-config.tssrc/features/employee-directory/components/employee-directory-header.tsxsrc/features/employee-directory/components/employee-directory-table.tsxsrc/features/training-records/components/training-record-form.tsxsrc/features/announcements/components/announcement-form.tsxsrc/features/announcements/components/announcement-view-page.tsxsrc/features/announcements/components/announcement-status-badge.tsxsrc/features/online-lessons/components/online-lesson-form.tsxsrc/features/reports/components/reports-page-content.tsxsrc/features/reports/components/report-table-card.tsxsrc/features/notifications/components/notifications-page.tsxsrc/features/audit-logs/components/audit-log-listing.tsxsrc/features/audit-logs/components/audit-log-table.tsxsrc/features/content-approval/components/content-approval-status-badge.tsx
Areas Not Verified
- Runtime browser validation of focus order, keyboard traversal, and screen-reader output
- Visual contrast measurement against rendered theme tokens
- All dialogs/sheets/drawers at runtime, including focus trap and mobile height behavior
- Full mobile behavior of the sidebar and complex tables in a live viewport
- Every feature module in the repo; this review focused on canonical and high-traffic dashboard surfaces