Files
nearle_console/src/components/nearle_components/CLAUDE.md

6.2 KiB
Raw Blame History

CLAUDE.md — src/components/nearle_components/

Rules for editing the shared NearlExpress UI primitives.

These components are imported across every page. Changes here have fan-out impact — measure twice, cut once.


1. What lives here

Component Use Status
LocationAutocomplete.js Zone picker on every operator page Canonical — has pill variant matching DT system
DebounceSearchBar.js 500ms-debounced search with ⌘/Ctrl+K focus Canonical
LoaderWithImage.js Inline branded spinner for "loading more" rows Canonical
GlobalToast.js Global toast wrapper Used at root
SearchBar.js Non-debounced search input Legacy — prefer DebounceSearchBar
TableLoader.js Inline table loading state Legacy — prefer OrdersTableSkeleton
TitleCard.js Old page header Legacy — do not use on new pages. The replacement is the gradient <Paper> header pattern documented in root CLAUDE.md §6, implemented in deliveries.js (search for the comment Header near the first <Paper> in the JSX return).

2. Design system token discipline

The DT design tokens (palette, alpha helpers, pillFieldSx, SoftPaper, AccentAvatar) are documented in the root CLAUDE.md §6 and the source-of-truth implementation is the token block near the top of src/pages/nearle/deliveries/deliveries.js (search for const DT = {).

Hard rules when editing components here:

  • Universal brand colour is #662582 (NearlExpress purple — from themes/theme/default.js primary.main). Every brand surface (page header, dialog header, KPI primary tile, search bars, edit-action buttons, scrollbars) uses this. Gradient pair: #662582 → #9255AB.
  • Semantic status palette is distinct from the brand. Use these for lifecycle indicators only: sky #0ea5e9, emerald #10b981, amber #f59e0b, red #ef4444, status-purple #8b5cf6 (lighter than brand), cyan #06b6d4, teal #14b8a6, orange #f97316, muted #94a3b8, indigo #6366f1 (Accepted status). Don't replace these with brand purple — operators colour-code on them.
  • Don't introduce a colour from theme.palette for new surfaces — those are Mantis defaults and don't match the DT system. Use the hex values above directly.
  • Border radii: 12 (inner), 16 (card), 999 (pill). No other values.
  • Shadows: DT.shadowSoft / DT.shadowMd / DT.shadowPop. No raw box-shadow strings.

Some existing redesigned pages (deliveries.js, Tenants.js, clientPricing.js) still use #6366f1 as the brand accent — this is a legacy from the first design pass. customers.js and the createorder1 Saved-Address dialog are already on #662582. When you next edit one of the legacy pages, migrate it to brand purple in the same PR.


3. LocationAutocomplete — the pill prop is opt-in

The component supports two visual modes, controlled by the pill prop:

// Default (legacy, "Select Zones" label, outlined TextField) — used by old pages
<LocationAutocomplete setAppId={...} setLocoName={...} />

// Pill variant — used by all redesigned pages (deliveries, tenants, pricing, customers)
<LocationAutocomplete
  pill
  accentColor="#6366f1"
  icon={<MdMyLocation size={14} />}
  placeholder="Select Zone"
  paperComponent={SoftPaper}
  setAppId={...}
  setLocoName={...}
/>
  • For any new page: use pill. Always.
  • For existing legacy pages (orders, invoice, riders, etc.): keep the default until that page is redesigned. Don't change them piecemeal.
  • The accentColor defaults to #6366f1 — only override when the page's accent is different (rare).

4. DebounceSearchBar — debounce + ⌘/Ctrl+K shortcut

<DebounceSearchBar
  value={searchword}                       // controlled input value
  onChange={setSearchword}                 // fires on every keystroke
  onDebouncedChange={setDebouncedSearch}   // fires 500ms after the last keystroke
  placeholder="Search (ctrl+k)"
  sx={{ ... }}                             // pill styling lives in the call site, not here
/>
  • Don't lower the debounce below 500ms. TanStack Query's cache keys include debouncedSearch, so each keystroke would cause a new server hit if the debounce drops.
  • ⌘/Ctrl+K to focus and Esc to blur are wired globally inside this component. Don't add competing keyboard shortcuts at the page level using the same keys.
  • The pill aesthetic (rounded 999, tinted bg, accent border) is applied via the sx prop at the call site — see the <DebounceSearchBar usage inside the "Status Tabs + Search" section of deliveries.js for the canonical incantation.

5. When to add a NEW shared component here

Only when:

  1. Used by two or more pages in production code.
  2. Has its own internal state or shortcuts (otherwise just use an AccentAvatar + Box inline).
  3. The component encapsulates a non-trivial pattern that's been duplicated more than twice.

Don't add a wrapper that just renames an MUI primitive (e.g. <NearleButton>). Don't add a component that's a single instance of a styled Paper.


6. When to inline instead

The DT token block at the top of each page is repeated intentionally. Don't extract it into a shared module here. Reasons:

  • It's a 30-line block of constants — repetition is fine.
  • Pages occasionally tweak a token for their own use (e.g. picking different KPI colours). A shared module would lock everyone into the same defaults.
  • Importing from a shared file creates a cross-page coupling that's painful when one page wants to evolve its visual language.

Same logic for SoftPaper, AccentAvatar, pillFieldSx — these are 520 line helpers that live inside each page file. Don't extract.


7. Backwards compatibility

If you change a component's public prop signature:

  • Old call sites still using the old prop name will break silently (React doesn't warn on unknown props).
  • Either: keep the old prop name working (alias both), OR grep src/pages/ for all consumers and update them in the same PR.

The component's forwardRef shape is part of the contract — Tenants.js uses tenantRef / locationRef to imperatively focus inputs. Don't break ref-forwarding.