@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)]"
|
|
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-
|
|
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-
|
|
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"
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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"
|
|
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"
|
|
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
|
|
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">
|
package/brands/engine/global.css
CHANGED
|
@@ -98,8 +98,8 @@
|
|
|
98
98
|
--dash-surface: #fef9ef;
|
|
99
99
|
--dash-border: #e2c97a;
|
|
100
100
|
--dash-accent: #FFB200;
|
|
101
|
-
--dash-success: #
|
|
102
|
-
--dash-info: #
|
|
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);
|
package/dist/styles/global.css
CHANGED
|
@@ -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:
|
|
99
|
-
--dash-metric-sub:
|
|
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
package/src/styles/global.css
CHANGED
|
@@ -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:
|
|
99
|
-
--dash-metric-sub:
|
|
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);
|