@schandlergarcia/sf-web-components 2.3.9 → 2.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,19 @@ 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
+ ## [2.3.11] - 2026-04-13
9
+
10
+ ### Added
11
+ - **Eva agent ChatBar on Partner Hub** — Integrated the `ChatBar` component with the `useEvaAgent` hook above the booking stats grid. Connects to the Agentforce Agent REST API on mount, provides contextual suggestions ("Summarize my penalties", "Which property is growing fastest?", "Show overdue invoices"), and opens as a command-palette overlay (⌘K).
12
+
13
+ ## [2.3.10] - 2026-04-13
14
+
15
+ ### Changed
16
+ - **Metric numbers now big in both themes** — `--dash-metric-size` is `3.25rem` in both neutral and Engine (no longer starts small). Subtitles bumped from `text-xs` to `text-sm` for readability.
17
+ - **Badges stay fixed size** — removed per-theme badge sizing; instead Engine uses brighter semantic colors (`--dash-success: #34d399`, `--dash-info: #67e8f9`) so status chips pop more.
18
+ - **Billing & Contract moved above Recent Activity** — section reorder puts revenue charts, invoices, and contract details higher in the page flow.
19
+ - **Two charts side by side** — added "Total revenue growth" bar chart next to the existing "Revenue by property" multi-line chart. Bar chart computes monthly totals from live property data and uses the theme accent color, showing clear upward growth.
20
+
8
21
  ## [2.3.9] - 2026-04-13
9
22
 
10
23
  ### Changed
@@ -1,9 +1,10 @@
1
- import { ListCard, ActivityCard, D3Chart, Dropdown, Button, Modal, CardSkeleton } from "@/components/library";
1
+ import { ListCard, ActivityCard, D3Chart, Dropdown, Button, Modal, CardSkeleton, ChatBar } from "@/components/library";
2
2
  import useDataSource from "@/components/library/data/useDataSource";
3
3
  import { useThemeMode } from "@/components/library/theme/AppThemeProvider";
4
4
  import { toast } from "sonner";
5
5
  import React from "react";
6
6
  import { usePartnerDashboardData } from "@/hooks/usePartnerDashboardData";
7
+ import useEvaAgent from "@/hooks/useEvaAgent";
7
8
  import { ENABLE_SAMPLE_DATA_CACHE } from "@/lib/dataStrategy";
8
9
  import {
9
10
  PENALTY_TABLE_ITEMS,
@@ -32,6 +33,7 @@ import {
32
33
  } from "@heroicons/react/24/outline";
33
34
  import * as d3 from "d3";
34
35
  import engineLogo from "@/assets/images/engine_logo.png";
36
+ import Data360Widget from "@/components/Data360Widget";
35
37
 
36
38
  /**
37
39
  * Partner Hub Dashboard
@@ -54,6 +56,9 @@ export default function PartnerHubDashboard() {
54
56
  const [isDisputesModalOpen, setIsDisputesModalOpen] = React.useState(false);
55
57
  const [isInvoicesModalOpen, setIsInvoicesModalOpen] = React.useState(false);
56
58
 
59
+ const eva = useEvaAgent();
60
+ React.useEffect(() => { eva.connect(); }, []);
61
+
57
62
  // Simulated logged-in partner (in real app, this comes from auth context)
58
63
  const currentPartner = {
59
64
  name: "Summit Hotels & Resorts",
@@ -662,6 +667,63 @@ export default function PartnerHubDashboard() {
662
667
  .style("fill", "currentColor");
663
668
  }, []);
664
669
 
670
+ const monthlyTotalRevenue = React.useMemo(() => {
671
+ if (!revenueTrendByProperty?.months || !revenueTrendByProperty?.properties) return null;
672
+ return revenueTrendByProperty.months.map((month: string, i: number) => ({
673
+ month,
674
+ total: revenueTrendByProperty.properties.reduce((sum: number, p: any) => sum + p.values[i], 0),
675
+ }));
676
+ }, [revenueTrendByProperty]);
677
+
678
+ const renderTotalRevenueGrowth = React.useCallback((svgEl: any, data: any, { width, height }: any) => {
679
+ if (!data || !data.length) return;
680
+ const margin = { top: 20, right: 20, bottom: 40, left: 70 };
681
+ const innerWidth = width - margin.left - margin.right;
682
+ const innerHeight = height - margin.top - margin.bottom;
683
+ if (innerWidth <= 0 || innerHeight <= 0) return;
684
+
685
+ const svg = d3.select(svgEl);
686
+ svg.selectAll("*").remove();
687
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
688
+
689
+ const x = d3.scaleBand().domain(data.map((d: any) => d.month)).range([0, innerWidth]).padding(0.35);
690
+ const maxVal = d3.max(data, (d: any) => d.total) || 0;
691
+ const y = d3.scaleLinear().domain([0, maxVal * 1.15]).range([innerHeight, 0]).nice();
692
+
693
+ g.append("g").attr("class", "grid")
694
+ .call(d3.axisLeft(y).ticks(5).tickSize(-innerWidth).tickFormat(() => ""))
695
+ .selectAll("line").style("stroke", "currentColor").style("stroke-opacity", "0.08");
696
+ g.select(".grid .domain").remove();
697
+
698
+ const accentColor = getComputedStyle(document.documentElement).getPropertyValue('--dash-accent').trim() || '#2563eb';
699
+
700
+ g.selectAll(".bar").data(data).join("rect")
701
+ .attr("x", (d: any) => x(d.month) ?? 0)
702
+ .attr("y", (d: any) => y(d.total))
703
+ .attr("width", x.bandwidth())
704
+ .attr("height", (d: any) => innerHeight - y(d.total))
705
+ .attr("rx", 4)
706
+ .attr("fill", accentColor)
707
+ .attr("fill-opacity", 0.85);
708
+
709
+ g.selectAll(".label").data(data).join("text")
710
+ .attr("x", (d: any) => (x(d.month) ?? 0) + x.bandwidth() / 2)
711
+ .attr("y", (d: any) => y(d.total) - 8)
712
+ .attr("text-anchor", "middle")
713
+ .style("font-size", "11px")
714
+ .style("font-weight", "600")
715
+ .style("fill", "currentColor")
716
+ .text((d: any) => `$${(d.total / 1000).toFixed(0)}K`);
717
+
718
+ g.append("g").attr("transform", `translate(0,${innerHeight})`)
719
+ .call(d3.axisBottom(x)).selectAll("text")
720
+ .style("font-size", "11px").style("fill", "currentColor").attr("dy", "1.2em");
721
+ g.select(".domain").style("stroke-opacity", "0.2");
722
+
723
+ g.append("g").call(d3.axisLeft(y).ticks(5).tickFormat(d3.format("$~s")))
724
+ .selectAll("text").style("font-size", "11px").style("fill", "currentColor");
725
+ }, []);
726
+
665
727
  return (
666
728
  <div className="heroui-scope min-h-screen bg-[var(--color-dash-surface)] dark:bg-[var(--color-dash-text)] transition-colors duration-300">
667
729
  {/* Header - Refined Engine Brand */}
@@ -777,6 +839,31 @@ export default function PartnerHubDashboard() {
777
839
 
778
840
  {/* Main Content */}
779
841
  <div className="max-w-[1600px] mx-auto px-8 -mt-12 space-y-10">
842
+ {/* Eva Agent ChatBar */}
843
+ <div className="relative z-10">
844
+ <ChatBar
845
+ title="Eva — Partner Assistant"
846
+ placeholder="Ask Eva anything about your properties, invoices, or penalties…"
847
+ suggestions={[
848
+ "Summarize my penalties",
849
+ "Which property is growing fastest?",
850
+ "Show overdue invoices",
851
+ ]}
852
+ onSend={async (text) => {
853
+ if (eva.isReady) {
854
+ await eva.sendMessage(text);
855
+ } else {
856
+ return "Eva is still connecting — please try again in a moment.";
857
+ }
858
+ }}
859
+ initialMessages={eva.messages.map((m) => ({
860
+ id: m.id,
861
+ role: m.role === "agent" ? "assistant" : "user",
862
+ content: m.text,
863
+ }))}
864
+ />
865
+ </div>
866
+
780
867
  {/* Quick Stats - Uniform metrics grid */}
781
868
  <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-5 animate-slide-up relative z-10">
782
869
  {/* Revenue */}
@@ -801,13 +888,13 @@ export default function PartnerHubDashboard() {
801
888
  <div className="bg-[var(--color-dash-success)]/10 rounded-lg p-2">
802
889
  <BanknotesIcon className="h-5 w-5 text-[var(--color-dash-success)]" />
803
890
  </div>
804
- <span className="inline-flex items-center rounded-full font-bold bg-[var(--color-dash-success)]/10 text-[var(--color-dash-success)]" style={{ fontSize: 'var(--dash-pct-size)', padding: 'var(--dash-pct-py) var(--dash-pct-px)' }}>
891
+ <span className="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-bold bg-[var(--color-dash-success)]/10 text-[var(--color-dash-success)]">
805
892
  +45%
806
893
  </span>
807
894
  </div>
808
- <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-xs font-semibold mb-2 uppercase tracking-wider">Total Revenue</p>
895
+ <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-sm font-semibold mb-2 uppercase tracking-wider">Total Revenue</p>
809
896
  <p className="font-black text-[var(--color-dash-text)] dark:text-white mb-1 leading-tight" style={{ fontSize: 'var(--dash-metric-size)' }}>${(myRevenue / 1000).toFixed(0)}K</p>
810
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">earned with Engine</p>
897
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">earned with Engine</p>
811
898
  </>
812
899
  )}
813
900
  </div>
@@ -827,13 +914,13 @@ export default function PartnerHubDashboard() {
827
914
  <div className="bg-[var(--color-dash-warning)]/10 rounded-lg p-2">
828
915
  <ExclamationTriangleIcon className="h-5 w-5 text-[var(--color-dash-warning)]" />
829
916
  </div>
830
- <span className="inline-flex items-center rounded-full font-bold bg-[var(--color-dash-warning)] text-white" style={{ fontSize: 'var(--dash-pct-size)', padding: 'var(--dash-pct-py) var(--dash-pct-px)' }}>
917
+ <span className="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-bold bg-[var(--color-dash-warning)] text-white">
831
918
  REVIEW
832
919
  </span>
833
920
  </div>
834
- <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-xs font-semibold mb-2 uppercase tracking-wider">Things to Review</p>
921
+ <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-sm font-semibold mb-2 uppercase tracking-wider">Things to Review</p>
835
922
  <p className="font-black text-[var(--color-dash-text)] dark:text-white mb-1 leading-tight" style={{ fontSize: 'var(--dash-metric-size)' }}>{myOpenDisputes}</p>
836
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">items need attention</p>
923
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">items need attention</p>
837
924
  </>
838
925
  )}
839
926
  </div>
@@ -854,9 +941,9 @@ export default function PartnerHubDashboard() {
854
941
  <BuildingOfficeIcon className="h-5 w-5 text-[var(--color-dash-accent)]" />
855
942
  </div>
856
943
  </div>
857
- <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-xs font-semibold mb-2 uppercase tracking-wider">Properties</p>
944
+ <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-sm font-semibold mb-2 uppercase tracking-wider">Properties</p>
858
945
  <p className="font-black text-[var(--color-dash-text)] dark:text-white mb-1 leading-tight" style={{ fontSize: 'var(--dash-metric-size)' }}>{myProperties}</p>
859
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">active locations</p>
946
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">active locations</p>
860
947
  </>
861
948
  )}
862
949
  </div>
@@ -877,9 +964,9 @@ export default function PartnerHubDashboard() {
877
964
  <ClockIcon className="h-5 w-5 text-[var(--color-dash-info)]" />
878
965
  </div>
879
966
  </div>
880
- <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-xs font-semibold mb-2 uppercase tracking-wider">Reservations</p>
967
+ <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-sm font-semibold mb-2 uppercase tracking-wider">Reservations</p>
881
968
  <p className="font-black text-[var(--color-dash-text)] dark:text-white mb-1 leading-tight" style={{ fontSize: 'var(--dash-metric-size)' }}>{myReservations}</p>
882
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">through Engine</p>
969
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">through Engine</p>
883
970
  </>
884
971
  )}
885
972
  </div>
@@ -900,15 +987,18 @@ export default function PartnerHubDashboard() {
900
987
  <ShieldCheckIcon className="h-5 w-5 text-[var(--color-dash-danger)]" />
901
988
  </div>
902
989
  </div>
903
- <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-xs font-semibold mb-2 uppercase tracking-wider">Invoices</p>
990
+ <p className="text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] text-sm font-semibold mb-2 uppercase tracking-wider">Invoices</p>
904
991
  <p className="font-black text-[var(--color-dash-text)] dark:text-white mb-1 leading-tight" style={{ fontSize: 'var(--dash-metric-size)' }}>{myPendingInvoices}</p>
905
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">ready to pay</p>
992
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">ready to pay</p>
906
993
  </>
907
994
  )}
908
995
  </div>
909
996
  </div>
910
997
  </div>
911
998
 
999
+ {/* Data 360 Widget */}
1000
+ <Data360Widget />
1001
+
912
1002
  {/* Property Leaderboard - NEW SECTION */}
913
1003
  {isLoading ? (
914
1004
  <div className="bg-gradient-to-br from-white via-[var(--color-dash-surface)] to-white dark:from-[var(--color-dash-text)] dark:via-[var(--color-dash-dark)] dark:to-[var(--color-dash-text)] rounded-2xl p-8 shadow-xl border border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
@@ -977,7 +1067,7 @@ export default function PartnerHubDashboard() {
977
1067
  <h3 className="text-xl font-bold text-[var(--color-dash-text)] dark:text-white">
978
1068
  {property.name}
979
1069
  </h3>
980
- <span className="inline-flex items-center rounded-full font-bold bg-[var(--color-dash-success)]/20 text-[var(--color-dash-success)] border border-[var(--color-dash-success)]/30" style={{ fontSize: 'var(--dash-pct-size)', padding: 'var(--dash-pct-py) var(--dash-pct-px)' }}>
1070
+ <span className="inline-flex items-center rounded-full px-3 py-1 text-xs font-bold bg-[var(--color-dash-success)]/20 text-[var(--color-dash-success)] border border-[var(--color-dash-success)]/30">
981
1071
  +{property.growth}% growth
982
1072
  </span>
983
1073
  </div>
@@ -1044,7 +1134,7 @@ export default function PartnerHubDashboard() {
1044
1134
  ATR-00001 · Summit Austin Convention Center · TechCorp Inc. booking
1045
1135
  </p>
1046
1136
  </div>
1047
- <span className="inline-flex items-center rounded-full font-bold bg-[var(--color-dash-warning)] text-white flex-shrink-0" style={{ fontSize: 'var(--dash-pct-size)', padding: 'var(--dash-pct-py) var(--dash-pct-px)' }}>
1137
+ <span className="inline-flex items-center rounded-full px-3 py-1 text-xs font-bold bg-[var(--color-dash-warning)] text-white flex-shrink-0">
1048
1138
  NEEDS REVIEW
1049
1139
  </span>
1050
1140
  </div>
@@ -1092,7 +1182,164 @@ export default function PartnerHubDashboard() {
1092
1182
  </div>
1093
1183
  )}
1094
1184
 
1095
- {/* Section - Conversational with Better Spacing */}
1185
+ {/* Section Billing & Contract Details */}
1186
+ <div className="pt-8 space-y-2">
1187
+ <h2 className="text-3xl font-bold text-[var(--color-dash-text)] dark:text-white tracking-tight">
1188
+ Billing & contract details
1189
+ </h2>
1190
+ <p className="text-lg text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1191
+ Keep track of invoices and your partnership terms
1192
+ </p>
1193
+ </div>
1194
+
1195
+ {/* Two Charts Grid */}
1196
+ {isLoading ? (
1197
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1198
+ <CardSkeleton lines={6} />
1199
+ <CardSkeleton lines={6} />
1200
+ </div>
1201
+ ) : (
1202
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1203
+ {/* Revenue Trend by Property (multi-line) */}
1204
+ <div className="bg-white dark:bg-[var(--color-dash-text)] border border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30 rounded-xl shadow-sm hover:shadow-lg transition-shadow duration-300 overflow-hidden">
1205
+ <div className="p-6 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1206
+ <h3 className="text-xl font-bold text-[var(--color-dash-text)] dark:text-white mb-1">
1207
+ Revenue by property
1208
+ </h3>
1209
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1210
+ Monthly trend across {revenueTrendByProperty.properties?.length || 4} properties
1211
+ </p>
1212
+ <div className="flex flex-wrap gap-3 mt-3">
1213
+ {revenueTrendByProperty.properties.map((prop) => (
1214
+ <div key={prop.name} className="flex items-center gap-1.5">
1215
+ <span className="inline-block h-2 w-2 rounded-full flex-shrink-0" style={{ backgroundColor: prop.color }} />
1216
+ <span className="text-xs font-medium text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">{prop.name.replace('Summit ', '')}</span>
1217
+ </div>
1218
+ ))}
1219
+ </div>
1220
+ </div>
1221
+ <div className="p-4 w-full">
1222
+ {revenueTrendByProperty?.months && revenueTrendByProperty?.properties ? (
1223
+ <div className="w-full" style={{ minHeight: '240px' }}>
1224
+ <D3Chart data={revenueTrendByProperty} renderChart={renderRevenueTrendByProperty} height={240} responsive={true} ariaLabel="Revenue trend by property" />
1225
+ </div>
1226
+ ) : (
1227
+ <div className="h-[240px] flex items-center justify-center text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">Loading chart data...</div>
1228
+ )}
1229
+ </div>
1230
+ </div>
1231
+
1232
+ {/* Total Monthly Revenue Growth (bar chart) */}
1233
+ <div className="bg-white dark:bg-[var(--color-dash-text)] border border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30 rounded-xl shadow-sm hover:shadow-lg transition-shadow duration-300 overflow-hidden">
1234
+ <div className="p-6 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1235
+ <h3 className="text-xl font-bold text-[var(--color-dash-text)] dark:text-white mb-1">
1236
+ Total revenue growth
1237
+ </h3>
1238
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1239
+ Combined monthly revenue — up 67% over 6 months
1240
+ </p>
1241
+ </div>
1242
+ <div className="p-4 w-full">
1243
+ {monthlyTotalRevenue ? (
1244
+ <div className="w-full" style={{ minHeight: '240px' }}>
1245
+ <D3Chart data={monthlyTotalRevenue} renderChart={renderTotalRevenueGrowth} height={240} responsive={true} ariaLabel="Total revenue growth" />
1246
+ </div>
1247
+ ) : (
1248
+ <div className="h-[240px] flex items-center justify-center text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">Loading chart data...</div>
1249
+ )}
1250
+ </div>
1251
+ </div>
1252
+ </div>
1253
+ )}
1254
+
1255
+ {/* Invoices & Contract */}
1256
+ {isLoading ? (
1257
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1258
+ <CardSkeleton lines={5} />
1259
+ <CardSkeleton lines={5} />
1260
+ </div>
1261
+ ) : (
1262
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1263
+ <ListCard
1264
+ title="Your invoices"
1265
+ subtitle="Recent statements"
1266
+ items={myInvoices.map((inv) => ({
1267
+ id: inv.id,
1268
+ title: inv.title,
1269
+ description: inv.description,
1270
+ status: inv.status,
1271
+ value: `$${inv.amount.toLocaleString()}`,
1272
+ timestamp: `Due ${inv.due}`,
1273
+ }))}
1274
+ maxBodyHeight={300}
1275
+ showStatus={true}
1276
+ showTimestamp={true}
1277
+ dense={false}
1278
+ divided={true}
1279
+ onItemClick={(item) => {
1280
+ toast.info(`Opening invoice ${item.title.split(' — ')[0]}`);
1281
+ }}
1282
+ emptyMessage="No invoices right now."
1283
+ loading={isLoading}
1284
+ />
1285
+
1286
+ <div className="bg-white dark:bg-[var(--color-dash-text)] border border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30 rounded-xl shadow-sm hover:shadow-lg transition-shadow duration-300 overflow-hidden">
1287
+ <div className="p-6 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1288
+ <h3 className="text-xl font-bold text-[var(--color-dash-text)] dark:text-white mb-1">
1289
+ Your Contract
1290
+ </h3>
1291
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1292
+ Partnership terms
1293
+ </p>
1294
+ </div>
1295
+ <div className="p-6 space-y-4">
1296
+ <div className="flex items-center justify-between pb-4 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1297
+ <div>
1298
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Contract ID</p>
1299
+ <p className="text-lg font-bold text-[var(--color-dash-text)] dark:text-white">CNTR-00002</p>
1300
+ </div>
1301
+ <span className="inline-flex items-center rounded-full px-3 py-1 text-xs font-medium bg-[var(--color-dash-success)]/10 text-[var(--color-dash-success)] border border-[var(--color-dash-success)]/30">
1302
+ Active
1303
+ </span>
1304
+ </div>
1305
+
1306
+ <div className="grid grid-cols-2 gap-4">
1307
+ <div>
1308
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Commission Rate</p>
1309
+ <p className="text-2xl font-bold text-[var(--color-dash-success)]">17%</p>
1310
+ </div>
1311
+ <div>
1312
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Contract Term</p>
1313
+ <p className="text-sm font-semibold text-[var(--color-dash-text)] dark:text-white">Mar 2025 - Feb 2027</p>
1314
+ </div>
1315
+ </div>
1316
+
1317
+ <div className="bg-[var(--color-dash-surface)] dark:bg-[var(--color-dash-muted)]/10 rounded-lg p-4 space-y-3">
1318
+ <div>
1319
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Attrition Method</p>
1320
+ <p className="text-sm font-semibold text-[var(--color-dash-text)] dark:text-white">Per Night (80% threshold)</p>
1321
+ </div>
1322
+ <div>
1323
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Resale Credit Policy</p>
1324
+ <p className="text-sm font-semibold text-[var(--color-dash-text)] dark:text-white">Partial Credit (50%)</p>
1325
+ </div>
1326
+ </div>
1327
+
1328
+ <div className="pt-2">
1329
+ <button
1330
+ onClick={() => toast.info("Opening full contract PDF...")}
1331
+ className="w-full inline-flex items-center justify-center gap-2 px-4 py-3 bg-[var(--color-dash-surface)] dark:bg-[var(--color-dash-muted)]/20 hover:bg-[var(--color-dash-accent)]/10 dark:hover:bg-[var(--color-dash-accent)]/10 text-[var(--color-dash-text)] dark:text-white font-semibold rounded-lg border border-[var(--color-dash-label)]/30 dark:border-[var(--color-dash-muted)]/50 hover:border-[var(--color-dash-accent)] transition-colors text-sm"
1332
+ >
1333
+ <DocumentArrowDownIcon className="h-4 w-4" />
1334
+ Download Full Contract
1335
+ </button>
1336
+ </div>
1337
+ </div>
1338
+ </div>
1339
+ </div>
1340
+ )}
1341
+
1342
+ {/* Section — Recent Activity */}
1096
1343
  <div className="pt-8 space-y-2">
1097
1344
  <h2 className="text-3xl font-bold text-[var(--color-dash-text)] dark:text-white tracking-tight">
1098
1345
  Recent activity
@@ -1102,8 +1349,6 @@ export default function PartnerHubDashboard() {
1102
1349
  </p>
1103
1350
  </div>
1104
1351
 
1105
- {/* Hero penalty section removed - now at top of page */}
1106
-
1107
1352
  {/* Action Items Grid */}
1108
1353
  {isLoading ? (
1109
1354
  <div className="grid grid-cols-1 md:grid-cols-2 gap-5">
@@ -1265,154 +1510,6 @@ export default function PartnerHubDashboard() {
1265
1510
  </div>
1266
1511
  )}
1267
1512
 
1268
- {/* Section */}
1269
- <div className="pt-8 space-y-2">
1270
- <h2 className="text-3xl font-bold text-[var(--color-dash-text)] dark:text-white tracking-tight">
1271
- Billing & contract details
1272
- </h2>
1273
- <p className="text-lg text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1274
- Keep track of invoices and your partnership terms
1275
- </p>
1276
- </div>
1277
-
1278
- {/* Revenue Trend by Property */}
1279
- {isLoading ? (
1280
- <CardSkeleton lines={6} />
1281
- ) : (
1282
- <div className="bg-white dark:bg-[var(--color-dash-text)] border border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30 rounded-xl shadow-sm hover:shadow-lg transition-shadow duration-300 overflow-hidden">
1283
- <div className="p-8 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1284
- <div className="flex items-start justify-between gap-4">
1285
- <div>
1286
- <h3 className="text-2xl font-bold text-[var(--color-dash-text)] dark:text-white mb-1">
1287
- Revenue trend by property
1288
- </h3>
1289
- <p className="text-base text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1290
- Monthly revenue earned through Engine across your {revenueTrendByProperty.properties?.length || 4} properties
1291
- </p>
1292
- </div>
1293
- </div>
1294
- {/* Legend */}
1295
- <div className="flex flex-wrap gap-4 mt-5">
1296
- {revenueTrendByProperty.properties.map((prop) => (
1297
- <div key={prop.name} className="flex items-center gap-2">
1298
- <span
1299
- className="inline-block h-2.5 w-2.5 rounded-full flex-shrink-0"
1300
- style={{ backgroundColor: prop.color }}
1301
- />
1302
- <span className="text-xs font-medium text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1303
- {prop.name}
1304
- </span>
1305
- </div>
1306
- ))}
1307
- </div>
1308
- </div>
1309
- <div className="p-6 w-full">
1310
- {revenueTrendByProperty && revenueTrendByProperty.months && revenueTrendByProperty.properties ? (
1311
- <div className="w-full" style={{ minHeight: '260px' }}>
1312
- <D3Chart
1313
- data={revenueTrendByProperty}
1314
- renderChart={renderRevenueTrendByProperty}
1315
- height={260}
1316
- responsive={true}
1317
- ariaLabel="Revenue trend by property"
1318
- />
1319
- </div>
1320
- ) : (
1321
- <div className="h-[260px] flex items-center justify-center text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1322
- Loading chart data...
1323
- </div>
1324
- )}
1325
- </div>
1326
- </div>
1327
- )}
1328
-
1329
- {/* Invoices & Contract */}
1330
- {isLoading ? (
1331
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1332
- <CardSkeleton lines={5} />
1333
- <CardSkeleton lines={5} />
1334
- </div>
1335
- ) : (
1336
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1337
- <ListCard
1338
- title="Your invoices"
1339
- subtitle="Recent statements"
1340
- items={myInvoices.map((inv) => ({
1341
- id: inv.id,
1342
- title: inv.title,
1343
- description: inv.description,
1344
- status: inv.status,
1345
- value: `$${inv.amount.toLocaleString()}`,
1346
- timestamp: `Due ${inv.due}`,
1347
- }))}
1348
- maxBodyHeight={300}
1349
- showStatus={true}
1350
- showTimestamp={true}
1351
- dense={false}
1352
- divided={true}
1353
- onItemClick={(item) => {
1354
- toast.info(`Opening invoice ${item.title.split(' — ')[0]}`);
1355
- }}
1356
- emptyMessage="No invoices right now."
1357
- loading={isLoading}
1358
- />
1359
-
1360
- <div className="bg-white dark:bg-[var(--color-dash-text)] border border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30 rounded-xl shadow-sm hover:shadow-lg transition-shadow duration-300 overflow-hidden">
1361
- <div className="p-6 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1362
- <h3 className="text-xl font-bold text-[var(--color-dash-text)] dark:text-white mb-1">
1363
- Your Contract
1364
- </h3>
1365
- <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1366
- Partnership terms
1367
- </p>
1368
- </div>
1369
- <div className="p-6 space-y-4">
1370
- <div className="flex items-center justify-between pb-4 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1371
- <div>
1372
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Contract ID</p>
1373
- <p className="text-lg font-bold text-[var(--color-dash-text)] dark:text-white">CNTR-00002</p>
1374
- </div>
1375
- <span className="inline-flex items-center rounded-full px-3 py-1 text-xs font-medium bg-[var(--color-dash-success)]/10 text-[var(--color-dash-success)] border border-[var(--color-dash-success)]/30">
1376
- Active
1377
- </span>
1378
- </div>
1379
-
1380
- <div className="grid grid-cols-2 gap-4">
1381
- <div>
1382
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Commission Rate</p>
1383
- <p className="text-2xl font-bold text-[var(--color-dash-success)]">17%</p>
1384
- </div>
1385
- <div>
1386
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Contract Term</p>
1387
- <p className="text-sm font-semibold text-[var(--color-dash-text)] dark:text-white">Mar 2025 - Feb 2027</p>
1388
- </div>
1389
- </div>
1390
-
1391
- <div className="bg-[var(--color-dash-surface)] dark:bg-[var(--color-dash-muted)]/10 rounded-lg p-4 space-y-3">
1392
- <div>
1393
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Attrition Method</p>
1394
- <p className="text-sm font-semibold text-[var(--color-dash-text)] dark:text-white">Per Night (80% threshold)</p>
1395
- </div>
1396
- <div>
1397
- <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Resale Credit Policy</p>
1398
- <p className="text-sm font-semibold text-[var(--color-dash-text)] dark:text-white">Partial Credit (50%)</p>
1399
- </div>
1400
- </div>
1401
-
1402
- <div className="pt-2">
1403
- <button
1404
- onClick={() => toast.info("Opening full contract PDF...")}
1405
- className="w-full inline-flex items-center justify-center gap-2 px-4 py-3 bg-[var(--color-dash-surface)] dark:bg-[var(--color-dash-muted)]/20 hover:bg-[var(--color-dash-accent)]/10 dark:hover:bg-[var(--color-dash-accent)]/10 text-[var(--color-dash-text)] dark:text-white font-semibold rounded-lg border border-[var(--color-dash-label)]/30 dark:border-[var(--color-dash-muted)]/50 hover:border-[var(--color-dash-accent)] transition-colors text-sm"
1406
- >
1407
- <DocumentArrowDownIcon className="h-4 w-4" />
1408
- Download Full Contract
1409
- </button>
1410
- </div>
1411
- </div>
1412
- </div>
1413
- </div>
1414
- )}
1415
-
1416
1513
  {/* Section */}
1417
1514
  <div className="pt-8 space-y-2">
1418
1515
  <h2 className="text-3xl font-bold text-[var(--color-dash-text)] dark:text-white tracking-tight">
@@ -98,8 +98,8 @@
98
98
  --dash-surface: #fef9ef;
99
99
  --dash-border: #e2c97a;
100
100
  --dash-accent: #FFB200;
101
- --dash-success: #1E9D6D;
102
- --dash-info: #7DCBD9;
101
+ --dash-success: #34d399;
102
+ --dash-info: #67e8f9;
103
103
  --dash-warning: #FD4B23;
104
104
  --dash-danger: #dc2626;
105
105
  --dash-dark: #0D1117;
@@ -110,9 +110,6 @@
110
110
  --dash-chart-4: #FD4B23;
111
111
  --dash-metric-size: 3.25rem;
112
112
  --dash-metric-sub: 2.25rem;
113
- --dash-pct-size: 0.875rem;
114
- --dash-pct-px: 0.75rem;
115
- --dash-pct-py: 0.25rem;
116
113
  --color-dash-text: var(--dash-text);
117
114
  --color-dash-muted: var(--dash-muted);
118
115
  --color-dash-label: var(--dash-label);
@@ -95,11 +95,8 @@
95
95
  --dash-chart-2: #16a34a;
96
96
  --dash-chart-3: #e11d48;
97
97
  --dash-chart-4: #7c3aed;
98
- --dash-metric-size: 2.25rem;
99
- --dash-metric-sub: 1.875rem;
100
- --dash-pct-size: 0.75rem;
101
- --dash-pct-px: 0.5rem;
102
- --dash-pct-py: 0.125rem;
98
+ --dash-metric-size: 3.25rem;
99
+ --dash-metric-sub: 2.25rem;
103
100
  --color-dash-text: var(--dash-text);
104
101
  --color-dash-muted: var(--dash-muted);
105
102
  --color-dash-label: var(--dash-label);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schandlergarcia/sf-web-components",
3
- "version": "2.3.9",
3
+ "version": "2.3.11",
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",
@@ -95,11 +95,8 @@
95
95
  --dash-chart-2: #16a34a;
96
96
  --dash-chart-3: #e11d48;
97
97
  --dash-chart-4: #7c3aed;
98
- --dash-metric-size: 2.25rem;
99
- --dash-metric-sub: 1.875rem;
100
- --dash-pct-size: 0.75rem;
101
- --dash-pct-px: 0.5rem;
102
- --dash-pct-py: 0.125rem;
98
+ --dash-metric-size: 3.25rem;
99
+ --dash-metric-sub: 2.25rem;
103
100
  --color-dash-text: var(--dash-text);
104
101
  --color-dash-muted: var(--dash-muted);
105
102
  --color-dash-label: var(--dash-label);