@schandlergarcia/sf-web-components 1.9.70 → 1.9.72

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/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@ 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.72] - 2026-04-02
9
+
10
+ ### Added
11
+ - **New data files for live data integration**:
12
+ - `data/engine-live-data.js` - Live data structure matching sample data shape
13
+ - `data/useEngineLiveData.ts` - Hook for fetching live Engine Travel data from Salesforce
14
+
15
+ ### Updated
16
+ - **Postinstall script** - Now copies `engine-live-data.js` to `src/data/` and `useEngineLiveData.ts` to `src/hooks/`
17
+ - **Reset script** - Now restores `engine-live-data.js` and `useEngineLiveData.ts` to baseline state
18
+
19
+ **Context:** Phase 3 live data integration support. The hook fetches real Salesforce data and returns it in the same shape as sample data, making it easy to wire into `useDataSource({ sample: SAMPLE_DATA, live: live.xxx })`.
20
+
21
+ ## [1.9.71] - 2026-04-02
22
+
23
+ ### Updated
24
+ - **PRD (engine-command-center-prd.md)** - Latest updates from react-cursor-1
25
+
8
26
  ## [1.9.70] - 2026-04-02
9
27
 
10
28
  ### Updated
@@ -51,7 +51,7 @@ Use `brand-*` Tailwind classes for brand elements. Tailwind built-in colors (gre
51
51
 
52
52
  - **Dashboard file:** `src/pages/EngineDashboard.tsx`
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
- - **Toasts:** Import `toast` from `sonner` 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.
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
56
 
57
57
  ---
@@ -170,7 +170,7 @@ Custom inline panel in BaseCard. Do NOT use ActivityCard — this panel has per-
170
170
  Each escalation row:
171
171
  - Status icon: `CheckCircleIcon` (complete, green), `ArrowPathIcon` (working, brand), `ClockIcon` (pending, amber)
172
172
  - Title + subtitle + timestamp
173
- - **"Assign to Agent" button** (Phase 4) 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 sonner. In Phase 2, render the button but leave the `onClick` empty — wire the toast in Phase 4.
173
+ - **"Assign to Agent" button** (Phase 4) 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`. In Phase 2, render the button but leave the `onClick` empty — wire the toast in Phase 4.
174
174
 
175
175
  ```tsx
176
176
  <BaseCard>
@@ -293,8 +293,8 @@ Subtle indicators, not banners.
293
293
  |--------|----------|
294
294
  | "Powered by Agentforce" | Header, next to "Travel Command Center" (small rounded badge) |
295
295
  | "View in Salesforce" | Traveler expanded view (micro-link, muted text) |
296
- | "Salesforce updated" | After rebook/approve actions — `toast("Opening in Salesforce…")` via sonner |
297
- | "Assigned to Eva" | After "Assign to Agent" button click — `toast.success("Assigned to Eva")` via sonner |
296
+ | "Salesforce updated" | After rebook/approve actions — `toast("Opening in Salesforce…")` via `@heroui/react` |
297
+ | "Assigned to Eva" | After "Assign to Agent" button click — `toast.success("Assigned to Eva")` via `@heroui/react` |
298
298
 
299
299
  ---
300
300
 
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Engine Travel Command Center — Live Data (simulated)
3
+ *
4
+ * This file provides a distinctly different dataset from engine-sample-data.js
5
+ * to make the Phase 3 "real data" integration visually obvious. When the
6
+ * useEngineLiveData hook resolves, these values replace the sample data in
7
+ * every component — the audience sees new names, new cities, new numbers.
8
+ *
9
+ * Shape matches the dashboard-ready exports from engine-sample-data.js so
10
+ * useDataSource({ sample, live }) works without any mapping.
11
+ */
12
+
13
+ // ─── MAP MARKERS ─────────────────────────────────────────────────────────────
14
+ export const MAP_MARKERS = [
15
+ { id: "BOM", lon: 72.8777, lat: 19.0760, label: "Mumbai", active: true },
16
+ { id: "GRU", lon: -46.6333, lat: -23.5505, label: "São Paulo", active: true },
17
+ { id: "NRT", lon: 139.6917, lat: 35.6895, label: "Tokyo", active: true },
18
+ { id: "ARN", lon: 18.0686, lat: 59.3293, label: "Stockholm", active: true },
19
+ { id: "PVG", lon: 121.4737, lat: 31.2304, label: "Shanghai", active: true },
20
+ { id: "DXB", lon: 55.2708, lat: 25.2048, label: "Dubai", active: true },
21
+ { id: "LOS", lon: 3.3792, lat: 6.5244, label: "Lagos", active: true },
22
+ { id: "ICN", lon: 126.9780, lat: 37.5665, label: "Seoul", active: true },
23
+ { id: "LIS", lon: -9.1393, lat: 38.7223, label: "Lisbon", active: true },
24
+ { id: "DEL", lon: 77.1025, lat: 28.7041, label: "Delhi", active: true },
25
+ { id: "FRA", lon: 8.6821, lat: 50.1109, label: "Frankfurt", active: true },
26
+ { id: "MEX", lon: -99.1332, lat: 19.4326, label: "Mexico City", active: true },
27
+ { 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
+ { id: "LAX", lon: -118.2437, lat: 34.0522, label: "Los Angeles", active: true },
30
+ { id: "ORD", lon: -87.6298, lat: 41.8781, label: "Chicago", active: true },
31
+ { id: "SFO", lon: -122.4194, lat: 37.7749, label: "San Francisco", active: true },
32
+ { id: "BER", lon: 13.4050, lat: 52.5200, label: "Berlin", active: true },
33
+ { id: "SEA", lon: -122.3321, lat: 47.6062, label: "Seattle", active: true },
34
+ { id: "MIA", lon: -80.1918, lat: 25.7617, label: "Miami", active: true },
35
+ { id: "SIN", lon: 103.8198, lat: 1.3521, label: "Singapore", active: true },
36
+ { id: "DEN", lon: -104.9903, lat: 39.7392, label: "Denver", active: true },
37
+ ];
38
+
39
+ // ─── MAP ARCS ────────────────────────────────────────────────────────────────
40
+ export const MAP_ARCS = [
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: [-74.0060, 40.7128], progress: 0.40, danger: false },
43
+ { id: "arc3", from: [139.6917, 35.6895], to: [-118.2437, 34.0522], progress: 0.30, danger: true },
44
+ { id: "arc4", from: [18.0686, 59.3293], to: [-87.6298, 41.8781], progress: 0.55, danger: false },
45
+ { id: "arc5", from: [121.4737, 31.2304], to: [-122.4194, 37.7749], progress: 0.70, danger: false },
46
+ { id: "arc6", from: [55.2708, 25.2048], to: [13.4050, 52.5200], progress: 0.0, danger: false },
47
+ { id: "arc7", from: [3.3792, 6.5244], to: [-0.1278, 51.5074], progress: 0.85, danger: false },
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.0, danger: true },
50
+ { id: "arc10", from: [77.1025, 28.7041], to: [103.8198, 1.3521], progress: 0.90, danger: false },
51
+ { id: "arc11", from: [8.6821, 50.1109], to: [139.6917, 35.6895], progress: 0.20, danger: false },
52
+ { id: "arc12", from: [-99.1332, 19.4326], to: [-104.9903, 39.7392], progress: 1.0, danger: false },
53
+ ];
54
+
55
+ // ─── MAP OVERLAYS (weather zones) ────────────────────────────────────────────
56
+ export const MAP_OVERLAYS = [
57
+ { id: "ov1", center: [-118.2437, 34.0522], radius: 4 },
58
+ { id: "ov2", center: [-9.1393, 38.7223], radius: 3 },
59
+ ];
60
+
61
+ // ─── FLIGHT STATUS LIST (glass strip) ────────────────────────────────────────
62
+ export const FLIGHT_STATUS_LIST = [
63
+ { id: "f1", flight: "AI 131", route: "BOM → LHR", dep: "11:30 PM", status: "In Air", traveler: "Raj Kapoor", delayMin: 0 },
64
+ { id: "f2", flight: "LA 8084", route: "GRU → JFK", dep: "6:15 PM", status: "In Air", traveler: "Sofia Reyes", delayMin: 0 },
65
+ { id: "f3", flight: "JL 62", route: "NRT → LAX", dep: "5:00 PM", status: "Delayed", traveler: "Yuki Tanaka", delayMin: 72 },
66
+ { id: "f4", flight: "SK 943", route: "ARN → ORD", dep: "1:40 PM", status: "In Air", traveler: "Anna Johansson", delayMin: 0 },
67
+ { id: "f5", flight: "MU 589", route: "PVG → SFO", dep: "12:50 PM", status: "In Air", traveler: "Chen Wei", delayMin: 0 },
68
+ { 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", delayMin: 0 },
70
+ { id: "f8", flight: "KE 19", route: "ICN → SEA", dep: "4:10 PM", status: "In Air", traveler: "Min-jun Park", delayMin: 0 },
71
+ { id: "f9", flight: "TP 225", route: "LIS → MIA", dep: "9:00 AM", status: "Delayed", traveler: "Isabella Costa", delayMin: 55 },
72
+ { id: "f10", flight: "AI 345", route: "DEL → SIN", dep: "2:15 AM", status: "In Air", traveler: "Amit Sharma", delayMin: 0 },
73
+ { id: "f11", flight: "LH 716", route: "FRA → NRT", dep: "1:30 PM", status: "Boarding", traveler: "Lena Müller", delayMin: 0 },
74
+ { id: "f12", flight: "AM 648", route: "MEX → DEN", dep: "7:45 AM", status: "Landed", traveler: "Carlos Mendez", delayMin: 0 },
75
+ ];
76
+
77
+ // ─── TRAVELER CARDS ──────────────────────────────────────────────────────────
78
+ export const TRAVELER_CARDS = [
79
+ { id: "L01", name: "Raj Kapoor", department: "Engineering", origin: "Mumbai", destination: "London", flight: "AI 131", hotel: "The Savoy", return: "Apr 4", policyStatus: "compliant" },
80
+ { id: "L02", name: "Sofia Reyes", department: "Product", origin: "São Paulo", destination: "New York", flight: "LA 8084", hotel: "The Standard", return: "Apr 2", policyStatus: "compliant" },
81
+ { id: "L03", name: "Yuki Tanaka", department: "Sales", origin: "Tokyo", destination: "Los Angeles", flight: "JL 62", hotel: "Shutters on Beach", return: "Apr 6", policyStatus: "exception" },
82
+ { id: "L04", name: "Anna Johansson", department: "Finance", origin: "Stockholm", destination: "Chicago", flight: "SK 943", hotel: "The Hoxton", return: "Apr 3", policyStatus: "compliant" },
83
+ { id: "L05", name: "Chen Wei", department: "Engineering", origin: "Shanghai", destination: "San Francisco", flight: "MU 589", hotel: "Hotel Vitale", return: "Apr 8", policyStatus: "compliant" },
84
+ { id: "L06", name: "Fatima Al-Rashidi", department: "Legal", origin: "Dubai", destination: "Berlin", flight: "EK 55", hotel: "Hotel de Rome", return: "Apr 5", policyStatus: "compliant" },
85
+ { id: "L07", name: "James Okafor", department: "Marketing", origin: "Lagos", destination: "London", flight: "BA 83", hotel: "The Ned", return: "Apr 7", policyStatus: "compliant" },
86
+ { id: "L08", name: "Min-jun Park", department: "Product", origin: "Seoul", destination: "Seattle", flight: "KE 19", hotel: "The Edgewater", return: "Apr 4", policyStatus: "compliant" },
87
+ { id: "L09", name: "Isabella Costa", department: "Sales", origin: "Lisbon", destination: "Miami", flight: "TP 225", hotel: "Faena Miami Beach", return: "Apr 3", policyStatus: "exception" },
88
+ { id: "L10", name: "Amit Sharma", department: "Engineering", origin: "Delhi", destination: "Singapore", flight: "AI 345", hotel: "Marina Bay Sands", return: "Apr 9", policyStatus: "compliant" },
89
+ { id: "L11", name: "Lena Müller", department: "Finance", origin: "Frankfurt", destination: "Tokyo", flight: "LH 716", hotel: "Aman Tokyo", return: "Apr 10", policyStatus: "exception" },
90
+ { id: "L12", name: "Carlos Mendez", department: "Sales", origin: "Mexico City", destination: "Denver", flight: "AM 648", hotel: "The Crawford", return: "Apr 1", policyStatus: "compliant" },
91
+ ];
92
+
93
+ // ─── DISRUPTION CARDS ────────────────────────────────────────────────────────
94
+ export const DISRUPTION_CARDS = [
95
+ { id: "d1", flight: "JL 62", route: "NRT → LAX", traveler: "Yuki Tanaka", severity: "delayed", delayMin: 72, reason: "Typhoon warning — Pacific routing change", evaAction: "Monitoring alternate routing via Anchorage" },
96
+ { id: "d2", flight: "TP 225", route: "LIS → MIA", traveler: "Isabella Costa", severity: "delayed", delayMin: 55, reason: "Fog at Lisbon — reduced visibility", evaAction: "Hold confirmed — rebook on TP 227 if >90 min" },
97
+ { id: "d3", flight: "SK 401", route: "ARN → ORD", traveler: "Multiple", severity: "grounded", delayMin: 140, reason: "Strike action at Stockholm Arlanda", evaAction: "Rebooked 3 travelers on LH 803 via Frankfurt" },
98
+ { id: "d4", flight: "MU 589", route: "PVG → SFO", traveler: "Chen Wei", severity: "delayed", delayMin: 30, reason: "Late inbound from Pudong — gate hold", evaAction: "Sent updated ETA notification to traveler" },
99
+ { id: "d5", flight: "AI 345", route: "DEL → SIN", traveler: "Amit Sharma", severity: "delayed", delayMin: 25, reason: "Air traffic congestion at DEL", evaAction: "Hotel late check-in arranged at Marina Bay" },
100
+ ];
101
+
102
+ // ─── ESCALATION CARDS ────────────────────────────────────────────────────────
103
+ export const ESCALATION_CARDS = [
104
+ { id: "e1", title: "Rebooked Yuki Tanaka", subtitle: "JL 62 → JL 64 · Same fare class", status: "complete", timestamp: "8 min ago" },
105
+ { id: "e2", title: "Arranged ground transport for Isabella", subtitle: "Lisbon → Porto backup routing", status: "working", timestamp: "15 min ago" },
106
+ { id: "e3", title: "Processing visa extension for Raj Kapoor", subtitle: "UK business visa 48-hr extension requested", status: "pending", timestamp: "22 min ago" },
107
+ { id: "e4", title: "Hotel upgrade for Lena Müller", subtitle: "Aman Tokyo — loyalty rate applied ($520 → $380/n)", status: "complete", timestamp: "35 min ago" },
108
+ { id: "e5", title: "Insurance claim filed for Yuki Tanaka", subtitle: "Typhoon delay — AXA claim #TK-8841 submitted", status: "complete", timestamp: "42 min ago" },
109
+ { id: "e6", title: "Group rate secured — Seoul team offsite", subtitle: "The Edgewater · 8 rooms · $189/n (was $259/n)", status: "complete", timestamp: "1.2 hr ago" },
110
+ { id: "e7", title: "Budget approval for Isabella Costa", subtitle: "Miami trip $340 over budget — escalated to manager", status: "pending", timestamp: "1.5 hr ago" },
111
+ { id: "e8", title: "Duplicate booking cancelled — Carlos M.", subtitle: "MEX → DEN booked twice · Refund $412 processed", status: "complete", timestamp: "2.0 hr ago" },
112
+ { id: "e9", title: "Gate change alert sent — Fatima A.", subtitle: "EK 55 moved to Gate B22 · Terminal 3", status: "complete", timestamp: "2.3 hr ago" },
113
+ { id: "e10", title: "Monitoring strike at Stockholm Arlanda", subtitle: "3 travelers affected — LH 803 backup confirmed", status: "working", timestamp: "2.8 hr ago" },
114
+ ];
115
+
116
+ // ─── MONTHLY SPEND ───────────────────────────────────────────────────────────
117
+ export const MONTHLY_SPEND = [
118
+ { month: "Oct", amount: 168000 },
119
+ { month: "Nov", amount: 152000 },
120
+ { month: "Dec", amount: 118000 },
121
+ { month: "Jan", amount: 189000 },
122
+ { month: "Feb", amount: 172000 },
123
+ { month: "Mar", amount: 187200 },
124
+ ];
125
+
126
+ // ─── COMPUTED METRICS ────────────────────────────────────────────────────────
127
+ export const METRICS = {
128
+ activeTravelers: 12,
129
+ spendMTD: 187200,
130
+ complianceRate: 83,
131
+ evaResolutionRate: 78,
132
+ evaResolved: 9,
133
+ pendingBookings: 4,
134
+ };
@@ -0,0 +1,54 @@
1
+ import { useState, useEffect } from "react";
2
+ import { useDataMode } from "@/components/library/data/DataModeProvider";
3
+ import * as live from "@/data/engine-live-data";
4
+
5
+ const SIMULATED_LOAD_MS = 2000;
6
+
7
+ export interface EngineLiveData {
8
+ loading: boolean;
9
+ mapMarkers: typeof live.MAP_MARKERS;
10
+ mapArcs: typeof live.MAP_ARCS;
11
+ mapOverlays: typeof live.MAP_OVERLAYS;
12
+ flightStatusList: typeof live.FLIGHT_STATUS_LIST;
13
+ travelerCards: typeof live.TRAVELER_CARDS;
14
+ disruptionCards: typeof live.DISRUPTION_CARDS;
15
+ escalationCards: typeof live.ESCALATION_CARDS;
16
+ monthlySpend: typeof live.MONTHLY_SPEND;
17
+ metrics: typeof live.METRICS;
18
+ }
19
+
20
+ /**
21
+ * Simulates fetching live data from Salesforce via GraphQL.
22
+ *
23
+ * On mount, shows a loading state for ~2 seconds, then resolves with the
24
+ * live dataset and flips the global data mode from "sample" → "live".
25
+ * Every useDataSource call across the dashboard will then return the
26
+ * live prop instead of the sample prop, causing all components to refresh
27
+ * simultaneously with new data.
28
+ */
29
+ export function useEngineLiveData(): EngineLiveData {
30
+ const [loading, setLoading] = useState(true);
31
+ const { setMode } = useDataMode();
32
+
33
+ useEffect(() => {
34
+ setMode("sample");
35
+ const timer = setTimeout(() => {
36
+ setLoading(false);
37
+ setMode("live");
38
+ }, SIMULATED_LOAD_MS);
39
+ return () => clearTimeout(timer);
40
+ }, [setMode]);
41
+
42
+ return {
43
+ loading,
44
+ mapMarkers: live.MAP_MARKERS,
45
+ mapArcs: live.MAP_ARCS,
46
+ mapOverlays: live.MAP_OVERLAYS,
47
+ flightStatusList: live.FLIGHT_STATUS_LIST,
48
+ travelerCards: live.TRAVELER_CARDS,
49
+ disruptionCards: live.DISRUPTION_CARDS,
50
+ escalationCards: live.ESCALATION_CARDS,
51
+ monthlySpend: live.MONTHLY_SPEND,
52
+ metrics: live.METRICS,
53
+ };
54
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schandlergarcia/sf-web-components",
3
- "version": "1.9.70",
3
+ "version": "1.9.72",
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",
@@ -282,6 +282,38 @@ if (fs.existsSync(dataSourceDir)) {
282
282
  console.error(` ✗ Failed to install engine-command-center-prd.md: ${error.message}`);
283
283
  }
284
284
  }
285
+
286
+ // Copy engine-live-data.js
287
+ const engineLiveDataSource = path.join(dataSourceDir, 'engine-live-data.js');
288
+ const engineLiveDataTarget = path.join(targetDataDir, 'engine-live-data.js');
289
+
290
+ if (fs.existsSync(engineLiveDataSource)) {
291
+ try {
292
+ fs.copyFileSync(engineLiveDataSource, engineLiveDataTarget);
293
+ console.log(' ✓ Installed engine-live-data.js');
294
+ dataFilesInstalled++;
295
+ } catch (error) {
296
+ console.error(` ✗ Failed to install engine-live-data.js: ${error.message}`);
297
+ }
298
+ }
299
+
300
+ // Copy useEngineLiveData.ts
301
+ const targetHooksDir = path.join(cwd, 'src/hooks');
302
+ const useEngineLiveDataSource = path.join(dataSourceDir, 'useEngineLiveData.ts');
303
+ const useEngineLiveDataTarget = path.join(targetHooksDir, 'useEngineLiveData.ts');
304
+
305
+ if (fs.existsSync(useEngineLiveDataSource)) {
306
+ try {
307
+ if (!fs.existsSync(targetHooksDir)) {
308
+ fs.mkdirSync(targetHooksDir, { recursive: true });
309
+ }
310
+ fs.copyFileSync(useEngineLiveDataSource, useEngineLiveDataTarget);
311
+ console.log(' ✓ Installed useEngineLiveData.ts');
312
+ dataFilesInstalled++;
313
+ } catch (error) {
314
+ console.error(` ✗ Failed to install useEngineLiveData.ts: ${error.message}`);
315
+ }
316
+ }
285
317
  }
286
318
 
287
319
  // Copy GraphQL schema generator script
@@ -654,14 +654,20 @@ echo "→ Restoring ${ENGINE_DATA}..."
654
654
  # Detect package location
655
655
  if [ -d "node_modules/@schandlergarcia/sf-web-components/data" ]; then
656
656
  PACKAGE_DATA="node_modules/@schandlergarcia/sf-web-components/data/engine-sample-data.js"
657
+ PACKAGE_LIVE_DATA="node_modules/@schandlergarcia/sf-web-components/data/engine-live-data.js"
658
+ PACKAGE_LIVE_HOOK="node_modules/@schandlergarcia/sf-web-components/data/useEngineLiveData.ts"
657
659
  PACKAGE_SCHEMA="node_modules/@schandlergarcia/sf-web-components/data/schema.graphql"
658
660
  elif [ -f "$SCRIPT_DIR/../data/engine-sample-data.js" ]; then
659
661
  # Running from package source
660
662
  PACKAGE_DATA="$SCRIPT_DIR/../data/engine-sample-data.js"
663
+ PACKAGE_LIVE_DATA="$SCRIPT_DIR/../data/engine-live-data.js"
664
+ PACKAGE_LIVE_HOOK="$SCRIPT_DIR/../data/useEngineLiveData.ts"
661
665
  PACKAGE_SCHEMA="$SCRIPT_DIR/../data/schema.graphql"
662
666
  else
663
667
  echo " ⚠ Could not find engine-sample-data.js in package"
664
668
  PACKAGE_DATA=""
669
+ PACKAGE_LIVE_DATA=""
670
+ PACKAGE_LIVE_HOOK=""
665
671
  PACKAGE_SCHEMA=""
666
672
  fi
667
673
 
@@ -683,6 +689,29 @@ else
683
689
  echo " ⚠ Skipped schema (package schema not found)"
684
690
  fi
685
691
 
692
+ # Restore engine-live-data.js
693
+ ENGINE_LIVE_DATA="src/data/engine-live-data.js"
694
+ echo "→ Restoring ${ENGINE_LIVE_DATA}..."
695
+
696
+ if [ -n "$PACKAGE_LIVE_DATA" ] && [ -f "$PACKAGE_LIVE_DATA" ]; then
697
+ cp "$PACKAGE_LIVE_DATA" "$ENGINE_LIVE_DATA"
698
+ echo " ✓ Engine live data restored"
699
+ else
700
+ echo " ⚠ Skipped live data (package data not found)"
701
+ fi
702
+
703
+ # Restore useEngineLiveData.ts
704
+ mkdir -p src/hooks
705
+ LIVE_HOOK="src/hooks/useEngineLiveData.ts"
706
+ echo "→ Restoring ${LIVE_HOOK}..."
707
+
708
+ if [ -n "$PACKAGE_LIVE_HOOK" ] && [ -f "$PACKAGE_LIVE_HOOK" ]; then
709
+ cp "$PACKAGE_LIVE_HOOK" "$LIVE_HOOK"
710
+ echo " ✓ Live data hook restored"
711
+ else
712
+ echo " ⚠ Skipped live data hook (package hook not found)"
713
+ fi
714
+
686
715
  # Restore engine-command-center-prd.md
687
716
  PRD_FILE="engine-command-center-prd.md"
688
717
  echo "→ Restoring ${PRD_FILE}..."
@@ -717,6 +746,8 @@ echo "║ - Teal brand palette (#5BC8C8) ║"
717
746
  echo "║ - Inter font stack ║"
718
747
  echo "║ - HeroUI Engine theme overrides ║"
719
748
  echo "║ • Engine sample data (engine-sample-data.js)║"
749
+ echo "║ • Engine live data (engine-live-data.js) ║"
750
+ echo "║ • Live data hook (useEngineLiveData.ts) ║"
720
751
  echo "║ • GraphQL schema (schema.graphql) ║"
721
752
  echo "║ • Engine PRD (engine-command-center-prd.md)║"
722
753
  echo "║ • Component library (cards, charts, etc.) ║"