@schandlergarcia/sf-web-components 1.9.59 → 1.9.61
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.
- package/.a4drules/features/engine-dashboard-rule.md +42 -35
- package/.a4drules/features/pre-code-checklist.md +156 -13
- package/.a4drules/skills/component-library/SKILL.md +39 -30
- package/.a4drules/webapp-data.md +2 -60
- package/CHANGELOG.md +32 -0
- package/data/engine-command-center-prd.md +146 -92
- package/package.json +1 -1
|
@@ -16,18 +16,31 @@ 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** —
|
|
20
|
-
2. **Phase 2: Components + Sample 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 AND add map 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,
|
|
23
|
+
- Import dashboard-ready derivatives (MAP_MARKERS, MAP_ARCS, MAP_OVERLAYS, TRAVELER_CARDS, ESCALATION_CARDS, MONTHLY_SPEND)
|
|
24
24
|
- DO NOT define sample data inline in the dashboard — causes file truncation
|
|
25
|
+
- **FOLLOW THE EXACT CODE EXAMPLES in PRD Section 7 (map) and Section 8c/8d (panels)** - copy the code blocks as shown
|
|
26
|
+
- **Map data:** Add markers, arcs, overlays to GeoMap to show where travelers are (see PRD Section 7)
|
|
27
|
+
- **Panel titles:** "Disruptions", "Active Travelers", "Escalations", "Travel Spend"
|
|
28
|
+
- **Escalations panel:** ActivityCard must be wrapped in BaseCard for visible card styling
|
|
29
|
+
- **Chart:** Line chart showing monthly spend trend (see PRD Section 8d code block for exact options)
|
|
30
|
+
- **DO NOT run validation or dev server** — phase is complete after wiring files
|
|
25
31
|
3. **Phase 3: Real Data** — Connect to Salesforce, keep UI identical to Phase 2
|
|
26
32
|
4. **Phase 4: Agent** — Add Eva ChatBar integration
|
|
27
33
|
|
|
28
|
-
### Phase 1
|
|
34
|
+
### Phase 1 Scope
|
|
29
35
|
|
|
30
|
-
**
|
|
36
|
+
**What to build in Phase 1:**
|
|
37
|
+
- ✅ Header bar with logo, title, and theme toggle (use slate scale colors, NO text-white)
|
|
38
|
+
- ✅ Hero map (GeoMap component with NO markers/arcs/overlays PROPS passed)
|
|
39
|
+
- ✅ Glass KPI overlays (4 hardcoded values, positioned absolutely over map)
|
|
40
|
+
- ✅ Flight status strip (4 hardcoded flights, positioned at map bottom)
|
|
41
|
+
- ✅ Data panel placeholders (BaseCard with centered text) - **ONLY these are placeholders**
|
|
42
|
+
|
|
43
|
+
**Data panel placeholders** use `BaseCard` with centered placeholder text. NO titles on placeholders:
|
|
31
44
|
|
|
32
45
|
```tsx
|
|
33
46
|
<BaseCard>
|
|
@@ -40,13 +53,14 @@ The Engine dashboard uses a **strict 4-phase build process.** You MUST complete
|
|
|
40
53
|
**Hero map** renders the actual GeoMap component (empty, no data):
|
|
41
54
|
|
|
42
55
|
```tsx
|
|
43
|
-
import { GeoMap
|
|
56
|
+
import { GeoMap } from "@/components/library";
|
|
57
|
+
import { useThemeMode } from "@/components/library/theme/AppThemeProvider";
|
|
44
58
|
|
|
45
59
|
export default function EngineDashboard() {
|
|
46
|
-
const { mode } =
|
|
60
|
+
const { mode } = useThemeMode();
|
|
47
61
|
|
|
48
62
|
return (
|
|
49
|
-
<div className="relative
|
|
63
|
+
<div className="relative h-[520px]">
|
|
50
64
|
<GeoMap
|
|
51
65
|
width={960}
|
|
52
66
|
height={520}
|
|
@@ -60,13 +74,18 @@ export default function EngineDashboard() {
|
|
|
60
74
|
|
|
61
75
|
All data panel placeholders: BaseCard, no title, centered text, `h-48`, `text-slate-400`.
|
|
62
76
|
|
|
63
|
-
Hero map in Phase 1: actual GeoMap component
|
|
77
|
+
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.
|
|
78
|
+
|
|
79
|
+
**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:
|
|
80
|
+
- Container has fixed height (`className="relative h-[520px]"`)
|
|
81
|
+
- GeoMap has `className="h-full w-full"`
|
|
82
|
+
- No console errors from GeoMap component
|
|
64
83
|
|
|
65
84
|
**DO NOT:**
|
|
66
85
|
- Mix phases (don't add sample data in Phase 1, don't add Eva in Phase 2, etc.)
|
|
67
|
-
-
|
|
68
|
-
- Proceed to the next phase with validator errors
|
|
86
|
+
- Run `npm run dev` or `npm run validate:dashboard` (wastes turns, not required)
|
|
69
87
|
- Use BaseCard titles in Phase 1 placeholders (causes text to run together)
|
|
88
|
+
- Use `h-screen` or viewport-locked layout (full-page scroll required)
|
|
70
89
|
|
|
71
90
|
### Phase 3: Real Data Integration
|
|
72
91
|
|
|
@@ -138,29 +157,13 @@ The `useDataSource` hook automatically uses `live` data when available, falling
|
|
|
138
157
|
|
|
139
158
|
**Troubleshooting:** If you encounter GraphQL schema introspection failures, see `.a4drules/troubleshooting/graphql-introspection-failure.md` for the complete workaround pattern.
|
|
140
159
|
|
|
141
|
-
##
|
|
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
|
-
```
|
|
160
|
+
## Phase Completion (NO VALIDATION REQUIRED)
|
|
149
161
|
|
|
150
|
-
|
|
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
|
|
162
|
+
After wiring the dashboard into CommandCenter, Home, and routes, the phase is complete.
|
|
156
163
|
|
|
157
|
-
|
|
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
|
|
164
|
+
**🚫 CRITICAL: DO NOT run `npm run dev` or `npm run validate:dashboard`**
|
|
162
165
|
|
|
163
|
-
Do NOT
|
|
166
|
+
These commands are NOT required for phase completion. Do NOT execute them. The phase is complete after wiring the files.
|
|
164
167
|
|
|
165
168
|
## File Requirements
|
|
166
169
|
|
|
@@ -168,15 +171,18 @@ Do NOT report the phase as complete until the validator shows zero errors.
|
|
|
168
171
|
- **Location:** `src/pages/EngineDashboard.tsx` (NOT `src/components/pages/`)
|
|
169
172
|
- **Imports:** ONLY from `@/components/library` — never shadcn, never Lucide, never Recharts
|
|
170
173
|
|
|
171
|
-
## Layout Pattern: Visualization-Hero
|
|
174
|
+
## Layout Pattern: Visualization-Hero with Full-Page Scroll
|
|
172
175
|
|
|
173
176
|
The Engine dashboard uses the **visualization-hero** layout (see PRD section 5). This means:
|
|
174
177
|
|
|
175
|
-
1. **Hero map:** Full-width,
|
|
176
|
-
2. **Data panels below:**
|
|
178
|
+
1. **Hero map:** Full-width, fixed height (`h-[520px]`), GeoMap with glass overlays and flight status strip
|
|
179
|
+
2. **Data panels below:** Natural flow with `px-4 py-5` (NO overflow constraints)
|
|
180
|
+
3. **Full-page scroll:** Entire dashboard scrolls naturally (NO `h-screen` on outer container)
|
|
177
181
|
|
|
178
182
|
**DO NOT:**
|
|
179
183
|
- Put the map in a 1/3 or 1/2 grid column (it's hero, not sidebar)
|
|
184
|
+
- Use `h-screen` or viewport-locked layout (full-page scroll required)
|
|
185
|
+
- Use `overflow-y-auto` or flex height constraints on data panels
|
|
180
186
|
- Wrap GeoMap in ChartCard (render directly)
|
|
181
187
|
- Skip the glass KPI overlays or flight status strip
|
|
182
188
|
- Make the map too small (minimum 400px height)
|
|
@@ -295,8 +301,9 @@ These elements distinguish the Engine dashboard from generic dashboards. They mu
|
|
|
295
301
|
- Multi-tab layout with content swapping (build one scrollable page)
|
|
296
302
|
- `<nav>` or header bar inside the dashboard (AppLayout handles navigation)
|
|
297
303
|
- Map in a sidebar grid (it's hero — full width)
|
|
304
|
+
- **Using `h-screen` or viewport-locked layout** (full-page scroll required)
|
|
298
305
|
- More than 4 KPIs in a row
|
|
299
306
|
- Using `Math.random()` in sample data
|
|
300
|
-
-
|
|
307
|
+
- **Running `npm run dev` or `npm run validate:dashboard`** (not required, wastes turns)
|
|
301
308
|
- Reporting phase complete before wiring the dashboard into the app
|
|
302
309
|
- 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. **
|
|
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) + Monthly Spend 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
|
+
Travel Spend 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
|
|
29
|
-
-
|
|
30
|
-
-
|
|
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. **
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
|
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
|
-
|
|
|
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
|
package/.a4drules/webapp-data.md
CHANGED
|
@@ -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,38 @@ 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.61] - 2026-04-01
|
|
9
|
+
|
|
10
|
+
### Updated
|
|
11
|
+
- **Synced latest .a4drules and PRD from reactapp4** - Pulled latest documentation updates
|
|
12
|
+
- All `.a4drules/features/` files updated
|
|
13
|
+
- All `.a4drules/skills/` files updated
|
|
14
|
+
- All `.a4drules/troubleshooting/` files updated
|
|
15
|
+
- Root `.a4drules/*.md` files updated
|
|
16
|
+
- `data/engine-command-center-prd.md` updated to latest version
|
|
17
|
+
|
|
18
|
+
## [1.9.60] - 2026-04-01
|
|
19
|
+
|
|
20
|
+
### Updated
|
|
21
|
+
- **Synced .a4drules and PRD from reactapp4** - Updated all documentation and rules
|
|
22
|
+
- `.a4drules/features/engine-dashboard-rule.md` - Updated Phase 1/Phase 2 guidance with exact code examples
|
|
23
|
+
- Added specific instructions to follow PRD Section 8c/8d code blocks exactly
|
|
24
|
+
- Clarified Phase 1 includes glass KPI overlays and flight status strip (not just placeholders)
|
|
25
|
+
- Added chart configuration details (gradient colors, barRadius: 8, height: 320)
|
|
26
|
+
- Fixed import example to use `useThemeMode` (not `useAppTheme`)
|
|
27
|
+
- `.a4drules/features/command-center-dashboard-rule.md` - Latest dashboard rules
|
|
28
|
+
- `.a4drules/features/phase2-data-pattern.md` - Sample data wiring patterns
|
|
29
|
+
- `.a4drules/features/pre-code-checklist.md` - Pre-implementation checklist
|
|
30
|
+
- `.a4drules/skills/` - All skills updated from reactapp4
|
|
31
|
+
- `.a4drules/troubleshooting/` - Troubleshooting guides
|
|
32
|
+
- `.a4drules/validation-requirements.md` - Latest validation rules
|
|
33
|
+
- `.a4drules/webapp-data.md` - Data access patterns
|
|
34
|
+
- `.a4drules/webapp-ui.md` - UI platform rules
|
|
35
|
+
- `data/engine-command-center-prd.md` - Latest PRD with updated build instructions
|
|
36
|
+
|
|
37
|
+
### Context
|
|
38
|
+
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.
|
|
39
|
+
|
|
8
40
|
## [1.9.59] - 2026-04-01
|
|
9
41
|
|
|
10
42
|
### 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 (
|
|
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 (
|
|
95
|
-
│ │
|
|
96
|
-
│ ┌─── 1/3 ───────┐ ┌─── 2/3 ────────────────────┐ │
|
|
97
|
-
│ │ Disruptions │ │ Active Travelers │ │
|
|
98
|
-
│ │ (custom panel) │ │ (expandable cards, scroll) │ │
|
|
99
|
-
│ └────────────────┘ └────────────────────────────┘ │
|
|
100
|
-
│ │
|
|
101
|
-
│ ┌─── 1/2 ───────┐ ┌─── 1/2 ────────────────────┐ │
|
|
102
|
-
│ │
|
|
103
|
-
│ │ (ActivityCard) │ │ (ChartCard + D3Chart
|
|
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 │ │ Travel Spend (Monthly) │ │ ↕
|
|
103
|
+
│ │ (ActivityCard) │ │ (ChartCard + D3Chart line) │ │ ↕
|
|
104
|
+
│ └────────────────┘ └────────────────────────────┘ │ ↕
|
|
115
105
|
└─────────────────────────────────────────────────────────────┘
|
|
116
106
|
```
|
|
117
107
|
|
|
118
108
|
### Layout Rules
|
|
119
109
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
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
|
-
|
|
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
|
|
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 } =
|
|
158
|
+
const { mode } = useThemeMode();
|
|
156
159
|
|
|
157
160
|
return (
|
|
158
|
-
<div className="relative
|
|
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
|
|
172
|
-
-
|
|
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
|
|
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
|
|
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>
|
|
@@ -209,20 +215,26 @@ The `ChatBar` replaces any FAB or sliding panel. It opens inline as a command pa
|
|
|
209
215
|
|
|
210
216
|
**Component:** `GeoMap` (from `@/components/library`)
|
|
211
217
|
|
|
212
|
-
|
|
218
|
+
**Phase 1:** Render GeoMap with NO data props (no markers/arcs/overlays)
|
|
219
|
+
**Phase 2:** Add markers, arcs, and overlays from sample data to show where travelers are
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { MAP_MARKERS, MAP_ARCS, MAP_OVERLAYS } from "@/data/engine-sample-data";
|
|
223
|
+
|
|
224
|
+
// Phase 2 - with map data
|
|
213
225
|
<GeoMap
|
|
214
226
|
width={960}
|
|
215
227
|
height={520}
|
|
216
228
|
theme={mode === "dark" ? "dark" : "light"}
|
|
217
|
-
markers={
|
|
218
|
-
arcs={
|
|
219
|
-
overlays={
|
|
229
|
+
markers={useDataSource({ sample: MAP_MARKERS, live: [] })}
|
|
230
|
+
arcs={useDataSource({ sample: MAP_ARCS, live: [] })}
|
|
231
|
+
overlays={useDataSource({ sample: MAP_OVERLAYS, live: [] })}
|
|
220
232
|
zoomable
|
|
221
233
|
className="h-full w-full"
|
|
222
234
|
/>
|
|
223
235
|
```
|
|
224
236
|
|
|
225
|
-
**Markers:** One per city (origin and destination). Each marker: `{ id, lon, lat, label, active: true }`.
|
|
237
|
+
**Markers:** One per city (origin and destination). Each marker: `{ id, lon, lat, label, active: true }`. Shows where travelers are located.
|
|
226
238
|
|
|
227
239
|
**Arcs:** One per active flight route. Each arc: `{ id, from: [lon, lat], to: [lon, lat], progress: 0–1 }`. Set `danger: true` on disrupted routes (delayed 60+ min or grounded). The `progress` value places an animated pulsing dot showing the flight's current position along the great circle arc.
|
|
228
240
|
|
|
@@ -242,6 +254,10 @@ Each pill: `bg-black/40 backdrop-blur-md border border-white/10 rounded-lg px-3
|
|
|
242
254
|
|
|
243
255
|
## 8. Data Panels
|
|
244
256
|
|
|
257
|
+
**CRITICAL: Panel titles MUST match PRD exactly, even if data export has different name.**
|
|
258
|
+
|
|
259
|
+
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.
|
|
260
|
+
|
|
245
261
|
### 8a. Disruptions Panel (1/3 width)
|
|
246
262
|
|
|
247
263
|
Custom inline component inside a `BaseCard`. Shows only flights that are delayed 60+ min or grounded.
|
|
@@ -261,42 +277,81 @@ Each traveler row:
|
|
|
261
277
|
- `UIChip` for policy status (success = compliant, warning = exception)
|
|
262
278
|
- Click to expand: 4-col grid showing Flight, Hotel, Return date, Destination
|
|
263
279
|
|
|
264
|
-
### 8c.
|
|
280
|
+
### 8c. Escalations (1/2 width)
|
|
265
281
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
282
|
+
**CRITICAL: ActivityCard has no card styling by default. Must wrap in BaseCard for visible card background.**
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
<BaseCard>
|
|
286
|
+
<ActivityCard
|
|
287
|
+
title="Escalations"
|
|
288
|
+
actions={useDataSource({ sample: ESCALATION_CARDS, live: [] })}
|
|
289
|
+
/>
|
|
290
|
+
</BaseCard>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Data source:** Import `ESCALATION_CARDS` from sample data (alias of `EVA_ACTIONS`)
|
|
294
|
+
|
|
295
|
+
Each escalation has:
|
|
296
|
+
- Title (issue description)
|
|
297
|
+
- Subtitle (details + context)
|
|
298
|
+
- Status: `"working"` (Eva is handling), `"pending"` (needs review), or `"complete"` (resolved)
|
|
270
299
|
- Timestamp
|
|
271
300
|
|
|
272
|
-
|
|
301
|
+
Examples from sample data:
|
|
302
|
+
- "Processing approval for Omar Hassan" - subtitle: "Paris trip over budget · escalated to manager" (status: pending)
|
|
303
|
+
- "Monitoring weather delay for Elena Rodriguez" - subtitle: "AF 99 · CDG arrival delayed 45 min · No action yet" (status: working)
|
|
304
|
+
- "Rebooked cancelled flight for Sarah Chen" - subtitle: "LH 431 → LH 433 · Same fare class" (status: complete)
|
|
273
305
|
|
|
274
|
-
|
|
275
|
-
- X-axis: destination city names (categorical — use `scaleBand`, not `scaleLinear`)
|
|
276
|
-
- Y-axis: traveler count
|
|
277
|
-
- Height: 280px
|
|
278
|
-
- `responsive={true}`
|
|
306
|
+
### 8d. Monthly Spend Trend (1/2 width)
|
|
279
307
|
|
|
280
|
-
|
|
308
|
+
`ChartCard` wrapping a `D3Chart` with `D3ChartTemplates.lineChart`.
|
|
281
309
|
|
|
282
|
-
|
|
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)
|
|
310
|
+
**CRITICAL: Use this exact code structure:**
|
|
286
311
|
|
|
287
|
-
|
|
312
|
+
```tsx
|
|
313
|
+
<ChartCard
|
|
314
|
+
title="Travel Spend"
|
|
315
|
+
subtitle="Monthly trend (6 months)"
|
|
316
|
+
chart={
|
|
317
|
+
<D3Chart
|
|
318
|
+
data={useDataSource({ sample: MONTHLY_SPEND, live: [] })}
|
|
319
|
+
renderChart={D3ChartTemplates.lineChart}
|
|
320
|
+
options={{
|
|
321
|
+
xKey: "month",
|
|
322
|
+
yKey: "amount",
|
|
323
|
+
color: "#5BC8C8",
|
|
324
|
+
lineWidth: 3,
|
|
325
|
+
showDots: true,
|
|
326
|
+
dotRadius: 4,
|
|
327
|
+
showArea: true,
|
|
328
|
+
areaOpacity: 0.1,
|
|
329
|
+
margin: { top: 20, right: 20, bottom: 40, left: 60 },
|
|
330
|
+
showGrid: true,
|
|
331
|
+
formatY: (d) => `$${(d / 1000).toFixed(0)}K`,
|
|
332
|
+
}}
|
|
333
|
+
responsive
|
|
334
|
+
height={320}
|
|
335
|
+
/>
|
|
336
|
+
}
|
|
337
|
+
/>
|
|
338
|
+
```
|
|
288
339
|
|
|
289
|
-
|
|
290
|
-
- Status uses canonical values: `"operational"`, `"degraded"`
|
|
291
|
-
- `showTimestamp` and `showProgress` enabled
|
|
340
|
+
**Data source:** Import `MONTHLY_SPEND` from sample data
|
|
292
341
|
|
|
293
|
-
|
|
342
|
+
**Requirements:**
|
|
343
|
+
- X-axis: month names (Oct through Mar)
|
|
344
|
+
- Y-axis: spend amount formatted as $XXK
|
|
345
|
+
- Height: 320px
|
|
346
|
+
- Line color: Engine teal (#5BC8C8)
|
|
347
|
+
- Line width: 3px
|
|
348
|
+
- Show dots at data points (radius: 4)
|
|
349
|
+
- Show filled area under line (opacity: 0.1)
|
|
350
|
+
- responsive={true}
|
|
294
351
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
- Height: 240px
|
|
299
|
-
- `responsive={true}`
|
|
352
|
+
**Why this chart:** Shows spend trends over time so travel managers can spot anomalies, budget overruns, or seasonal patterns. Actionable data for financial planning.
|
|
353
|
+
|
|
354
|
+
**That's it!** Only 4 panels total: Disruptions, Active Travelers, Escalations, and Monthly Spend Trend.
|
|
300
355
|
|
|
301
356
|
---
|
|
302
357
|
|
|
@@ -325,18 +380,17 @@ Eva surfaces as a `ChatBar` in the header. Not a FAB. Not a sliding panel. Not a
|
|
|
325
380
|
|
|
326
381
|
---
|
|
327
382
|
|
|
328
|
-
## 10. Salesforce Signals
|
|
383
|
+
## 10. Salesforce Signals (Phase 4 Only)
|
|
384
|
+
|
|
385
|
+
**⚠️ These are added in Phase 4, NOT Phase 1.** Phase 1 has only the Engine logo and "Travel Command Center" title.
|
|
329
386
|
|
|
330
387
|
Subtle, contextual indicators — like "Sent from iPhone", not promotional banners.
|
|
331
388
|
|
|
332
|
-
| Signal | Location | Implementation |
|
|
333
|
-
|
|
334
|
-
| "
|
|
335
|
-
| "
|
|
336
|
-
| "
|
|
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 |
|
|
389
|
+
| Signal | Location | Implementation | Phase |
|
|
390
|
+
|--------|----------|----------------|-------|
|
|
391
|
+
| "☁ View in Salesforce" | Traveler expanded view, booking rows | Micro-link, muted text | Phase 4 |
|
|
392
|
+
| "✓ Salesforce updated" | After rebook/approve actions | `toast()` with success tone | Phase 4 |
|
|
393
|
+
| "Powered by Agentforce" | ChatBar title or subtitle area | Small badge/chip | Phase 4 |
|
|
340
394
|
|
|
341
395
|
---
|
|
342
396
|
|
|
@@ -367,13 +421,11 @@ Mandatory on every element. The dashboard must work in both light and dark mode
|
|
|
367
421
|
|
|
368
422
|
**Policy Item** — `id`, `title`, `description`, `status` (operational | degraded), `timestamp`
|
|
369
423
|
|
|
370
|
-
**
|
|
371
|
-
|
|
372
|
-
**Monthly Spend** — `{ x: month, y: amount }` array
|
|
424
|
+
**Escalation** — `id`, `title`, `subtitle`, `status` (complete | working | pending), `timestamp`
|
|
373
425
|
|
|
374
|
-
**
|
|
426
|
+
**Monthly Spend** — `{ month: string, amount: number }` array. Six months of travel spend data (Oct through Mar). Amounts in dollars, typically $98K-$156K range.
|
|
375
427
|
|
|
376
|
-
**Sample data:** 8–10 travelers, 8 flights, 4 disruptions, 8 bookings, 5 policy items, 8
|
|
428
|
+
**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
429
|
|
|
378
430
|
---
|
|
379
431
|
|
|
@@ -395,7 +447,9 @@ Mandatory on every element. The dashboard must work in both light and dark mode
|
|
|
395
447
|
|
|
396
448
|
> **Skills:** command-center-builder, command-center-project, component-library
|
|
397
449
|
>
|
|
398
|
-
> Replace placeholders with library components. Import data from the pre-existing `src/data/engine-sample-data.js` file. Build
|
|
450
|
+
> 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 Monthly Spend Trend chart. Follow the EXACT code examples in section 8 - copy the code blocks exactly as shown.
|
|
451
|
+
>
|
|
452
|
+
> **Add map data:** Import MAP_MARKERS, MAP_ARCS, MAP_OVERLAYS from sample data and pass to GeoMap component (see Section 7). The map should show where travelers are with markers for cities, arcs for flight routes, and overlays for disruptions.
|
|
399
453
|
|
|
400
454
|
---
|
|
401
455
|
|
package/package.json
CHANGED