@schandlergarcia/sf-web-components 1.9.67 → 1.9.69
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/skills/command-center-builder/SKILL.md +26 -146
- package/.a4drules/skills/command-center-builder/charts-visualization.md +1 -136
- package/.a4drules/skills/command-center-builder/completion-checklist.md +1 -61
- package/.a4drules/skills/command-center-builder/components-styling.md +1 -97
- package/.a4drules/skills/command-center-builder/data-forms-ai.md +1 -43
- package/.a4drules/skills/command-center-builder/getting-started.md +1 -125
- package/.a4drules/skills/command-center-builder/improved-build-process.md +1 -30
- package/.a4drules/skills/command-center-builder/page-layout.md +1 -145
- package/CHANGELOG.md +47 -19
- package/data/engine-command-center-prd.md +156 -301
- package/dist/styles/global.css +238 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Engine Travel Command Center
|
|
2
2
|
|
|
3
|
-
Product Requirements Document
|
|
3
|
+
Product Requirements Document
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -8,28 +8,25 @@ Product Requirements Document · TDX26 Demo Build
|
|
|
8
8
|
|
|
9
9
|
The Engine Travel Command Center is a real-time operations dashboard for corporate travel managers who use Engine (engine.com). It gives a single-screen view of every active traveler, booking, flight, policy flag, and agent interaction — built on Salesforce Data Cloud.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
**Demo context:** Built live at TDX26 using Agentforce Vibes. The arc is: PRD → scaffold → data → agent → intelligence. Each build prompt maps to one beat.
|
|
11
|
+
**Build approach:** Incremental — PRD → scaffold → data → agent → intelligence.
|
|
14
12
|
|
|
15
13
|
---
|
|
16
14
|
|
|
17
15
|
## 2. Users
|
|
18
16
|
|
|
19
17
|
**Primary — Sarah Chen, Travel Manager at Acme Corp**
|
|
20
|
-
Manages Acme's travel program: bookings, policy enforcement, exceptions, traveler monitoring.
|
|
18
|
+
Manages Acme's travel program: bookings, policy enforcement, exceptions, traveler monitoring.
|
|
21
19
|
|
|
22
20
|
**Secondary — Eva (Agentforce Agent)**
|
|
23
|
-
Engine's Agentforce-powered AI agent. Handles traveler requests autonomously — booking changes, policy questions, itinerary lookups. Resolves ~30% of requests without human involvement. Surfaces
|
|
21
|
+
Engine's Agentforce-powered AI agent. Handles traveler requests autonomously — booking changes, policy questions, itinerary lookups. Resolves ~30% of requests without human involvement. Surfaces via `ChatBar` below the hero map.
|
|
24
22
|
|
|
25
23
|
---
|
|
26
24
|
|
|
27
25
|
## 3. Brand Tokens
|
|
28
26
|
|
|
29
|
-
Update `src/styles/global.css` — replace the existing `--color-brand-*` palette inside the `@theme inline` block
|
|
27
|
+
Update `src/styles/global.css` — replace the existing `--color-brand-*` palette inside the `@theme inline` block:
|
|
30
28
|
|
|
31
29
|
```css
|
|
32
|
-
/* Engine teal brand palette */
|
|
33
30
|
--color-brand-50: #ECFDF9;
|
|
34
31
|
--color-brand-100: #D1FAF0;
|
|
35
32
|
--color-brand-200: #A7F3E1;
|
|
@@ -41,185 +38,96 @@ Update `src/styles/global.css` — replace the existing `--color-brand-*` palett
|
|
|
41
38
|
--color-brand-800: #115E59;
|
|
42
39
|
--color-brand-900: #134E4A;
|
|
43
40
|
--color-brand-950: #042F2E;
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Additionally, add a custom `--color-engine-savings` token for the green savings accent:
|
|
47
|
-
|
|
48
|
-
```css
|
|
49
41
|
--color-engine-savings: #16A34A;
|
|
50
42
|
```
|
|
51
43
|
|
|
52
|
-
|
|
44
|
+
Use `brand-*` Tailwind classes for brand elements. Tailwind built-in colors (green, amber, red) for status. No hardcoded hex in components.
|
|
53
45
|
|
|
54
|
-
**Typography:** Inter (already
|
|
55
|
-
|
|
56
|
-
**Icons:** Heroicons 2 exclusively (`@heroicons/react`). No Lucide, Font Awesome, or other libraries inside command center pages.
|
|
46
|
+
**Typography:** Inter (already `--font-sans`). **Icons:** Heroicons 2 (`@heroicons/react`).
|
|
57
47
|
|
|
58
48
|
---
|
|
59
49
|
|
|
60
50
|
## 4. Architecture
|
|
61
51
|
|
|
62
|
-
**Dashboard file:** `src/pages/EngineDashboard.tsx`
|
|
63
|
-
|
|
64
|
-
**
|
|
65
|
-
|
|
66
|
-
**Imports:** All components from `@/components/library` barrel. Theme access from `@/components/library/theme/AppThemeProvider`.
|
|
52
|
+
- **Dashboard file:** `src/pages/EngineDashboard.tsx`
|
|
53
|
+
- **Wiring:** `CommandCenter.tsx` imports and renders `EngineDashboard` inside the existing provider stack. Never recreate providers in the dashboard.
|
|
54
|
+
- **Imports:** Components from `@/components/library`. Theme from `@/components/library/theme/AppThemeProvider`.
|
|
67
55
|
|
|
68
56
|
---
|
|
69
57
|
|
|
70
|
-
## 5. Layout
|
|
58
|
+
## 5. Layout
|
|
71
59
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
### Structure (top to bottom)
|
|
60
|
+
Visualization-hero layout. Full-page scroll (no `h-screen`).
|
|
75
61
|
|
|
76
62
|
```
|
|
77
|
-
|
|
78
|
-
│ HEADER
|
|
79
|
-
│ Engine logo + "Travel Command Center"
|
|
80
|
-
|
|
81
|
-
│ HERO MAP (h-[520px]
|
|
82
|
-
│
|
|
83
|
-
│
|
|
84
|
-
│
|
|
85
|
-
│
|
|
86
|
-
│
|
|
87
|
-
│
|
|
88
|
-
|
|
89
|
-
│
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
│
|
|
93
|
-
│
|
|
94
|
-
│
|
|
95
|
-
│ │
|
|
96
|
-
│
|
|
97
|
-
│
|
|
98
|
-
│
|
|
99
|
-
│
|
|
100
|
-
│ │
|
|
101
|
-
│
|
|
102
|
-
|
|
103
|
-
└─────────────────────────────────────────────────────────────┘
|
|
63
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
64
|
+
│ HEADER (h-12, sticky, bg-slate-900) │
|
|
65
|
+
│ Engine logo + "Travel Command Center" + badge | actions │
|
|
66
|
+
├──────────────────────────────────────────────────────────────┤
|
|
67
|
+
│ HERO MAP (h-[520px], GeoMap, relative) │
|
|
68
|
+
│ ┌─ glass KPI overlays (absolute top-left) ───────────────┐ │
|
|
69
|
+
│ │ Active Travelers | Spend MTD | Compliance | Eva Resolved│ │
|
|
70
|
+
│ └────────────────────────────────────────────────────────┘ │
|
|
71
|
+
│ ┌─ flight status strip (absolute bottom) ────────────────┐ │
|
|
72
|
+
│ │ BA 286 · In Air | NH 109 · In Air | LH 431 · Delayed │ │
|
|
73
|
+
│ └────────────────────────────────────────────────────────┘ │
|
|
74
|
+
├──────────────────────────────────────────────────────────────┤
|
|
75
|
+
│ EVA CHATBAR (px-4 pt-4, full-width command palette strip) │
|
|
76
|
+
├──────────────────────────────────────────────────────────────┤
|
|
77
|
+
│ DATA PANELS (px-4 py-5 space-y-6) │
|
|
78
|
+
│ │
|
|
79
|
+
│ Row 1: grid grid-cols-1 items-start gap-4 lg:grid-cols-3 │
|
|
80
|
+
│ ┌── 2/3 (lg:col-span-2) ──────┐ ┌── 1/3 ───────────────┐ │
|
|
81
|
+
│ │ Escalations (custom panel) │ │ Disruptions (custom) │ │
|
|
82
|
+
│ └───────────────────────────────┘ └──────────────────────┘ │
|
|
83
|
+
│ │
|
|
84
|
+
│ Row 2: grid grid-cols-1 items-start gap-4 lg:grid-cols-3 │
|
|
85
|
+
│ ┌── 2/3 (lg:col-span-2) ──────┐ ┌── 1/3 ───────────────┐ │
|
|
86
|
+
│ │ Active Travelers (expandable) │ │ Travel Spend (chart) │ │
|
|
87
|
+
│ └───────────────────────────────┘ └──────────────────────┘ │
|
|
88
|
+
└──────────────────────────────────────────────────────────────┘
|
|
104
89
|
```
|
|
105
90
|
|
|
106
|
-
### Layout
|
|
107
|
-
|
|
108
|
-
**CRITICAL: Full-page scroll, NOT viewport-locked sections.**
|
|
91
|
+
### Layout classes
|
|
109
92
|
|
|
110
|
-
|
|
93
|
+
- **Outer:** `<div className="flex flex-col bg-slate-50 dark:bg-slate-950">`
|
|
94
|
+
- **Map:** `<div className="relative h-[520px]">`
|
|
95
|
+
- **Eva:** `<div className="px-4 pt-4"><ChatBar ... /></div>`
|
|
96
|
+
- **Panels:** `<div className="px-4 py-5"><div className="space-y-6">...</div></div>`
|
|
97
|
+
- **Row 1:** `grid grid-cols-1 items-start gap-4 lg:grid-cols-3` — Escalations `lg:col-span-2`, Disruptions auto
|
|
98
|
+
- **Row 2:** `grid grid-cols-1 items-start gap-4 lg:grid-cols-3` — Travelers `lg:col-span-2`, Spend auto
|
|
111
99
|
|
|
112
|
-
|
|
113
|
-
- **Hero map:** Fixed height `h-[520px]` or `h-[600px]` with `relative` positioning for glass overlays
|
|
114
|
-
- **Data panels:** Natural flow with `px-4 py-5 space-y-6` (NO `overflow-y-auto`, NO flex height constraints)
|
|
115
|
-
- **Row 1** - Disruptions + Travelers: `grid grid-cols-1 items-start gap-4 lg:grid-cols-3` (disruptions 1/3, travelers `lg:col-span-2`)
|
|
116
|
-
- **Row 2** - Escalations + Chart: `grid grid-cols-1 items-start gap-4 lg:grid-cols-2`
|
|
117
|
-
- All grids use `items-start` for different-height cards
|
|
100
|
+
### Phase 1 placeholders
|
|
118
101
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
### Phase 1 Placeholder Rules
|
|
122
|
-
|
|
123
|
-
**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.
|
|
124
|
-
|
|
125
|
-
**What to build in Phase 1:**
|
|
126
|
-
- ✅ Header bar (with logo, title, theme toggle) - **use slate scale colors, NOT text-white**
|
|
127
|
-
- ✅ Hero map (GeoMap component with no markers/arcs/overlays props)
|
|
128
|
-
- ✅ Glass KPI overlays (4 KPIs, hardcoded values, positioned absolutely over map)
|
|
129
|
-
- ✅ Flight status strip (4 flights, hardcoded values, positioned at map bottom)
|
|
130
|
-
- ✅ Data panels (BaseCard placeholders with centered text) - **these are the only placeholders**
|
|
131
|
-
|
|
132
|
-
**Data panel placeholders** use `BaseCard` with centered text:
|
|
102
|
+
Phase 1 builds the header, map, glass overlays, and flight strip as real components. Only the ChatBar and 4 data panels below the map are placeholders:
|
|
133
103
|
|
|
134
104
|
```tsx
|
|
135
|
-
// ✅ Correct data panel placeholder
|
|
136
105
|
<BaseCard>
|
|
137
106
|
<div className="h-48 flex items-center justify-center text-slate-400">
|
|
138
|
-
|
|
107
|
+
Escalations Panel
|
|
139
108
|
</div>
|
|
140
109
|
</BaseCard>
|
|
141
|
-
|
|
142
|
-
// ❌ Wrong - title causes text to run together
|
|
143
|
-
<BaseCard title="Disruptions">
|
|
144
|
-
<div className="text-slate-400">No disruptions detected</div>
|
|
145
|
-
</BaseCard>
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
**Hero map** (render actual GeoMap component in Phase 1):
|
|
149
|
-
|
|
150
|
-
```tsx
|
|
151
|
-
// ✅ Correct - render actual GeoMap component (empty, no data)
|
|
152
|
-
import { GeoMap } from "@/components/library";
|
|
153
|
-
import { useThemeMode } from "@/components/library/theme/AppThemeProvider";
|
|
154
|
-
|
|
155
|
-
export default function EngineDashboard() {
|
|
156
|
-
const { mode } = useThemeMode();
|
|
157
|
-
|
|
158
|
-
return (
|
|
159
|
-
<div className="relative h-[520px]">
|
|
160
|
-
<GeoMap
|
|
161
|
-
width={960}
|
|
162
|
-
height={520}
|
|
163
|
-
theme={mode === "dark" ? "dark" : "light"}
|
|
164
|
-
className="h-full w-full"
|
|
165
|
-
/>
|
|
166
|
-
</div>
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
In Phase 1:
|
|
172
|
-
- GeoMap component renders with NO `markers`, `arcs`, or `overlays` props (these are GeoMap data props for Phase 2+)
|
|
173
|
-
- GeoMap will render the base world map (land, sphere, graticule) even without data - this is NOT a placeholder, it's the actual map component
|
|
174
|
-
- Glass KPI overlays and flight status strip ARE built in Phase 1 (as separate `<div>` elements positioned absolutely over the map)
|
|
175
|
-
- Uses `useThemeMode()` to get dark/light mode for theme prop
|
|
176
|
-
- **Verify:** You should see a blue world map (dark theme) or gray world map (light theme) with glass overlays on top
|
|
177
|
-
|
|
178
|
-
// ❌ Wrong - wrapped in BaseCard
|
|
179
|
-
<div className="relative h-[520px]">
|
|
180
|
-
<BaseCard>
|
|
181
|
-
<GeoMap ... />
|
|
182
|
-
</BaseCard>
|
|
183
|
-
</div>
|
|
184
|
-
|
|
185
|
-
// ❌ Wrong - text placeholder instead of GeoMap component
|
|
186
|
-
<div className="relative h-[520px]">
|
|
187
|
-
<div className="flex h-full items-center justify-center bg-slate-100 dark:bg-slate-900">
|
|
188
|
-
<span className="text-slate-400">Hero Map (GeoMap)</span>
|
|
189
|
-
</div>
|
|
190
|
-
</div>
|
|
191
110
|
```
|
|
192
111
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
Hero map uses: actual GeoMap component (no markers/arcs/overlays in Phase 1), direct render, fills hero container.
|
|
112
|
+
The GeoMap renders the base world map with no data props. Glass overlays and flight strip use hardcoded values.
|
|
196
113
|
|
|
197
114
|
---
|
|
198
115
|
|
|
199
116
|
## 6. Header
|
|
200
117
|
|
|
201
|
-
Compact `h-12` sticky header
|
|
118
|
+
Compact `h-12` sticky header (`bg-slate-900 dark:bg-slate-950`). No ChatBar in the header — Eva lives below the map.
|
|
202
119
|
|
|
203
|
-
|
|
|
204
|
-
|
|
205
|
-
|
|
|
206
|
-
| Right | `ChatBar` (Eva) + notification bell (with pending count badge) + theme toggle (sun/moon) |
|
|
207
|
-
|
|
208
|
-
The `ChatBar` replaces any FAB or sliding panel. It opens inline as a command palette overlay.
|
|
120
|
+
| Left | Right |
|
|
121
|
+
|------|-------|
|
|
122
|
+
| Engine logo (`GlobeAltIcon` in `bg-brand-600` square) + "ENGINE" wordmark + separator + "Travel Command Center" + "Powered by Agentforce" badge (`bg-brand-900/40 text-brand-400 rounded-full text-[10px]`) | Notification bell (badge count) + theme toggle (sun/moon) |
|
|
209
123
|
|
|
210
124
|
---
|
|
211
125
|
|
|
212
126
|
## 7. Hero Map
|
|
213
127
|
|
|
214
|
-
**Component:** `GeoMap`
|
|
215
|
-
|
|
216
|
-
**Phase 1:** Render GeoMap with NO data props (no markers/arcs/overlays)
|
|
217
|
-
**Phase 2:** Add markers, arcs, and overlays from sample data to show where travelers are
|
|
128
|
+
**Component:** `GeoMap` from `@/components/library`
|
|
218
129
|
|
|
219
130
|
```tsx
|
|
220
|
-
import { MAP_MARKERS, MAP_ARCS, MAP_OVERLAYS } from "@/data/engine-sample-data";
|
|
221
|
-
|
|
222
|
-
// Phase 2 - with map data
|
|
223
131
|
<GeoMap
|
|
224
132
|
width={960}
|
|
225
133
|
height={520}
|
|
@@ -232,86 +140,100 @@ import { MAP_MARKERS, MAP_ARCS, MAP_OVERLAYS } from "@/data/engine-sample-data";
|
|
|
232
140
|
/>
|
|
233
141
|
```
|
|
234
142
|
|
|
235
|
-
**Markers:** One per city
|
|
236
|
-
|
|
237
|
-
**
|
|
238
|
-
|
|
239
|
-
**
|
|
143
|
+
- **Markers:** One per city. `{ id, lon, lat, label, active: true }`
|
|
144
|
+
- **Arcs:** One per flight route. `{ id, from: [lon, lat], to: [lon, lat], progress: 0–1, danger: boolean }`. `danger: true` on disrupted routes.
|
|
145
|
+
- **Overlays:** Weather zones. `{ id, center: [lon, lat], radius: number }`
|
|
146
|
+
- **Phase 1:** Render GeoMap with no data props (map renders base world automatically)
|
|
147
|
+
- **Phase 2:** Add `MAP_MARKERS`, `MAP_ARCS`, `MAP_OVERLAYS` from `@/data/engine-sample-data`
|
|
240
148
|
|
|
241
|
-
**Glass KPI overlays
|
|
242
|
-
|
|
243
|
-
- Spend MTD (formatted with `fmtK()`)
|
|
244
|
-
- Compliance %
|
|
245
|
-
- Eva Resolved (count + "resolved")
|
|
149
|
+
**Glass KPI overlays** — 4 pills, `absolute left-3 top-3`:
|
|
150
|
+
Active Travelers (count), Spend MTD (`fmtK()`), Compliance %, Eva Resolved (count + "resolved").
|
|
246
151
|
|
|
247
|
-
|
|
152
|
+
Label styling: `text-[10px] font-medium uppercase tracking-wide text-slate-300`
|
|
153
|
+
Value styling: `text-sm font-semibold text-slate-50`
|
|
154
|
+
Pill styling: `bg-black/40 backdrop-blur-md border border-white/10 rounded-lg px-3 py-1.5`
|
|
155
|
+
Icon: `h-4 w-4 text-brand-400`
|
|
248
156
|
|
|
249
|
-
**Flight status strip
|
|
157
|
+
**Flight status strip** — `absolute bottom-3 left-3 right-3`, horizontal scroll. One pill per flight: flight number + status chip (green=On Time, amber=Delayed, sky=Boarding). Same glass styling.
|
|
250
158
|
|
|
251
159
|
---
|
|
252
160
|
|
|
253
161
|
## 8. Data Panels
|
|
254
162
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
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.
|
|
258
|
-
|
|
259
|
-
### 8a. Disruptions Panel (1/3 width)
|
|
260
|
-
|
|
261
|
-
Custom inline component inside a `BaseCard`. Shows only flights that are delayed 60+ min or grounded.
|
|
262
|
-
|
|
263
|
-
Each disruption card:
|
|
264
|
-
- Severity dot (rose for grounded, amber for delayed) + flight number + severity label + delay minutes
|
|
265
|
-
- Route + affected traveler name
|
|
266
|
-
- Reason text
|
|
267
|
-
- Eva action line with `SparklesIcon` showing what Eva is doing about it
|
|
268
|
-
|
|
269
|
-
### 8b. Active Travelers (2/3 width)
|
|
163
|
+
4 panels in 2 rows. Sample data imported from `src/data/engine-sample-data.js`.
|
|
270
164
|
|
|
271
|
-
|
|
165
|
+
### 8a. Escalations (Row 1, 2/3 width)
|
|
272
166
|
|
|
273
|
-
|
|
274
|
-
- `Avatar` (initials) + name + department + origin → destination
|
|
275
|
-
- `UIChip` for policy status (success = compliant, warning = exception)
|
|
276
|
-
- Click to expand: 4-col grid showing Flight, Hotel, Return date, Destination
|
|
167
|
+
Custom inline panel in BaseCard. Do NOT use ActivityCard — this panel has per-item "Assign to Agent" buttons.
|
|
277
168
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
169
|
+
Each escalation row:
|
|
170
|
+
- Status icon: `CheckCircleIcon` (complete, green), `ArrowPathIcon` (working, brand), `ClockIcon` (pending, amber)
|
|
171
|
+
- Title + subtitle + timestamp
|
|
172
|
+
- **"Assign to Agent" button** on items where status is NOT `"complete"`: teal button (`bg-brand-600`) with `SparklesIcon` + "Assign to Agent" text. On click: `toast.success("Assigned to Eva")`
|
|
281
173
|
|
|
282
174
|
```tsx
|
|
283
175
|
<BaseCard>
|
|
284
|
-
<
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
176
|
+
<div className="p-4">
|
|
177
|
+
<h3 className="mb-3 text-sm font-semibold text-slate-900 dark:text-slate-50">
|
|
178
|
+
Escalations
|
|
179
|
+
</h3>
|
|
180
|
+
<div className="divide-y divide-slate-100 dark:divide-slate-800">
|
|
181
|
+
{escalations.map((e) => {
|
|
182
|
+
const isOpen = e.status !== "complete";
|
|
183
|
+
return (
|
|
184
|
+
<div key={e.id} className="flex items-start gap-3 py-3">
|
|
185
|
+
<StatusIcon className={`mt-0.5 h-5 w-5 shrink-0 ${statusColor}`} />
|
|
186
|
+
<div className="min-w-0 flex-1">
|
|
187
|
+
<div className="text-sm font-medium text-slate-900 dark:text-slate-50">{e.title}</div>
|
|
188
|
+
<div className="mt-0.5 text-xs text-slate-500 dark:text-slate-400">
|
|
189
|
+
{e.subtitle} · {e.timestamp}
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
{isOpen && (
|
|
193
|
+
<button onClick={() => handleAssignToAgent(e)}
|
|
194
|
+
className="shrink-0 rounded-md bg-brand-600 px-2.5 py-1 text-xs font-medium text-slate-50 hover:bg-brand-700">
|
|
195
|
+
<span className="flex items-center gap-1">
|
|
196
|
+
<SparklesIcon className="h-3 w-3" /> Assign to Agent
|
|
197
|
+
</span>
|
|
198
|
+
</button>
|
|
199
|
+
)}
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
})}
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
288
205
|
</BaseCard>
|
|
289
206
|
```
|
|
290
207
|
|
|
291
|
-
|
|
208
|
+
Data: `ESCALATION_CARDS` from sample data.
|
|
209
|
+
|
|
210
|
+
### 8b. Disruptions (Row 1, 1/3 width)
|
|
211
|
+
|
|
212
|
+
Custom inline component in BaseCard. Shows flights delayed 60+ min or grounded.
|
|
213
|
+
|
|
214
|
+
Each disruption card:
|
|
215
|
+
- Severity dot (rose=grounded, amber=delayed) + flight number + delay minutes
|
|
216
|
+
- Route + traveler name
|
|
217
|
+
- Reason text
|
|
218
|
+
- Eva action line with `SparklesIcon`
|
|
219
|
+
|
|
220
|
+
Data: `DISRUPTION_CARDS` from sample data.
|
|
292
221
|
|
|
293
|
-
|
|
294
|
-
- Title (issue description)
|
|
295
|
-
- Subtitle (details + context)
|
|
296
|
-
- Status: `"working"` (Eva is handling), `"pending"` (needs review), or `"complete"` (resolved)
|
|
297
|
-
- Timestamp
|
|
222
|
+
### 8c. Active Travelers (Row 2, 2/3 width)
|
|
298
223
|
|
|
299
|
-
|
|
300
|
-
- "Processing approval for Omar Hassan" - subtitle: "Paris trip over budget · escalated to manager" (status: pending)
|
|
301
|
-
- "Monitoring weather delay for Elena Rodriguez" - subtitle: "AF 99 · CDG arrival delayed 45 min · No action yet" (status: working)
|
|
302
|
-
- "Rebooked cancelled flight for Priya Patel" - subtitle: "LH 431 → LH 433 · Same fare class" (status: complete)
|
|
224
|
+
BaseCard with `maxBodyHeight={420}`. Expandable traveler cards.
|
|
303
225
|
|
|
304
|
-
|
|
226
|
+
Each row: `Avatar` (initials) + name + department + origin → destination + policy chip (compliant=green, exception=amber).
|
|
227
|
+
Expand: 4-col grid — Flight, Hotel, Return, Destination + "View in Salesforce" link.
|
|
305
228
|
|
|
306
|
-
|
|
229
|
+
Data: `TRAVELER_CARDS` from sample data.
|
|
307
230
|
|
|
308
|
-
|
|
231
|
+
### 8d. Monthly Spend Trend (Row 2, 1/3 width)
|
|
309
232
|
|
|
310
233
|
```tsx
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
live: []
|
|
234
|
+
const spendChartData = useDataSource({
|
|
235
|
+
sample: MONTHLY_SPEND.map(m => ({ x: m.month, spend: m.amount })),
|
|
236
|
+
live: [],
|
|
315
237
|
});
|
|
316
238
|
|
|
317
239
|
<ChartCard
|
|
@@ -336,145 +258,78 @@ const spendChartData = useDataSource({
|
|
|
336
258
|
/>
|
|
337
259
|
```
|
|
338
260
|
|
|
339
|
-
**Data source:** Import `MONTHLY_SPEND` from sample data, transform to chart format
|
|
340
|
-
|
|
341
|
-
**Requirements:**
|
|
342
|
-
- X-axis: month names (Oct through Mar) - categorical
|
|
343
|
-
- Y-axis: spend amount in dollars (will show as thousands: 98000, 128000, etc.)
|
|
344
|
-
- Height: 320px
|
|
345
|
-
- Bar color: Engine teal (#5BC8C8)
|
|
346
|
-
- Bar radius: 6 for rounded corners
|
|
347
|
-
- **Data transformation:** map `{ month, amount }` to `{ x, spend }` format inline
|
|
348
|
-
- responsive={true}
|
|
349
|
-
|
|
350
|
-
**Why this chart:** Shows spend trends over time so travel managers can spot anomalies, budget overruns, or seasonal patterns. Using bars instead of line because D3 lineChart requires numeric x-axis.
|
|
351
|
-
|
|
352
|
-
**That's it!** Only 4 panels total: Disruptions, Active Travelers, Escalations, and Monthly Spend Trend.
|
|
353
|
-
|
|
354
261
|
---
|
|
355
262
|
|
|
356
263
|
## 9. Eva — ChatBar
|
|
357
264
|
|
|
358
|
-
Eva
|
|
265
|
+
Eva renders as a full-width `ChatBar` below the hero map, between the map and the data panels. NOT in the header. NOT a FAB or sliding panel.
|
|
359
266
|
|
|
360
|
-
```
|
|
361
|
-
<
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
267
|
+
```tsx
|
|
268
|
+
<div className="px-4 pt-4">
|
|
269
|
+
<ChatBar
|
|
270
|
+
title="Eva"
|
|
271
|
+
placeholder="Ask Eva anything about travelers, bookings, policy, or spend…"
|
|
272
|
+
suggestions={CHAT_SUGGESTIONS}
|
|
273
|
+
onSend={handleChat}
|
|
274
|
+
/>
|
|
275
|
+
</div>
|
|
367
276
|
```
|
|
368
277
|
|
|
369
|
-
|
|
370
|
-
- "Who's traveling internationally right now?"
|
|
371
|
-
- "Show bookings pending approval"
|
|
372
|
-
- "What has Eva resolved today?"
|
|
373
|
-
- "Travelers returning this week"
|
|
278
|
+
Suggestions: "Who's traveling internationally right now?", "Show bookings pending approval", "What has Eva resolved today?", "Travelers returning this week"
|
|
374
279
|
|
|
375
|
-
|
|
280
|
+
Define `handleChat` and `CHAT_SUGGESTIONS` at module scope.
|
|
376
281
|
|
|
377
|
-
**
|
|
282
|
+
**Phase 1:** Placeholder — do NOT add ChatBar. Just leave the space empty.
|
|
283
|
+
**Phase 4:** Add the ChatBar between the map and data panels.
|
|
378
284
|
|
|
379
285
|
---
|
|
380
286
|
|
|
381
|
-
## 10. Salesforce Signals (Phase 4
|
|
287
|
+
## 10. Salesforce Signals (Phase 4)
|
|
382
288
|
|
|
383
|
-
|
|
289
|
+
Subtle indicators, not banners.
|
|
384
290
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
|
388
|
-
|
|
389
|
-
| "
|
|
390
|
-
| "
|
|
391
|
-
| "Powered by Agentforce" | ChatBar title or subtitle area | Small badge/chip | Phase 4 |
|
|
291
|
+
| Signal | Location |
|
|
292
|
+
|--------|----------|
|
|
293
|
+
| "Powered by Agentforce" | Header, next to "Travel Command Center" (small rounded badge) |
|
|
294
|
+
| "View in Salesforce" | Traveler expanded view (micro-link, muted text) |
|
|
295
|
+
| "Salesforce updated" | After rebook/approve actions (`toast()`) |
|
|
296
|
+
| "Assigned to Eva" | After "Assign to Agent" button click (`toast.success()`) |
|
|
392
297
|
|
|
393
298
|
---
|
|
394
299
|
|
|
395
300
|
## 11. Dark Mode
|
|
396
301
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
- Use the standard dark mode pairs from the builder rules (bg-white/dark:bg-slate-900, etc.)
|
|
400
|
-
- The GeoMap has built-in dark/light themes — pass `theme={mode === "dark" ? "dark" : "light"}`
|
|
401
|
-
- Glass overlays use `bg-black/40 backdrop-blur-md` which works in both modes
|
|
402
|
-
- Custom inline components (disruption cards, flight chips) must include `dark:` variants on every color class
|
|
403
|
-
- Never use `text-black` or `text-white` directly — use the slate scale
|
|
404
|
-
- Theme toggle button in the header (sun/moon icon)
|
|
302
|
+
Every element supports light and dark. GeoMap: `theme={mode === "dark" ? "dark" : "light"}`. Glass overlays work in both modes. Use slate scale (no `text-white` or `text-black`). Theme toggle in header.
|
|
405
303
|
|
|
406
304
|
---
|
|
407
305
|
|
|
408
306
|
## 12. Data Model
|
|
409
307
|
|
|
410
|
-
**Traveler** — `id`, `name`, `department`, `destination`, `origin`, `hotel`, `flight`, `return`, `
|
|
411
|
-
|
|
412
|
-
**
|
|
413
|
-
|
|
414
|
-
**
|
|
415
|
-
|
|
416
|
-
**Map Coordinates** — City name → `[lon, lat]` lookup object. Markers derived from coordinates. Arcs derived from flight origin/destination pairs.
|
|
417
|
-
|
|
418
|
-
**Booking** — `id`, `traveler`, `type`, `destination`, `dates`, `cost`, `status` (Confirmed | Pending approval), `policy` (In policy | Over budget | Exception granted)
|
|
419
|
-
|
|
420
|
-
**Policy Item** — `id`, `title`, `description`, `status` (operational | degraded), `timestamp`
|
|
421
|
-
|
|
422
|
-
**Escalation** — `id`, `title`, `subtitle`, `status` (complete | working | pending), `timestamp`
|
|
423
|
-
|
|
424
|
-
**Monthly Spend** — `{ month: string, amount: number }` array. Six months of travel spend data (Oct through Mar). Amounts in dollars, typically $98K-$156K range.
|
|
425
|
-
|
|
426
|
-
**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.
|
|
308
|
+
- **Traveler** — `id`, `name`, `department`, `destination`, `origin`, `hotel`, `flight`, `return`, `policyStatus` (compliant | exception)
|
|
309
|
+
- **Flight** — `id`, `flight`, `route`, `dep`, `status` (On Time | Delayed | Boarding | In Air | Landed), `traveler`, `delayMin`
|
|
310
|
+
- **Disruption** — `id`, `flight`, `route`, `traveler`, `severity` (grounded | delayed), `delayMin`, `reason`, `evaAction`
|
|
311
|
+
- **Escalation** — `id`, `title`, `subtitle`, `status` (complete | working | pending), `timestamp`
|
|
312
|
+
- **Monthly Spend** — `{ month, amount }` array, 6 months (Oct–Mar), $98K–$156K range
|
|
313
|
+
- **Sample data:** Pre-built in `src/data/engine-sample-data.js`. 8 travelers, 8 flights, 4 disruptions, 8 escalations, 6 months spend. All deterministic.
|
|
427
314
|
|
|
428
315
|
---
|
|
429
316
|
|
|
430
317
|
## 13. Build Prompts
|
|
431
318
|
|
|
432
|
-
Build in 4 incremental phases.
|
|
433
|
-
|
|
434
|
-
---
|
|
319
|
+
Build in 4 incremental phases.
|
|
435
320
|
|
|
436
321
|
### Phase 1: Layout & Structure
|
|
437
322
|
|
|
438
323
|
> Scaffold the Engine Travel Command Center skeleton. Build the visualization-hero layout from section 5 with the header, hero map, glass KPI overlays, flight status strip, and placeholder cards for the data panels.
|
|
439
324
|
|
|
440
|
-
---
|
|
441
|
-
|
|
442
325
|
### Phase 2: Components & Sample Data
|
|
443
326
|
|
|
444
|
-
> Replace the placeholders with real components and wire up the sample data. Build the 4 data panels from section 8 — Disruptions, Active Travelers,
|
|
445
|
-
|
|
446
|
-
---
|
|
327
|
+
> Replace the placeholders with real components and wire up the sample data. Build the 4 data panels from section 8 — Escalations, Disruptions, Active Travelers, and Monthly Spend Trend. Add map markers, arcs, and overlays from the sample data so we can see where travelers are.
|
|
447
328
|
|
|
448
329
|
### Phase 3: Real Data Integration
|
|
449
330
|
|
|
450
331
|
> Connect the dashboard to live Salesforce data using GraphQL. Read the sample data file to see which fields are needed, then build queries and hooks for each object. The UI should stay identical — just swap the data source.
|
|
451
332
|
|
|
452
|
-
---
|
|
453
|
-
|
|
454
333
|
### Phase 4: Agentforce Integration
|
|
455
334
|
|
|
456
|
-
> Add Eva
|
|
457
|
-
|
|
458
|
-
---
|
|
459
|
-
|
|
460
|
-
## 14. What NOT to Do
|
|
461
|
-
|
|
462
|
-
These are explicit anti-patterns. If any prompt output includes these, it must be corrected:
|
|
463
|
-
|
|
464
|
-
- Do not use `react-simple-maps`, Recharts, or any charting library other than the built-in `D3Chart` + `D3ChartTemplates`
|
|
465
|
-
- Do not use Lucide icons, Font Awesome, or any icon library other than Heroicons 2
|
|
466
|
-
- Do not import from `src/components/ui/` (shadcn) — use `@/components/library` exclusively
|
|
467
|
-
- Do not use `cn()` helper — that belongs to the outer app
|
|
468
|
-
- Do not recreate `AppThemeProvider`, `DataModeProvider`, or `Toast.Provider` — `CommandCenter.tsx` provides them
|
|
469
|
-
- Do not build a FAB or sliding chat panel — use `ChatBar` in the header
|
|
470
|
-
- Do not hardcode hex color values in component JSX — use `brand-*` Tailwind classes and Tailwind built-in colors for status
|
|
471
|
-
- Do not use `bg-indigo-*` for brand — use `brand-*`
|
|
472
|
-
- Do not use `text-black` or `text-white` — use the slate scale
|
|
473
|
-
- Do not put more than 4 KPIs in a row
|
|
474
|
-
- Do not squeeze the map into a grid column — it must be full-width hero
|
|
475
|
-
- Do not wrap GeoMap in ChartCard — render it directly
|
|
476
|
-
- Do not use `Math.random()` in sample data
|
|
477
|
-
- Do not skip dark mode on any visible element
|
|
478
|
-
- Do not use inline `style={{}}` for layout except the flex properties on the hero/panel containers
|
|
479
|
-
- Do not put `ChatPanel` in the dashboard grid
|
|
480
|
-
- Do not use `position: fixed` without `createPortal` to `document.body`
|
|
335
|
+
> Add Eva below the map as a ChatBar. Add subtle Salesforce signals throughout — "Powered by Agentforce" badge in the header, "View in Salesforce" links in traveler details, success toasts, and "Assign to Agent" buttons on open escalations.
|