@schandlergarcia/sf-web-components 1.9.64 → 1.9.65

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,15 +5,7 @@ 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.64] - 2026-04-01
9
-
10
- ### Added
11
- - **New phase-based build system** - Self-contained step-by-step build instructions
12
- - `.a4drules/phases/phase-1-layout.md` - Layout setup with code template
13
- - `.a4drules/phases/phase-2-components.md` - Component implementation with exact imports
14
- - `.a4drules/phases/phase-3-live-data.md` - GraphQL integration
15
- - `.a4drules/phases/phase-4-agent.md` - Eva ChatBar implementation
16
- - These phase files replace the scattered instructions in multiple skill/feature files
8
+ ## [1.9.65] - 2026-04-01
17
9
 
18
10
  ### Fixed
19
11
  - **6 data bugs in engine-sample-data.js**:
@@ -27,20 +19,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
27
19
  ### Updated
28
20
  - **PRD (engine-command-center-prd.md)**:
29
21
  - Fixed "Sarah Chen" → "Priya Patel" in section 8c escalation example
30
- - Rewrote section 13 build prompts to reference new phase files
22
+ - Updated section 13 build prompts
31
23
  - **Simplified .a4drules documentation** - Removed redundancy and contradictions:
32
- - `features/engine-dashboard-rule.md` - Reduced from 310 to ~65 lines (non-negotiable constraints + phase routing)
24
+ - `features/engine-dashboard-rule.md` - Reduced from 310 to ~65 lines (non-negotiable constraints)
33
25
  - `features/command-center-dashboard-rule.md` - Reduced from ~100 to ~30 lines (10 core constraints)
34
26
  - `features/pre-code-checklist.md` - Reduced from 216 to ~25 lines (removed auto-load)
35
- - `features/phase2-data-pattern.md` - Reduced from 167 to ~20 lines (redirects to phase file)
27
+ - `features/phase2-data-pattern.md` - Reduced from 167 to ~20 lines
36
28
  - `skills/command-center-builder/SKILL.md` - Fixed map layout contradiction, removed validator
37
29
  - `skills/command-center-builder/page-layout.md` - Fixed map layout contradiction
38
30
  - `skills/command-center-builder/completion-checklist.md` - Replaced validator "MUST run" with "DO NOT run"
39
- - `skills/command-center-builder/improved-build-process.md` - Reduced from 341 to ~30 lines (redirects to phases)
31
+ - `skills/command-center-builder/improved-build-process.md` - Reduced from 341 to ~30 lines
40
32
  - `skills/command-center-project/SKILL.md` - Fixed file path contradiction (src/components/pages/ → src/pages/)
41
33
  - `skills/command-center-guide/SKILL.md` - Reduced from 270 to ~45 lines (simplified routing guide)
42
34
 
43
- **Context:** The phase-based system provides self-contained, copy-paste ready build instructions that eliminate the confusion caused by scattered, contradictory guidance across multiple files. All documentation now points to the phase files as the source of truth.
35
+ **Context:** Streamlined documentation to eliminate confusion caused by scattered, contradictory guidance across multiple files.
36
+
37
+ ## [1.9.64] - 2026-04-01
38
+
39
+ ### Updated
40
+ - **Documentation improvements** - Synced latest changes from react-cursor-1 including data bug fixes and simplified .a4drules structure
44
41
 
45
42
  ## [1.9.63] - 2026-04-01
46
43
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schandlergarcia/sf-web-components",
3
- "version": "1.9.64",
3
+ "version": "1.9.65",
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",
@@ -1,187 +0,0 @@
1
- ---
2
- name: engine-phase-1-layout
3
- description: >-
4
- Phase 1 of the Engine Travel Command Center build. Creates the complete layout
5
- skeleton with header, hero map, glass overlays, flight strip, and placeholder
6
- data panels. Use this when the build prompt says "Phase 1" or "scaffold".
7
- ---
8
-
9
- # Phase 1: Layout & Structure
10
-
11
- **Source of truth:** `engine-command-center-prd.md` (sections 3–6)
12
-
13
- **Goal:** Build the complete layout skeleton in one file. The hero map, glass KPI overlays, and flight status strip are real — only the 4 data panels below are placeholders.
14
-
15
- ## File Setup
16
-
17
- Create `src/pages/EngineDashboard.tsx` (.tsx, NOT .jsx).
18
-
19
- ## Code Template
20
-
21
- Copy this template, then fill in the `{/* TODO */}` sections using the PRD:
22
-
23
- ```tsx
24
- import { GeoMap, BaseCard } from "@/components/library";
25
- import { useThemeMode } from "@/components/library/theme/AppThemeProvider";
26
- import {
27
- GlobeAltIcon,
28
- SunIcon,
29
- MoonIcon,
30
- BellIcon,
31
- UsersIcon,
32
- BanknotesIcon,
33
- ShieldCheckIcon,
34
- SparklesIcon,
35
- } from "@heroicons/react/24/outline";
36
-
37
- export default function EngineDashboard() {
38
- const { mode, toggle } = useThemeMode();
39
-
40
- return (
41
- <div className="flex flex-col bg-slate-50 dark:bg-slate-950">
42
- {/* ── HEADER BAR ─────────────────────────────────────────── */}
43
- <header className="sticky top-0 z-50 flex h-12 items-center justify-between border-b border-slate-800 bg-slate-900 dark:bg-slate-950 px-4">
44
- {/* Left: logo + title */}
45
- <div className="flex items-center gap-2">
46
- <div className="flex h-7 w-7 items-center justify-center rounded-md bg-brand-600">
47
- <GlobeAltIcon className="h-4 w-4 text-slate-50" />
48
- </div>
49
- <span className="text-sm font-bold tracking-wider text-slate-50">ENGINE</span>
50
- <span className="mx-2 h-4 w-px bg-slate-700" />
51
- <span className="text-sm font-medium text-slate-300">Travel Command Center</span>
52
- </div>
53
- {/* Right: actions */}
54
- <div className="flex items-center gap-3">
55
- {/* ChatBar goes here in Phase 4 */}
56
- <button className="relative text-slate-400 hover:text-slate-200">
57
- <BellIcon className="h-5 w-5" />
58
- <span className="absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full bg-rose-500 text-[10px] font-bold text-slate-50">3</span>
59
- </button>
60
- <button onClick={toggle} className="text-slate-400 hover:text-slate-200">
61
- {mode === "dark" ? <SunIcon className="h-5 w-5" /> : <MoonIcon className="h-5 w-5" />}
62
- </button>
63
- </div>
64
- </header>
65
-
66
- {/* ── HERO MAP ───────────────────────────────────────────── */}
67
- <div className="relative h-[520px]">
68
- <GeoMap
69
- width={960}
70
- height={520}
71
- theme={mode === "dark" ? "dark" : "light"}
72
- className="h-full w-full"
73
- />
74
-
75
- {/* Glass KPI overlays — 4 pills, absolute top-left */}
76
- <div className="absolute left-3 top-3 flex flex-wrap gap-2">
77
- {[
78
- { icon: UsersIcon, label: "Active Travelers", value: "8" },
79
- { icon: BanknotesIcon, label: "Spend MTD", value: "$128.4K" },
80
- { icon: ShieldCheckIcon, label: "Compliance", value: "75%" },
81
- { icon: SparklesIcon, label: "Eva Resolved", value: "6 resolved" },
82
- ].map((kpi) => (
83
- <div
84
- key={kpi.label}
85
- className="flex items-center gap-2 rounded-lg border border-white/10 bg-black/40 px-3 py-1.5 backdrop-blur-md"
86
- >
87
- <kpi.icon className="h-4 w-4 text-brand-400" />
88
- <div>
89
- <div className="text-[10px] uppercase tracking-wider text-slate-300">{kpi.label}</div>
90
- <div className="text-sm font-semibold text-slate-50">{kpi.value}</div>
91
- </div>
92
- </div>
93
- ))}
94
- </div>
95
-
96
- {/* Flight status strip — absolute bottom */}
97
- <div className="absolute bottom-3 left-3 right-3 flex gap-2 overflow-x-auto">
98
- {[
99
- { flight: "BA 286", route: "SFO → LHR", status: "In Air" },
100
- { flight: "NH 109", route: "JFK → NRT", status: "In Air" },
101
- { flight: "LH 431", route: "ORD → BER", status: "Delayed" },
102
- { flight: "SQ 37", route: "LAX → SIN", status: "Boarding" },
103
- ].map((f) => (
104
- <div
105
- key={f.flight}
106
- className="flex shrink-0 items-center gap-2 rounded-lg border border-white/10 bg-black/40 px-3 py-1.5 backdrop-blur-md"
107
- >
108
- <span className="text-sm font-medium text-slate-50">{f.flight}</span>
109
- <span className="text-xs text-slate-400">{f.route}</span>
110
- <span
111
- className={`rounded-full px-2 py-0.5 text-[10px] font-semibold ${
112
- f.status === "In Air" ? "bg-green-500/20 text-green-400" :
113
- f.status === "Delayed" ? "bg-amber-500/20 text-amber-400" :
114
- f.status === "Boarding" ? "bg-sky-500/20 text-sky-400" :
115
- "bg-slate-500/20 text-slate-400"
116
- }`}
117
- >
118
- {f.status}
119
- </span>
120
- </div>
121
- ))}
122
- </div>
123
- </div>
124
-
125
- {/* ── DATA PANELS (placeholders) ─────────────────────────── */}
126
- <div className="px-4 py-5">
127
- <div className="space-y-6">
128
- {/* Row 1: Disruptions (1/3) + Active Travelers (2/3) */}
129
- <div className="grid grid-cols-1 items-start gap-4 lg:grid-cols-3">
130
- <BaseCard>
131
- <div className="flex h-48 items-center justify-center text-slate-400">
132
- Disruptions Panel
133
- </div>
134
- </BaseCard>
135
- <div className="lg:col-span-2">
136
- <BaseCard>
137
- <div className="flex h-48 items-center justify-center text-slate-400">
138
- Active Travelers Panel
139
- </div>
140
- </BaseCard>
141
- </div>
142
- </div>
143
-
144
- {/* Row 2: Escalations (1/2) + Monthly Spend Chart (1/2) */}
145
- <div className="grid grid-cols-1 items-start gap-4 lg:grid-cols-2">
146
- <BaseCard>
147
- <div className="flex h-48 items-center justify-center text-slate-400">
148
- Escalations Panel
149
- </div>
150
- </BaseCard>
151
- <BaseCard>
152
- <div className="flex h-48 items-center justify-center text-slate-400">
153
- Travel Spend Panel
154
- </div>
155
- </BaseCard>
156
- </div>
157
- </div>
158
- </div>
159
- </div>
160
- );
161
- }
162
- ```
163
-
164
- ## Brand Tokens
165
-
166
- Update `src/styles/global.css` — replace the `--color-brand-*` palette inside the `@theme inline` block with the Engine teal palette from PRD section 3. Also add `--color-engine-savings: #16A34A`.
167
-
168
- ## Wiring (all 3 required)
169
-
170
- 1. **CommandCenter.tsx** — import `EngineDashboard` from `"../../pages/EngineDashboard"` and render it
171
- 2. **Home.tsx** — import `CommandCenter` and render it
172
- 3. **routes.tsx** — set `Home` as the index route, move `Search` to `/search`
173
-
174
- ## Constraints (5 only)
175
-
176
- 1. File MUST be `.tsx` in `src/pages/`
177
- 2. Import ONLY from `@/components/library` and `@heroicons/react`
178
- 3. Colors: slate scale only — NO `text-white`, `text-black`, `bg-black` (exception: `bg-black/40` with opacity is OK for glass)
179
- 4. Full-page scroll — NO `h-screen` on outer container
180
- 5. DO NOT run `npm run dev` or `npm run validate:dashboard` — phase is complete after wiring
181
-
182
- ## Phase 1 does NOT include
183
-
184
- - Sample data (Phase 2)
185
- - ChatBar / Eva (Phase 4)
186
- - Salesforce signals like "Powered by..." (Phase 4)
187
- - Any `npm install` commands
@@ -1,176 +0,0 @@
1
- ---
2
- name: engine-phase-2-components
3
- description: >-
4
- Phase 2 of the Engine Travel Command Center build. Replaces placeholder panels
5
- with library components wired to pre-existing sample data. Adds map data.
6
- Use this when the build prompt says "Phase 2" or "components".
7
- ---
8
-
9
- # Phase 2: Components & Sample Data
10
-
11
- **Source of truth:** `engine-command-center-prd.md` (sections 7–8)
12
-
13
- **Goal:** Replace the 4 placeholder data panels with real library components. Add map data (markers, arcs, overlays). The sample data file already exists — just import from it.
14
-
15
- ## Critical: Data file already exists
16
-
17
- `src/data/engine-sample-data.js` is pre-built with ~370 lines of sample data. **DO NOT create a new data file.** Just import from the existing one.
18
-
19
- ## Imports to add to EngineDashboard.tsx
20
-
21
- ```tsx
22
- import {
23
- GeoMap,
24
- BaseCard,
25
- ActivityCard,
26
- ChartCard,
27
- D3Chart,
28
- D3ChartTemplates,
29
- Avatar,
30
- UIChip,
31
- } from "@/components/library";
32
- import useDataSource from "@/components/library/data/useDataSource";
33
- import {
34
- MAP_MARKERS,
35
- MAP_ARCS,
36
- MAP_OVERLAYS,
37
- FLIGHT_STATUS_LIST,
38
- TRAVELER_CARDS,
39
- DISRUPTION_CARDS,
40
- ESCALATION_CARDS,
41
- MONTHLY_SPEND,
42
- METRICS,
43
- } from "@/data/engine-sample-data";
44
- ```
45
-
46
- ## Changes to make
47
-
48
- ### 1. Hero Map — add data props
49
-
50
- ```tsx
51
- <GeoMap
52
- width={960}
53
- height={520}
54
- theme={mode === "dark" ? "dark" : "light"}
55
- markers={useDataSource({ sample: MAP_MARKERS, live: [] })}
56
- arcs={useDataSource({ sample: MAP_ARCS, live: [] })}
57
- overlays={useDataSource({ sample: MAP_OVERLAYS, live: [] })}
58
- zoomable
59
- className="h-full w-full"
60
- />
61
- ```
62
-
63
- ### 2. Glass KPI overlays — use METRICS
64
-
65
- Replace hardcoded KPI values with `METRICS.activeTravelers`, `METRICS.spendMTD`, `METRICS.complianceRate`, `METRICS.evaResolved`.
66
-
67
- Use `fmtK()` helper for spend formatting:
68
-
69
- ```tsx
70
- function fmtK(n: number) {
71
- if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
72
- if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
73
- return n.toLocaleString();
74
- }
75
- ```
76
-
77
- ### 3. Flight status strip — use FLIGHT_STATUS_LIST
78
-
79
- Replace hardcoded flights with `FLIGHT_STATUS_LIST.map(...)`.
80
-
81
- ### 4. Disruptions Panel (1/3 width) — custom inline component
82
-
83
- Replace the placeholder BaseCard. Build a custom panel inside a BaseCard showing only disrupted flights. Each disruption card shows severity dot, flight number, route, traveler, reason, and Eva action.
84
-
85
- ```tsx
86
- <BaseCard>
87
- <div className="space-y-3 p-1">
88
- <h3 className="text-sm font-semibold text-slate-900 dark:text-slate-50">Disruptions</h3>
89
- {useDataSource({ sample: DISRUPTION_CARDS, live: [] }).map((d) => (
90
- <div key={d.id} className="rounded-lg border border-slate-200 p-3 dark:border-slate-800">
91
- <div className="flex items-center gap-2">
92
- <span className={`h-2 w-2 rounded-full ${d.severity === "grounded" ? "bg-rose-500" : "bg-amber-500"}`} />
93
- <span className="text-sm font-medium text-slate-900 dark:text-slate-50">{d.flight}</span>
94
- <span className={`text-xs ${d.severity === "grounded" ? "text-rose-500" : "text-amber-500"}`}>
95
- {d.severity} · {d.delayMin}min
96
- </span>
97
- </div>
98
- <div className="mt-1 text-xs text-slate-500 dark:text-slate-400">{d.route} · {d.traveler}</div>
99
- <div className="mt-1 text-xs text-slate-500 dark:text-slate-400">{d.reason}</div>
100
- <div className="mt-2 flex items-center gap-1 text-xs text-brand-600 dark:text-brand-400">
101
- <SparklesIcon className="h-3 w-3" />
102
- <span>{d.evaAction}</span>
103
- </div>
104
- </div>
105
- ))}
106
- </div>
107
- </BaseCard>
108
- ```
109
-
110
- ### 5. Active Travelers (2/3 width) — expandable cards
111
-
112
- Replace the placeholder. Use BaseCard with `maxBodyHeight={420}` for internal scroll. Build expandable traveler rows using `useState` for the expanded ID.
113
-
114
- Each row: Avatar (initials) + name + department + origin → destination + UIChip for policy status. Click to expand shows 4-col detail grid (Flight, Hotel, Return, Destination).
115
-
116
- ### 6. Escalations (1/2 width) — ActivityCard in BaseCard
117
-
118
- **Copy this exactly from the PRD:**
119
-
120
- ```tsx
121
- <BaseCard>
122
- <ActivityCard
123
- title="Escalations"
124
- actions={useDataSource({ sample: ESCALATION_CARDS, live: [] })}
125
- />
126
- </BaseCard>
127
- ```
128
-
129
- ActivityCard MUST be wrapped in BaseCard for visible card styling.
130
-
131
- ### 7. Monthly Spend Trend (1/2 width) — ChartCard + D3Chart
132
-
133
- **Copy this exactly from the PRD:**
134
-
135
- ```tsx
136
- const spendChartData = useDataSource({
137
- sample: MONTHLY_SPEND.map(m => ({ x: m.month, spend: m.amount })),
138
- live: [],
139
- });
140
-
141
- <ChartCard
142
- title="Travel Spend"
143
- subtitle="Monthly trend (6 months)"
144
- chart={
145
- <D3Chart
146
- data={spendChartData}
147
- renderChart={D3ChartTemplates.groupedBarChart}
148
- options={{
149
- xKey: "x",
150
- groups: ["spend"],
151
- colors: ["#5BC8C8"],
152
- barRadius: 6,
153
- margin: { top: 20, right: 20, bottom: 40, left: 60 },
154
- showGrid: true,
155
- }}
156
- responsive
157
- height={320}
158
- />
159
- }
160
- />
161
- ```
162
-
163
- ## Constraints (5 only)
164
-
165
- 1. **DO NOT create a new data file** — import from the existing `src/data/engine-sample-data.js`
166
- 2. Import ONLY from `@/components/library` and `@heroicons/react` — no shadcn, no Lucide, no Recharts
167
- 3. Wrap `ActivityCard` in `BaseCard` (ActivityCard has no card styling by default)
168
- 4. Use `useDataSource({ sample: X, live: [] })` for all data — enables Phase 3 swap
169
- 5. DO NOT run `npm run dev` or `npm run validate:dashboard`
170
-
171
- ## Phase 2 does NOT include
172
-
173
- - Live Salesforce data (Phase 3)
174
- - ChatBar / Eva (Phase 4)
175
- - Salesforce signals (Phase 4)
176
- - Any `npm install` commands
@@ -1,85 +0,0 @@
1
- ---
2
- name: engine-phase-3-live-data
3
- description: >-
4
- Phase 3 of the Engine Travel Command Center build. Connects the dashboard to
5
- live Salesforce Data Cloud via GraphQL. UI stays identical to Phase 2.
6
- Use this when the build prompt says "Phase 3" or "real data".
7
- ---
8
-
9
- # Phase 3: Real Data Integration
10
-
11
- **Source of truth:** `engine-command-center-prd.md` (section 13)
12
-
13
- **Goal:** Connect the dashboard to live Salesforce data via GraphQL. The UI stays identical to Phase 2 — only the data source changes.
14
-
15
- ## Approach
16
-
17
- The sample data file (`src/data/engine-sample-data.js`) already uses real Salesforce field names (Trip__c, Flight__c, Contact, etc.). Read the file header to understand the schema.
18
-
19
- ## Custom objects
20
-
21
- | Object | Purpose |
22
- |--------|---------|
23
- | Contact | Travelers (with Home_Airport__c, Travel_Policy_Tier__c, etc.) |
24
- | Trip__c | Origin, destination, dates, cost, policy status |
25
- | Flight__c | Flight number, airports, status, delay, traveler lookup |
26
- | Booking__c | Upcoming reservations |
27
- | Disruption__c | Delays, cancellations, severity |
28
- | Rebooking_Action__c | Eva activity log |
29
- | Travel_Policy__c | Policy rules and status |
30
-
31
- ## Implementation steps
32
-
33
- ### Step 1: Read the sample data file
34
-
35
- Read `src/data/engine-sample-data.js` to understand which Salesforce fields are needed for each object.
36
-
37
- ### Step 2: Use GraphQL skills to create queries and hooks
38
-
39
- For each object, use the Salesforce GraphQL skills:
40
-
41
- 1. Use the `exploring-webapp-graphql-schema` skill to look up the object in `schema.graphql`
42
- 2. Use the `generating-webapp-graphql-read-query` skill to create a typed query
43
- 3. Use the `using-webapp-graphql` skill to create a data hook (e.g., `useTravelers`, `useFlights`)
44
-
45
- Each hook returns `{ data, loading, error }`.
46
-
47
- ### Step 3: Update useDataSource calls
48
-
49
- Change each `useDataSource` call to include live data:
50
-
51
- ```tsx
52
- // Phase 2 (sample only)
53
- const travelers = useDataSource({ sample: TRAVELER_CARDS, live: [] });
54
-
55
- // Phase 3 (live with sample fallback)
56
- const { data: liveTravelers, loading, error } = useTravelers();
57
- const travelers = useDataSource({
58
- sample: TRAVELER_CARDS,
59
- live: liveTravelers ?? [],
60
- });
61
- ```
62
-
63
- The `useDataSource` hook automatically uses `live` when available, falling back to `sample` on error.
64
-
65
- ### Step 4: Add loading and error states
66
-
67
- Add `loading` and `error` handling to each section. Library card components accept `loading` and `error` props.
68
-
69
- ## Data strategy
70
-
71
- The app uses a sample data cache (`ENABLE_SAMPLE_DATA_CACHE = true` in `src/lib/dataStrategy.ts`) for instant loading and offline capability. This is production-appropriate — build all GraphQL queries and hooks as normal.
72
-
73
- ## Constraints (5 only)
74
-
75
- 1. **DO NOT modify UI components** — only change data sources
76
- 2. **DO NOT add DataModeToggle** — live data only (sample is fallback for errors)
77
- 3. Use exact Salesforce field names from the sample data file
78
- 4. Schema file (`schema.graphql`) is pre-built in the repo — no generation needed
79
- 5. DO NOT run `npm run dev` or `npm run validate:dashboard`
80
-
81
- ## Phase 3 does NOT include
82
-
83
- - ChatBar / Eva (Phase 4)
84
- - Salesforce signals (Phase 4)
85
- - UI changes of any kind
@@ -1,73 +0,0 @@
1
- ---
2
- name: engine-phase-4-agent
3
- description: >-
4
- Phase 4 of the Engine Travel Command Center build. Adds Eva ChatBar to the
5
- header and Salesforce signals throughout the dashboard.
6
- Use this when the build prompt says "Phase 4" or "agent".
7
- ---
8
-
9
- # Phase 4: Agentforce Integration
10
-
11
- **Source of truth:** `engine-command-center-prd.md` (sections 9–10)
12
-
13
- **Goal:** Add Eva as a ChatBar in the header. Add subtle Salesforce signals throughout the dashboard.
14
-
15
- ## Eva — ChatBar in header
16
-
17
- Eva surfaces as a `ChatBar` in the header. Not a FAB. Not a sliding panel. Not a `ChatPanel` in the grid.
18
-
19
- ### Code
20
-
21
- Define the handler and suggestions at **module scope** (outside the component):
22
-
23
- ```tsx
24
- import { ChatBar } from "@/components/library";
25
-
26
- const CHAT_SUGGESTIONS = [
27
- "Who's traveling internationally right now?",
28
- "Show bookings pending approval",
29
- "What has Eva resolved today?",
30
- "Travelers returning this week",
31
- ];
32
-
33
- function handleChat(message: string) {
34
- // Agentforce integration or mock response
35
- return {
36
- text: `Eva is looking into: "${message}"`,
37
- components: [],
38
- };
39
- }
40
- ```
41
-
42
- Add the ChatBar to the header (right side, before the notification bell):
43
-
44
- ```tsx
45
- <ChatBar
46
- title="Eva"
47
- placeholder="Ask about travelers, bookings, policy, spend…"
48
- suggestions={CHAT_SUGGESTIONS}
49
- onSend={handleChat}
50
- />
51
- ```
52
-
53
- ### Agent responses
54
-
55
- Return structured `components` arrays for data (MetricCard, DataTable, StatusCard) — never markdown tables in text content.
56
-
57
- ## Salesforce Signals
58
-
59
- Subtle, contextual indicators — like "Sent from iPhone", not promotional banners.
60
-
61
- | Signal | Location | Implementation |
62
- |--------|----------|----------------|
63
- | "View in Salesforce" | Traveler expanded view, booking rows | Micro-link, muted text (`text-slate-400`) |
64
- | "Salesforce updated" | After rebook/approve actions | `toast()` with success tone |
65
- | "Powered by Agentforce" | ChatBar subtitle area | Small badge/chip |
66
-
67
- ## Constraints (5 only)
68
-
69
- 1. ChatBar goes in the **header**, not as a floating panel or grid element
70
- 2. `CHAT_SUGGESTIONS` and `handleChat` defined at **module scope** (outside component body)
71
- 3. Salesforce signals are subtle micro-text — not banners or badges
72
- 4. Import ONLY from `@/components/library` and `@heroicons/react`
73
- 5. DO NOT run `npm run dev` or `npm run validate:dashboard`