@schandlergarcia/sf-web-components 1.9.29 → 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/README.md +22 -0
- package/data/README.md +124 -0
- package/data/copy-to-webapp.sh +61 -0
- package/data/engine-sample-data.js +366 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -92,10 +92,32 @@ npm run build:types
|
|
|
92
92
|
|
|
93
93
|
## Publishing
|
|
94
94
|
|
|
95
|
+
This package publishes to the **public npm registry** at https://registry.npmjs.org.
|
|
96
|
+
|
|
97
|
+
### Prerequisites
|
|
98
|
+
- Be logged in to npm: `npm login`
|
|
99
|
+
- Have publish permissions for the `@schandlergarcia` scope
|
|
100
|
+
|
|
101
|
+
### Publish a New Version
|
|
102
|
+
|
|
95
103
|
```bash
|
|
104
|
+
# Bump version (patch, minor, or major)
|
|
105
|
+
npm version patch # 1.9.29 → 1.9.30
|
|
106
|
+
npm version minor # 1.9.29 → 1.10.0
|
|
107
|
+
npm version major # 1.9.29 → 2.0.0
|
|
108
|
+
|
|
109
|
+
# Or manually edit package.json version field
|
|
110
|
+
|
|
111
|
+
# Build and publish
|
|
112
|
+
npm run build
|
|
96
113
|
npm publish
|
|
97
114
|
```
|
|
98
115
|
|
|
116
|
+
The package is published as **public** and can be installed by anyone:
|
|
117
|
+
```bash
|
|
118
|
+
npm install @schandlergarcia/sf-web-components
|
|
119
|
+
```
|
|
120
|
+
|
|
99
121
|
|
|
100
122
|
## 🤖 AI Agent Skills
|
|
101
123
|
|
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.
|
|
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
|
],
|
|
@@ -34,7 +35,6 @@
|
|
|
34
35
|
"build": "vite build && cp -r src/styles dist/",
|
|
35
36
|
"build:types": "tsc --emitDeclarationOnly",
|
|
36
37
|
"prepublishOnly": "npm run build",
|
|
37
|
-
"postinstall": "node scripts/postinstall.mjs",
|
|
38
38
|
"reset:command-center": "bash scripts/reset-command-center.sh",
|
|
39
39
|
"validate:dashboard": "bash scripts/validate-dashboard.sh",
|
|
40
40
|
"graphql:schema": "node scripts/get-graphql-schema.mjs"
|