Skip to main content

COMPONENT_INVENTORY.md — human.work

Every UI component with location, role usage, props/states, and design notes. Cross-reference: VIEWS_BY_ROLE.md, FRONTEND_ARCHITECTURE.md, DESIGN_PRINCIPLES.md. Last updated: 2026-05-04.

Note (2026-05-03): Expert pool UI (PoolCard, /ops/pools, /workspace/pools) is disabled pending redesign on the new direct Expert ↔ Org model (pool tables removed). PortalChat.tsx now uses EXPERT_ROLES from /client/PortalChat.tsx. /portal/* prefix is gone — all client routes use /client/*.

Layout: components are organized into 5 directories under frontend/src/components/:

DirectoryOwnerRole-gating allowed
ui/Design systemNo — pure primitives
shared/AnyNo — must be role-agnostic
client/Client portal teamYes — client-only logic
internal/Expert / AM / Superadmin teamYes — operator-only logic
analytics/Analytics surfaces (cross-role)No

Plus root-level legacy: components/Nav.tsx, components/UserFooter.tsx, components/IntegrationStatus.tsx, components/slug-availability-input.tsx.


1. ui/ — primitives (design system)

These have no business logic and import only from utilities. They are the lowest layer.

Button

  • File: components/ui/Button.tsx
  • Used by: All roles (Account Manager wizard, login, integrations, etc.)
  • Props/states: variant: "primary" | "secondary" | "ghost" | "danger", size: "sm" | "md" | "lg", loading, disabled, children, native button props.
  • Design notes:
    • Primary uses --accent bg + white text; hover --accent-hover; disabled 0.5 opacity.
    • Secondary uses --bg-surface + --border + --text-primary; hover --bg-hover.
    • Ghost has no background; hover --bg-hover.
    • Danger uses --danger semantic.
    • Heights: sm 28px, md 36px, lg 44px (touch target).
    • 8px border-radius.

Badge

  • File: components/ui/Badge.tsx
  • Used by: All roles (status pills, role tags, etc.)
  • Props/states: variant: "default" | "success" | "warning" | "danger" | "info" | "neutral", children.
  • Design notes:
    • 10–11px font, 600 weight, uppercase, 0.04em tracking.
    • 2px vertical / 6–8px horizontal padding, 4px radius.
    • Each variant uses paired --{variant}-subtle bg + --{variant}`` text.
    • Do not use raw hex — always tokens.

Avatar

  • File: components/ui/Avatar.tsx
  • Used by: All roles
  • Props/states: name, src?, size: number (default 32), color? (override).
  • Design notes:
    • Falls back to deterministic initial avatar using a hash of the name → background color from a curated 8-tone palette.
    • The Specialist persona always uses --accent (claret) regardless of name — this is the workspace identity.
    • Image avatars are object-cover, circle-clipped.
    • Online dot is a child element, not part of Avatar (callers add it).

TicketStatusBadge

  • File: components/ui/TicketStatusBadge.tsx
  • Used by: Client (read-only), Expert (interactive variant lives elsewhere)
  • Props/states: status: "open" | "pending" | "in_review" | "resolved" | "snoozed" | "archived".
  • Design notes:
    • Color mapping: open → success, pending → warning, in_review → info, resolved → neutral, snoozed → muted, archived → muted.
    • 11px font, 20px pill radius.

2. shared/ — role-agnostic utilities

ChannelBadge

  • File: components/shared/ChannelBadge.tsx
  • Used by: All roles wherever a conversation appears (PortalChat header, queue list, ticket detail)
  • Props/states: channel: "web" | "email" | "whatsapp" | "slack" | "telegram" | "wechat" | "teams".
  • Design notes:
    • Uses ChannelIcon SVG + label.
    • Each channel has a brand-tinted bg + text via tokens (not raw hex). E.g. WhatsApp: success-subtle bg + success-fg text.
    • 11px font, 4px radius, 2/8 padding.

ChannelIcon

  • File: components/shared/ChannelIcon.tsx
  • Used by: ChannelBadge, integration tiles
  • Props/states: channel, size.
  • Design notes: SVG, currentColor. Use semantically (no embedded color).

RelativeTime

  • File: components/shared/RelativeTime.tsx
  • Used by: Queue rows, message metadata, ticket lists
  • Props/states: timestamp, format?: "short" | "full".
  • Design notes: tabular-nums for alignment, --text-muted color, 11–12px.

Skeleton

  • File: components/shared/Skeleton.tsx
  • Used by: Queue list loading state, ticket detail loading state, dashboard loading
  • Props/states: width, height, variant?: "text" | "rect" | "circle".
  • Design notes: --bg-hover bg, 4–8px radius, optional pulse animation.

Toast

  • File: components/shared/Toast.tsx
  • Used by: All roles (mounted at root via Toaster)
  • Props/states: toast.success(msg), toast.error(msg|Error), toast.info(msg). Auto-dismiss 4s.
  • Design notes:
    • Bottom-right stacked, max-width 400.
    • Each toast: surface bg + 1px border + 4px left bar in semantic color (success/danger/info/warning).
    • Slide-up + fade-in animation (animate-slide-up).
    • Click dismisses.

ErrorBoundary

  • File: components/shared/ErrorBoundary.tsx
  • Used by: Wraps each top-level layout
  • Props/states: fallback?: ReactNode.
  • Design notes: Friendly fallback UI ("Something went wrong — refresh") with claret retry button.

DarkModeProvider

  • File: components/shared/DarkModeProvider.tsx
  • Used by: Mounted in app/layout.tsx; consumed by UserFooter and any component calling useTheme()
  • Props/states: theme: "light" | "dark", toggle(). Persisted in localStorage.hw_theme. Sets [data-theme] attribute on <html>.
  • Design notes: System preference (prefers-color-scheme: dark) honored on first visit when no stored value.

ServiceWorkerRegistrar

  • File: components/shared/ServiceWorkerRegistrar.tsx
  • Used by: Mounted in root layout
  • Props/states: none (side-effect only).
  • Design notes: Registers /sw.js. Hooks for push notification subscription are stubbed (E-P3 gap).

3. client/ — client portal

PortalChat

  • File: components/client/PortalChat.tsx (~1,500 LOC)
  • Used by: /client/chat, /client/chat/[id]
  • Props/states: initialId?: string. Internal state: conversations, selectedId, messages, selectedExpertId, sidebarOpen, threadNames.
  • Design notes:
    • Two main subcomponents inside: Sidebar, ChatPanel (+ ExpertProfile, MessageBubble, WorkforceEmptyState, WorkerAvatar).
    • Sidebar: --bg-sidebar, 256px wide, three sections (workspace header, Specialists, Threads), UserFooter at bottom.
    • Bubble shape: outgoing claret 18px 18px 4px 18px, incoming bg-surface with 1px border 4px 18px 18px 18px.
    • Role gating lives here:
      • EXPERT_ROLES = ["expert", "account_manager", "superadmin"].
      • Internal notes filtered for non-experts (if (msg.isInternal && !isExpertViewer) return null).
      • Status dropdown vs read-only badge: isExpert ? <ExpertChatOverlay/> : <span/>.
      • Approval banner / confidence scores / "Expert" sender label / internal note toggle: all isExpert gated.
    • Polling: every 15s for the open thread.
    • Active thread row: --accent-subtle bg + 3px --accent left border.
    • Hover: --bg-hover.

PortalNav

  • File: components/client/PortalNav.tsx
  • Used by: All /client/* non-chat routes (tickets, settings)
  • Props/states: stateless except pathname from usePathname().
  • Design notes:
    • Top bar layout, claret avatar logo + workspace name, nav links (Chat / Tickets / Settings), user avatar right.
    • Hidden on /client/chat (full-screen layout).

TrialBanner

  • File: components/client/TrialBanner.tsx
  • Used by: Top of /client/* (except chat full-screen)
  • Props/states: hooks GET /client/trial-info. Internal: dismissedThisSession.
  • Design notes:
    • Sticky top, --warning-subtle bg + --warning left bar, 32px tall.
    • Copy: "Your trial ends in N days. Add billing to keep service. [Add billing →]"
    • Dismissible per session (sessionStorage flag).

ChannelConfigForm

  • File: components/client/ChannelConfigForm.tsx
  • Used by: /client/settings/channels/new, /client/settings/channels/[id]
  • Props/states: channel, initialConfig, onSave.
  • Design notes: Per-channel form (token, webhook URL, whitelist editor). Test-inbound button. Save / Disconnect.

IntegrationCard

  • File: components/client/IntegrationCard.tsx
  • Used by: /client/settings/channels
  • Props/states: channel, connected, health: "healthy" | "warning" | "error" | "unknown", onClick.
  • Design notes: Card 220px tall, channel icon + name + connection status pill + last-event timestamp. Connected uses --bg-surface, available uses --bg-canvas + dashed border.

TestResult

  • File: components/client/TestResult.tsx
  • Used by: Integration detail page (test inbound feature)
  • Props/states: result: { status: "success" | "fail", message, latency, payload }.
  • Design notes: Inline result panel, semantic color left bar + monospace JSON preview.

WhatsAppQrModal

  • File: components/client/WhatsAppQrModal.tsx
  • Used by: WhatsApp integration setup
  • Props/states: open, qrDataUrl, onClose.
  • Design notes: Centered modal, QR centered, instructions below, "Refresh QR" button. Note: today this connects via Twilio number pool primarily; QR flow is for the alternative Baileys WhatsApp service.

4. internal/ — operator surfaces (expert / AM / superadmin)

QueueItem

  • File: components/internal/QueueItem.tsx
  • Used by: /workspace/queue, /ops/queue
  • Props/states: item: QueueItem, selected, onClick, currentUserId?.
  • Design notes:
    • 64px min-height row.
    • Left risk bar 3px (theme-aware bar token: critical → danger, high/medium → warning, low → teal).
    • Selected overrides bar with --accent, bg becomes --accent-subtle.
    • Customer name (13/500), 2-line message preview (12/secondary), badge row (risk badge with --risk-* tokens, confidence %, AssigneePill, ChannelBadge).
    • Hover: --bg-hover.

TicketDetail

  • File: app/workspace/queue/TicketDetail.tsx (lives at the route, not in internal/, but functionally an internal component)
  • Used by: /workspace/queue/[id], /ops/queue right pane
  • Props/states: item: QueueItem, onResolved.
  • Design notes:
    • Header: id, risk badge, channel badge, status dropdown.
    • Customer thread + AI suggestion panel with ConfidenceBar.
    • Action bar: Accept & Send / Edit / Ignore & Write / Defer / Reassign / Resolve.
    • Internal-collab thread rendered inline, dashed amber border.
    • Risk badge bg/text uses theme-aware --risk-* tokens.

ExpertChatOverlay

  • File: components/internal/ExpertChatOverlay.tsx
  • Used by: Inside PortalChat.tsx (header) when isExpert === true
  • Props/states: conversation, userId, onStatusChange, onAssign.
  • Design notes:
    • Status dropdown (<select> styled to match design system).
    • "Assign to me" button.
    • Renders only when the viewer has expert role.

ConfidenceBar

  • File: components/internal/ConfidenceBar.tsx
  • Used by: AI suggestion panel in TicketDetail, message metadata for experts
  • Props/states: confidence: number (0–100).
  • Design notes:
    • 6px tall horizontal bar.
    • Color: 0–49 danger, 50–69 warning, 70–84 info, 85+ success.
    • Numeric label right-aligned next to the bar (12/600 tabular-nums).
    • Threshold marker (vertical line) at the org's configured threshold.

ResolveForm

  • File: components/internal/ResolveForm.tsx
  • Used by: Ticket detail "Resolve" action (modal)
  • Props/states: ticketId, onResolved, optional correction fields.
  • Design notes:
    • Modal with: resolution outcome (radio), optional correction notes (textarea), error-type select (E-L2 — currently a gap).
    • Primary "Mark resolved", secondary "Cancel".

ConversationHistory

  • File: components/internal/ConversationHistory.tsx
  • Used by: Expert ticket detail, superadmin org detail
  • Props/states: conversationId, paginate?.
  • Design notes: Same MessageBubble rendering as PortalChat but full-history scrollable view; expert-mode by default (shows confidence, internal notes).

StatusBadge

  • File: components/internal/StatusBadge.tsx
  • Used by: Queue rows, ticket detail header, superadmin org list
  • Props/states: status (lifecycle status: pending / in_review / resolved / snoozed / archived).
  • Design notes:
    • Pill, 11px font, 4px radius.
    • Each status has a paired --{semantic}-subtle bg + --{semantic}`` text.

LiveBadge

  • File: components/internal/LiveBadge.tsx
  • Used by: Live-online indicators (e.g. "Online · Support Specialist" in chat header) — though that specific copy is currently inline
  • Props/states: status: "online" | "away" | "offline".
  • Design notes:
    • 8px green dot with animate-pulse-live for online (1.5s pulse).
    • Inline-flex, 6px gap to label.

PoolCard

  • File: components/internal/PoolCard.tsx
  • Used by: /workspace/pools, /ops/pools
  • Props/states: pool: { id, name, domain, memberCount, queueDepth, slaPct }, onOpen.
  • Design notes: Card 200px tall, header (name + domain badge), body stats, footer "View →" link.
  • File: components/Nav.tsx
  • Used by: /integrations, /dashboard (legacy routes pre-role-split)
  • Status: Will be deprecated as those routes migrate to role-prefixed equivalents.

5. analytics/ — chart components (used in any analytics surface)

SummaryCards

  • File: components/analytics/SummaryCards.tsx
  • Used by: /workspace/analytics, /ops/analytics (the client /portal/admin/analytics route was retired in the 2026-05-02 refactor)
  • Props/states: cards: { label, value, delta?, trend? }[].
  • Design notes:
    • 4-up grid, each card: label (uppercase 10/700 muted), value (24/700), delta (12 with semantic color).
    • Border 1px subtle, 12px radius.

VolumeChart

  • File: components/analytics/VolumeChart.tsx
  • Used by: All analytics surfaces
  • Props/states: data: { date, value }[], range.
  • Design notes: Line chart, 240px tall. Stroke --accent, fill --accent-subtle. X-axis ticks 11/muted.

AiVsExpertChart

  • File: components/analytics/AiVsExpertChart.tsx
  • Used by: All analytics surfaces (esp. C-V4)
  • Props/states: data: { date, ai, expert }[].
  • Design notes: Stacked bar chart. AI = --info, Expert = --accent. Legend top-right.

ConfidenceHistogram

  • File: components/analytics/ConfidenceHistogram.tsx
  • Used by: /workspace/analytics, /ops/analytics
  • Props/states: bins: number[].
  • Design notes: 10 bins (0-9, 10-19, …, 90-100). Each bar colored by confidence band (same scale as ConfidenceBar).

ResponseTimeChart

  • File: components/analytics/ResponseTimeChart.tsx
  • Used by: All analytics surfaces
  • Props/states: data: { date, p50, p95 }[].
  • Design notes: Two-line chart. P50 --info, P95 --warning. Y-axis seconds/minutes.

StatusBreakdownChart

  • File: components/analytics/StatusBreakdownChart.tsx
  • Used by: All analytics surfaces
  • Props/states: breakdown: { status, count }[].
  • Design notes: Donut chart. Each slice uses status-paired token (open/success, pending/warning, etc.). Center label = total count.

TopOrgsTable

  • File: components/analytics/TopOrgsTable.tsx
  • Used by: /ops/analytics
  • Props/states: orgs: { id, name, slug, ticketCount, mrr, plan }[].
  • Design notes: Standard table, 13px body. Row hover --bg-hover. Click → /ops/clients/[id].

AnalyticsFilters

  • File: components/analytics/AnalyticsFilters.tsx
  • Used by: All analytics surfaces
  • Props/states: range, onRangeChange, optional org, pool, expert filters.
  • Design notes: Right-aligned filter row above the dashboard. Date-range picker presets (7d / 30d / 90d / Custom).

shared.tsx

  • File: components/analytics/shared.tsx
  • Used by: Internal helpers for the analytics charts
  • Design notes: Common axes, tooltip styling, color tokens. Centralized to keep all charts consistent.

6. Root-level

UserFooter

  • File: components/UserFooter.tsx
  • Used by: PortalChat sidebar, Portal admin sidebar. (The unified /ops/* operator surface and /workspace/* expert surface use the top-nav avatar instead — see INFORMATION_ARCHITECTURE.md §7.)
  • Props/states: reads JWT (hw_token) for name/email/initials/platformRole. Uses useTheme() for the toggle.
  • Design notes:
    • 12px top padding, 8px gap stack.
    • Avatar 32px claret circle with initials.
    • Name 12/600 primary, email 11/muted.
    • Theme toggle 16px icon (sun in dark, moon in light), hover --text-secondary + --bg-hover.
    • Footer links 11/muted, role-aware (Expert sees "My Profile", admin sees "Account Settings"+"Billing", etc.).
    • "Sign out" 11/muted button.

IntegrationStatus

  • File: components/IntegrationStatus.tsx
  • Used by: Integration detail pages (currently legacy)
  • Status: Keeping for compatibility; new code should use IntegrationCard + a fresh detail layout.

slug-availability-input

  • File: components/slug-availability-input.tsx
  • Used by: /ops/clients/new (Step 1 — Company Info)
  • Props/states: value, onChange, onValidityChange. Internal: debounced API check.
  • Design notes:
    • Input with live validation: ✓ green when available, ✗ red when taken/invalid, spinner while checking.
    • Inline preview to the right: ``{value}.human.work in muted monospace.
    • Reserved-words list and personal-domain list enforced client-side; server is the source of truth.

7. Open issues per component (cross-reference IMPLEMENTATION_STATUS.md)

ComponentIssue
PortalChatApproval banner is expert-only; needs client variant (C-W8). Search input not in sidebar (C-W6).
TicketDetailDefer UI not yet shipped (E-R10). Reassign UI not yet shipped (E-R11).
ResolveFormNo error-type select (E-L2).
ServiceWorkerRegistrarPush notification subscription is stubbed (E-P3).
LiveBadgeOnline/away/offline only — no "in another conversation" state.
PoolCardNo detail page yet — clicking goes nowhere meaningful for non-superadmin.
Nav (legacy)To be deleted once /integrations and /dashboard migrate.
WhatsAppQrModalToday's WhatsApp is Twilio number pool — QR is for the alternative Baileys path. Disambiguate copy.
Theme toggleSun/moon icons live inline in UserFooter; consider extracting <ThemeToggle/> to standardize.

Owner: Design + Frontend team