@schandlergarcia/sf-web-components 2.3.9 → 2.3.10

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,14 @@ 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.10] - 2026-04-13
9
+
10
+ ### Changed
11
+ - **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.
12
+ - **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.
13
+ - **Billing & Contract moved above Recent Activity** — section reorder puts revenue charts, invoices, and contract details higher in the page flow.
14
+ - **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.
15
+
8
16
  ## [2.3.9] - 2026-04-13
9
17
 
10
18
  ### Changed
@@ -662,6 +662,63 @@ export default function PartnerHubDashboard() {
662
662
  .style("fill", "currentColor");
663
663
  }, []);
664
664
 
665
+ const monthlyTotalRevenue = React.useMemo(() => {
666
+ if (!revenueTrendByProperty?.months || !revenueTrendByProperty?.properties) return null;
667
+ return revenueTrendByProperty.months.map((month: string, i: number) => ({
668
+ month,
669
+ total: revenueTrendByProperty.properties.reduce((sum: number, p: any) => sum + p.values[i], 0),
670
+ }));
671
+ }, [revenueTrendByProperty]);
672
+
673
+ const renderTotalRevenueGrowth = React.useCallback((svgEl: any, data: any, { width, height }: any) => {
674
+ if (!data || !data.length) return;
675
+ const margin = { top: 20, right: 20, bottom: 40, left: 70 };
676
+ const innerWidth = width - margin.left - margin.right;
677
+ const innerHeight = height - margin.top - margin.bottom;
678
+ if (innerWidth <= 0 || innerHeight <= 0) return;
679
+
680
+ const svg = d3.select(svgEl);
681
+ svg.selectAll("*").remove();
682
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
683
+
684
+ const x = d3.scaleBand().domain(data.map((d: any) => d.month)).range([0, innerWidth]).padding(0.35);
685
+ const maxVal = d3.max(data, (d: any) => d.total) || 0;
686
+ const y = d3.scaleLinear().domain([0, maxVal * 1.15]).range([innerHeight, 0]).nice();
687
+
688
+ g.append("g").attr("class", "grid")
689
+ .call(d3.axisLeft(y).ticks(5).tickSize(-innerWidth).tickFormat(() => ""))
690
+ .selectAll("line").style("stroke", "currentColor").style("stroke-opacity", "0.08");
691
+ g.select(".grid .domain").remove();
692
+
693
+ const accentColor = getComputedStyle(document.documentElement).getPropertyValue('--dash-accent').trim() || '#2563eb';
694
+
695
+ g.selectAll(".bar").data(data).join("rect")
696
+ .attr("x", (d: any) => x(d.month) ?? 0)
697
+ .attr("y", (d: any) => y(d.total))
698
+ .attr("width", x.bandwidth())
699
+ .attr("height", (d: any) => innerHeight - y(d.total))
700
+ .attr("rx", 4)
701
+ .attr("fill", accentColor)
702
+ .attr("fill-opacity", 0.85);
703
+
704
+ g.selectAll(".label").data(data).join("text")
705
+ .attr("x", (d: any) => (x(d.month) ?? 0) + x.bandwidth() / 2)
706
+ .attr("y", (d: any) => y(d.total) - 8)
707
+ .attr("text-anchor", "middle")
708
+ .style("font-size", "11px")
709
+ .style("font-weight", "600")
710
+ .style("fill", "currentColor")
711
+ .text((d: any) => `$${(d.total / 1000).toFixed(0)}K`);
712
+
713
+ g.append("g").attr("transform", `translate(0,${innerHeight})`)
714
+ .call(d3.axisBottom(x)).selectAll("text")
715
+ .style("font-size", "11px").style("fill", "currentColor").attr("dy", "1.2em");
716
+ g.select(".domain").style("stroke-opacity", "0.2");
717
+
718
+ g.append("g").call(d3.axisLeft(y).ticks(5).tickFormat(d3.format("$~s")))
719
+ .selectAll("text").style("font-size", "11px").style("fill", "currentColor");
720
+ }, []);
721
+
665
722
  return (
666
723
  <div className="heroui-scope min-h-screen bg-[var(--color-dash-surface)] dark:bg-[var(--color-dash-text)] transition-colors duration-300">
667
724
  {/* Header - Refined Engine Brand */}
@@ -801,13 +858,13 @@ export default function PartnerHubDashboard() {
801
858
  <div className="bg-[var(--color-dash-success)]/10 rounded-lg p-2">
802
859
  <BanknotesIcon className="h-5 w-5 text-[var(--color-dash-success)]" />
803
860
  </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)' }}>
861
+ <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
862
  +45%
806
863
  </span>
807
864
  </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>
865
+ <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
866
  <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>
867
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">earned with Engine</p>
811
868
  </>
812
869
  )}
813
870
  </div>
@@ -827,13 +884,13 @@ export default function PartnerHubDashboard() {
827
884
  <div className="bg-[var(--color-dash-warning)]/10 rounded-lg p-2">
828
885
  <ExclamationTriangleIcon className="h-5 w-5 text-[var(--color-dash-warning)]" />
829
886
  </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)' }}>
887
+ <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
888
  REVIEW
832
889
  </span>
833
890
  </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>
891
+ <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
892
  <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>
893
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">items need attention</p>
837
894
  </>
838
895
  )}
839
896
  </div>
@@ -854,9 +911,9 @@ export default function PartnerHubDashboard() {
854
911
  <BuildingOfficeIcon className="h-5 w-5 text-[var(--color-dash-accent)]" />
855
912
  </div>
856
913
  </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>
914
+ <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
915
  <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>
916
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">active locations</p>
860
917
  </>
861
918
  )}
862
919
  </div>
@@ -877,9 +934,9 @@ export default function PartnerHubDashboard() {
877
934
  <ClockIcon className="h-5 w-5 text-[var(--color-dash-info)]" />
878
935
  </div>
879
936
  </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>
937
+ <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
938
  <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>
939
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">through Engine</p>
883
940
  </>
884
941
  )}
885
942
  </div>
@@ -900,9 +957,9 @@ export default function PartnerHubDashboard() {
900
957
  <ShieldCheckIcon className="h-5 w-5 text-[var(--color-dash-danger)]" />
901
958
  </div>
902
959
  </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>
960
+ <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
961
  <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>
962
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">ready to pay</p>
906
963
  </>
907
964
  )}
908
965
  </div>
@@ -977,7 +1034,7 @@ export default function PartnerHubDashboard() {
977
1034
  <h3 className="text-xl font-bold text-[var(--color-dash-text)] dark:text-white">
978
1035
  {property.name}
979
1036
  </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)' }}>
1037
+ <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
1038
  +{property.growth}% growth
982
1039
  </span>
983
1040
  </div>
@@ -1044,7 +1101,7 @@ export default function PartnerHubDashboard() {
1044
1101
  ATR-00001 · Summit Austin Convention Center · TechCorp Inc. booking
1045
1102
  </p>
1046
1103
  </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)' }}>
1104
+ <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
1105
  NEEDS REVIEW
1049
1106
  </span>
1050
1107
  </div>
@@ -1092,7 +1149,164 @@ export default function PartnerHubDashboard() {
1092
1149
  </div>
1093
1150
  )}
1094
1151
 
1095
- {/* Section - Conversational with Better Spacing */}
1152
+ {/* Section Billing & Contract Details */}
1153
+ <div className="pt-8 space-y-2">
1154
+ <h2 className="text-3xl font-bold text-[var(--color-dash-text)] dark:text-white tracking-tight">
1155
+ Billing & contract details
1156
+ </h2>
1157
+ <p className="text-lg text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1158
+ Keep track of invoices and your partnership terms
1159
+ </p>
1160
+ </div>
1161
+
1162
+ {/* Two Charts Grid */}
1163
+ {isLoading ? (
1164
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1165
+ <CardSkeleton lines={6} />
1166
+ <CardSkeleton lines={6} />
1167
+ </div>
1168
+ ) : (
1169
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1170
+ {/* Revenue Trend by Property (multi-line) */}
1171
+ <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">
1172
+ <div className="p-6 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1173
+ <h3 className="text-xl font-bold text-[var(--color-dash-text)] dark:text-white mb-1">
1174
+ Revenue by property
1175
+ </h3>
1176
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1177
+ Monthly trend across {revenueTrendByProperty.properties?.length || 4} properties
1178
+ </p>
1179
+ <div className="flex flex-wrap gap-3 mt-3">
1180
+ {revenueTrendByProperty.properties.map((prop) => (
1181
+ <div key={prop.name} className="flex items-center gap-1.5">
1182
+ <span className="inline-block h-2 w-2 rounded-full flex-shrink-0" style={{ backgroundColor: prop.color }} />
1183
+ <span className="text-xs font-medium text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">{prop.name.replace('Summit ', '')}</span>
1184
+ </div>
1185
+ ))}
1186
+ </div>
1187
+ </div>
1188
+ <div className="p-4 w-full">
1189
+ {revenueTrendByProperty?.months && revenueTrendByProperty?.properties ? (
1190
+ <div className="w-full" style={{ minHeight: '240px' }}>
1191
+ <D3Chart data={revenueTrendByProperty} renderChart={renderRevenueTrendByProperty} height={240} responsive={true} ariaLabel="Revenue trend by property" />
1192
+ </div>
1193
+ ) : (
1194
+ <div className="h-[240px] flex items-center justify-center text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">Loading chart data...</div>
1195
+ )}
1196
+ </div>
1197
+ </div>
1198
+
1199
+ {/* Total Monthly Revenue Growth (bar chart) */}
1200
+ <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">
1201
+ <div className="p-6 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1202
+ <h3 className="text-xl font-bold text-[var(--color-dash-text)] dark:text-white mb-1">
1203
+ Total revenue growth
1204
+ </h3>
1205
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1206
+ Combined monthly revenue — up 67% over 6 months
1207
+ </p>
1208
+ </div>
1209
+ <div className="p-4 w-full">
1210
+ {monthlyTotalRevenue ? (
1211
+ <div className="w-full" style={{ minHeight: '240px' }}>
1212
+ <D3Chart data={monthlyTotalRevenue} renderChart={renderTotalRevenueGrowth} height={240} responsive={true} ariaLabel="Total revenue growth" />
1213
+ </div>
1214
+ ) : (
1215
+ <div className="h-[240px] flex items-center justify-center text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">Loading chart data...</div>
1216
+ )}
1217
+ </div>
1218
+ </div>
1219
+ </div>
1220
+ )}
1221
+
1222
+ {/* Invoices & Contract */}
1223
+ {isLoading ? (
1224
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1225
+ <CardSkeleton lines={5} />
1226
+ <CardSkeleton lines={5} />
1227
+ </div>
1228
+ ) : (
1229
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
1230
+ <ListCard
1231
+ title="Your invoices"
1232
+ subtitle="Recent statements"
1233
+ items={myInvoices.map((inv) => ({
1234
+ id: inv.id,
1235
+ title: inv.title,
1236
+ description: inv.description,
1237
+ status: inv.status,
1238
+ value: `$${inv.amount.toLocaleString()}`,
1239
+ timestamp: `Due ${inv.due}`,
1240
+ }))}
1241
+ maxBodyHeight={300}
1242
+ showStatus={true}
1243
+ showTimestamp={true}
1244
+ dense={false}
1245
+ divided={true}
1246
+ onItemClick={(item) => {
1247
+ toast.info(`Opening invoice ${item.title.split(' — ')[0]}`);
1248
+ }}
1249
+ emptyMessage="No invoices right now."
1250
+ loading={isLoading}
1251
+ />
1252
+
1253
+ <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">
1254
+ <div className="p-6 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1255
+ <h3 className="text-xl font-bold text-[var(--color-dash-text)] dark:text-white mb-1">
1256
+ Your Contract
1257
+ </h3>
1258
+ <p className="text-sm text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)]">
1259
+ Partnership terms
1260
+ </p>
1261
+ </div>
1262
+ <div className="p-6 space-y-4">
1263
+ <div className="flex items-center justify-between pb-4 border-b border-[var(--color-dash-label)]/20 dark:border-[var(--color-dash-muted)]/30">
1264
+ <div>
1265
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Contract ID</p>
1266
+ <p className="text-lg font-bold text-[var(--color-dash-text)] dark:text-white">CNTR-00002</p>
1267
+ </div>
1268
+ <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">
1269
+ Active
1270
+ </span>
1271
+ </div>
1272
+
1273
+ <div className="grid grid-cols-2 gap-4">
1274
+ <div>
1275
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Commission Rate</p>
1276
+ <p className="text-2xl font-bold text-[var(--color-dash-success)]">17%</p>
1277
+ </div>
1278
+ <div>
1279
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Contract Term</p>
1280
+ <p className="text-sm font-semibold text-[var(--color-dash-text)] dark:text-white">Mar 2025 - Feb 2027</p>
1281
+ </div>
1282
+ </div>
1283
+
1284
+ <div className="bg-[var(--color-dash-surface)] dark:bg-[var(--color-dash-muted)]/10 rounded-lg p-4 space-y-3">
1285
+ <div>
1286
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Attrition Method</p>
1287
+ <p className="text-sm font-semibold text-[var(--color-dash-text)] dark:text-white">Per Night (80% threshold)</p>
1288
+ </div>
1289
+ <div>
1290
+ <p className="text-xs text-[var(--color-dash-muted)] dark:text-[var(--color-dash-label)] mb-1 uppercase tracking-wider">Resale Credit Policy</p>
1291
+ <p className="text-sm font-semibold text-[var(--color-dash-text)] dark:text-white">Partial Credit (50%)</p>
1292
+ </div>
1293
+ </div>
1294
+
1295
+ <div className="pt-2">
1296
+ <button
1297
+ onClick={() => toast.info("Opening full contract PDF...")}
1298
+ 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"
1299
+ >
1300
+ <DocumentArrowDownIcon className="h-4 w-4" />
1301
+ Download Full Contract
1302
+ </button>
1303
+ </div>
1304
+ </div>
1305
+ </div>
1306
+ </div>
1307
+ )}
1308
+
1309
+ {/* Section — Recent Activity */}
1096
1310
  <div className="pt-8 space-y-2">
1097
1311
  <h2 className="text-3xl font-bold text-[var(--color-dash-text)] dark:text-white tracking-tight">
1098
1312
  Recent activity
@@ -1102,8 +1316,6 @@ export default function PartnerHubDashboard() {
1102
1316
  </p>
1103
1317
  </div>
1104
1318
 
1105
- {/* Hero penalty section removed - now at top of page */}
1106
-
1107
1319
  {/* Action Items Grid */}
1108
1320
  {isLoading ? (
1109
1321
  <div className="grid grid-cols-1 md:grid-cols-2 gap-5">
@@ -1265,154 +1477,6 @@ export default function PartnerHubDashboard() {
1265
1477
  </div>
1266
1478
  )}
1267
1479
 
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
1480
  {/* Section */}
1417
1481
  <div className="pt-8 space-y-2">
1418
1482
  <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.10",
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);