@schandlergarcia/sf-web-components 1.9.30 → 1.9.31

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/data/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # Data Assets
2
+
3
+ This directory contains pre-packaged data assets for demo builds and prototyping.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ data/
9
+ ├── engine-sample-data.js # Engine Travel Command Center sample data
10
+ └── README.md # This file
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Engine Travel Command Center Sample Data
16
+
17
+ **Purpose:** Pre-seeded, dashboard-ready data for the Engine Travel demo. All field names match the Salesforce org schema (Trip__c, Flight__c, Booking__c, Disruption__c, Rebooking_Action__c, Travel_Policy__c) so switching from sample → live queries requires only a data-source swap.
18
+
19
+ **Exports:**
20
+
21
+ Raw Salesforce-shaped records:
22
+ - `AIRPORTS` — Airport reference data with coordinates
23
+ - `TRAVELERS` — Contact records (travelers)
24
+ - `TRIPS` — Trip__c records
25
+ - `FLIGHTS` — Flight__c records with real-time status
26
+ - `HOTELS` — Hotel reservation records
27
+ - `DISRUPTIONS` — Disruption__c records (delays, weather, closures)
28
+ - `BOOKINGS` — Upcoming booking records
29
+ - `REBOOKING_ACTIONS` — Rebooking_Action__c records (Eva activity)
30
+ - `TRAVEL_POLICIES` — Travel_Policy__c records
31
+ - `ACCOUNT` — Account stats
32
+ - `MONTHLY_SPEND` — Spend history aggregated by month
33
+
34
+ Dashboard-ready derivatives (pre-computed for immediate use):
35
+ - `MAP_MARKERS` — City markers for GeoMap
36
+ - `MAP_ARCS` — Flight arcs with progress & danger flags
37
+ - `MAP_OVERLAYS` — Weather/disruption overlay circles
38
+ - `FLIGHT_STATUS_LIST` — Glass strip flight status data
39
+ - `TRAVELER_CARDS` — Traveler card props
40
+ - `DISRUPTION_CARDS` — Disruption card props
41
+ - `EVA_ACTIONS` — Eva activity feed items
42
+ - `BOOKING_ROWS` — Booking table rows
43
+ - `POLICY_ITEMS` — Policy status items
44
+ - `DESTINATION_CHART_DATA` — Destination bar chart data
45
+ - `SPEND_CHART_DATA` — Spend trend line data
46
+ - `METRICS` — Computed KPI metrics (active travelers, spend MTD, compliance rate, etc.)
47
+
48
+ **Copy to webapp:**
49
+
50
+ When building the Engine dashboard, copy this file to your webapp source:
51
+
52
+ ```bash
53
+ cp data/engine-sample-data.js force-app/main/default/webapplications/enginewebexperience/src/data/engine-sample-data.js
54
+ ```
55
+
56
+ Or if you're starting fresh:
57
+
58
+ ```bash
59
+ # From project root
60
+ cp data/engine-sample-data.js <your-webapp-path>/src/data/
61
+ ```
62
+
63
+ **Import in components:**
64
+
65
+ ```javascript
66
+ import {
67
+ MAP_MARKERS,
68
+ MAP_ARCS,
69
+ MAP_OVERLAYS,
70
+ FLIGHT_STATUS_LIST,
71
+ TRAVELER_CARDS,
72
+ DISRUPTION_CARDS,
73
+ EVA_ACTIONS,
74
+ BOOKING_ROWS,
75
+ POLICY_ITEMS,
76
+ DESTINATION_CHART_DATA,
77
+ SPEND_CHART_DATA,
78
+ METRICS,
79
+ } from '@/data/engine-sample-data';
80
+
81
+ // Use directly in components
82
+ <GeoMap markers={MAP_MARKERS} arcs={MAP_ARCS} overlays={MAP_OVERLAYS} />
83
+ ```
84
+
85
+ **Switching to live Data Cloud:**
86
+
87
+ The sample data uses the same field names as your Salesforce org schema. When you're ready to switch to live data:
88
+
89
+ 1. Query the objects using GraphQL or REST:
90
+ - Trip__c
91
+ - Flight__c
92
+ - Booking__c
93
+ - Disruption__c
94
+ - Rebooking_Action__c
95
+ - Travel_Policy__c
96
+
97
+ 2. Transform the query results using the same shape as the dashboard-ready exports
98
+
99
+ 3. Replace the imports — your components don't need to change
100
+
101
+ **Field mapping reference:**
102
+
103
+ All sample data uses Salesforce API field names:
104
+ - Standard fields: `Id`, `Name`, `CreatedDate`
105
+ - Custom fields: `Trip__c`, `Flight_Number__c`, `Departure_Airport__c`, `Status__c`, etc.
106
+ - Relationships: `Contact__c`, `Trip__c`, `Impacted_Flight__c`
107
+
108
+ ## Adding New Data Assets
109
+
110
+ When adding new sample data:
111
+
112
+ 1. Create a new `.js` file in this directory
113
+ 2. Use Salesforce API field names throughout
114
+ 3. Export both raw records AND dashboard-ready derivatives
115
+ 4. Document the exports in this README
116
+ 5. Include transformation functions if needed
117
+
118
+ ## Guidelines
119
+
120
+ - **Field names must match Salesforce schema** — this makes the live data swap seamless
121
+ - **Pre-compute dashboard derivatives** — components should receive ready-to-render data
122
+ - **Include realistic variety** — different statuses, edge cases, empty states
123
+ - **Use ISO dates** — easier to parse and localize
124
+ - **Keep data fresh** — dates relative to current time where relevant
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Copy sample data to webapp src directory
4
+ #
5
+ # Usage:
6
+ # ./data/copy-to-webapp.sh [webapp-path]
7
+ #
8
+ # Examples:
9
+ # ./data/copy-to-webapp.sh force-app/main/default/webapplications/enginewebexperience
10
+ # ./data/copy-to-webapp.sh /path/to/your/webapp
11
+ #
12
+
13
+ set -e
14
+
15
+ # Get the directory where this script lives
16
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
18
+
19
+ # Default webapp path (Engine Travel Command Center)
20
+ DEFAULT_WEBAPP="force-app/main/default/webapplications/enginewebexperience"
21
+
22
+ # Use provided path or default
23
+ WEBAPP_PATH="${1:-$DEFAULT_WEBAPP}"
24
+
25
+ # Make it absolute if relative
26
+ if [[ ! "$WEBAPP_PATH" = /* ]]; then
27
+ WEBAPP_PATH="$PROJECT_ROOT/$WEBAPP_PATH"
28
+ fi
29
+
30
+ # Verify webapp exists
31
+ if [ ! -d "$WEBAPP_PATH" ]; then
32
+ echo "❌ Error: Webapp directory not found: $WEBAPP_PATH"
33
+ echo ""
34
+ echo "Usage: $0 [webapp-path]"
35
+ echo ""
36
+ echo "Examples:"
37
+ echo " $0"
38
+ echo " $0 force-app/main/default/webapplications/enginewebexperience"
39
+ echo " $0 /absolute/path/to/webapp"
40
+ exit 1
41
+ fi
42
+
43
+ # Create src/data directory if it doesn't exist
44
+ DATA_DIR="$WEBAPP_PATH/src/data"
45
+ mkdir -p "$DATA_DIR"
46
+
47
+ # Copy the sample data file
48
+ echo "📦 Copying sample data to webapp..."
49
+ cp "$SCRIPT_DIR/engine-sample-data.js" "$DATA_DIR/engine-sample-data.js"
50
+
51
+ echo "✅ Sample data copied to: $DATA_DIR/engine-sample-data.js"
52
+ echo ""
53
+ echo "Import in your components:"
54
+ echo ""
55
+ echo " import {"
56
+ echo " MAP_MARKERS,"
57
+ echo " MAP_ARCS,"
58
+ echo " TRAVELER_CARDS,"
59
+ echo " // ... etc"
60
+ echo " } from '@/data/engine-sample-data';"
61
+ echo ""
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Engine Travel Command Center — Sample Data
3
+ *
4
+ * Field names match the Salesforce org schema (Trip__c, Flight__c, Booking__c,
5
+ * Disruption__c, Rebooking_Action__c, Travel_Policy__c, etc.) so switching
6
+ * from sample → live Data Cloud queries requires only a data-source swap,
7
+ * not a field-name refactor.
8
+ *
9
+ * Each section exports both the raw records AND dashboard-ready derivatives
10
+ * (map markers, arcs, chart data, formatted metrics).
11
+ */
12
+
13
+ // ─── AIRPORTS (reference) ───────────────────────────────────────────────────
14
+ export const AIRPORTS = [
15
+ { IATA_Code__c: "SFO", City__c: "San Francisco", Latitude__c: 37.7749, Longitude__c: -122.4194 },
16
+ { IATA_Code__c: "JFK", City__c: "New York", Latitude__c: 40.7128, Longitude__c: -74.0060 },
17
+ { IATA_Code__c: "ORD", City__c: "Chicago", Latitude__c: 41.8781, Longitude__c: -87.6298 },
18
+ { IATA_Code__c: "LAX", City__c: "Los Angeles", Latitude__c: 34.0522, Longitude__c: -118.2437 },
19
+ { IATA_Code__c: "MIA", City__c: "Miami", Latitude__c: 25.7617, Longitude__c: -80.1918 },
20
+ { IATA_Code__c: "SEA", City__c: "Seattle", Latitude__c: 47.6062, Longitude__c: -122.3321 },
21
+ { IATA_Code__c: "BOS", City__c: "Boston", Latitude__c: 42.3601, Longitude__c: -71.0589 },
22
+ { IATA_Code__c: "DEN", City__c: "Denver", Latitude__c: 39.7392, Longitude__c: -104.9903 },
23
+ { IATA_Code__c: "AUS", City__c: "Austin", Latitude__c: 30.2672, Longitude__c: -97.7431 },
24
+ { IATA_Code__c: "ATL", City__c: "Atlanta", Latitude__c: 33.7490, Longitude__c: -84.3880 },
25
+ { IATA_Code__c: "LHR", City__c: "London", Latitude__c: 51.5074, Longitude__c: -0.1278 },
26
+ { IATA_Code__c: "NRT", City__c: "Tokyo", Latitude__c: 35.6895, Longitude__c: 139.6917 },
27
+ { IATA_Code__c: "TXL", City__c: "Berlin", Latitude__c: 52.5200, Longitude__c: 13.4050 },
28
+ { IATA_Code__c: "SIN", City__c: "Singapore", Latitude__c: 1.3521, Longitude__c: 103.8198 },
29
+ { IATA_Code__c: "CDG", City__c: "Paris", Latitude__c: 48.8566, Longitude__c: 2.3522 },
30
+ { IATA_Code__c: "DXB", City__c: "Dubai", Latitude__c: 25.2048, Longitude__c: 55.2708 },
31
+ { IATA_Code__c: "SYD", City__c: "Sydney", Latitude__c: -33.8688, Longitude__c: 151.2093 },
32
+ ];
33
+
34
+ const airportByCode = Object.fromEntries(
35
+ AIRPORTS.map((a) => [a.IATA_Code__c, a])
36
+ );
37
+
38
+ // ─── CONTACTS / TRAVELERS ───────────────────────────────────────────────────
39
+ export const TRAVELERS = [
40
+ { Id: "003T1", FirstName: "Sarah", LastName: "Chen", Department: "Engineering", Home_Airport__c: "SFO", Travel_Policy_Tier__c: "Manager", Is_Active_Traveler__c: true, Role__c: "Traveler" },
41
+ { Id: "003T2", FirstName: "Marcus", LastName: "Johnson", Department: "Sales", Home_Airport__c: "JFK", Travel_Policy_Tier__c: "Standard", Is_Active_Traveler__c: true, Role__c: "Traveler" },
42
+ { Id: "003T3", FirstName: "Priya", LastName: "Patel", Department: "Product", Home_Airport__c: "ORD", Travel_Policy_Tier__c: "Standard", Is_Active_Traveler__c: true, Role__c: "Traveler" },
43
+ { Id: "003T4", FirstName: "David", LastName: "Kim", Department: "Finance", Home_Airport__c: "LAX", Travel_Policy_Tier__c: "Executive", Is_Active_Traveler__c: true, Role__c: "Traveler" },
44
+ { Id: "003T5", FirstName: "Elena", LastName: "Rodriguez", Department: "Marketing", Home_Airport__c: "MIA", Travel_Policy_Tier__c: "Standard", Is_Active_Traveler__c: true, Role__c: "Traveler" },
45
+ { Id: "003T6", FirstName: "James", LastName: "Wright", Department: "Engineering", Home_Airport__c: "SEA", Travel_Policy_Tier__c: "Standard", Is_Active_Traveler__c: true, Role__c: "Traveler" },
46
+ { Id: "003T7", FirstName: "Aisha", LastName: "Mohammed", Department: "Legal", Home_Airport__c: "BOS", Travel_Policy_Tier__c: "Manager", Is_Active_Traveler__c: true, Role__c: "Traveler" },
47
+ { Id: "003T8", FirstName: "Tom", LastName: "O'Brien", Department: "Sales", Home_Airport__c: "DEN", Travel_Policy_Tier__c: "Standard", Is_Active_Traveler__c: true, Role__c: "Traveler" },
48
+ ];
49
+
50
+ // ─── TRIPS ──────────────────────────────────────────────────────────────────
51
+ export const TRIPS = [
52
+ { Id: "a00T1", Trip_Name__c: "Chen – London", Contact__c: "003T1", Origin_City__c: "San Francisco", Origin_Airport__c: "SFO", Destination_City__c: "London", Destination_Airport__c: "LHR", Start_Date__c: "2026-03-24", End_Date__c: "2026-03-28", Status__c: "In Progress", Total_Cost__c: 4200, In_Policy__c: true, Has_Disruption__c: false },
53
+ { Id: "a00T2", Trip_Name__c: "Johnson – Tokyo", Contact__c: "003T2", Origin_City__c: "New York", Origin_Airport__c: "JFK", Destination_City__c: "Tokyo", Destination_Airport__c: "NRT", Start_Date__c: "2026-03-24", End_Date__c: "2026-03-30", Status__c: "In Progress", Total_Cost__c: 5800, In_Policy__c: true, Has_Disruption__c: false },
54
+ { Id: "a00T3", Trip_Name__c: "Patel – Berlin", Contact__c: "003T3", Origin_City__c: "Chicago", Origin_Airport__c: "ORD", Destination_City__c: "Berlin", Destination_Airport__c: "TXL", Start_Date__c: "2026-03-24", End_Date__c: "2026-03-27", Status__c: "In Progress", Total_Cost__c: 3400, In_Policy__c: false, Has_Disruption__c: true },
55
+ { Id: "a00T4", Trip_Name__c: "Kim – Singapore", Contact__c: "003T4", Origin_City__c: "Los Angeles", Origin_Airport__c: "LAX", Destination_City__c: "Singapore", Destination_Airport__c: "SIN", Start_Date__c: "2026-03-25", End_Date__c: "2026-04-01", Status__c: "In Progress", Total_Cost__c: 6100, In_Policy__c: true, Has_Disruption__c: false },
56
+ { Id: "a00T5", Trip_Name__c: "Rodriguez – Paris", Contact__c: "003T5", Origin_City__c: "Miami", Origin_Airport__c: "MIA", Destination_City__c: "Paris", Destination_Airport__c: "CDG", Start_Date__c: "2026-03-24", End_Date__c: "2026-03-26", Status__c: "In Progress", Total_Cost__c: 2900, In_Policy__c: true, Has_Disruption__c: true },
57
+ { Id: "a00T6", Trip_Name__c: "Wright – Austin", Contact__c: "003T6", Origin_City__c: "Seattle", Origin_Airport__c: "SEA", Destination_City__c: "Austin", Destination_Airport__c: "AUS", Start_Date__c: "2026-03-24", End_Date__c: "2026-03-25", Status__c: "In Progress", Total_Cost__c: 820, In_Policy__c: true, Has_Disruption__c: false },
58
+ { Id: "a00T7", Trip_Name__c: "Mohammed – Dubai", Contact__c: "003T7", Origin_City__c: "Boston", Origin_Airport__c: "BOS", Destination_City__c: "Dubai", Destination_Airport__c: "DXB", Start_Date__c: "2026-03-25", End_Date__c: "2026-03-31", Status__c: "In Progress", Total_Cost__c: 5200, In_Policy__c: false, Has_Disruption__c: false },
59
+ { Id: "a00T8", Trip_Name__c: "O'Brien – Sydney", Contact__c: "003T8", Origin_City__c: "Denver", Origin_Airport__c: "DEN", Destination_City__c: "Sydney", Destination_Airport__c: "SYD", Start_Date__c: "2026-03-25", End_Date__c: "2026-04-02", Status__c: "In Progress", Total_Cost__c: 7400, In_Policy__c: true, Has_Disruption__c: false },
60
+ ];
61
+
62
+ // ─── FLIGHTS ────────────────────────────────────────────────────────────────
63
+ export const FLIGHTS = [
64
+ { Id: "a01F1", Flight_Number__c: "BA 286", Airline__c: "British Airways", Departure_Airport__c: "SFO", Departure_City__c: "San Francisco", Departure_Longitude__c: -122.4194, Departure_Latitude__c: 37.7749, Arrival_Airport__c: "LHR", Arrival_City__c: "London", Arrival_Longitude__c: -0.1278, Arrival_Latitude__c: 51.5074, Departure_DateTime__c: "2026-03-25T22:45:00Z", Flight_Status__c: "In Air", Delay_Minutes__c: 0, Cabin_Class__c: "Business", Contact__c: "003T1" },
65
+ { Id: "a01F2", Flight_Number__c: "NH 109", Airline__c: "All Nippon Airways", Departure_Airport__c: "JFK", Departure_City__c: "New York", Departure_Longitude__c: -74.0060, Departure_Latitude__c: 40.7128, Arrival_Airport__c: "NRT", Arrival_City__c: "Tokyo", Arrival_Longitude__c: 139.6917, Arrival_Latitude__c: 35.6895, Departure_DateTime__c: "2026-03-25T11:30:00Z", Flight_Status__c: "In Air", Delay_Minutes__c: 0, Cabin_Class__c: "Economy", Contact__c: "003T2" },
66
+ { Id: "a01F3", Flight_Number__c: "LH 431", Airline__c: "Lufthansa", Departure_Airport__c: "ORD", Departure_City__c: "Chicago", Departure_Longitude__c: -87.6298, Departure_Latitude__c: 41.8781, Arrival_Airport__c: "TXL", Arrival_City__c: "Berlin", Arrival_Longitude__c: 13.4050, Arrival_Latitude__c: 52.5200, Departure_DateTime__c: "2026-03-25T17:15:00Z", Flight_Status__c: "Delayed", Delay_Minutes__c: 95, Cabin_Class__c: "Economy", Contact__c: "003T3" },
67
+ { Id: "a01F4", Flight_Number__c: "SQ 37", Airline__c: "Singapore Airlines", Departure_Airport__c: "LAX", Departure_City__c: "Los Angeles", Departure_Longitude__c: -118.2437, Departure_Latitude__c: 34.0522, Arrival_Airport__c: "SIN", Arrival_City__c: "Singapore", Arrival_Longitude__c: 103.8198, Arrival_Latitude__c: 1.3521, Departure_DateTime__c: "2026-03-25T23:00:00Z", Flight_Status__c: "Boarding", Delay_Minutes__c: 0, Cabin_Class__c: "Business", Contact__c: "003T4" },
68
+ { Id: "a01F5", Flight_Number__c: "AF 99", Airline__c: "Air France", Departure_Airport__c: "MIA", Departure_City__c: "Miami", Departure_Longitude__c: -80.1918, Departure_Latitude__c: 25.7617, Arrival_Airport__c: "CDG", Arrival_City__c: "Paris", Arrival_Longitude__c: 2.3522, Arrival_Latitude__c: 48.8566, Departure_DateTime__c: "2026-03-25T18:20:00Z", Flight_Status__c: "Delayed", Delay_Minutes__c: 45, Cabin_Class__c: "Premium Economy", Contact__c: "003T5" },
69
+ { Id: "a01F6", Flight_Number__c: "AS 670", Airline__c: "Alaska Airlines", Departure_Airport__c: "SEA", Departure_City__c: "Seattle", Departure_Longitude__c: -122.3321, Departure_Latitude__c: 47.6062, Arrival_Airport__c: "AUS", Arrival_City__c: "Austin", Arrival_Longitude__c: -97.7431, Arrival_Latitude__c: 30.2672, Departure_DateTime__c: "2026-03-25T08:05:00Z", Flight_Status__c: "Landed", Delay_Minutes__c: 0, Cabin_Class__c: "Economy", Contact__c: "003T6" },
70
+ { Id: "a01F7", Flight_Number__c: "EK 238", Airline__c: "Emirates", Departure_Airport__c: "BOS", Departure_City__c: "Boston", Departure_Longitude__c: -71.0589, Departure_Latitude__c: 42.3601, Arrival_Airport__c: "DXB", Arrival_City__c: "Dubai", Arrival_Longitude__c: 55.2708, Arrival_Latitude__c: 25.2048, Departure_DateTime__c: "2026-03-25T21:30:00Z", Flight_Status__c: "Scheduled", Delay_Minutes__c: 0, Cabin_Class__c: "Economy", Contact__c: "003T7" },
71
+ { Id: "a01F8", Flight_Number__c: "QF 16", Airline__c: "Qantas", Departure_Airport__c: "DEN", Departure_City__c: "Denver", Departure_Longitude__c: -104.9903, Departure_Latitude__c: 39.7392, Arrival_Airport__c: "SYD", Arrival_City__c: "Sydney", Arrival_Longitude__c: 151.2093, Arrival_Latitude__c: -33.8688, Departure_DateTime__c: "2026-03-25T22:10:00Z", Flight_Status__c: "In Air", Delay_Minutes__c: 0, Cabin_Class__c: "Economy", Contact__c: "003T8" },
72
+ ];
73
+
74
+ // ─── HOTEL RESERVATIONS ─────────────────────────────────────────────────────
75
+ export const HOTELS = [
76
+ { Id: "a02H1", Hotel_Name__c: "The Ned", City__c: "London", Nightly_Rate__c: 320, Check_In_Date__c: "2026-03-24", Check_Out_Date__c: "2026-03-28", Status__c: "Checked In", Contact__c: "003T1" },
77
+ { Id: "a02H2", Hotel_Name__c: "Park Hyatt", City__c: "Tokyo", Nightly_Rate__c: 450, Check_In_Date__c: "2026-03-25", Check_Out_Date__c: "2026-03-30", Status__c: "Reserved", Contact__c: "003T2" },
78
+ { Id: "a02H3", Hotel_Name__c: "Hotel Adlon", City__c: "Berlin", Nightly_Rate__c: 410, Check_In_Date__c: "2026-03-24", Check_Out_Date__c: "2026-03-27", Status__c: "Reserved", Contact__c: "003T3" },
79
+ { Id: "a02H4", Hotel_Name__c: "Marina Bay Sands", City__c: "Singapore", Nightly_Rate__c: 380, Check_In_Date__c: "2026-03-26", Check_Out_Date__c: "2026-04-01", Status__c: "Reserved", Contact__c: "003T4" },
80
+ { Id: "a02H5", Hotel_Name__c: "Le Marais Hotel", City__c: "Paris", Nightly_Rate__c: 275, Check_In_Date__c: "2026-03-24", Check_Out_Date__c: "2026-03-26", Status__c: "Checked In", Contact__c: "003T5" },
81
+ { Id: "a02H6", Hotel_Name__c: "Line Hotel", City__c: "Austin", Nightly_Rate__c: 159, Check_In_Date__c: "2026-03-24", Check_Out_Date__c: "2026-03-25", Status__c: "Checked In", Contact__c: "003T6" },
82
+ { Id: "a02H7", Hotel_Name__c: "Jumeirah Emirates", City__c: "Dubai", Nightly_Rate__c: 340, Check_In_Date__c: "2026-03-26", Check_Out_Date__c: "2026-03-31", Status__c: "Reserved", Contact__c: "003T7" },
83
+ { Id: "a02H8", Hotel_Name__c: "QT Sydney", City__c: "Sydney", Nightly_Rate__c: 290, Check_In_Date__c: "2026-03-26", Check_Out_Date__c: "2026-04-02", Status__c: "Reserved", Contact__c: "003T8" },
84
+ ];
85
+
86
+ // ─── DISRUPTIONS ────────────────────────────────────────────────────────────
87
+ export const DISRUPTIONS = [
88
+ { Id: "a03D1", Flight_Number__c: "LH 431", Disruption_Type__c: "Flight Delay", Severity__c: "High", Status__c: "In Progress", Impacted_Flight__c: "a01F3", Trip__c: "a00T3", City__c: "Chicago", Affected_Traveler_Count__c: 1, Auto_Rebook_Eligible__c: true, Recommended_Action__c: "Rebook on LH 433 (dep 7:50p)", Description__c: "Mechanical — crew change required" },
89
+ { Id: "a03D2", Flight_Number__c: "AF 99", Disruption_Type__c: "Weather Event", Severity__c: "Medium", Status__c: "Assessing Impact", Impacted_Flight__c: "a01F5", Trip__c: "a00T5", City__c: "Paris", Affected_Traveler_Count__c: 1, Auto_Rebook_Eligible__c: false, Recommended_Action__c: "Monitoring — no action needed yet", Description__c: "Thunderstorms at CDG" },
90
+ { Id: "a03D3", Flight_Number__c: "UA 412", Disruption_Type__c: "Airport Closure", Severity__c: "Critical", Status__c: "In Progress", Impacted_Flight__c: null, Trip__c: null, City__c: "Chicago", Affected_Traveler_Count__c: 2, Auto_Rebook_Eligible__c: true, Recommended_Action__c: "Rebooked on AA 1582 (dep 3:15p)", Description__c: "ATC ground stop — O'Hare capacity" },
91
+ { Id: "a03D4", Flight_Number__c: "DL 209", Disruption_Type__c: "Airline Schedule Change", Severity__c: "Medium", Status__c: "In Progress", Impacted_Flight__c: null, Trip__c: null, City__c: "Los Angeles", Affected_Traveler_Count__c: 1, Auto_Rebook_Eligible__c: false, Recommended_Action__c: "Hotel backup hold at LAX Marriott", Description__c: "Late inbound aircraft" },
92
+ ];
93
+
94
+ // ─── BOOKINGS (upcoming) ────────────────────────────────────────────────────
95
+ export const BOOKINGS = [
96
+ { Id: "a04B1", Contact__c: "003T9", Booking_Type__c: "Flight", Status__c: "Confirmed", Cost__c: 824, In_Policy__c: true, _travelerName: "Lisa Park", _destination: "Denver → Chicago", _dates: "Mar 28–30" },
97
+ { Id: "a04B2", Contact__c: "003T10", Booking_Type__c: "Flight", Status__c: "Confirmed", Cost__c: 412, In_Policy__c: true, _travelerName: "Ryan Foster", _destination: "NYC → San Francisco", _dates: "Mar 29" },
98
+ { Id: "a04B3", Contact__c: "003T11", Booking_Type__c: "Flight", Status__c: "Confirmed", Cost__c: 2340, In_Policy__c: false, _travelerName: "Mei Wong", _destination: "Seattle → London", _dates: "Apr 1–5" },
99
+ { Id: "a04B4", Contact__c: "003T12", Booking_Type__c: "Hotel", Status__c: "Confirmed", Cost__c: 380, In_Policy__c: true, _travelerName: "Carlos Vega", _destination: "Austin", _dates: "Apr 2–4" },
100
+ { Id: "a04B5", Contact__c: "003T13", Booking_Type__c: "Flight", Status__c: "Confirmed", Cost__c: 1890, In_Policy__c: true, _travelerName: "Nina Kowalski", _destination: "Boston → Berlin", _dates: "Apr 3–7" },
101
+ { Id: "a04B6", Contact__c: "003T14", Booking_Type__c: "Flight", Status__c: "Confirmed", Cost__c: 298, In_Policy__c: true, _travelerName: "Andre Williams", _destination: "LA → Miami", _dates: "Apr 5" },
102
+ { Id: "a04B7", Contact__c: "003T15", Booking_Type__c: "Flight", Status__c: "Confirmed", Cost__c: 3150, In_Policy__c: false, _travelerName: "Hannah Lee", _destination: "Chicago → Tokyo", _dates: "Apr 7–12" },
103
+ { Id: "a04B8", Contact__c: "003T16", Booking_Type__c: "Flight", Status__c: "Confirmed", Cost__c: 2100, In_Policy__c: false, _travelerName: "Omar Hassan", _destination: "Denver → Paris", _dates: "Apr 8–11" },
104
+ ];
105
+
106
+ // ─── REBOOKING ACTIONS (Eva activity) ───────────────────────────────────────
107
+ export const REBOOKING_ACTIONS = [
108
+ { Id: "a05R1", Action_Type__c: "Manual Rebook", Status__c: "Completed", Handled_By__c: "Eva (Agent)", Contact__c: "003T1", Original_Flight__c: "LH 431", New_Flight__c: "LH 433", Cost_Difference__c: 0, Notes__c: "Rebooked cancelled flight for Sarah Chen — LH 431 → LH 433 · Same fare class", Created_DateTime__c: "2026-03-25T14:58:00Z" },
109
+ { Id: "a05R2", Action_Type__c: "Manual Rebook", Status__c: "Completed", Handled_By__c: "Eva (Agent)", Contact__c: "003T11", Original_Flight__c: null, New_Flight__c: null, Cost_Difference__c: -221, Notes__c: "Found policy-compliant hotel for Mei Wong — Hotel Adlon ($410/n) → Motel One ($189/n)", Created_DateTime__c: "2026-03-25T14:52:00Z" },
110
+ { Id: "a05R3", Action_Type__c: "Escalation", Status__c: "In Progress", Handled_By__c: "Eva (Agent)", Contact__c: "003T16", Original_Flight__c: null, New_Flight__c: null, Cost_Difference__c: 0, Notes__c: "Processing approval for Omar Hassan — Paris trip over budget — escalated to manager", Created_DateTime__c: "2026-03-25T14:48:00Z" },
111
+ { Id: "a05R4", Action_Type__c: "Auto-Cancel", Status__c: "Completed", Handled_By__c: "Eva (Agent)", Contact__c: "003T14", Original_Flight__c: null, New_Flight__c: null, Cost_Difference__c: 0, Notes__c: "Auto-approved Andre Williams flight — LA → Miami · $298 · Within policy", Created_DateTime__c: "2026-03-25T14:35:00Z" },
112
+ { Id: "a05R5", Action_Type__c: "Manual Rebook", Status__c: "Completed", Handled_By__c: "Eva (Agent)", Contact__c: "003T4", Original_Flight__c: "SQ 37", New_Flight__c: null, Cost_Difference__c: 0, Notes__c: "Sent itinerary update to David Kim — Gate change SQ 37 · Terminal 2 → Terminal 3", Created_DateTime__c: "2026-03-25T14:26:00Z" },
113
+ { Id: "a05R6", Action_Type__c: "Manual Rebook", Status__c: "Completed", Handled_By__c: "Eva (Agent)", Contact__c: "003T6", Original_Flight__c: null, New_Flight__c: null, Cost_Difference__c: -60, Notes__c: "Negotiated group rate for Austin offsite — Line Hotel · 12 rooms · $159/n (was $219/n)", Created_DateTime__c: "2026-03-25T13:00:00Z" },
114
+ { Id: "a05R7", Action_Type__c: "Auto-Cancel", Status__c: "Completed", Handled_By__c: "Eva (Agent)", Contact__c: "003T10", Original_Flight__c: null, New_Flight__c: null, Cost_Difference__c: -412, Notes__c: "Flagged duplicate booking for Ryan Foster — NYC → SFO booked twice · Cancelled duplicate", Created_DateTime__c: "2026-03-25T12:30:00Z" },
115
+ { Id: "a05R8", Action_Type__c: "Waitlist", Status__c: "In Progress", Handled_By__c: "Eva (Agent)", Contact__c: "003T5", Original_Flight__c: "AF 99", New_Flight__c: null, Cost_Difference__c: 0, Notes__c: "Monitoring weather delay for Elena Rodriguez — AF 99 · CDG arrival delayed 45 min · No action yet", Created_DateTime__c: "2026-03-25T12:00:00Z" },
116
+ ];
117
+
118
+ // ─── TRAVEL POLICIES ────────────────────────────────────────────────────────
119
+ export const TRAVEL_POLICIES = [
120
+ { Id: "a06P1", Name: "Flight booking policy", Description__c: "Economy required for domestic under 4 hrs", Active__c: true, Policy_Tier__c: "Standard", Max_Flight_Cost__c: 800, Advance_Booking_Days__c: 7, _health: "operational", _lastEvaluated: "2026-03-24T10:00:00Z" },
121
+ { Id: "a06P2", Name: "Hotel nightly rate cap", Description__c: "$275/night domestic, $350/night international", Active__c: true, Policy_Tier__c: "Standard", Max_Hotel_Rate__c: 275, Advance_Booking_Days__c: null, _health: "degraded", _lastEvaluated: "2026-03-24T09:00:00Z" },
122
+ { Id: "a06P3", Name: "Advance booking window", Description__c: "14-day minimum for international travel", Active__c: true, Policy_Tier__c: "Standard", Max_Flight_Cost__c: null, Advance_Booking_Days__c: 14, _health: "operational", _lastEvaluated: "2026-03-24T08:00:00Z" },
123
+ { Id: "a06P4", Name: "Preferred vendor usage", Description__c: "United, Delta, Marriott, Hilton preferred", Active__c: true, Policy_Tier__c: "Standard", Preferred_Airlines__c: "United, Delta", Preferred_Hotel_Chains__c: "Marriott, Hilton", _health: "operational", _lastEvaluated: "2026-03-23T16:00:00Z" },
124
+ { Id: "a06P5", Name: "Expense receipt compliance", Description__c: "All receipts within 5 business days", Active__c: true, Policy_Tier__c: "Standard", Max_Flight_Cost__c: null, Advance_Booking_Days__c: null, _health: "degraded", _lastEvaluated: "2026-03-23T14:00:00Z" },
125
+ ];
126
+
127
+ // ─── ACCOUNT STATS ──────────────────────────────────────────────────────────
128
+ export const ACCOUNT = {
129
+ Id: "001A1",
130
+ Name: "Acme Corp",
131
+ Account_Tier__c: "Enterprise",
132
+ Active_Travelers__c: 8,
133
+ Annual_Travel_Spend__c: 1540000,
134
+ Total_Trips_YTD__c: 142,
135
+ CSAT_Score__c: 4.7,
136
+ Travel_Policy_Enabled__c: true,
137
+ Flex_Pro_Subscriber__c: true,
138
+ };
139
+
140
+ // ─── SPEND HISTORY (aggregated) ─────────────────────────────────────────────
141
+ export const MONTHLY_SPEND = [
142
+ { month: "Oct", amount: 142000 },
143
+ { month: "Nov", amount: 128000 },
144
+ { month: "Dec", amount: 98000 },
145
+ { month: "Jan", amount: 156000 },
146
+ { month: "Feb", amount: 134000 },
147
+ { month: "Mar", amount: 128400 },
148
+ ];
149
+
150
+ // ═══════════════════════════════════════════════════════════════════════════
151
+ // DASHBOARD-READY DERIVATIVES
152
+ // These transform the Salesforce-shaped records into the props that
153
+ // GeoMap, ChartCard, TableCard, etc. consume directly.
154
+ // ═══════════════════════════════════════════════════════════════════════════
155
+
156
+ // ─── MAP: markers ───────────────────────────────────────────────────────────
157
+ const usedCodes = new Set();
158
+ FLIGHTS.forEach((f) => {
159
+ usedCodes.add(f.Departure_Airport__c);
160
+ usedCodes.add(f.Arrival_Airport__c);
161
+ });
162
+
163
+ export const MAP_MARKERS = AIRPORTS.filter((a) =>
164
+ usedCodes.has(a.IATA_Code__c)
165
+ ).map((a) => ({
166
+ id: a.IATA_Code__c,
167
+ lon: a.Longitude__c,
168
+ lat: a.Latitude__c,
169
+ label: a.City__c,
170
+ active: true,
171
+ }));
172
+
173
+ // ─── MAP: arcs ──────────────────────────────────────────────────────────────
174
+ const FLIGHT_PROGRESS = {
175
+ "In Air": 0.55,
176
+ Boarding: 0.05,
177
+ Delayed: 0.0,
178
+ Scheduled: 0.0,
179
+ Landed: 1.0,
180
+ };
181
+
182
+ const disruptedFlightIds = new Set(
183
+ DISRUPTIONS.map((d) => d.Impacted_Flight__c).filter(Boolean)
184
+ );
185
+
186
+ export const MAP_ARCS = FLIGHTS.map((f) => ({
187
+ id: f.Id,
188
+ from: [f.Departure_Longitude__c, f.Departure_Latitude__c],
189
+ to: [f.Arrival_Longitude__c, f.Arrival_Latitude__c],
190
+ progress: FLIGHT_PROGRESS[f.Flight_Status__c] ?? 0,
191
+ danger: disruptedFlightIds.has(f.Id) || f.Delay_Minutes__c >= 60,
192
+ }));
193
+
194
+ // ─── MAP: overlays (weather / disruption zones) ─────────────────────────────
195
+ export const MAP_OVERLAYS = DISRUPTIONS.filter(
196
+ (d) => d.Disruption_Type__c === "Weather Event"
197
+ ).map((d) => {
198
+ const airport = airportByCode[d.City__c] ?? airportByCode["CDG"];
199
+ return {
200
+ id: d.Id,
201
+ center: [airport?.Longitude__c ?? 2.35, airport?.Latitude__c ?? 48.86],
202
+ radius: 4,
203
+ };
204
+ });
205
+
206
+ // ─── FLIGHT STATUS (for glass strip) ────────────────────────────────────────
207
+ const travelerByContactId = Object.fromEntries(
208
+ TRAVELERS.map((t) => [t.Id, t])
209
+ );
210
+
211
+ export const FLIGHT_STATUS_LIST = FLIGHTS.map((f) => {
212
+ const t = travelerByContactId[f.Contact__c];
213
+ return {
214
+ id: f.Id,
215
+ flight: f.Flight_Number__c,
216
+ route: `${f.Departure_Airport__c} → ${f.Arrival_Airport__c}`,
217
+ dep: new Date(f.Departure_DateTime__c).toLocaleTimeString("en-US", {
218
+ hour: "numeric",
219
+ minute: "2-digit",
220
+ }),
221
+ status: f.Flight_Status__c,
222
+ traveler: t ? `${t.FirstName} ${t.LastName}` : "",
223
+ delayMin: f.Delay_Minutes__c,
224
+ };
225
+ });
226
+
227
+ // ─── TRAVELER CARDS ─────────────────────────────────────────────────────────
228
+ const hotelByContact = Object.fromEntries(
229
+ HOTELS.map((h) => [h.Contact__c, h])
230
+ );
231
+
232
+ const tripByContact = Object.fromEntries(
233
+ TRIPS.map((t) => [t.Contact__c, t])
234
+ );
235
+
236
+ const flightByContact = Object.fromEntries(
237
+ FLIGHTS.map((f) => [f.Contact__c, f])
238
+ );
239
+
240
+ export const TRAVELER_CARDS = TRAVELERS.map((t) => {
241
+ const trip = tripByContact[t.Id];
242
+ const flight = flightByContact[t.Id];
243
+ const hotel = hotelByContact[t.Id];
244
+ return {
245
+ id: t.Id,
246
+ name: `${t.FirstName} ${t.LastName}`,
247
+ department: t.Department,
248
+ origin: trip?.Origin_City__c ?? "",
249
+ destination: trip?.Destination_City__c ?? "",
250
+ flight: flight?.Flight_Number__c ?? "",
251
+ hotel: hotel?.Hotel_Name__c ?? "",
252
+ return: trip?.End_Date__c
253
+ ? new Date(trip.End_Date__c).toLocaleDateString("en-US", {
254
+ month: "short",
255
+ day: "numeric",
256
+ })
257
+ : "",
258
+ policyStatus: trip?.In_Policy__c ? "compliant" : "exception",
259
+ };
260
+ });
261
+
262
+ // ─── DISRUPTION CARDS ───────────────────────────────────────────────────────
263
+ export const DISRUPTION_CARDS = DISRUPTIONS.map((d) => {
264
+ const flight = FLIGHTS.find((f) => f.Id === d.Impacted_Flight__c);
265
+ const traveler = flight
266
+ ? travelerByContactId[flight.Contact__c]
267
+ : null;
268
+ return {
269
+ id: d.Id,
270
+ flight: d.Flight_Number__c,
271
+ route: flight
272
+ ? `${flight.Departure_Airport__c} → ${flight.Arrival_Airport__c}`
273
+ : d.City__c,
274
+ traveler: traveler
275
+ ? `${traveler.FirstName} ${traveler.LastName}`
276
+ : "Multiple travelers",
277
+ severity:
278
+ d.Severity__c === "Critical" || d.Severity__c === "High"
279
+ ? "grounded"
280
+ : "delayed",
281
+ delayMin:
282
+ flight?.Delay_Minutes__c ??
283
+ (d.Severity__c === "Critical" ? 120 : 70),
284
+ reason: d.Description__c,
285
+ evaAction: d.Recommended_Action__c,
286
+ };
287
+ });
288
+
289
+ // ─── EVA ACTIVITY FEED ──────────────────────────────────────────────────────
290
+ const NOW = new Date("2026-03-25T15:00:00Z").getTime();
291
+
292
+ function relativeTime(iso) {
293
+ const diff = NOW - new Date(iso).getTime();
294
+ const min = Math.round(diff / 60000);
295
+ if (min < 60) return `${min} min ago`;
296
+ const hr = (min / 60).toFixed(1);
297
+ return `${hr} hr ago`;
298
+ }
299
+
300
+ export const EVA_ACTIONS = REBOOKING_ACTIONS.map((r) => {
301
+ const parts = r.Notes__c.split(" — ");
302
+ return {
303
+ id: r.Id,
304
+ title: parts[0] ?? r.Notes__c,
305
+ subtitle: parts[1] ?? "",
306
+ status: r.Status__c === "Completed" ? "complete" : "working",
307
+ timestamp: relativeTime(r.Created_DateTime__c),
308
+ };
309
+ });
310
+
311
+ // ─── BOOKING TABLE ──────────────────────────────────────────────────────────
312
+ export const BOOKING_ROWS = BOOKINGS.map((b) => ({
313
+ id: b.Id,
314
+ traveler: b._travelerName,
315
+ type: b.Booking_Type__c,
316
+ destination: b._destination,
317
+ dates: b._dates,
318
+ cost: `$${b.Cost__c.toLocaleString()}`,
319
+ status: b.Status__c,
320
+ policy: b.In_Policy__c
321
+ ? "In policy"
322
+ : b.Cost__c > 2000
323
+ ? "Over budget"
324
+ : "Exception granted",
325
+ }));
326
+
327
+ // ─── POLICY STATUS ITEMS ────────────────────────────────────────────────────
328
+ export const POLICY_ITEMS = TRAVEL_POLICIES.map((p) => ({
329
+ id: p.Id,
330
+ title: p.Name,
331
+ description: p.Description__c,
332
+ status: p._health,
333
+ timestamp: p._lastEvaluated,
334
+ }));
335
+
336
+ // ─── CHART DATA ─────────────────────────────────────────────────────────────
337
+ export const DESTINATION_CHART_DATA = Object.entries(
338
+ TRIPS.reduce((acc, t) => {
339
+ acc[t.Destination_City__c] = (acc[t.Destination_City__c] || 0) + 1;
340
+ return acc;
341
+ }, {})
342
+ ).map(([city, count]) => ({ x: city, travelers: count }));
343
+
344
+ export const SPEND_CHART_DATA = MONTHLY_SPEND.map((m) => ({
345
+ x: m.month,
346
+ y: m.amount,
347
+ }));
348
+
349
+ // ─── COMPUTED METRICS ───────────────────────────────────────────────────────
350
+ export const METRICS = {
351
+ activeTravelers: TRAVELERS.length,
352
+ spendMTD: MONTHLY_SPEND.find((m) => m.month === "Mar")?.amount ?? 0,
353
+ complianceRate: Math.round(
354
+ (TRIPS.filter((t) => t.In_Policy__c).length / TRIPS.length) * 100
355
+ ),
356
+ evaResolutionRate: Math.round(
357
+ (REBOOKING_ACTIONS.filter((r) => r.Status__c === "Completed").length /
358
+ REBOOKING_ACTIONS.length) *
359
+ 100
360
+ ),
361
+ evaResolved: REBOOKING_ACTIONS.filter((r) => r.Status__c === "Completed")
362
+ .length,
363
+ pendingBookings: BOOKINGS.filter(
364
+ (b) => b.Status__c === "Pending approval"
365
+ ).length,
366
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schandlergarcia/sf-web-components",
3
- "version": "1.9.30",
3
+ "version": "1.9.31",
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",
@@ -27,6 +27,7 @@
27
27
  "files": [
28
28
  "dist",
29
29
  "scripts",
30
+ "data",
30
31
  "README.md",
31
32
  ".a4drules"
32
33
  ],