@schandlergarcia/sf-web-components 1.9.72 → 1.9.74
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 +38 -3
- package/CHANGELOG.md +23 -0
- package/assets/images/engine_logo.png +0 -0
- package/data/engine-command-center-prd.md +201 -40
- package/data/engine-live-data.js +51 -50
- package/dist/styles/global.css +6 -6
- package/package.json +2 -1
- package/scripts/postinstall.mjs +19 -0
- package/scripts/reset-command-center.sh +23 -0
|
@@ -104,7 +104,7 @@ No `<nav>`, header bar, tab bar, or content-swapping via `useState("activeTab")`
|
|
|
104
104
|
|
|
105
105
|
- Dashboard page files: `src/pages/` (e.g. `EngineDashboard.tsx`, `FleetDashboard.tsx`) — **NOT** `src/components/pages/`
|
|
106
106
|
- File format: `.tsx` (MUST be TypeScript) — this is a TypeScript project, all React components use `.tsx`, NEVER `.jsx`.
|
|
107
|
-
- `CommandCenter.tsx` wraps with `heroui-scope` div + `AppThemeProvider` + `DataModeProvider` + `Toast.Provider` from `@heroui/react`. **Never recreate these providers in dashboard pages.** When wiring a new dashboard, only change the import — preserve the `heroui-scope` wrapper and `Toast.Provider` exactly as-is. For toasts inside dashboards,
|
|
107
|
+
- `CommandCenter.tsx` wraps with `heroui-scope` div + `AppThemeProvider` + `DataModeProvider` + `Toast.Provider` from `@heroui/react`. **Never recreate these providers in dashboard pages.** When wiring a new dashboard, only change the import — preserve the `heroui-scope` wrapper and `Toast.Provider` exactly as-is. For toasts inside dashboards, import `toast` from `@heroui/react` (or `@/components/library`) — NOT from `sonner`.
|
|
108
108
|
|
|
109
109
|
### Wiring a new dashboard (REQUIRED STEPS)
|
|
110
110
|
|
|
@@ -321,6 +321,7 @@ Three layers: `filterUtils.js` (pure) → `usePageFilters` hook (state) → `Fil
|
|
|
321
321
|
- Same layout for both modes — only data changes.
|
|
322
322
|
- Sample data: 10–50 items, realistic, deterministic (no `Math.random()`).
|
|
323
323
|
- Define sample data as constants outside the component body.
|
|
324
|
+
- **Live data simulation:** When GraphQL is unavailable, use a separate live data file (`engine-live-data.js`) with a visibly different dataset. Create a hook that simulates async loading via `setTimeout`, then calls `setMode("live")` to flip all `useDataSource` calls at once. This makes the data transition visible — components refresh with new values after a loading period.
|
|
324
325
|
|
|
325
326
|
```jsx
|
|
326
327
|
// ✅ Correct: data defined outside, selected by mode
|
|
@@ -490,7 +491,7 @@ Before finishing a dashboard page, verify ALL of these:
|
|
|
490
491
|
|
|
491
492
|
## Post-Completion Verification
|
|
492
493
|
|
|
493
|
-
**DO NOT run `npm run validate:dashboard`, `npm run dev`, `npm run build`, or `tsc` during builds.** These waste time and are not required for
|
|
494
|
+
**DO NOT run `npm run validate:dashboard`, `npm run dev`, `npm run build`, or `tsc` during builds.** These waste time and are not required for completion.
|
|
494
495
|
|
|
495
496
|
Instead, verify correctness by reviewing the code against the Pre-Completion Checklist above. Confirm that all three wiring files are updated (CommandCenter.tsx, Home.tsx, routes.tsx).
|
|
496
497
|
|
|
@@ -504,8 +505,42 @@ Instead, verify correctness by reviewing the code against the Pre-Completion Che
|
|
|
504
505
|
- Passing D3Chart as children to ChartCard — use `chart={<D3Chart ... />}` prop
|
|
505
506
|
- Adding `<nav>` or tab-swapping (`useState("activeTab")`) inside dashboards
|
|
506
507
|
- Recreating providers — `CommandCenter.tsx` already provides them. Do not replace `Toast.Provider` with `Toaster` from sonner, and do not remove the `heroui-scope` div
|
|
507
|
-
-
|
|
508
|
+
- Importing `toast` from `sonner` — use `toast` / `toast.success` from `@heroui/react` (or `@/components/library`) instead. The `Toast.Provider` is HeroUI's, so only HeroUI's `toast` renders through it
|
|
508
509
|
- Using `text-black`, `text-white`, `bg-black` — use slate scale
|
|
509
510
|
- Hardcoded data without `useDataSource` — always support sample/live switching
|
|
510
511
|
- `position: fixed` without `createPortal`
|
|
511
512
|
- `Math.random()` in sample data
|
|
513
|
+
|
|
514
|
+
## Salesforce Metadata Patterns
|
|
515
|
+
|
|
516
|
+
This is an SFDX project (`force-app/main/default/`). When the build requires metadata changes — permission sets, custom fields, flows, record types — write standard SFDX XML files and deploy with the Salesforce CLI.
|
|
517
|
+
|
|
518
|
+
### File locations
|
|
519
|
+
|
|
520
|
+
| Metadata type | Path pattern |
|
|
521
|
+
|---|---|
|
|
522
|
+
| Permission Set | `force-app/main/default/permissionsets/{Name}.permissionset-meta.xml` |
|
|
523
|
+
| Custom Field | `force-app/main/default/objects/{Object}/fields/{Field}.field-meta.xml` |
|
|
524
|
+
| Flow | `force-app/main/default/flows/{Name}.flow-meta.xml` |
|
|
525
|
+
| Record Type | `force-app/main/default/objects/{Object}/recordTypes/{Name}.recordType-meta.xml` |
|
|
526
|
+
| Email Template | `force-app/main/default/email/{Folder}/{Name}.email-meta.xml` |
|
|
527
|
+
|
|
528
|
+
### Deploy command
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
sf project deploy start --source-dir force-app/main/default/permissionsets/MyPermSet.permissionset-meta.xml
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
Use `--source-dir` to deploy individual files. For multiple files, point to the parent directory.
|
|
535
|
+
|
|
536
|
+
### When to create metadata
|
|
537
|
+
|
|
538
|
+
During the build, proactively check whether the Salesforce org has the metadata needed for the features you're building. If something is missing — a field isn't accessible, a record type doesn't exist, a flow would automate a manual process — tell the user what's missing and ask before creating it. The PRD's build prompts include specific scripted moments for these interactions.
|
|
539
|
+
|
|
540
|
+
### Key rules
|
|
541
|
+
|
|
542
|
+
- Always use API version `62.0` or higher
|
|
543
|
+
- Permission set field permissions: set `readable` to `true`, `editable` to `false` for read-only dashboard fields
|
|
544
|
+
- Flows: set `status` to `Draft` — the user will activate after review
|
|
545
|
+
- Never deploy destructive changes without explicit confirmation
|
|
546
|
+
- Never modify standard Salesforce objects' core fields — only add custom fields
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ 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.74] - 2026-04-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Engine logo asset** - `assets/images/engine_logo.png` restored from internal-app-standard-config
|
|
12
|
+
- Postinstall script copies to `src/assets/images/engine_logo.png`
|
|
13
|
+
- Reset script restores to baseline
|
|
14
|
+
|
|
15
|
+
### Updated
|
|
16
|
+
- **PRD (engine-command-center-prd.md)** - Latest rewritten version from react-cursor-1
|
|
17
|
+
- **Live data files**:
|
|
18
|
+
- `data/engine-live-data.js` - Updated with Midwest storm dataset
|
|
19
|
+
- `data/useEngineLiveData.ts` - Updated loading hook
|
|
20
|
+
- **Global styles (src/styles/global.css)** - Added ChatBar overlay padding rule
|
|
21
|
+
- **Builder skill (SKILL.md)** - Updated with metadata patterns
|
|
22
|
+
- **package.json** - Added "assets" to files array
|
|
23
|
+
|
|
24
|
+
**Context:** Restored Engine logo asset that was previously missing. All Engine branding assets now included in package.
|
|
25
|
+
|
|
26
|
+
## [1.9.73] - 2026-04-02
|
|
27
|
+
|
|
28
|
+
### Updated
|
|
29
|
+
- **PRD, live data, global styles, and SKILL.md** - Latest updates from react-cursor-1
|
|
30
|
+
|
|
8
31
|
## [1.9.72] - 2026-04-02
|
|
9
32
|
|
|
10
33
|
### Added
|
|
Binary file
|
|
@@ -8,7 +8,7 @@ Product Requirements Document
|
|
|
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
|
-
**Build approach:** Incremental — PRD →
|
|
11
|
+
**Build approach:** Incremental — PRD → dashboard → data → agent.
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -53,6 +53,7 @@ Use `brand-*` Tailwind classes for brand elements. Tailwind built-in colors (gre
|
|
|
53
53
|
- **Wiring:** `CommandCenter.tsx` imports and renders `EngineDashboard` inside the existing provider stack. Never recreate providers in the dashboard. When updating `CommandCenter.tsx`, only change the dashboard import line — preserve the `heroui-scope` wrapper div and `Toast.Provider` from `@heroui/react` exactly as-is.
|
|
54
54
|
- **Toasts:** Import `toast` from `@heroui/react` in dashboard pages. Use `toast.success("message")` for success toasts and `toast("message")` for informational ones. The `Toast.Provider` in CommandCenter handles rendering — do not add a second `Toaster` or replace the existing provider.
|
|
55
55
|
- **Imports:** Components from `@/components/library`. Theme from `@/components/library/theme/AppThemeProvider`.
|
|
56
|
+
- **Salesforce metadata:** This is an SFDX project. Metadata lives in `force-app/main/default/`. When creating permission sets, custom fields, flows, or other metadata, write standard SFDX XML files and deploy with `sf project deploy start`.
|
|
56
57
|
|
|
57
58
|
---
|
|
58
59
|
|
|
@@ -98,20 +99,6 @@ Visualization-hero layout. Full-page scroll (no `h-screen`).
|
|
|
98
99
|
- **Row 1:** `grid grid-cols-1 items-start gap-4 lg:grid-cols-3` — Escalations `lg:col-span-2`, Disruptions auto
|
|
99
100
|
- **Row 2:** `grid grid-cols-1 items-start gap-4 lg:grid-cols-3` — Travelers `lg:col-span-2`, Spend auto
|
|
100
101
|
|
|
101
|
-
### Phase 1 placeholders
|
|
102
|
-
|
|
103
|
-
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:
|
|
104
|
-
|
|
105
|
-
```tsx
|
|
106
|
-
<BaseCard>
|
|
107
|
-
<div className="h-48 flex items-center justify-center text-slate-400">
|
|
108
|
-
Escalations Panel
|
|
109
|
-
</div>
|
|
110
|
-
</BaseCard>
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
The GeoMap renders the base world map with no data props. Glass overlays and flight strip use hardcoded values.
|
|
114
|
-
|
|
115
102
|
---
|
|
116
103
|
|
|
117
104
|
## 6. Header
|
|
@@ -120,7 +107,7 @@ Compact `h-12` sticky header (`bg-slate-900 dark:bg-slate-950`). No ChatBar in t
|
|
|
120
107
|
|
|
121
108
|
| Left | Right |
|
|
122
109
|
|------|-------|
|
|
123
|
-
| Engine logo (`GlobeAltIcon` in `bg-brand-600` square) + "ENGINE" wordmark + separator + "Travel Command Center" + "Powered by Agentforce" badge (
|
|
110
|
+
| 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) |
|
|
124
111
|
|
|
125
112
|
---
|
|
126
113
|
|
|
@@ -133,9 +120,9 @@ Compact `h-12` sticky header (`bg-slate-900 dark:bg-slate-950`). No ChatBar in t
|
|
|
133
120
|
width={960}
|
|
134
121
|
height={520}
|
|
135
122
|
theme={mode === "dark" ? "dark" : "light"}
|
|
136
|
-
markers={useDataSource({ sample: MAP_MARKERS, live:
|
|
137
|
-
arcs={useDataSource({ sample: MAP_ARCS, live:
|
|
138
|
-
overlays={useDataSource({ sample: MAP_OVERLAYS, live:
|
|
123
|
+
markers={useDataSource({ sample: MAP_MARKERS, live: live.mapMarkers })}
|
|
124
|
+
arcs={useDataSource({ sample: MAP_ARCS, live: live.mapArcs })}
|
|
125
|
+
overlays={useDataSource({ sample: MAP_OVERLAYS, live: live.mapOverlays })}
|
|
139
126
|
zoomable
|
|
140
127
|
className="h-full w-full"
|
|
141
128
|
/>
|
|
@@ -144,8 +131,6 @@ Compact `h-12` sticky header (`bg-slate-900 dark:bg-slate-950`). No ChatBar in t
|
|
|
144
131
|
- **Markers:** One per city. `{ id, lon, lat, label, active: true }`
|
|
145
132
|
- **Arcs:** One per flight route. `{ id, from: [lon, lat], to: [lon, lat], progress: 0–1, danger: boolean }`. `danger: true` on disrupted routes.
|
|
146
133
|
- **Overlays:** Weather zones. `{ id, center: [lon, lat], radius: number }`
|
|
147
|
-
- **Phase 1:** Render GeoMap with no data props (map renders base world automatically)
|
|
148
|
-
- **Phase 2:** Add `MAP_MARKERS`, `MAP_ARCS`, `MAP_OVERLAYS` from `@/data/engine-sample-data`
|
|
149
134
|
|
|
150
135
|
**Glass KPI overlays** — 4 pills, `absolute left-3 top-3`:
|
|
151
136
|
Active Travelers (count), Spend MTD (`fmtK()`), Compliance %, Eva Resolved (count + "resolved").
|
|
@@ -170,7 +155,7 @@ Custom inline panel in BaseCard. Do NOT use ActivityCard — this panel has per-
|
|
|
170
155
|
Each escalation row:
|
|
171
156
|
- Status icon: `CheckCircleIcon` (complete, green), `ArrowPathIcon` (working, brand), `ClockIcon` (pending, amber)
|
|
172
157
|
- Title + subtitle + timestamp
|
|
173
|
-
- **"Assign to Agent" button**
|
|
158
|
+
- **"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")` via `@heroui/react`.
|
|
174
159
|
|
|
175
160
|
```tsx
|
|
176
161
|
<BaseCard>
|
|
@@ -191,7 +176,7 @@ Each escalation row:
|
|
|
191
176
|
</div>
|
|
192
177
|
</div>
|
|
193
178
|
{isOpen && (
|
|
194
|
-
<button onClick={() =>
|
|
179
|
+
<button onClick={() => toast.success("Assigned to Eva")}
|
|
195
180
|
className="shrink-0 rounded-md bg-brand-600 px-2.5 py-1 text-xs font-medium text-slate-50 hover:bg-brand-700">
|
|
196
181
|
<span className="flex items-center gap-1">
|
|
197
182
|
<SparklesIcon className="h-3 w-3" /> Assign to Agent
|
|
@@ -234,7 +219,7 @@ Data: `TRAVELER_CARDS` from sample data.
|
|
|
234
219
|
```tsx
|
|
235
220
|
const spendChartData = useDataSource({
|
|
236
221
|
sample: MONTHLY_SPEND.map(m => ({ x: m.month, spend: m.amount })),
|
|
237
|
-
live:
|
|
222
|
+
live: live.monthlySpend.map(m => ({ x: m.month, spend: m.amount })),
|
|
238
223
|
});
|
|
239
224
|
|
|
240
225
|
<ChartCard
|
|
@@ -276,18 +261,15 @@ Eva renders as a full-width `ChatBar` below the hero map, between the map and th
|
|
|
276
261
|
</div>
|
|
277
262
|
```
|
|
278
263
|
|
|
279
|
-
Suggestions: "
|
|
264
|
+
Suggestions: "Storm warning in the Midwest — which travelers are affected?", "What's our severe weather rebooking policy?", "Notify Anna and Sofia about the Chicago delays", "Create a support case for Anna Johansson's flight"
|
|
280
265
|
|
|
281
266
|
Define `handleChat` and `CHAT_SUGGESTIONS` at module scope.
|
|
282
267
|
|
|
283
|
-
**Phase 1:** Placeholder — do NOT add ChatBar. Just leave the space empty.
|
|
284
|
-
**Phase 4:** Add the ChatBar between the map and data panels.
|
|
285
|
-
|
|
286
268
|
---
|
|
287
269
|
|
|
288
|
-
## 10. Salesforce Signals
|
|
270
|
+
## 10. Salesforce Signals
|
|
289
271
|
|
|
290
|
-
Subtle indicators
|
|
272
|
+
Subtle indicators throughout the dashboard — not banners.
|
|
291
273
|
|
|
292
274
|
| Signal | Location |
|
|
293
275
|
|--------|----------|
|
|
@@ -317,27 +299,206 @@ Every element supports light and dark. GeoMap: `theme={mode === "dark" ? "dark"
|
|
|
317
299
|
|
|
318
300
|
## 13. Build Prompts
|
|
319
301
|
|
|
320
|
-
Build in
|
|
302
|
+
Build incrementally in 3 prompts. Each prompt builds on the previous result.
|
|
321
303
|
|
|
322
|
-
|
|
304
|
+
---
|
|
323
305
|
|
|
324
|
-
|
|
306
|
+
### Build the Dashboard
|
|
325
307
|
|
|
326
|
-
|
|
308
|
+
> Build the Engine Travel Command Center dashboard. Read the PRD for the full spec. Create the visualization-hero layout with the sticky header, hero GeoMap, glass KPI overlays, flight status strip, and all 4 data panels — Escalations, Disruptions, Active Travelers, and Monthly Spend Trend. Wire up the sample data from `src/data/engine-sample-data.js` so we can see real travelers, flights, and map markers. Include the "Assign to Agent" buttons on open escalations, the "View in Salesforce" links in traveler details, the "Powered by Agentforce" badge in the header, and the Salesforce signal toasts. Skip the Eva ChatBar for now — we'll add that after we connect to live data.
|
|
327
309
|
|
|
328
|
-
|
|
310
|
+
---
|
|
329
311
|
|
|
330
|
-
###
|
|
312
|
+
### Connect to Salesforce Data
|
|
331
313
|
|
|
332
|
-
> Connect the dashboard to live Salesforce data
|
|
314
|
+
> Connect the dashboard to live Salesforce data. A second dataset already exists in `src/data/engine-live-data.js` with 12 travelers across global routes and different KPIs (distinct from the 8-traveler sample data). A hook already exists at `src/hooks/useEngineLiveData.ts` — it imports the live data, simulates a 2-second loading delay, then calls `setMode("live")` to flip the global data mode.
|
|
315
|
+
>
|
|
316
|
+
> Import `useEngineLiveData` in the dashboard and populate the `live` prop on each `useDataSource` call:
|
|
333
317
|
>
|
|
334
318
|
> ```tsx
|
|
335
319
|
> const live = useEngineLiveData();
|
|
336
320
|
> const markers = useDataSource({ sample: MAP_MARKERS, live: live.mapMarkers });
|
|
321
|
+
> const arcs = useDataSource({ sample: MAP_ARCS, live: live.mapArcs });
|
|
322
|
+
> ```
|
|
323
|
+
>
|
|
324
|
+
> Also update the KPI overlays to re-derive from whichever metrics are active:
|
|
325
|
+
>
|
|
326
|
+
> ```tsx
|
|
327
|
+
> const activeMetrics = live.loading ? METRICS : live.metrics;
|
|
337
328
|
> ```
|
|
338
329
|
>
|
|
339
|
-
> The
|
|
330
|
+
> When the page loads, the audience will see: sample data renders immediately → after 2 seconds components refresh with different travelers, cities, and numbers → proving the data integration works. The layout stays identical — only the data changes.
|
|
331
|
+
|
|
332
|
+
**Scripted metadata interaction — Permission Set:**
|
|
333
|
+
After wiring the live data, check the field-level security for the objects being queried. The `External_Travel_Manager` permission set does not have read access to `Disruption__c.Severity__c`. Tell the user:
|
|
334
|
+
|
|
335
|
+
> "I notice the `External_Travel_Manager` permission set doesn't have read access to `Disruption__c.Severity__c`. This field is needed to display disruption severity in the dashboard. Would you like me to update the permission set?"
|
|
336
|
+
|
|
337
|
+
When the user confirms, create:
|
|
338
|
+
|
|
339
|
+
`force-app/main/default/permissionsets/External_Travel_Manager.permissionset-meta.xml`
|
|
340
|
+
|
|
341
|
+
```xml
|
|
342
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
343
|
+
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
344
|
+
<label>External Travel Manager</label>
|
|
345
|
+
<description>Field access for the Engine Travel Command Center dashboard</description>
|
|
346
|
+
<fieldPermissions>
|
|
347
|
+
<editable>false</editable>
|
|
348
|
+
<field>Disruption__c.Severity__c</field>
|
|
349
|
+
<readable>true</readable>
|
|
350
|
+
</fieldPermissions>
|
|
351
|
+
<fieldPermissions>
|
|
352
|
+
<editable>false</editable>
|
|
353
|
+
<field>Disruption__c.Affected_Traveler_Count__c</field>
|
|
354
|
+
<readable>true</readable>
|
|
355
|
+
</fieldPermissions>
|
|
356
|
+
<fieldPermissions>
|
|
357
|
+
<editable>false</editable>
|
|
358
|
+
<field>Flight__c.Delay_Minutes__c</field>
|
|
359
|
+
<readable>true</readable>
|
|
360
|
+
</fieldPermissions>
|
|
361
|
+
<fieldPermissions>
|
|
362
|
+
<editable>false</editable>
|
|
363
|
+
<field>Flight__c.Flight_Status__c</field>
|
|
364
|
+
<readable>true</readable>
|
|
365
|
+
</fieldPermissions>
|
|
366
|
+
<fieldPermissions>
|
|
367
|
+
<editable>false</editable>
|
|
368
|
+
<field>Rebooking_Action__c.Status__c</field>
|
|
369
|
+
<readable>true</readable>
|
|
370
|
+
</fieldPermissions>
|
|
371
|
+
<hasActivationRequired>false</hasActivationRequired>
|
|
372
|
+
<license>Salesforce</license>
|
|
373
|
+
</PermissionSet>
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Then run: `sf project deploy start --source-dir force-app/main/default/permissionsets/External_Travel_Manager.permissionset-meta.xml`
|
|
377
|
+
|
|
378
|
+
**Scripted metadata interaction — Custom Field:**
|
|
379
|
+
After fixing the permission set, notice that `Flight__c` has no way to track weather impact on individual flights. Tell the user:
|
|
380
|
+
|
|
381
|
+
> "There's no `Weather_Impact__c` field on `Flight__c` to track weather-related disruptions. This would help the dashboard filter storm-affected flights. Want me to create it?"
|
|
382
|
+
|
|
383
|
+
When the user confirms, create:
|
|
384
|
+
|
|
385
|
+
`force-app/main/default/objects/Flight__c/fields/Weather_Impact__c.field-meta.xml`
|
|
386
|
+
|
|
387
|
+
```xml
|
|
388
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
389
|
+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
390
|
+
<fullName>Weather_Impact__c</fullName>
|
|
391
|
+
<label>Weather Impact</label>
|
|
392
|
+
<type>Picklist</type>
|
|
393
|
+
<required>false</required>
|
|
394
|
+
<valueSet>
|
|
395
|
+
<restricted>true</restricted>
|
|
396
|
+
<valueSetDefinition>
|
|
397
|
+
<sorted>false</sorted>
|
|
398
|
+
<value><fullName>None</fullName><default>true</default><label>None</label></value>
|
|
399
|
+
<value><fullName>Minor</fullName><default>false</default><label>Minor</label></value>
|
|
400
|
+
<value><fullName>Moderate</fullName><default>false</default><label>Moderate</label></value>
|
|
401
|
+
<value><fullName>Severe</fullName><default>false</default><label>Severe</label></value>
|
|
402
|
+
</valueSetDefinition>
|
|
403
|
+
</valueSet>
|
|
404
|
+
</CustomField>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Then run: `sf project deploy start --source-dir force-app/main/default/objects/Flight__c/fields/Weather_Impact__c.field-meta.xml`
|
|
408
|
+
|
|
409
|
+
Also update the permission set to include read access to the new field.
|
|
340
410
|
|
|
341
|
-
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
### Add Agentforce
|
|
414
|
+
|
|
415
|
+
> Add Eva to the dashboard. Place the ChatBar between the map and data panels using the suggestions from section 9. Wire up the `handleChat` mock response.
|
|
416
|
+
|
|
417
|
+
**Scripted metadata interaction — Flow for Weather Notifications:**
|
|
418
|
+
After adding the ChatBar, tell the user:
|
|
419
|
+
|
|
420
|
+
> "Since the dashboard handles weather disruptions, I can create a Flow that automatically sends weather delay alerts to affected travelers. It would query `Disruption__c` records where `Disruption_Type__c = 'Weather Event'`, match them to `Contact` records via `Flight__c`, and send a notification email. Want me to build it?"
|
|
421
|
+
|
|
422
|
+
When the user confirms, create:
|
|
423
|
+
|
|
424
|
+
`force-app/main/default/flows/Travel_Weather_Alert_Notification.flow-meta.xml`
|
|
425
|
+
|
|
426
|
+
```xml
|
|
427
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
428
|
+
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
429
|
+
<apiVersion>62.0</apiVersion>
|
|
430
|
+
<label>Travel Weather Alert Notification</label>
|
|
431
|
+
<description>Sends weather delay alerts to travelers affected by disruptions. Triggered when a Disruption__c record is created or updated with Disruption_Type__c = Weather Event.</description>
|
|
432
|
+
<status>Draft</status>
|
|
433
|
+
<processType>AutoLaunchedFlow</processType>
|
|
434
|
+
<start>
|
|
435
|
+
<object>Disruption__c</object>
|
|
436
|
+
<triggerType>RecordAfterSave</triggerType>
|
|
437
|
+
<recordTriggerType>CreateAndUpdate</recordTriggerType>
|
|
438
|
+
<filterLogic>and</filterLogic>
|
|
439
|
+
<filters>
|
|
440
|
+
<field>Disruption_Type__c</field>
|
|
441
|
+
<operator>EqualTo</operator>
|
|
442
|
+
<value><stringValue>Weather Event</stringValue></value>
|
|
443
|
+
</filters>
|
|
444
|
+
</start>
|
|
445
|
+
<interviewLabel>Travel Weather Alert {!$Flow.CurrentDateTime}</interviewLabel>
|
|
446
|
+
</Flow>
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Then run: `sf project deploy start --source-dir force-app/main/default/flows/Travel_Weather_Alert_Notification.flow-meta.xml`
|
|
450
|
+
|
|
451
|
+
**Scripted metadata interaction — Case Record Type:**
|
|
452
|
+
After creating the Flow, tell the user:
|
|
453
|
+
|
|
454
|
+
> "The 'Create a support case' prompt needs a dedicated record type. The Case object doesn't have a `Travel_Support` record type yet. Should I create it?"
|
|
455
|
+
|
|
456
|
+
When the user confirms, create:
|
|
457
|
+
|
|
458
|
+
`force-app/main/default/objects/Case/recordTypes/Travel_Support.recordType-meta.xml`
|
|
459
|
+
|
|
460
|
+
```xml
|
|
461
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
462
|
+
<RecordType xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
463
|
+
<fullName>Travel_Support</fullName>
|
|
464
|
+
<label>Travel Support</label>
|
|
465
|
+
<description>Support cases for travel disruptions, rebookings, and weather events</description>
|
|
466
|
+
<active>true</active>
|
|
467
|
+
</RecordType>
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Then run: `sf project deploy start --source-dir force-app/main/default/objects/Case/recordTypes/Travel_Support.recordType-meta.xml`
|
|
471
|
+
|
|
472
|
+
**Scripted metadata interaction — Email Template:**
|
|
473
|
+
Finally, tell the user:
|
|
474
|
+
|
|
475
|
+
> "I'll also create an email template for weather delay notifications — the Flow can use it to send branded alerts with flight details and alternate routing options."
|
|
476
|
+
|
|
477
|
+
Create:
|
|
478
|
+
|
|
479
|
+
`force-app/main/default/email/Travel_Alerts/Weather_Delay_Notification.email-meta.xml`
|
|
480
|
+
|
|
481
|
+
```xml
|
|
482
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
483
|
+
<EmailTemplate xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
484
|
+
<name>Weather Delay Notification</name>
|
|
485
|
+
<available>true</available>
|
|
486
|
+
<description>Sent to travelers when their flight is affected by a weather disruption</description>
|
|
487
|
+
<encodingKey>UTF-8</encodingKey>
|
|
488
|
+
<style>freeForm</style>
|
|
489
|
+
<subject>Weather Alert: Your flight {!Flight__c.Flight_Number__c} is affected</subject>
|
|
490
|
+
<type>custom</type>
|
|
491
|
+
<textOnly>Hi {!Contact.FirstName},
|
|
492
|
+
|
|
493
|
+
Your flight {!Flight__c.Flight_Number__c} ({!Flight__c.Departure_Airport__c} → {!Flight__c.Arrival_Airport__c}) has been affected by severe weather.
|
|
494
|
+
|
|
495
|
+
Current delay: {!Disruption__c.Description__c}
|
|
496
|
+
Eva is monitoring the situation and will notify you of any changes.
|
|
497
|
+
|
|
498
|
+
If you need immediate assistance, reply to this email or ask Eva in the Engine Travel app.
|
|
499
|
+
|
|
500
|
+
— Engine Travel Team</textOnly>
|
|
501
|
+
</EmailTemplate>
|
|
502
|
+
```
|
|
342
503
|
|
|
343
|
-
|
|
504
|
+
Then run: `sf project deploy start --source-dir force-app/main/default/email/`
|
package/data/engine-live-data.js
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* useEngineLiveData hook resolves, these values replace the sample data in
|
|
7
7
|
* every component — the audience sees new names, new cities, new numbers.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* SCENARIO: Severe thunderstorm system moving across the Midwest US.
|
|
10
|
+
* Three travelers affected — two inbound to Chicago (ORD), one in Denver (DEN).
|
|
11
|
+
* The demo prompts walk through: awareness → policy → notify → case creation.
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
// ─── MAP MARKERS ─────────────────────────────────────────────────────────────
|
|
@@ -25,7 +26,6 @@ export const MAP_MARKERS = [
|
|
|
25
26
|
{ id: "FRA", lon: 8.6821, lat: 50.1109, label: "Frankfurt", active: true },
|
|
26
27
|
{ id: "MEX", lon: -99.1332, lat: 19.4326, label: "Mexico City", active: true },
|
|
27
28
|
{ id: "LHR", lon: -0.1278, lat: 51.5074, label: "London", active: true },
|
|
28
|
-
{ id: "JFK", lon: -74.0060, lat: 40.7128, label: "New York", active: true },
|
|
29
29
|
{ id: "LAX", lon: -118.2437, lat: 34.0522, label: "Los Angeles", active: true },
|
|
30
30
|
{ id: "ORD", lon: -87.6298, lat: 41.8781, label: "Chicago", active: true },
|
|
31
31
|
{ id: "SFO", lon: -122.4194, lat: 37.7749, label: "San Francisco", active: true },
|
|
@@ -39,78 +39,79 @@ export const MAP_MARKERS = [
|
|
|
39
39
|
// ─── MAP ARCS ────────────────────────────────────────────────────────────────
|
|
40
40
|
export const MAP_ARCS = [
|
|
41
41
|
{ id: "arc1", from: [72.8777, 19.0760], to: [-0.1278, 51.5074], progress: 0.65, danger: false },
|
|
42
|
-
{ id: "arc2", from: [-46.6333, -23.5505], to: [-
|
|
43
|
-
{ id: "arc3", from: [139.6917, 35.6895], to: [-118.2437, 34.0522], progress: 0.30, danger:
|
|
44
|
-
{ id: "arc4", from: [18.0686, 59.3293], to: [-87.6298, 41.8781], progress: 0.55, danger:
|
|
42
|
+
{ id: "arc2", from: [-46.6333, -23.5505], to: [-87.6298, 41.8781], progress: 0.40, danger: true },
|
|
43
|
+
{ id: "arc3", from: [139.6917, 35.6895], to: [-118.2437, 34.0522], progress: 0.30, danger: false },
|
|
44
|
+
{ id: "arc4", from: [18.0686, 59.3293], to: [-87.6298, 41.8781], progress: 0.55, danger: true },
|
|
45
45
|
{ id: "arc5", from: [121.4737, 31.2304], to: [-122.4194, 37.7749], progress: 0.70, danger: false },
|
|
46
46
|
{ id: "arc6", from: [55.2708, 25.2048], to: [13.4050, 52.5200], progress: 0.0, danger: false },
|
|
47
47
|
{ id: "arc7", from: [3.3792, 6.5244], to: [-0.1278, 51.5074], progress: 0.85, danger: false },
|
|
48
48
|
{ id: "arc8", from: [126.9780, 37.5665], to: [-122.3321, 47.6062], progress: 0.45, danger: false },
|
|
49
|
-
{ id: "arc9", from: [-9.1393, 38.7223], to: [-80.1918, 25.7617], progress: 0.
|
|
49
|
+
{ id: "arc9", from: [-9.1393, 38.7223], to: [-80.1918, 25.7617], progress: 0.80, danger: false },
|
|
50
50
|
{ id: "arc10", from: [77.1025, 28.7041], to: [103.8198, 1.3521], progress: 0.90, danger: false },
|
|
51
51
|
{ id: "arc11", from: [8.6821, 50.1109], to: [139.6917, 35.6895], progress: 0.20, danger: false },
|
|
52
52
|
{ id: "arc12", from: [-99.1332, 19.4326], to: [-104.9903, 39.7392], progress: 1.0, danger: false },
|
|
53
53
|
];
|
|
54
54
|
|
|
55
|
-
// ─── MAP OVERLAYS (
|
|
55
|
+
// ─── MAP OVERLAYS (storm zones) ──────────────────────────────────────────────
|
|
56
56
|
export const MAP_OVERLAYS = [
|
|
57
|
-
{ id: "ov1", center: [-
|
|
58
|
-
{ id: "ov2", center: [-
|
|
57
|
+
{ id: "ov1", center: [-87.6298, 41.8781], radius: 5 },
|
|
58
|
+
{ id: "ov2", center: [-94.5786, 39.0997], radius: 4 },
|
|
59
|
+
{ id: "ov3", center: [-104.9903, 39.7392], radius: 3 },
|
|
59
60
|
];
|
|
60
61
|
|
|
61
62
|
// ─── FLIGHT STATUS LIST (glass strip) ────────────────────────────────────────
|
|
62
63
|
export const FLIGHT_STATUS_LIST = [
|
|
63
|
-
{ id: "f1", flight: "AI 131", route: "BOM → LHR", dep: "11:30 PM", status: "In Air", traveler: "Raj Kapoor",
|
|
64
|
-
{ id: "f2", flight: "LA
|
|
65
|
-
{ id: "f3", flight: "JL 62", route: "NRT → LAX", dep: "5:00 PM", status: "
|
|
66
|
-
{ id: "f4", flight: "SK 943", route: "ARN → ORD", dep: "1:40 PM", status: "
|
|
67
|
-
{ id: "f5", flight: "MU 589", route: "PVG → SFO", dep: "12:50 PM", status: "In Air", traveler: "Chen Wei",
|
|
64
|
+
{ id: "f1", flight: "AI 131", route: "BOM → LHR", dep: "11:30 PM", status: "In Air", traveler: "Raj Kapoor", delayMin: 0 },
|
|
65
|
+
{ id: "f2", flight: "LA 8070", route: "GRU → ORD", dep: "6:15 PM", status: "Delayed", traveler: "Sofia Reyes", delayMin: 65 },
|
|
66
|
+
{ id: "f3", flight: "JL 62", route: "NRT → LAX", dep: "5:00 PM", status: "In Air", traveler: "Yuki Tanaka", delayMin: 0 },
|
|
67
|
+
{ id: "f4", flight: "SK 943", route: "ARN → ORD", dep: "1:40 PM", status: "Delayed", traveler: "Anna Johansson", delayMin: 90 },
|
|
68
|
+
{ id: "f5", flight: "MU 589", route: "PVG → SFO", dep: "12:50 PM", status: "In Air", traveler: "Chen Wei", delayMin: 0 },
|
|
68
69
|
{ id: "f6", flight: "EK 55", route: "DXB → BER", dep: "8:30 AM", status: "Scheduled", traveler: "Fatima Al-Rashidi", delayMin: 0 },
|
|
69
|
-
{ id: "f7", flight: "BA 83", route: "LOS → LHR", dep: "10:20 PM", status: "In Air", traveler: "James Okafor",
|
|
70
|
-
{ id: "f8", flight: "KE 19", route: "ICN → SEA", dep: "4:10 PM", status: "In Air", traveler: "Min-jun Park",
|
|
71
|
-
{ id: "f9", flight: "TP 225", route: "LIS → MIA", dep: "9:00 AM", status: "
|
|
72
|
-
{ id: "f10", flight: "AI 345", route: "DEL → SIN", dep: "2:15 AM", status: "In Air", traveler: "Amit Sharma",
|
|
73
|
-
{ id: "f11", flight: "LH 716", route: "FRA → NRT", dep: "1:30 PM", status: "Boarding", traveler: "Lena Müller",
|
|
74
|
-
{ id: "f12", flight: "AM 648", route: "MEX → DEN", dep: "7:45 AM", status: "Landed", traveler: "Carlos Mendez",
|
|
70
|
+
{ id: "f7", flight: "BA 83", route: "LOS → LHR", dep: "10:20 PM", status: "In Air", traveler: "James Okafor", delayMin: 0 },
|
|
71
|
+
{ id: "f8", flight: "KE 19", route: "ICN → SEA", dep: "4:10 PM", status: "In Air", traveler: "Min-jun Park", delayMin: 0 },
|
|
72
|
+
{ id: "f9", flight: "TP 225", route: "LIS → MIA", dep: "9:00 AM", status: "In Air", traveler: "Isabella Costa", delayMin: 0 },
|
|
73
|
+
{ id: "f10", flight: "AI 345", route: "DEL → SIN", dep: "2:15 AM", status: "In Air", traveler: "Amit Sharma", delayMin: 0 },
|
|
74
|
+
{ id: "f11", flight: "LH 716", route: "FRA → NRT", dep: "1:30 PM", status: "Boarding", traveler: "Lena Müller", delayMin: 0 },
|
|
75
|
+
{ id: "f12", flight: "AM 648", route: "MEX → DEN", dep: "7:45 AM", status: "Landed", traveler: "Carlos Mendez", delayMin: 0 },
|
|
75
76
|
];
|
|
76
77
|
|
|
77
78
|
// ─── TRAVELER CARDS ──────────────────────────────────────────────────────────
|
|
78
79
|
export const TRAVELER_CARDS = [
|
|
79
|
-
{ id: "L01", name: "Raj Kapoor", department: "Engineering", origin: "Mumbai", destination: "London", flight: "AI 131", hotel: "The Savoy",
|
|
80
|
-
{ id: "L02", name: "Sofia Reyes", department: "Product", origin: "São Paulo", destination: "
|
|
81
|
-
{ id: "L03", name: "Yuki Tanaka", department: "Sales", origin: "Tokyo", destination: "Los Angeles", flight: "JL 62", hotel: "Shutters on Beach",
|
|
82
|
-
{ id: "L04", name: "Anna Johansson", department: "Finance", origin: "Stockholm", destination: "Chicago", flight: "SK 943", hotel: "The Hoxton",
|
|
83
|
-
{ id: "L05", name: "Chen Wei", department: "Engineering", origin: "Shanghai", destination: "San Francisco", flight: "MU 589", hotel: "Hotel Vitale",
|
|
84
|
-
{ id: "L06", name: "Fatima Al-Rashidi", department: "Legal", origin: "Dubai", destination: "Berlin", flight: "EK 55", hotel: "Hotel de Rome",
|
|
85
|
-
{ id: "L07", name: "James Okafor", department: "Marketing", origin: "Lagos", destination: "London", flight: "BA 83", hotel: "The Ned",
|
|
86
|
-
{ id: "L08", name: "Min-jun Park", department: "Product", origin: "Seoul", destination: "Seattle", flight: "KE 19", hotel: "The Edgewater",
|
|
87
|
-
{ id: "L09", name: "Isabella Costa", department: "Sales", origin: "Lisbon", destination: "Miami", flight: "TP 225", hotel: "Faena Miami Beach",
|
|
88
|
-
{ id: "L10", name: "Amit Sharma", department: "Engineering", origin: "Delhi", destination: "Singapore", flight: "AI 345", hotel: "Marina Bay Sands",
|
|
89
|
-
{ id: "L11", name: "Lena Müller", department: "Finance", origin: "Frankfurt", destination: "Tokyo", flight: "LH 716", hotel: "Aman Tokyo",
|
|
90
|
-
{ id: "L12", name: "Carlos Mendez", department: "Sales", origin: "Mexico City", destination: "Denver", flight: "AM 648", hotel: "The Crawford",
|
|
80
|
+
{ id: "L01", name: "Raj Kapoor", department: "Engineering", origin: "Mumbai", destination: "London", flight: "AI 131", hotel: "The Savoy", return: "Apr 4", policyStatus: "compliant" },
|
|
81
|
+
{ id: "L02", name: "Sofia Reyes", department: "Product", origin: "São Paulo", destination: "Chicago", flight: "LA 8070", hotel: "The Langham Chicago", return: "Apr 2", policyStatus: "compliant" },
|
|
82
|
+
{ id: "L03", name: "Yuki Tanaka", department: "Sales", origin: "Tokyo", destination: "Los Angeles", flight: "JL 62", hotel: "Shutters on Beach", return: "Apr 6", policyStatus: "compliant" },
|
|
83
|
+
{ id: "L04", name: "Anna Johansson", department: "Finance", origin: "Stockholm", destination: "Chicago", flight: "SK 943", hotel: "The Hoxton Chicago", return: "Apr 3", policyStatus: "compliant" },
|
|
84
|
+
{ id: "L05", name: "Chen Wei", department: "Engineering", origin: "Shanghai", destination: "San Francisco", flight: "MU 589", hotel: "Hotel Vitale", return: "Apr 8", policyStatus: "compliant" },
|
|
85
|
+
{ id: "L06", name: "Fatima Al-Rashidi", department: "Legal", origin: "Dubai", destination: "Berlin", flight: "EK 55", hotel: "Hotel de Rome", return: "Apr 5", policyStatus: "compliant" },
|
|
86
|
+
{ id: "L07", name: "James Okafor", department: "Marketing", origin: "Lagos", destination: "London", flight: "BA 83", hotel: "The Ned", return: "Apr 7", policyStatus: "compliant" },
|
|
87
|
+
{ id: "L08", name: "Min-jun Park", department: "Product", origin: "Seoul", destination: "Seattle", flight: "KE 19", hotel: "The Edgewater", return: "Apr 4", policyStatus: "compliant" },
|
|
88
|
+
{ id: "L09", name: "Isabella Costa", department: "Sales", origin: "Lisbon", destination: "Miami", flight: "TP 225", hotel: "Faena Miami Beach", return: "Apr 3", policyStatus: "compliant" },
|
|
89
|
+
{ id: "L10", name: "Amit Sharma", department: "Engineering", origin: "Delhi", destination: "Singapore", flight: "AI 345", hotel: "Marina Bay Sands", return: "Apr 9", policyStatus: "compliant" },
|
|
90
|
+
{ id: "L11", name: "Lena Müller", department: "Finance", origin: "Frankfurt", destination: "Tokyo", flight: "LH 716", hotel: "Aman Tokyo", return: "Apr 10", policyStatus: "exception" },
|
|
91
|
+
{ id: "L12", name: "Carlos Mendez", department: "Sales", origin: "Mexico City", destination: "Denver", flight: "AM 648", hotel: "The Crawford Denver", return: "Apr 1", policyStatus: "compliant" },
|
|
91
92
|
];
|
|
92
93
|
|
|
93
94
|
// ─── DISRUPTION CARDS ────────────────────────────────────────────────────────
|
|
94
95
|
export const DISRUPTION_CARDS = [
|
|
95
|
-
{ id: "d1", flight: "
|
|
96
|
-
{ id: "d2", flight: "
|
|
97
|
-
{ id: "d3", flight: "
|
|
98
|
-
{ id: "d4", flight: "
|
|
99
|
-
{ id: "d5", flight: "
|
|
96
|
+
{ id: "d1", flight: "SK 943", route: "ARN → ORD", traveler: "Anna Johansson", severity: "grounded", delayMin: 90, reason: "Severe thunderstorm at O'Hare — ATC ground stop", evaAction: "Rerouting options: DTW connection or hold for next window" },
|
|
97
|
+
{ id: "d2", flight: "LA 8070", route: "GRU → ORD", traveler: "Sofia Reyes", severity: "delayed", delayMin: 65, reason: "Storm system at ORD — holding pattern over Indiana", evaAction: "Monitoring approach window — ETA updated to 9:20 PM CT" },
|
|
98
|
+
{ id: "d3", flight: "AM 648", route: "MEX → DEN", traveler: "Carlos Mendez", severity: "delayed", delayMin: 0, reason: "Landed — storm front moving toward Denver overnight", evaAction: "Return flight at risk — watching AM 649 departure tomorrow" },
|
|
99
|
+
{ id: "d4", flight: "UA 412", route: "ORD → DEN", traveler: "Multiple", severity: "grounded", delayMin: 120, reason: "ATC ground stop at O'Hare — all departures suspended", evaAction: "6 connecting flights affected — rebooking in progress" },
|
|
100
|
+
{ id: "d5", flight: "LH 716", route: "FRA → NRT", traveler: "Lena Müller", severity: "delayed", delayMin: 25, reason: "Late inbound aircraft from Munich", evaAction: "Boarding now — minimal impact, hotel notified of late arrival" },
|
|
100
101
|
];
|
|
101
102
|
|
|
102
103
|
// ─── ESCALATION CARDS ────────────────────────────────────────────────────────
|
|
103
104
|
export const ESCALATION_CARDS = [
|
|
104
|
-
{ id: "e1", title: "
|
|
105
|
-
{ id: "e2", title: "
|
|
106
|
-
{ id: "e3", title: "
|
|
107
|
-
{ id: "e4", title: "
|
|
108
|
-
{ id: "e5", title: "
|
|
109
|
-
{ id: "e6", title: "
|
|
110
|
-
{ id: "e7", title: "
|
|
111
|
-
{ id: "e8", title: "Duplicate booking cancelled —
|
|
112
|
-
{ id: "e9", title: "
|
|
113
|
-
{ id: "e10", title: "
|
|
105
|
+
{ id: "e1", title: "Midwest storm alert — 3 travelers affected", subtitle: "Anna Johansson, Sofia Reyes, Carlos Mendez in impact zone", status: "working", timestamp: "4 min ago" },
|
|
106
|
+
{ id: "e2", title: "Rerouting Anna Johansson via Detroit", subtitle: "SK 943 grounded — alternate DL 1482 ARN → DTW → ORD", status: "working", timestamp: "12 min ago" },
|
|
107
|
+
{ id: "e3", title: "Hotel backup hold at Langham Chicago", subtitle: "Late arrival guaranteed for Sofia Reyes — LA 8070 delayed", status: "complete", timestamp: "18 min ago" },
|
|
108
|
+
{ id: "e4", title: "Weather alert sent to Carlos Mendez", subtitle: "Storm moving toward Denver — AM 649 return flight at risk", status: "complete", timestamp: "25 min ago" },
|
|
109
|
+
{ id: "e5", title: "Sent delay notification to Anna Johansson", subtitle: "SK 943 +90 min — updated itinerary with new gate info", status: "complete", timestamp: "30 min ago" },
|
|
110
|
+
{ id: "e6", title: "Hotel upgrade for Lena Müller", subtitle: "Aman Tokyo — loyalty rate applied ($520 → $380/n)", status: "complete", timestamp: "45 min ago" },
|
|
111
|
+
{ id: "e7", title: "Group rate secured — Seoul team offsite", subtitle: "The Edgewater · 8 rooms · $189/n (was $259/n)", status: "complete", timestamp: "1.2 hr ago" },
|
|
112
|
+
{ id: "e8", title: "Duplicate booking cancelled — Isabella Costa", subtitle: "LIS → MIA booked twice · Refund $380 processed", status: "complete", timestamp: "1.8 hr ago" },
|
|
113
|
+
{ id: "e9", title: "Travel policy exception — Lena Müller", subtitle: "Aman Tokyo $520/n exceeds $350 cap — manager approved", status: "complete", timestamp: "2.1 hr ago" },
|
|
114
|
+
{ id: "e10", title: "Insurance pre-filed for Chicago delays", subtitle: "AXA claims for SK 943 and LA 8070 — weather disruption", status: "pending", timestamp: "2 min ago" },
|
|
114
115
|
];
|
|
115
116
|
|
|
116
117
|
// ─── MONTHLY SPEND ───────────────────────────────────────────────────────────
|
|
@@ -127,8 +128,8 @@ export const MONTHLY_SPEND = [
|
|
|
127
128
|
export const METRICS = {
|
|
128
129
|
activeTravelers: 12,
|
|
129
130
|
spendMTD: 187200,
|
|
130
|
-
complianceRate:
|
|
131
|
+
complianceRate: 92,
|
|
131
132
|
evaResolutionRate: 78,
|
|
132
133
|
evaResolved: 9,
|
|
133
|
-
pendingBookings:
|
|
134
|
+
pendingBookings: 3,
|
|
134
135
|
};
|
package/dist/styles/global.css
CHANGED
|
@@ -208,6 +208,12 @@
|
|
|
208
208
|
--link: oklch(0.2103 0.0059 285.89);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
/* ChatBar expanded overlay — horizontal padding so it doesn't hit window edges */
|
|
212
|
+
body > .fixed.inset-x-0.rounded-2xl {
|
|
213
|
+
left: 1.5rem !important;
|
|
214
|
+
right: 1.5rem !important;
|
|
215
|
+
}
|
|
216
|
+
|
|
211
217
|
.dark .heroui-scope,
|
|
212
218
|
.heroui-scope.dark {
|
|
213
219
|
--muted: oklch(70.5% 0.015 286.067);
|
|
@@ -230,9 +236,3 @@
|
|
|
230
236
|
--focus: oklch(0.6204 0.195 253.83);
|
|
231
237
|
--link: oklch(0.9911 0 0);
|
|
232
238
|
}
|
|
233
|
-
|
|
234
|
-
/* ChatBar overlay — add horizontal padding so it doesn't hit window edges */
|
|
235
|
-
body > .fixed.inset-x-0.rounded-2xl {
|
|
236
|
-
left: 1.5rem !important;
|
|
237
|
-
right: 1.5rem !important;
|
|
238
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schandlergarcia/sf-web-components",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.74",
|
|
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",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"dist",
|
|
29
29
|
"scripts",
|
|
30
30
|
"data",
|
|
31
|
+
"assets",
|
|
31
32
|
"src/templates",
|
|
32
33
|
"src/components",
|
|
33
34
|
"src/lib",
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -314,6 +314,25 @@ if (fs.existsSync(dataSourceDir)) {
|
|
|
314
314
|
console.error(` ✗ Failed to install useEngineLiveData.ts: ${error.message}`);
|
|
315
315
|
}
|
|
316
316
|
}
|
|
317
|
+
|
|
318
|
+
// Copy engine_logo.png
|
|
319
|
+
const assetsSourceDir = path.join(packageRoot, 'assets/images');
|
|
320
|
+
const targetAssetsDir = path.join(cwd, 'src/assets/images');
|
|
321
|
+
const engineLogoSource = path.join(assetsSourceDir, 'engine_logo.png');
|
|
322
|
+
const engineLogoTarget = path.join(targetAssetsDir, 'engine_logo.png');
|
|
323
|
+
|
|
324
|
+
if (fs.existsSync(engineLogoSource)) {
|
|
325
|
+
try {
|
|
326
|
+
if (!fs.existsSync(targetAssetsDir)) {
|
|
327
|
+
fs.mkdirSync(targetAssetsDir, { recursive: true });
|
|
328
|
+
}
|
|
329
|
+
fs.copyFileSync(engineLogoSource, engineLogoTarget);
|
|
330
|
+
console.log(' ✓ Installed engine_logo.png');
|
|
331
|
+
dataFilesInstalled++;
|
|
332
|
+
} catch (error) {
|
|
333
|
+
console.error(` ✗ Failed to install engine_logo.png: ${error.message}`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
317
336
|
}
|
|
318
337
|
|
|
319
338
|
// Copy GraphQL schema generator script
|
|
@@ -733,6 +733,28 @@ else
|
|
|
733
733
|
echo " ⚠ Skipped PRD (package PRD not found)"
|
|
734
734
|
fi
|
|
735
735
|
|
|
736
|
+
# Restore engine_logo.png
|
|
737
|
+
mkdir -p src/assets/images
|
|
738
|
+
ENGINE_LOGO="src/assets/images/engine_logo.png"
|
|
739
|
+
echo "→ Restoring ${ENGINE_LOGO}..."
|
|
740
|
+
|
|
741
|
+
# Detect package location for logo
|
|
742
|
+
if [ -d "node_modules/@schandlergarcia/sf-web-components/assets/images" ]; then
|
|
743
|
+
PACKAGE_LOGO="node_modules/@schandlergarcia/sf-web-components/assets/images/engine_logo.png"
|
|
744
|
+
elif [ -f "$SCRIPT_DIR/../assets/images/engine_logo.png" ]; then
|
|
745
|
+
# Running from package source
|
|
746
|
+
PACKAGE_LOGO="$SCRIPT_DIR/../assets/images/engine_logo.png"
|
|
747
|
+
else
|
|
748
|
+
PACKAGE_LOGO=""
|
|
749
|
+
fi
|
|
750
|
+
|
|
751
|
+
if [ -n "$PACKAGE_LOGO" ] && [ -f "$PACKAGE_LOGO" ]; then
|
|
752
|
+
cp "$PACKAGE_LOGO" "$ENGINE_LOGO"
|
|
753
|
+
echo " ✓ Engine logo restored"
|
|
754
|
+
else
|
|
755
|
+
echo " ⚠ Skipped logo (package logo not found)"
|
|
756
|
+
fi
|
|
757
|
+
|
|
736
758
|
echo ""
|
|
737
759
|
|
|
738
760
|
# ── Done ─────────────────────────────────────────────────────────────────────
|
|
@@ -750,6 +772,7 @@ echo "║ • Engine live data (engine-live-data.js) ║"
|
|
|
750
772
|
echo "║ • Live data hook (useEngineLiveData.ts) ║"
|
|
751
773
|
echo "║ • GraphQL schema (schema.graphql) ║"
|
|
752
774
|
echo "║ • Engine PRD (engine-command-center-prd.md)║"
|
|
775
|
+
echo "║ • Engine logo (engine_logo.png) ║"
|
|
753
776
|
echo "║ • Component library (cards, charts, etc.) ║"
|
|
754
777
|
echo "║ • HeroUI wrappers & theme providers ║"
|
|
755
778
|
echo "║ • Salesforce SDK stubs for local dev ║"
|