@schandlergarcia/sf-web-components 1.9.59 → 1.9.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,18 +16,29 @@ These rules apply ONLY when building the Engine Travel Command Center dashboard
16
16
 
17
17
  The Engine dashboard uses a **strict 4-phase build process.** You MUST complete each phase fully before starting the next:
18
18
 
19
- 1. **Phase 1: Layout** — Structure only, placeholders, no real components
20
- 2. **Phase 2: Components + Sample Data** — Full UI with hardcoded realistic data
19
+ 1. **Phase 1: Layout** — Complete layout structure (header, map, glass KPI overlays, flight strip) + data panel placeholders ONLY
20
+ 2. **Phase 2: Components + Sample Data** — Replace data panel placeholders with real library components + sample data
21
21
  - **CRITICAL:** Sample data file already exists at `src/data/engine-sample-data.js`
22
22
  - **DO NOT create a new data file** — just import from the existing one
23
- - Import dashboard-ready derivatives (MAP_MARKERS, TRAVELER_CARDS, etc.)
23
+ - Import dashboard-ready derivatives (MAP_MARKERS, TRAVELER_CARDS, ESCALATION_CARDS, DESTINATION_CHART_DATA)
24
24
  - DO NOT define sample data inline in the dashboard — causes file truncation
25
+ - **FOLLOW THE EXACT CODE EXAMPLES in PRD Section 8c and 8d** - copy the code blocks as shown
26
+ - Panel titles: "Disruptions", "Active Travelers", "Escalations", "Travelers by Destination"
27
+ - Chart must use gradient color array, barRadius: 8, height: 320 (see PRD Section 8d code block)
28
+ - **DO NOT run validation or dev server** — phase is complete after wiring files
25
29
  3. **Phase 3: Real Data** — Connect to Salesforce, keep UI identical to Phase 2
26
30
  4. **Phase 4: Agent** — Add Eva ChatBar integration
27
31
 
28
- ### Phase 1 Placeholder Format
32
+ ### Phase 1 Scope
29
33
 
30
- **Data panels** use `BaseCard` with centered placeholder text. NO titles on placeholders:
34
+ **What to build in Phase 1:**
35
+ - ✅ Header bar with logo, title, and theme toggle (use slate scale colors, NO text-white)
36
+ - ✅ Hero map (GeoMap component with NO markers/arcs/overlays PROPS passed)
37
+ - ✅ Glass KPI overlays (4 hardcoded values, positioned absolutely over map)
38
+ - ✅ Flight status strip (4 hardcoded flights, positioned at map bottom)
39
+ - ✅ Data panel placeholders (BaseCard with centered text) - **ONLY these are placeholders**
40
+
41
+ **Data panel placeholders** use `BaseCard` with centered placeholder text. NO titles on placeholders:
31
42
 
32
43
  ```tsx
33
44
  <BaseCard>
@@ -40,13 +51,14 @@ The Engine dashboard uses a **strict 4-phase build process.** You MUST complete
40
51
  **Hero map** renders the actual GeoMap component (empty, no data):
41
52
 
42
53
  ```tsx
43
- import { GeoMap, useAppTheme } from "@/components/library";
54
+ import { GeoMap } from "@/components/library";
55
+ import { useThemeMode } from "@/components/library/theme/AppThemeProvider";
44
56
 
45
57
  export default function EngineDashboard() {
46
- const { mode } = useAppTheme();
58
+ const { mode } = useThemeMode();
47
59
 
48
60
  return (
49
- <div className="relative" style={{ flex: "1.15 1 0", minHeight: 0 }}>
61
+ <div className="relative h-[520px]">
50
62
  <GeoMap
51
63
  width={960}
52
64
  height={520}
@@ -60,13 +72,18 @@ export default function EngineDashboard() {
60
72
 
61
73
  All data panel placeholders: BaseCard, no title, centered text, `h-48`, `text-slate-400`.
62
74
 
63
- Hero map in Phase 1: actual GeoMap component (no markers/arcs/overlays yet), NOT wrapped in BaseCard.
75
+ Hero map in Phase 1: actual GeoMap component with NO `markers`/`arcs`/`overlays` props passed (these are GeoMap data props for Phase 2+). The base world map (land, sphere, graticule) will render even with no data. Glass KPI overlays and flight status strip ARE built in Phase 1 as separate `<div>` elements positioned absolutely over the map - these provide visual confirmation the map area is rendering. GeoMap is NOT wrapped in BaseCard.
76
+
77
+ **Verify the map renders:** After building, check that you can see the world map base layer (blue land on dark theme, gray land on light theme). If the map area appears blank, check:
78
+ - Container has fixed height (`className="relative h-[520px]"`)
79
+ - GeoMap has `className="h-full w-full"`
80
+ - No console errors from GeoMap component
64
81
 
65
82
  **DO NOT:**
66
83
  - Mix phases (don't add sample data in Phase 1, don't add Eva in Phase 2, etc.)
67
- - Skip validation between phases
68
- - Proceed to the next phase with validator errors
84
+ - Run `npm run dev` or `npm run validate:dashboard` (wastes turns, not required)
69
85
  - Use BaseCard titles in Phase 1 placeholders (causes text to run together)
86
+ - Use `h-screen` or viewport-locked layout (full-page scroll required)
70
87
 
71
88
  ### Phase 3: Real Data Integration
72
89
 
@@ -138,29 +155,13 @@ The `useDataSource` hook automatically uses `live` data when available, falling
138
155
 
139
156
  **Troubleshooting:** If you encounter GraphQL schema introspection failures, see `.a4drules/troubleshooting/graphql-introspection-failure.md` for the complete workaround pattern.
140
157
 
141
- ## Validation Checkpoints (ZERO ERRORS REQUIRED)
142
-
143
- After EVERY change, run the validator from the webapp directory:
144
-
145
- ```bash
146
- cd force-app/main/default/webapplications/reactapp4
147
- npm run validate:dashboard
148
- ```
158
+ ## Phase Completion (NO VALIDATION REQUIRED)
149
159
 
150
- **Zero errors required.** If the validator reports ANY errors:
151
- 1. Read the error message carefully
152
- 2. Identify which rule was violated
153
- 3. Fix it by switching to the correct library component
154
- 4. Re-run the validator
155
- 5. Repeat until zero errors
160
+ After wiring the dashboard into CommandCenter, Home, and routes, the phase is complete.
156
161
 
157
- **Common fixes:**
158
- - "Hand-rolled card detected" → Wrap in `WidgetCard`, `ListCard`, `BaseCard`, etc.
159
- - "Forbidden color: text-white" → Change to `text-slate-50` or `text-slate-900`
160
- - "shadcn import detected" → Replace with library equivalent from `@/components/library`
161
- - "Missing useDataSource" → Add `useDataSource({ sample, live })` pattern
162
+ **🚫 CRITICAL: DO NOT run `npm run dev` or `npm run validate:dashboard`**
162
163
 
163
- Do NOT report the phase as complete until the validator shows zero errors.
164
+ These commands are NOT required for phase completion. Do NOT execute them. The phase is complete after wiring the files.
164
165
 
165
166
  ## File Requirements
166
167
 
@@ -168,15 +169,18 @@ Do NOT report the phase as complete until the validator shows zero errors.
168
169
  - **Location:** `src/pages/EngineDashboard.tsx` (NOT `src/components/pages/`)
169
170
  - **Imports:** ONLY from `@/components/library` — never shadcn, never Lucide, never Recharts
170
171
 
171
- ## Layout Pattern: Visualization-Hero
172
+ ## Layout Pattern: Visualization-Hero with Full-Page Scroll
172
173
 
173
174
  The Engine dashboard uses the **visualization-hero** layout (see PRD section 5). This means:
174
175
 
175
- 1. **Hero map:** Full-width, large (`flex: 1.15 1 0`), GeoMap with glass overlays and flight status strip
176
- 2. **Data panels below:** Standard grid sections (`flex: 1 1 0`)
176
+ 1. **Hero map:** Full-width, fixed height (`h-[520px]`), GeoMap with glass overlays and flight status strip
177
+ 2. **Data panels below:** Natural flow with `px-4 py-5` (NO overflow constraints)
178
+ 3. **Full-page scroll:** Entire dashboard scrolls naturally (NO `h-screen` on outer container)
177
179
 
178
180
  **DO NOT:**
179
181
  - Put the map in a 1/3 or 1/2 grid column (it's hero, not sidebar)
182
+ - Use `h-screen` or viewport-locked layout (full-page scroll required)
183
+ - Use `overflow-y-auto` or flex height constraints on data panels
180
184
  - Wrap GeoMap in ChartCard (render directly)
181
185
  - Skip the glass KPI overlays or flight status strip
182
186
  - Make the map too small (minimum 400px height)
@@ -295,8 +299,9 @@ These elements distinguish the Engine dashboard from generic dashboards. They mu
295
299
  - Multi-tab layout with content swapping (build one scrollable page)
296
300
  - `<nav>` or header bar inside the dashboard (AppLayout handles navigation)
297
301
  - Map in a sidebar grid (it's hero — full width)
302
+ - **Using `h-screen` or viewport-locked layout** (full-page scroll required)
298
303
  - More than 4 KPIs in a row
299
304
  - Using `Math.random()` in sample data
300
- - Skipping validator errors
305
+ - **Running `npm run dev` or `npm run validate:dashboard`** (not required, wastes turns)
301
306
  - Reporting phase complete before wiring the dashboard into the app
302
307
  - Mixing phases (adding sample data in Phase 1, adding Eva in Phase 2, etc.)
@@ -8,6 +8,18 @@ paths:
8
8
 
9
9
  Before writing any code for command center dashboards, verify these requirements from the PRD and skills.
10
10
 
11
+ ## FIRST: Read These Files
12
+
13
+ **Before writing a single line of code, read these files:**
14
+ 1. `.a4drules/skills/component-library/SKILL.md` (lines 15-40) - Import Pattern section
15
+ 2. `engine-command-center-prd.md` - Phase 1 Placeholder Rules section
16
+ 3. This file - Phase 1 Code Template section
17
+
18
+ **Verify you know:**
19
+ - [ ] Exact import statement for `useThemeMode` hook
20
+ - [ ] What "Phase 1 placeholder" means (data panels ONLY, not entire dashboard)
21
+ - [ ] Which colors are forbidden (`text-white`, `text-black`, `bg-black` without opacity)
22
+
11
23
  ## File Creation Checklist
12
24
 
13
25
  When creating a new dashboard file, confirm:
@@ -15,7 +27,83 @@ When creating a new dashboard file, confirm:
15
27
  1. **File path:** `src/pages/DashboardName.tsx` (NOT `src/components/pages/`)
16
28
  2. **File extension:** `.tsx` (NOT `.jsx`) — this is a TypeScript project
17
29
  3. **Imports:** `@/components/library` ONLY (NOT `@/components/ui/`, NOT `lucide-react`, NOT `recharts`)
18
- 4. **Colors:** Slate scale ONLY (NOT `text-white`, NOT `text-black`, NOT `bg-black`)
30
+ 4. **Import names:** Check SKILL.md for exact names DO NOT guess or invent import names
31
+ - Theme toggle: `useThemeMode` (NOT `useAppTheme`, NOT `useTheme`)
32
+ - Data source: `import useDataSource from "..."` (default export, NOT named)
33
+ 5. **Colors:** Slate scale ONLY (NOT `text-white`, NOT `text-black`, NOT `bg-black`)
34
+
35
+ ## Phase 1 Code Template
36
+
37
+ **START WITH THIS EXACT STRUCTURE:**
38
+
39
+ ```tsx
40
+ import { GeoMap, BaseCard } from "@/components/library";
41
+ import { useThemeMode } from "@/components/library/theme/AppThemeProvider";
42
+ import { /* Heroicons */ } from "@heroicons/react/24/outline";
43
+
44
+ export default function EngineDashboard() {
45
+ const { mode, toggle } = useThemeMode();
46
+
47
+ return (
48
+ <div className="flex flex-col bg-slate-50 dark:bg-slate-950">
49
+ {/* Header Bar - h-12, sticky, slate-900 bg */}
50
+ <header className="sticky top-0 z-50 flex h-12 items-center justify-between border-b border-slate-800 bg-slate-900 px-4">
51
+ {/* Logo + title with text-slate-50 (NOT text-white) */}
52
+ </header>
53
+
54
+ {/* Hero Map - fixed height h-[520px], GeoMap renders world automatically */}
55
+ <div className="relative h-[520px]">
56
+ <GeoMap width={960} height={520} theme={mode === "dark" ? "dark" : "light"} className="h-full w-full" />
57
+
58
+ {/* Glass KPI overlays - positioned absolutely, text-slate-50 */}
59
+ <div className="absolute left-3 top-3 flex gap-2">
60
+ {/* 4 KPI divs with border-white/10, bg-black/40, backdrop-blur-md */}
61
+ </div>
62
+
63
+ {/* Flight status strip - positioned absolutely at bottom */}
64
+ <div className="absolute bottom-3 left-3 right-3 flex gap-2 overflow-x-auto">
65
+ {/* 4 flight divs with status badges */}
66
+ </div>
67
+ </div>
68
+
69
+ {/* Data Panels - natural flow, full-page scroll, 4 panels total */}
70
+ <div className="px-4 py-5">
71
+ <div className="space-y-6">
72
+ {/* Row 1: Disruptions (1/3) + Active Travelers (2/3) */}
73
+ <div className="grid grid-cols-1 items-start gap-4 lg:grid-cols-3">
74
+ <BaseCard>
75
+ <div className="flex h-48 items-center justify-center text-slate-400">
76
+ Disruptions Panel
77
+ </div>
78
+ </BaseCard>
79
+ <div className="lg:col-span-2">
80
+ <BaseCard>
81
+ <div className="flex h-48 items-center justify-center text-slate-400">
82
+ Active Travelers Panel
83
+ </div>
84
+ </BaseCard>
85
+ </div>
86
+ </div>
87
+
88
+ {/* Row 2: Escalations (1/2) + Destination Chart (1/2) */}
89
+ <div className="grid grid-cols-1 items-start gap-4 lg:grid-cols-2">
90
+ <BaseCard>
91
+ <div className="flex h-48 items-center justify-center text-slate-400">
92
+ Escalations Panel
93
+ </div>
94
+ </BaseCard>
95
+ <BaseCard>
96
+ <div className="flex h-48 items-center justify-center text-slate-400">
97
+ Travelers by Destination Panel
98
+ </div>
99
+ </BaseCard>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ </div>
104
+ );
105
+ }
106
+ ```
19
107
 
20
108
  ## During Code Generation Checklist
21
109
 
@@ -25,9 +113,19 @@ As you write the dashboard code:
25
113
  2. **Every chart** uses `ChartCard` + `D3Chart` or `GeoMap` — NO Recharts, NO Chart.js, NO custom SVG
26
114
  3. **Every color** uses semantic classes or slate scale — NO `text-white`, NO `bg-black`, NO hardcoded hex
27
115
  4. **Dark mode** on every element — `dark:` variants on all custom styling
28
- 5. **Phase 1 placeholders:**
29
- - Data panels: use BaseCard with NO title prop, centered text
30
- - Hero map: render actual GeoMap component (empty, no markers/arcs/overlays), NOT wrapped in BaseCard
116
+ 5. **Phase 1 scope - Build COMPLETE layout structure:**
117
+ - Outer container: `className="flex flex-col bg-slate-50 dark:bg-slate-950"` (NO `h-screen` - full-page scroll)
118
+ - Header bar (logo, title, actions) with slate scale colors (NO text-white)
119
+ - ✅ Header text: ONLY "ENGINE" + "Travel Command Center" (NO "Powered by..." branding in Phase 1)
120
+ - ✅ Hero map container: `className="relative h-[520px]"` (fixed height, NOT flex-based)
121
+ - ✅ Hero map (GeoMap component with NO markers/arcs/overlays PROPS, `className="h-full w-full"`)
122
+ - ✅ Glass KPI overlays (4 hardcoded KPIs, positioned absolutely over map)
123
+ - ✅ Flight status strip (4 hardcoded flights, positioned at map bottom)
124
+ - ✅ Data panels container: `className="px-4 py-5"` (NO `overflow-y-auto`, NO flex constraints - natural flow)
125
+ - ✅ **4 data panel placeholders** (2 rows: Disruptions/Travelers, Escalations/Destinations) - BaseCard with NO title prop, centered text
126
+ - ❌ **Phase 1 EXCLUDES:** Salesforce/Data Cloud branding (Phase 4), ChatBar (Phase 4), real data (Phase 2+)
127
+ - "Placeholder" means data panels below the map, NOT the header/overlays/map
128
+ - **Full-page scroll:** Entire dashboard scrolls naturally (map scrolls up as user scrolls down)
31
129
 
32
130
  ## After Code Generation Checklist
33
131
 
@@ -38,13 +136,33 @@ After writing the dashboard code:
38
136
  - [ ] `Home.tsx` renders `CommandCenter`
39
137
  - [ ] `routes.tsx` has correct routes
40
138
 
41
- 2. **Validation:**
42
- ```bash
43
- cd force-app/main/default/webapplications/reactapp4
44
- npm run validate:dashboard
45
- ```
46
- - [ ] Zero errors required
47
- - [ ] Fix all errors before proceeding
139
+ 2. **Completion:**
140
+ - [ ] All files wired correctly
141
+ - [ ] **DO NOT run `npm run dev` or `npm run validate:dashboard`** - not required for ANY phase completion
142
+
143
+ ## Color Reference (CRITICAL)
144
+
145
+ **NEVER use these:**
146
+
147
+ | ❌ FORBIDDEN | ✅ USE INSTEAD | Where |
148
+ |-------------|---------------|-------|
149
+ | `text-white` | `text-slate-50` | Header text, overlay text |
150
+ | `text-black` | `text-slate-900` | Body text (light mode) |
151
+ | `bg-black` | `bg-slate-900` or `bg-black/40` (with opacity) | Backgrounds |
152
+ | `bg-white` | `bg-slate-50` | Page background (light mode) |
153
+
154
+ **Exception:** `bg-black/40`, `bg-white/10`, `border-white/10` are allowed (opacity variants for glass effect)
155
+
156
+ ## Verification Checklist
157
+
158
+ After building, you should see:
159
+ - [ ] Header bar with Engine logo and "Travel Command Center" title
160
+ - [ ] **World map visible** (blue/teal land on dark background OR gray land on light background)
161
+ - [ ] 4 glass KPI boxes in top-left of map (semi-transparent with numbers)
162
+ - [ ] 4 flight status boxes at bottom of map (with colored badges)
163
+ - [ ] **4 white/dark cards below map** (2 rows: row 1 has 1/3 + 2/3 split, row 2 has 1/2 + 1/2 split)
164
+ - [ ] Page scrolls when you scroll the data panels section
165
+ - [ ] Theme toggle works (sun/moon icon in header)
48
166
 
49
167
  ## Quick Reference
50
168
 
@@ -53,10 +171,11 @@ After writing the dashboard code:
53
171
  | File path? | `src/pages/EngineDashboard.tsx` |
54
172
  | Extension? | `.tsx` (TypeScript) |
55
173
  | Import from? | `@/components/library` |
56
- | Colors? | Slate scale (`text-slate-50`, `bg-slate-900`) |
174
+ | Hook import? | `import { useThemeMode } from "@/components/library/theme/AppThemeProvider"` |
175
+ | Colors? | Slate scale (`text-slate-50`, `bg-slate-900`) - NEVER `text-white` |
57
176
  | Cards? | Library components (MetricCard, ListCard, etc.) |
58
177
  | Charts? | `ChartCard` + `D3Chart` or `GeoMap` |
59
- | Validate? | `npm run validate:dashboard` zero errors |
178
+ | After building? | Wire into CommandCenter/Home/routes - DO NOT run dev server |
60
179
 
61
180
  ## Common Mistakes to Avoid
62
181
 
@@ -66,6 +185,30 @@ After writing the dashboard code:
66
185
  ❌ `bg-black` → ✅ `bg-slate-900`
67
186
  ❌ `<div className="bg-white border rounded-lg p-4">` → ✅ `<BaseCard>` or `<WidgetCard>`
68
187
  ❌ `import { Button } from '@/components/ui/button'` → ✅ `import { UIButton } from '@/components/library'`
188
+ ❌ `import { useAppTheme } from '@/components/library'` → ✅ `import { useThemeMode } from '@/components/library'`
189
+ ❌ `"Powered by Salesforce Data Cloud"` in Phase 1 → ✅ This is Phase 4 only (see PRD Section 10)
190
+ ❌ Running `npm run dev` after building → ✅ Not needed - validation is sufficient
191
+
192
+ ## Troubleshooting
193
+
194
+ **If you get TypeScript error about imports:**
195
+ 1. ❌ DO NOT follow "did you mean default import?" suggestion
196
+ 2. ✅ READ `.a4drules/skills/component-library/SKILL.md` Import Pattern section
197
+ 3. ✅ USE the exact import shown in the docs
198
+
199
+ **If map doesn't render:**
200
+ 1. ✅ Verify container has `style={{ flex: "1.15 1 0", minHeight: 0 }}`
201
+ 2. ✅ Verify GeoMap has `className="h-full w-full"`
202
+ 3. ✅ GeoMap shows world map automatically - no props needed
203
+
204
+ **If colors look wrong:**
205
+ 1. ✅ Search your code for `text-white` - should be `text-slate-50`
206
+ 2. ✅ Search your code for `text-black` - should be `text-slate-900`
207
+ 3. ✅ Exception: `bg-black/40` and `border-white/10` (with opacity) are OK
208
+
209
+ **If data panels don't scroll:**
210
+ 1. ✅ Verify data panels container has `overflow-y-auto` className
211
+ 2. ✅ Verify it has `style={{ flex: "1 1 0" }}`
69
212
 
70
213
  ## Enforcement
71
214
 
@@ -14,18 +14,55 @@ Vendored from command-center-starter. Do not modify library files.
14
14
 
15
15
  ## Import Pattern
16
16
 
17
+ **CRITICAL: Do NOT guess or invent import names.** Check this file for exact names before writing imports.
18
+
17
19
  ```tsx
18
20
  // Named imports from the barrel (preferred)
19
21
  import { MetricCard, ChartCard, TableCard, ListCard } from "@/components/library";
20
22
 
21
23
  // Default exports that need direct import
22
- import useDataSource from "@/components/library/data/useDataSource";
23
- import { useThemeMode } from "@/components/library/theme/AppThemeProvider";
24
+ import useDataSource from "@/components/library/data/useDataSource"; // DEFAULT export
25
+ import { useThemeMode } from "@/components/library/theme/AppThemeProvider"; // NAMED export
24
26
 
25
27
  // Import types (TypeScript)
26
28
  import type { MetricCardProps } from "@/components/library";
27
29
  ```
28
30
 
31
+ **Common name mistakes:**
32
+ - ❌ `useAppTheme` → ✅ `useThemeMode`
33
+ - ❌ `useTheme` → ✅ `useThemeMode`
34
+ - ❌ `import { useDataSource }` → ✅ `import useDataSource` (no braces, default export)
35
+
36
+ ---
37
+
38
+ ## Do Not
39
+
40
+ - **Guess or invent import names** — always check this file first. Common mistakes: `useAppTheme` (doesn't exist), `useTheme` (doesn't exist) → use `useThemeMode`
41
+ - Use `import { useAppTheme }` or `import useThemeMode` (default) — **both are wrong**. The hook is `useThemeMode` (named export), the component is `AppThemeProvider` (default export). Correct: `import { useThemeMode } from "@/components/library/theme/AppThemeProvider"`. If TypeScript suggests "did you mean default import?" when you have the wrong name, check the docs — don't blindly switch to default import
42
+ - `import { useDataSource }` — it's a **default** export, use `import useDataSource from "..."`
43
+ - Import from individual library files when the barrel exports it
44
+ - Modify vendored library files
45
+ - Import shadcn (`@/components/ui/`) in command center code — shadcn components (`Button`, `Card`, `Input`, `Select`, `Alert`, `Skeleton`, etc.) exist for the outer app only. In command center pages, use the equivalent library component (`UIButton`, `BaseCard`/`WidgetCard`, `UIInput`, `Select`, `Alert`, `Skeleton`, etc. from `@/components/library`)
46
+ - Use Lucide icons (`lucide-react`) in command center code — use Heroicons (`@heroicons/react`) instead
47
+ - Pass `items` to ActivityCard — use `actions`
48
+ - Pass children to CalloutCard — use `message` prop
49
+ - Pass `(row)` to TableCard render — it receives `(value, row)`
50
+ - Use `template` prop on D3Chart — use `renderChart` function reference
51
+ - Wrap GeoMap in ChartCard — render directly in a container div
52
+ - Use ActivityCard for scrollable feeds — use ListCard with `maxBodyHeight`
53
+ - Use raw `Modal` for form dialogs — use `FormModal` instead
54
+ - Use `Tabs` as page-level navigation — only use inside cards for sub-sections
55
+ - Pass `filteredData` to components — use `sortedData` from usePageFilters
56
+ - Use `CardSkeleton` and `Skeleton` interchangeably — `CardSkeleton` for card placeholders, `Skeleton` for inline shapes
57
+ - Recreate form state manually — use `useFormState` hook
58
+ - Use `ChatPanel` on dashboards — use `ChatBar` (command palette style)
59
+ - Pass children to `WidgetCard` — it ignores children and shows "No sections." Use the `sections` prop instead: `<WidgetCard sections={[{ id: "main", content: <div>...</div> }]} />`
60
+ - Add `p-5`, `p-6`, etc. to WidgetCard `header` or section `content` — BaseCard already applies `p-4` padding, so extra padding causes double spacing
61
+ - Pass initials strings as `avatar` in ListCard items — `avatar: "MR"` is treated as an image URL and breaks. Instead, omit `avatar` to auto-generate initials from `title`/`name`, or pass a ReactNode like `<Avatar initials="MR" />`
62
+ - Hand-roll a card container (`<div className="bg-white border rounded ...">`) when `WidgetCard` with a single section can wrap your custom content
63
+ - Use Recharts, Chart.js, or any third-party chart library — only `D3Chart` and `GeoMap` are allowed
64
+ - Dismiss `validate:dashboard` errors as "justified" — every error has a library component fix
65
+
29
66
  ---
30
67
 
31
68
  ## When to Use Each Component
@@ -998,31 +1035,3 @@ import { ScrollShadow } from "@/components/library";
998
1035
  </ScrollShadow>
999
1036
  ```
1000
1037
  Adds fade shadows at scroll edges to indicate more content.
1001
-
1002
- ---
1003
-
1004
- ## Do Not
1005
-
1006
- - Import from individual library files when the barrel exports it
1007
- - Modify vendored library files
1008
- - Import shadcn (`@/components/ui/`) in command center code — shadcn components (`Button`, `Card`, `Input`, `Select`, `Alert`, `Skeleton`, etc.) exist for the outer app only. In command center pages, use the equivalent library component (`UIButton`, `BaseCard`/`WidgetCard`, `UIInput`, `Select`, `Alert`, `Skeleton`, etc. from `@/components/library`)
1009
- - Use Lucide icons (`lucide-react`) in command center code — use Heroicons (`@heroicons/react`) instead
1010
- - `import { useDataSource }` — it's a **default** export
1011
- - Pass `items` to ActivityCard — use `actions`
1012
- - Pass children to CalloutCard — use `message` prop
1013
- - Pass `(row)` to TableCard render — it receives `(value, row)`
1014
- - Use `template` prop on D3Chart — use `renderChart` function reference
1015
- - Wrap GeoMap in ChartCard — render directly in a container div
1016
- - Use ActivityCard for scrollable feeds — use ListCard with `maxBodyHeight`
1017
- - Use raw `Modal` for form dialogs — use `FormModal` instead
1018
- - Use `Tabs` as page-level navigation — only use inside cards for sub-sections
1019
- - Pass `filteredData` to components — use `sortedData` from usePageFilters
1020
- - Use `CardSkeleton` and `Skeleton` interchangeably — `CardSkeleton` for card placeholders, `Skeleton` for inline shapes
1021
- - Recreate form state manually — use `useFormState` hook
1022
- - Use `ChatPanel` on dashboards — use `ChatBar` (command palette style)
1023
- - Pass children to `WidgetCard` — it ignores children and shows "No sections." Use the `sections` prop instead: `<WidgetCard sections={[{ id: "main", content: <div>...</div> }]} />`
1024
- - Add `p-5`, `p-6`, etc. to WidgetCard `header` or section `content` — BaseCard already applies `p-4` padding, so extra padding causes double spacing
1025
- - Pass initials strings as `avatar` in ListCard items — `avatar: "MR"` is treated as an image URL and breaks. Instead, omit `avatar` to auto-generate initials from `title`/`name`, or pass a ReactNode like `<Avatar initials="MR" />`
1026
- - Hand-roll a card container (`<div className="bg-white border rounded ...">`) when `WidgetCard` with a single section can wrap your custom content
1027
- - Use Recharts, Chart.js, or any third-party chart library — only `D3Chart` and `GeoMap` are allowed
1028
- - Dismiss `validate:dashboard` errors as "justified" — every error has a library component fix
@@ -251,10 +251,9 @@ if (response?.errors?.length) {
251
251
  }
252
252
 
253
253
  const accounts = response?.data?.uiapi?.query?.Account?.edges?.map(e => e.node) ?? [];
254
+ ```
254
255
 
255
- ---
256
-
257
- ## Sample Data Cache Pattern
256
+ ### Sample Data Cache Pattern
258
257
 
259
258
  The app uses `useDataSource` to provide a sample data cache for optimal performance:
260
259
 
@@ -279,63 +278,6 @@ const travelers = useDataSource({
279
278
  3. The cache provides instant loading and offline capability
280
279
  4. All code is production-ready — switching to live data requires only changing the flag
281
280
 
282
- **Example implementation:**
283
-
284
- ```typescript
285
- // 1. Create the data hook with real GraphQL query
286
- function useTravelers() {
287
- const [data, setData] = useState<any[] | null>(null);
288
- const [loading, setLoading] = useState(true);
289
- const [error, setError] = useState<Error | null>(null);
290
-
291
- useEffect(() => {
292
- async function fetchData() {
293
- try {
294
- const sdk = await createDataSDK();
295
- const response = await sdk.graphql?.(GET_TRAVELERS);
296
-
297
- if (response?.errors?.length) {
298
- throw new Error(response.errors.map((e: any) => e.message).join("; "));
299
- }
300
-
301
- const travelers = response?.data?.uiapi?.query?.Contact?.edges?.map((e: any) => e.node) ?? [];
302
- setData(travelers);
303
- } catch (err) {
304
- setError(err instanceof Error ? err : new Error(String(err)));
305
- } finally {
306
- setLoading(false);
307
- }
308
- }
309
- fetchData();
310
- }, []);
311
-
312
- return { data, loading, error };
313
- }
314
-
315
- // 2. Use in component with useDataSource pattern
316
- function TravelersPanel() {
317
- const { data: liveTravelers } = useTravelers();
318
- const travelers = useDataSource({
319
- sample: SAMPLE_TRAVELERS,
320
- live: liveTravelers ?? [],
321
- });
322
-
323
- return <TravelersList travelers={travelers} />;
324
- }
325
- ```
326
-
327
- **Benefits:**
328
- - ✓ Instant data loading (no network latency)
329
- - ✓ No API rate limiting concerns
330
- - ✓ Consistent data for demos and testing
331
- - ✓ Works offline
332
- - ✓ Reduced backend load
333
-
334
- **DO NOT:**
335
- - Disable the cache or mention it as a "demo mode" limitation
336
- - Skip building real GraphQL queries — always build them
337
- - Add toggle UI for switching between sample/live — the flag handles it
338
-
339
281
  ---
340
282
 
341
283
  ## REST API Patterns
package/CHANGELOG.md CHANGED
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.9.60] - 2026-04-01
9
+
10
+ ### Updated
11
+ - **Synced .a4drules and PRD from reactapp4** - Updated all documentation and rules
12
+ - `.a4drules/features/engine-dashboard-rule.md` - Updated Phase 1/Phase 2 guidance with exact code examples
13
+ - Added specific instructions to follow PRD Section 8c/8d code blocks exactly
14
+ - Clarified Phase 1 includes glass KPI overlays and flight status strip (not just placeholders)
15
+ - Added chart configuration details (gradient colors, barRadius: 8, height: 320)
16
+ - Fixed import example to use `useThemeMode` (not `useAppTheme`)
17
+ - `.a4drules/features/command-center-dashboard-rule.md` - Latest dashboard rules
18
+ - `.a4drules/features/phase2-data-pattern.md` - Sample data wiring patterns
19
+ - `.a4drules/features/pre-code-checklist.md` - Pre-implementation checklist
20
+ - `.a4drules/skills/` - All skills updated from reactapp4
21
+ - `.a4drules/troubleshooting/` - Troubleshooting guides
22
+ - `.a4drules/validation-requirements.md` - Latest validation rules
23
+ - `.a4drules/webapp-data.md` - Data access patterns
24
+ - `.a4drules/webapp-ui.md` - UI platform rules
25
+ - `data/engine-command-center-prd.md` - Latest PRD with updated build instructions
26
+
27
+ ### Context
28
+ The reactapp4 project had the most up-to-date Engine Travel Command Center documentation including the corrected `useThemeMode` hook import pattern and detailed phase-by-phase build instructions. This sync ensures all new projects get the latest guidance.
29
+
8
30
  ## [1.9.59] - 2026-04-01
9
31
 
10
32
  ### Fixed
@@ -80,54 +80,56 @@ This dashboard uses the **visualization-hero** layout. The live flight map is th
80
80
  │ HEADER BAR (h-12, sticky) │
81
81
  │ Engine logo + "Travel Command Center" | ChatBar | actions │
82
82
  ├─────────────────────────────────────────────────────────────┤
83
- │ HERO MAP (flex: 1.15 1 0, GeoMap, dark theme)
84
- │ │
85
- │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
86
- │ │ KPI │ │ KPI │ │ KPI │ │ KPI │ ← glass │
87
- │ │ overlay │ │ overlay │ │ overlay │ │ overlay │ overlays │
88
- │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
89
- │ │
90
- │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ← flight │
91
- │ │ BA286 │ │ NH109 │ │ LH431 │ │ SQ 37 │ status │
92
- │ └───────┘ └───────┘ └───────┘ └───────┘ strip │
93
- ├─────────────────────────────────────────────────────────────┤
94
- │ DATA PANELS (flex: 1 1 0, px-4 py-5, space-y-6)
95
- │ │
96
- │ ┌─── 1/3 ───────┐ ┌─── 2/3 ────────────────────┐ │
97
- │ │ Disruptions │ │ Active Travelers │ │
98
- │ │ (custom panel) │ │ (expandable cards, scroll) │ │
99
- │ └────────────────┘ └────────────────────────────┘ │
100
- │ │
101
- │ ┌─── 1/2 ───────┐ ┌─── 1/2 ────────────────────┐ │
102
- │ │ Eva Activity │ │ Travelers by Destination │ │
103
- │ │ (ActivityCard) │ │ (ChartCard + D3Chart bar) │ │
104
- │ └────────────────┘ └────────────────────────────┘ │
105
- │ │
106
- │ ┌─── full width ────────────────────────────────┐ │
107
- │ │ Upcoming Bookings (TableCard, searchable, │ │
108
- │ │ sortable, paginated) │ │
109
- │ └────────────────────────────────────────────────┘ │
110
- │ │
111
- │ ┌─── 1/2 ───────┐ ┌─── 1/2 ────────────────────┐ │
112
- │ │ Policy Status │ │ Monthly Travel Spend │ │
113
- │ │ (StatusCard) │ │ (ChartCard + D3Chart line) │ │
114
- │ └────────────────┘ └────────────────────────────┘ │
83
+ │ HERO MAP (h-[520px] or h-[600px], GeoMap)
84
+ │ │ ↕ Full-page
85
+ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ ↕ scroll
86
+ │ │ KPI │ │ KPI │ │ KPI │ │ KPI │ ← glass │
87
+ │ │ overlay │ │ overlay │ │ overlay │ │ overlay │ overlays │
88
+ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
89
+ │ │
90
+ │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ← flight │
91
+ │ │ BA286 │ │ NH109 │ │ LH431 │ │ SQ 37 │ status │
92
+ │ └───────┘ └───────┘ └───────┘ └───────┘ strip │
93
+ ├─────────────────────────────────────────────────────────────┤
94
+ │ DATA PANELS (px-4 py-5, space-y-6, natural flow)
95
+ │ │
96
+ │ ┌─── 1/3 ───────┐ ┌─── 2/3 ────────────────────┐ │
97
+ │ │ Disruptions │ │ Active Travelers │ │
98
+ │ │ (custom panel) │ │ (expandable cards, scroll) │ │
99
+ │ └────────────────┘ └────────────────────────────┘ │
100
+ │ │
101
+ │ ┌─── 1/2 ───────┐ ┌─── 1/2 ────────────────────┐ │
102
+ │ │ Escalations │ │ Travelers by Destination │ │
103
+ │ │ (ActivityCard) │ │ (ChartCard + D3Chart) │ │
104
+ │ └────────────────┘ └────────────────────────────┘ │
115
105
  └─────────────────────────────────────────────────────────────┘
116
106
  ```
117
107
 
118
108
  ### Layout Rules
119
109
 
120
- - Hero map: `<div className="relative" style={{ flex: "1.15 1 0", minHeight: 0 }}>`
121
- - Data panels: `style={{ flex: "1 1 0" }}` with `px-4 py-5` and `space-y-6`
122
- - Disruptions + Travelers: `grid grid-cols-1 items-start gap-4 lg:grid-cols-3` (disruptions 1/3, travelers `lg:col-span-2`)
123
- - Eva + Chart: `grid grid-cols-1 items-start gap-4 lg:grid-cols-2`
124
- - Bookings table: full width
125
- - Policy + Spend: `grid grid-cols-1 items-start gap-4 lg:grid-cols-2`
110
+ **CRITICAL: Full-page scroll, NOT viewport-locked sections.**
111
+
112
+ The entire dashboard scrolls as one page. Do NOT use `h-screen` or flex height constraints that lock sections to viewport.
113
+
114
+ - **Outer container:** `<div className="flex flex-col bg-slate-50 dark:bg-slate-950">` (NO `h-screen`)
115
+ - **Hero map:** Fixed height `h-[520px]` or `h-[600px]` with `relative` positioning for glass overlays
116
+ - **Data panels:** Natural flow with `px-4 py-5 space-y-6` (NO `overflow-y-auto`, NO flex height constraints)
117
+ - **Row 1** - Disruptions + Travelers: `grid grid-cols-1 items-start gap-4 lg:grid-cols-3` (disruptions 1/3, travelers `lg:col-span-2`)
118
+ - **Row 2** - Escalations + Chart: `grid grid-cols-1 items-start gap-4 lg:grid-cols-2`
126
119
  - All grids use `items-start` for different-height cards
127
120
 
121
+ **Why full-page scroll:** Users need to see the map in context while scrolling through data. A fixed-height map that stays visible while data scrolls below creates a cramped, split-screen feeling. Full-page scroll is more natural and gives each section breathing room.
122
+
128
123
  ### Phase 1 Placeholder Rules
129
124
 
130
- For skeleton/placeholder cards (Phase 1 only):
125
+ **Phase 1 builds the complete layout structure** including header bar, hero map, glass KPI overlays, flight status strip, and data panels. The only "placeholders" are the **data panels** below the map.
126
+
127
+ **What to build in Phase 1:**
128
+ - ✅ Header bar (with logo, title, theme toggle) - **use slate scale colors, NOT text-white**
129
+ - ✅ Hero map (GeoMap component with no markers/arcs/overlays props)
130
+ - ✅ Glass KPI overlays (4 KPIs, hardcoded values, positioned absolutely over map)
131
+ - ✅ Flight status strip (4 flights, hardcoded values, positioned at map bottom)
132
+ - ✅ Data panels (BaseCard placeholders with centered text) - **these are the only placeholders**
131
133
 
132
134
  **Data panel placeholders** use `BaseCard` with centered text:
133
135
 
@@ -149,13 +151,14 @@ For skeleton/placeholder cards (Phase 1 only):
149
151
 
150
152
  ```tsx
151
153
  // ✅ Correct - render actual GeoMap component (empty, no data)
152
- import { GeoMap, useAppTheme } from "@/components/library";
154
+ import { GeoMap } from "@/components/library";
155
+ import { useThemeMode } from "@/components/library/theme/AppThemeProvider";
153
156
 
154
157
  export default function EngineDashboard() {
155
- const { mode } = useAppTheme();
158
+ const { mode } = useThemeMode();
156
159
 
157
160
  return (
158
- <div className="relative" style={{ flex: "1.15 1 0", minHeight: 0 }}>
161
+ <div className="relative h-[520px]">
159
162
  <GeoMap
160
163
  width={960}
161
164
  height={520}
@@ -168,18 +171,21 @@ export default function EngineDashboard() {
168
171
  ```
169
172
 
170
173
  In Phase 1:
171
- - GeoMap renders with NO markers, arcs, or overlays props
172
- - Uses `useAppTheme()` to get dark/light mode for theme prop
174
+ - GeoMap component renders with NO `markers`, `arcs`, or `overlays` props (these are GeoMap data props for Phase 2+)
175
+ - GeoMap will render the base world map (land, sphere, graticule) even without data - this is NOT a placeholder, it's the actual map component
176
+ - Glass KPI overlays and flight status strip ARE built in Phase 1 (as separate `<div>` elements positioned absolutely over the map)
177
+ - Uses `useThemeMode()` to get dark/light mode for theme prop
178
+ - **Verify:** You should see a blue world map (dark theme) or gray world map (light theme) with glass overlays on top
173
179
 
174
180
  // ❌ Wrong - wrapped in BaseCard
175
- <div className="relative" style={{ flex: "1.15 1 0", minHeight: 0 }}>
181
+ <div className="relative h-[520px]">
176
182
  <BaseCard>
177
183
  <GeoMap ... />
178
184
  </BaseCard>
179
185
  </div>
180
186
 
181
187
  // ❌ Wrong - text placeholder instead of GeoMap component
182
- <div className="relative" style={{ flex: "1.15 1 0", minHeight: 0 }}>
188
+ <div className="relative h-[520px]">
183
189
  <div className="flex h-full items-center justify-center bg-slate-100 dark:bg-slate-900">
184
190
  <span className="text-slate-400">Hero Map (GeoMap)</span>
185
191
  </div>
@@ -242,6 +248,10 @@ Each pill: `bg-black/40 backdrop-blur-md border border-white/10 rounded-lg px-3
242
248
 
243
249
  ## 8. Data Panels
244
250
 
251
+ **CRITICAL: Panel titles MUST match PRD exactly, even if data export has different name.**
252
+
253
+ For example: Panel titled "Escalations" uses data exported as `EVA_ACTIONS` or `ESCALATION_CARDS` (both are aliases). The PRD panel title takes precedence over data export names.
254
+
245
255
  ### 8a. Disruptions Panel (1/3 width)
246
256
 
247
257
  Custom inline component inside a `BaseCard`. Shows only flights that are delayed 60+ min or grounded.
@@ -261,42 +271,70 @@ Each traveler row:
261
271
  - `UIChip` for policy status (success = compliant, warning = exception)
262
272
  - Click to expand: 4-col grid showing Flight, Hotel, Return date, Destination
263
273
 
264
- ### 8c. Eva Activity (1/2 width)
274
+ ### 8c. Escalations (1/2 width)
275
+
276
+ `ActivityCard` showing escalations that require attention or can be sent to Eva for resolution.
277
+
278
+ **Data source:** Import `ESCALATION_CARDS` from sample data (alias of `EVA_ACTIONS`)
279
+
280
+ ```tsx
281
+ <ActivityCard
282
+ title="Escalations"
283
+ actions={useDataSource({ sample: ESCALATION_CARDS, live: [] })}
284
+ />
285
+ ```
265
286
 
266
- `ActivityCard` showing Eva's autonomous actions. Each action has:
267
- - Title (what Eva did)
268
- - Subtitle (details + savings/context)
269
- - Status: `"complete"` or `"working"`
287
+ Each escalation has:
288
+ - Title (issue description)
289
+ - Subtitle (details + context)
290
+ - Status: `"working"` (Eva is handling), `"pending"` (needs review), or `"complete"` (resolved)
270
291
  - Timestamp
271
292
 
293
+ Examples from sample data:
294
+ - "Processing approval for Omar Hassan" - subtitle: "Paris trip over budget · escalated to manager" (status: pending)
295
+ - "Monitoring weather delay for Elena Rodriguez" - subtitle: "AF 99 · CDG arrival delayed 45 min · No action yet" (status: working)
296
+ - "Rebooked cancelled flight for Sarah Chen" - subtitle: "LH 431 → LH 433 · Same fare class" (status: complete)
297
+
272
298
  ### 8d. Travelers by Destination (1/2 width)
273
299
 
274
300
  `ChartCard` wrapping a `D3Chart` with `D3ChartTemplates.groupedBarChart`.
275
- - X-axis: destination city names (categorical — use `scaleBand`, not `scaleLinear`)
276
- - Y-axis: traveler count
277
- - Height: 280px
278
- - `responsive={true}`
279
-
280
- ### 8e. Upcoming Bookings (full width)
281
301
 
282
- `TableCard` with columns: Traveler, Type, Route, Dates, Cost, Status, Policy.
283
- - `sortable`, `searchable`, `paginated`, `pageSize={5}`
284
- - Status column: custom render with colored chips (Confirmed = green, Pending = amber)
285
- - Policy column: `UIChip` with semantic tones (success/danger/warning)
302
+ **CRITICAL: Use this exact code structure:**
286
303
 
287
- ### 8f. Policy Compliance (1/2 width)
288
-
289
- `StatusCard` with policy rule items. Each item: `{ title, description, status, timestamp }`.
290
- - Status uses canonical values: `"operational"`, `"degraded"`
291
- - `showTimestamp` and `showProgress` enabled
304
+ ```tsx
305
+ <ChartCard
306
+ title="Travelers by Destination"
307
+ subtitle="Active trips by city"
308
+ chart={
309
+ <D3Chart
310
+ data={destinationData}
311
+ renderChart={D3ChartTemplates.groupedBarChart}
312
+ options={{
313
+ xKey: "x",
314
+ groups: ["travelers"],
315
+ colors: ["#5BC8C8", "#34D3AB", "#0D9488", "#0F766E", "#16A34A", "#5BC8C8", "#34D3AB", "#0D9488"],
316
+ barRadius: 8,
317
+ barPadding: 0.3,
318
+ margin: { top: 20, right: 20, bottom: 40, left: 40 },
319
+ showGrid: true,
320
+ }}
321
+ responsive
322
+ height={320}
323
+ />
324
+ }
325
+ />
326
+ ```
292
327
 
293
- ### 8g. Monthly Travel Spend (1/2 width)
328
+ **Requirements:**
329
+ - X-axis: destination city names (categorical — `scaleBand` via xKey: "x")
330
+ - Y-axis: traveler count (from groups: ["travelers"])
331
+ - Height: 320px (NOT 280px)
332
+ - Colors: **Must use gradient array** (8 colors, teal/green gradient matching Engine brand)
333
+ - barRadius: 8 (NOT 4)
334
+ - barPadding: 0.3 (for better spacing)
335
+ - responsive={true}
294
336
 
295
- `ChartCard` wrapping a `D3Chart` with `D3ChartTemplates.lineChart`.
296
- - X-axis: month labels (Oct–Mar)
297
- - Y-axis: dollar amounts
298
- - Height: 240px
299
- - `responsive={true}`
337
+ **That's it!** Only 4 panels total: Disruptions, Active Travelers, Escalations, and Travelers by Destination.
300
338
 
301
339
  ---
302
340
 
@@ -325,18 +363,17 @@ Eva surfaces as a `ChatBar` in the header. Not a FAB. Not a sliding panel. Not a
325
363
 
326
364
  ---
327
365
 
328
- ## 10. Salesforce Signals
366
+ ## 10. Salesforce Signals (Phase 4 Only)
367
+
368
+ **⚠️ These are added in Phase 4, NOT Phase 1.** Phase 1 has only the Engine logo and "Travel Command Center" title.
329
369
 
330
370
  Subtle, contextual indicators — like "Sent from iPhone", not promotional banners.
331
371
 
332
- | Signal | Location | Implementation |
333
- |--------|----------|----------------|
334
- | "Powered by Salesforce Data Cloud" | Header subtitle, next to "Travel Command Center" | `UIText` size xs, muted |
335
- | "Powered by Salesforce Data Cloud" | Glass KPI overlay or header area | White/translucent text |
336
- | " View in Salesforce" | Traveler expanded view, booking rows | Micro-link, muted text |
337
- | "✓ Salesforce updated" | After rebook/approve actions | `toast()` with success tone |
338
- | "Powered by Agentforce" | ChatBar title or subtitle area | Small badge/chip |
339
- | "Last synced · Data Cloud" | Footer or header timestamp | Ticking timestamp, muted |
372
+ | Signal | Location | Implementation | Phase |
373
+ |--------|----------|----------------|-------|
374
+ | " View in Salesforce" | Traveler expanded view, booking rows | Micro-link, muted text | Phase 4 |
375
+ | " Salesforce updated" | After rebook/approve actions | `toast()` with success tone | Phase 4 |
376
+ | "Powered by Agentforce" | ChatBar title or subtitle area | Small badge/chip | Phase 4 |
340
377
 
341
378
  ---
342
379
 
@@ -367,13 +404,13 @@ Mandatory on every element. The dashboard must work in both light and dark mode
367
404
 
368
405
  **Policy Item** — `id`, `title`, `description`, `status` (operational | degraded), `timestamp`
369
406
 
370
- **Eva Action** — `id`, `title`, `subtitle`, `status` (complete | working), `timestamp`
407
+ **Escalation** — `id`, `title`, `subtitle`, `status` (complete | working | pending), `timestamp`
371
408
 
372
409
  **Monthly Spend** — `{ x: month, y: amount }` array
373
410
 
374
411
  **Destination Chart** — `{ x: city, travelers: count }` array
375
412
 
376
- **Sample data:** 8–10 travelers, 8 flights, 4 disruptions, 8 bookings, 5 policy items, 8 Eva actions, 6 months of spend. All deterministic (no `Math.random()`). Include realistic names, routes, dollar amounts, and a mix of all status types.
413
+ **Sample data:** 8–10 travelers, 8 flights, 4 disruptions, 8 bookings, 5 policy items, 8 escalations, 6 months of spend. All deterministic (no `Math.random()`). Include realistic names, routes, dollar amounts, and a mix of all status types.
377
414
 
378
415
  ---
379
416
 
@@ -395,7 +432,7 @@ Mandatory on every element. The dashboard must work in both light and dark mode
395
432
 
396
433
  > **Skills:** command-center-builder, command-center-project, component-library
397
434
  >
398
- > Replace placeholders with library components. Import data from the pre-existing `src/data/engine-sample-data.js` file. Build all panels from section 8.
435
+ > Replace placeholders with library components. Import data from the pre-existing `src/data/engine-sample-data.js` file. Build the 4 data panels from section 8: Disruptions, Active Travelers, Escalations, and Travelers by Destination chart. Follow the EXACT code examples in section 8 - copy the code blocks exactly as shown.
399
436
 
400
437
  ---
401
438
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schandlergarcia/sf-web-components",
3
- "version": "1.9.59",
3
+ "version": "1.9.60",
4
4
  "description": "Reusable Salesforce web components library with Tailwind CSS v4 and shadcn/ui",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",