@burdenoff/microfe-ggnomad 2026.705.3 → 2026.705.5

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.
@@ -4,150 +4,208 @@ import { StatCard as o } from "../components/StatCard.js";
4
4
  import { StatusBadge as s } from "../components/StatusBadge.js";
5
5
  import { SectionCard as c } from "../components/SectionCard.js";
6
6
  import "../components/index.js";
7
- import { Building as l, CalendarCheck as u, Compass as d, DollarSign as f, Hotel as p, Search as m, Users as h } from "lucide-react";
8
- import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
9
- import { useNavigate as _ } from "react-router-dom";
10
- import { useQuery as v } from "@apollo/client/react";
11
- import { EmphasisPanel as y, IllustratedEmptyState as b, NextSteps as x, PagePurpose as S } from "@burdenoff/fe-libs/ui";
12
- import { jsx as C, jsxs as w } from "react/jsx-runtime";
7
+ import { useMemo as l } from "react";
8
+ import { Building as u, CalendarCheck as d, Compass as f, DollarSign as p, Hotel as m, Search as h, Users as g } from "lucide-react";
9
+ import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
10
+ import { useNavigate as v } from "react-router-dom";
11
+ import { useQuery as y } from "@apollo/client/react";
12
+ import { EmphasisPanel as b, IllustratedEmptyState as x, NextSteps as S, PagePurpose as C } from "@burdenoff/fe-libs/ui";
13
+ import { jsx as w, jsxs as T } from "react/jsx-runtime";
13
14
  //#region src/ggnomad/pages/DashboardPage.tsx
14
- function T() {
15
- let { t: T } = g(), E = _(), D = v(n), O = v(e, { variables: {
15
+ var E = [
16
+ "var(--color-chart-1)",
17
+ "var(--color-chart-2)",
18
+ "var(--color-chart-3)",
19
+ "var(--color-chart-4)",
20
+ "var(--color-chart-5)"
21
+ ], D = (e) => e.replace(/[_-]+/g, " ").trim().replace(/\b\w/g, (e) => e.toUpperCase()) || e;
22
+ function O() {
23
+ let { t: O } = _(), k = v(), A = y(n), j = y(e, { variables: {
16
24
  first: 5,
17
25
  skip: 0
18
- } }), k = v(r, { variables: {
26
+ } }), M = y(r, { variables: {
19
27
  first: 4,
20
28
  skip: 0
21
- } }), A = v(i, { variables: {
29
+ } }), N = y(i, { variables: {
22
30
  first: 4,
23
31
  skip: 0
24
- } }), j = v(t, { variables: {
32
+ } }), P = y(t, { variables: {
25
33
  first: 4,
26
34
  skip: 0
27
- } }), M = D.data?.ggnomadOverviewStats, N = O.data?.ggnomadBookings ?? [];
28
- return /* @__PURE__ */ w(a, {
35
+ } }), F = A.data?.ggnomadOverviewStats, I = A.data?.ggnomadAnalytics, L = j.data?.ggnomadBookings ?? [], R = l(() => {
36
+ let e = I?.revenueByCategory ?? {};
37
+ return Object.entries(e).map(([e, t]) => ({
38
+ label: D(e),
39
+ value: Number(t)
40
+ })).filter((e) => Number.isFinite(e.value) && e.value > 0).sort((e, t) => t.value - e.value);
41
+ }, [I?.revenueByCategory]), z = R.length > 0 ? R[0].value : 0;
42
+ return /* @__PURE__ */ T(a, {
29
43
  hero: !0,
30
- title: T("ggnomad.dashboard.title", "GGNomad Dashboard"),
31
- titleAccent: T("ggnomad.dashboard.title.accent", "GGNomad"),
32
- subtitle: T("ggnomad.dashboard.subtitle", "Unified travel, hospitality, tourism and entertainment operations"),
44
+ title: O("ggnomad.dashboard.title", "GGNomad Dashboard"),
45
+ titleAccent: O("ggnomad.dashboard.title.accent", "GGNomad"),
46
+ subtitle: O("ggnomad.dashboard.subtitle", "Unified travel, hospitality, tourism and entertainment operations"),
33
47
  children: [
34
- /* @__PURE__ */ C(S, {
35
- icon: /* @__PURE__ */ C(d, { className: "size-4" }),
36
- children: T("ggnomad.dashboard.purpose", "Your command centre for the whole GGNomad marketplace — see live revenue, users, listings and bookings across travel, hospitality, tourism and entertainment in one place, and jump straight into the area you want to work on.")
48
+ /* @__PURE__ */ w(C, {
49
+ icon: /* @__PURE__ */ w(f, { className: "size-4" }),
50
+ children: O("ggnomad.dashboard.purpose", "Your command centre for the whole GGNomad marketplace — see live revenue, users, listings and bookings across travel, hospitality, tourism and entertainment in one place, and jump straight into the area you want to work on.")
37
51
  }),
38
- /* @__PURE__ */ C(x, {
52
+ /* @__PURE__ */ w(S, {
39
53
  storageKey: "ggnomad-dashboard",
40
54
  steps: [
41
55
  {
42
56
  id: "search",
43
- label: T("ggnomad.dashboard.next.search", "Search the catalogue"),
44
- description: T("ggnomad.dashboard.next.searchDesc", "Find inventory across every domain at once."),
45
- icon: /* @__PURE__ */ C(m, { className: "size-4" }),
46
- onClick: () => E("search")
57
+ label: O("ggnomad.dashboard.next.search", "Search the catalogue"),
58
+ description: O("ggnomad.dashboard.next.searchDesc", "Find inventory across every domain at once."),
59
+ icon: /* @__PURE__ */ w(h, { className: "size-4" }),
60
+ onClick: () => k("search")
47
61
  },
48
62
  {
49
63
  id: "stays",
50
- label: T("ggnomad.dashboard.next.stays", "Browse places to stay"),
51
- description: T("ggnomad.dashboard.next.staysDesc", "Explore hospitality listings and open a property."),
52
- icon: /* @__PURE__ */ C(p, { className: "size-4" }),
53
- onClick: () => E("hospitality")
64
+ label: O("ggnomad.dashboard.next.stays", "Browse places to stay"),
65
+ description: O("ggnomad.dashboard.next.staysDesc", "Explore hospitality listings and open a property."),
66
+ icon: /* @__PURE__ */ w(m, { className: "size-4" }),
67
+ onClick: () => k("hospitality")
54
68
  },
55
69
  {
56
70
  id: "tourism",
57
- label: T("ggnomad.dashboard.next.tourism", "Discover tours & activities"),
58
- description: T("ggnomad.dashboard.next.tourismDesc", "Plan what to do at each destination."),
59
- icon: /* @__PURE__ */ C(d, { className: "size-4" }),
60
- onClick: () => E("tourism")
71
+ label: O("ggnomad.dashboard.next.tourism", "Discover tours & activities"),
72
+ description: O("ggnomad.dashboard.next.tourismDesc", "Plan what to do at each destination."),
73
+ icon: /* @__PURE__ */ w(f, { className: "size-4" }),
74
+ onClick: () => k("tourism")
61
75
  },
62
76
  {
63
77
  id: "bookings",
64
- label: T("ggnomad.dashboard.next.bookings", "Manage bookings"),
65
- description: T("ggnomad.dashboard.next.bookingsDesc", "Track and cancel reservations in real time."),
66
- icon: /* @__PURE__ */ C(u, { className: "size-4" }),
67
- onClick: () => E("bookings")
78
+ label: O("ggnomad.dashboard.next.bookings", "Manage bookings"),
79
+ description: O("ggnomad.dashboard.next.bookingsDesc", "Track and cancel reservations in real time."),
80
+ icon: /* @__PURE__ */ w(d, { className: "size-4" }),
81
+ onClick: () => k("bookings")
68
82
  }
69
83
  ]
70
84
  }),
71
- /* @__PURE__ */ w("section", {
85
+ /* @__PURE__ */ T("section", {
72
86
  className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-4",
73
87
  children: [
74
- /* @__PURE__ */ C(o, {
88
+ /* @__PURE__ */ w(o, {
75
89
  hero: !0,
76
- label: T("ggnomad.dashboard.stats.monthlyRevenue", "Monthly Revenue"),
77
- value: `$${Number(M?.monthlyRevenue ?? 0).toLocaleString()}`,
78
- icon: /* @__PURE__ */ C(f, {})
90
+ label: O("ggnomad.dashboard.stats.monthlyRevenue", "Monthly Revenue"),
91
+ value: `$${Number(F?.monthlyRevenue ?? 0).toLocaleString()}`,
92
+ icon: /* @__PURE__ */ w(p, {})
79
93
  }),
80
- /* @__PURE__ */ C(o, {
81
- label: T("ggnomad.dashboard.stats.users", "Users"),
82
- value: Number(M?.users ?? 0).toLocaleString(),
83
- icon: /* @__PURE__ */ C(h, {})
94
+ /* @__PURE__ */ w(o, {
95
+ label: O("ggnomad.dashboard.stats.users", "Users"),
96
+ value: Number(F?.users ?? 0).toLocaleString(),
97
+ icon: /* @__PURE__ */ w(g, {})
84
98
  }),
85
- /* @__PURE__ */ C(o, {
86
- label: T("ggnomad.dashboard.stats.listings", "Listings"),
87
- value: Number(M?.listings ?? 0).toLocaleString(),
88
- icon: /* @__PURE__ */ C(l, {})
99
+ /* @__PURE__ */ w(o, {
100
+ label: O("ggnomad.dashboard.stats.listings", "Listings"),
101
+ value: Number(F?.listings ?? 0).toLocaleString(),
102
+ icon: /* @__PURE__ */ w(u, {})
89
103
  }),
90
- /* @__PURE__ */ C(o, {
91
- label: T("ggnomad.dashboard.stats.bookings", "Bookings"),
92
- value: Number(M?.bookings ?? 0).toLocaleString(),
93
- icon: /* @__PURE__ */ C(u, {})
104
+ /* @__PURE__ */ w(o, {
105
+ label: O("ggnomad.dashboard.stats.bookings", "Bookings"),
106
+ value: Number(F?.bookings ?? 0).toLocaleString(),
107
+ icon: /* @__PURE__ */ w(d, {})
94
108
  })
95
109
  ]
96
110
  }),
97
- /* @__PURE__ */ w(y, { children: [/* @__PURE__ */ w("div", {
111
+ /* @__PURE__ */ T(b, { children: [/* @__PURE__ */ T("div", {
98
112
  className: "grid gap-4 sm:grid-cols-3",
99
113
  children: [
100
- /* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("p", {
114
+ /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
101
115
  className: "text-sm text-text-secondary",
102
- children: T("ggnomad.dashboard.inventory.properties", "Properties")
103
- }), /* @__PURE__ */ C("p", {
116
+ children: O("ggnomad.dashboard.inventory.properties", "Properties")
117
+ }), /* @__PURE__ */ w("p", {
104
118
  className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
105
- children: k.data?.ggnomadProperties?.length ?? 0
119
+ children: M.data?.ggnomadProperties?.length ?? 0
106
120
  })] }),
107
- /* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("p", {
121
+ /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
108
122
  className: "text-sm text-text-secondary",
109
- children: T("ggnomad.dashboard.inventory.tours", "Tours")
110
- }), /* @__PURE__ */ C("p", {
123
+ children: O("ggnomad.dashboard.inventory.tours", "Tours")
124
+ }), /* @__PURE__ */ w("p", {
111
125
  className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
112
- children: A.data?.ggnomadTours?.length ?? 0
126
+ children: N.data?.ggnomadTours?.length ?? 0
113
127
  })] }),
114
- /* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("p", {
128
+ /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
115
129
  className: "text-sm text-text-secondary",
116
- children: T("ggnomad.dashboard.inventory.events", "Events")
117
- }), /* @__PURE__ */ C("p", {
130
+ children: O("ggnomad.dashboard.inventory.events", "Events")
131
+ }), /* @__PURE__ */ w("p", {
118
132
  className: "mt-1 text-2xl font-semibold tabular-nums text-text-primary",
119
- children: j.data?.ggnomadEvents?.length ?? 0
133
+ children: P.data?.ggnomadEvents?.length ?? 0
120
134
  })] })
121
135
  ]
122
- }), /* @__PURE__ */ C("p", {
136
+ }), /* @__PURE__ */ w("p", {
123
137
  className: "mt-4 text-sm text-text-secondary",
124
- children: T("ggnomad.dashboard.inventory.liveDataNotice", "Data is live from `wspace-ggnomad-svc` GraphQL APIs.")
138
+ children: O("ggnomad.dashboard.inventory.liveDataNotice", "Data is live from `wspace-ggnomad-svc` GraphQL APIs.")
125
139
  })] }),
126
- /* @__PURE__ */ C(c, {
127
- title: T("ggnomad.dashboard.sections.recentBookings", "Recent bookings"),
128
- children: N.length === 0 ? /* @__PURE__ */ C(b, {
140
+ /* @__PURE__ */ w(c, {
141
+ title: O("ggnomad.dashboard.sections.recentBookings", "Recent bookings"),
142
+ children: L.length === 0 ? /* @__PURE__ */ w(x, {
129
143
  illustration: "empty-data",
130
- title: T("ggnomad.dashboard.recentBookings.emptyTitle", "No recent bookings"),
131
- description: T("ggnomad.dashboard.recentBookings.emptyDescription", "New bookings across travel, hospitality and tourism will appear here.")
132
- }) : /* @__PURE__ */ C("ul", {
144
+ title: O("ggnomad.dashboard.recentBookings.emptyTitle", "No recent bookings"),
145
+ description: O("ggnomad.dashboard.recentBookings.emptyDescription", "New bookings across travel, hospitality and tourism will appear here.")
146
+ }) : /* @__PURE__ */ w("ul", {
133
147
  className: "space-y-2 text-sm",
134
- children: N.map((e) => /* @__PURE__ */ w("li", {
148
+ children: L.map((e) => /* @__PURE__ */ T("li", {
135
149
  className: "flex items-center justify-between gap-3 rounded-lg border border-border-seam bg-bg-surface/40 p-3",
136
- children: [/* @__PURE__ */ w("span", {
150
+ children: [/* @__PURE__ */ T("span", {
137
151
  className: "min-w-0 truncate text-text-primary",
138
152
  children: [
139
153
  e.referenceCode,
140
154
  " — ",
141
155
  e.itemName
142
156
  ]
143
- }), /* @__PURE__ */ C(s, { status: e.status })]
157
+ }), /* @__PURE__ */ w(s, { status: e.status })]
144
158
  }, e.id))
145
159
  })
160
+ }),
161
+ /* @__PURE__ */ w(c, {
162
+ title: O("ggnomad.dashboard.sections.revenueByCategory", "Revenue by category"),
163
+ children: R.length === 0 ? /* @__PURE__ */ T("div", {
164
+ className: "flex flex-col items-center gap-2 py-8 text-center",
165
+ children: [
166
+ /* @__PURE__ */ w("span", {
167
+ className: "flex size-10 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-secondary",
168
+ children: /* @__PURE__ */ w(p, { className: "size-5" })
169
+ }),
170
+ /* @__PURE__ */ w("p", {
171
+ className: "text-sm font-medium text-text-primary",
172
+ children: O("ggnomad.dashboard.empty.title", "Revenue data coming soon")
173
+ }),
174
+ /* @__PURE__ */ w("p", {
175
+ className: "max-w-sm text-sm text-text-secondary",
176
+ children: O("ggnomad.dashboard.empty.description", "Revenue by category appears here as bookings come in across stays, tours and events.")
177
+ })
178
+ ]
179
+ }) : /* @__PURE__ */ w("ul", {
180
+ className: "flex flex-col gap-4",
181
+ children: R.map((e, t) => {
182
+ let n = z > 0 ? Math.max(e.value / z * 100, 2) : 0;
183
+ return /* @__PURE__ */ T("li", { children: [/* @__PURE__ */ T("div", {
184
+ className: "flex items-baseline justify-between gap-3",
185
+ children: [/* @__PURE__ */ w("span", {
186
+ className: "truncate text-sm font-medium text-text-primary",
187
+ children: e.label
188
+ }), /* @__PURE__ */ T("span", {
189
+ className: "flex-shrink-0 text-sm tabular-nums text-text-secondary",
190
+ children: ["$", e.value.toLocaleString()]
191
+ })]
192
+ }), /* @__PURE__ */ w("div", {
193
+ className: "mt-1.5 h-2.5 w-full overflow-hidden rounded-full bg-bg-sunken",
194
+ children: /* @__PURE__ */ w("div", {
195
+ className: "h-full rounded-full transition-[width] duration-500 ease-out",
196
+ style: {
197
+ width: `${n}%`,
198
+ backgroundColor: E[t % E.length]
199
+ }
200
+ })
201
+ })] }, e.label);
202
+ })
203
+ })
146
204
  })
147
205
  ]
148
206
  });
149
207
  }
150
208
  //#endregion
151
- export { T as DashboardPage };
209
+ export { O as DashboardPage };
152
210
 
153
211
  //# sourceMappingURL=DashboardPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/ggnomad/pages/DashboardPage.tsx"],"sourcesContent":["import { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Building, CalendarCheck, Compass, DollarSign, Hotel, Search, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n EmphasisPanel,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n GGNOMAD_OVERVIEW_QUERY,\n GGNOMAD_BOOKINGS_QUERY,\n GGNOMAD_PROPERTIES_QUERY,\n GGNOMAD_TOURS_QUERY,\n GGNOMAD_EVENTS_QUERY,\n} from '../graphql';\nimport { PageShell } from './PageShell';\nimport { SectionCard, StatCard, StatusBadge } from '../components';\n\nexport function DashboardPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const overview = useQuery(\n GGNOMAD_OVERVIEW_QUERY as TypedDocumentNode<\n {\n ggnomadOverviewStats: {\n users: number;\n listings: number;\n bookings: number;\n monthlyRevenue: number;\n };\n },\n Record<string, never>\n >\n );\n const bookings = useQuery(\n GGNOMAD_BOOKINGS_QUERY as TypedDocumentNode<\n {\n ggnomadBookings: Array<{\n id: string;\n referenceCode: string;\n itemName: string;\n status: string;\n }>;\n },\n { first: number; skip: number }\n >,\n {\n variables: { first: 5, skip: 0 },\n }\n );\n const properties = useQuery(\n GGNOMAD_PROPERTIES_QUERY as TypedDocumentNode<\n { ggnomadProperties: Array<{ id: string }> },\n { first: number; skip: number }\n >,\n { variables: { first: 4, skip: 0 } }\n );\n const tours = useQuery(\n GGNOMAD_TOURS_QUERY as TypedDocumentNode<\n { ggnomadTours: Array<{ id: string }> },\n { first: number; skip: number }\n >,\n {\n variables: { first: 4, skip: 0 },\n }\n );\n const events = useQuery(\n GGNOMAD_EVENTS_QUERY as TypedDocumentNode<\n { ggnomadEvents: Array<{ id: string }> },\n { first: number; skip: number }\n >,\n {\n variables: { first: 4, skip: 0 },\n }\n );\n\n const stats = overview.data?.ggnomadOverviewStats;\n const recentBookings = bookings.data?.ggnomadBookings ?? [];\n\n return (\n <PageShell\n hero\n title={t('ggnomad.dashboard.title', 'GGNomad Dashboard')}\n titleAccent={t('ggnomad.dashboard.title.accent', 'GGNomad')}\n subtitle={t(\n 'ggnomad.dashboard.subtitle',\n 'Unified travel, hospitality, tourism and entertainment operations'\n )}\n >\n <PagePurpose icon={<Compass className=\"size-4\" />}>\n {t(\n 'ggnomad.dashboard.purpose',\n 'Your command centre for the whole GGNomad marketplace — see live revenue, users, listings and bookings across travel, hospitality, tourism and entertainment in one place, and jump straight into the area you want to work on.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"ggnomad-dashboard\"\n steps={[\n {\n id: 'search',\n label: t('ggnomad.dashboard.next.search', 'Search the catalogue'),\n description: t(\n 'ggnomad.dashboard.next.searchDesc',\n 'Find inventory across every domain at once.'\n ),\n icon: <Search className=\"size-4\" />,\n onClick: () => navigate('search'),\n },\n {\n id: 'stays',\n label: t('ggnomad.dashboard.next.stays', 'Browse places to stay'),\n description: t(\n 'ggnomad.dashboard.next.staysDesc',\n 'Explore hospitality listings and open a property.'\n ),\n icon: <Hotel className=\"size-4\" />,\n onClick: () => navigate('hospitality'),\n },\n {\n id: 'tourism',\n label: t('ggnomad.dashboard.next.tourism', 'Discover tours & activities'),\n description: t(\n 'ggnomad.dashboard.next.tourismDesc',\n 'Plan what to do at each destination.'\n ),\n icon: <Compass className=\"size-4\" />,\n onClick: () => navigate('tourism'),\n },\n {\n id: 'bookings',\n label: t('ggnomad.dashboard.next.bookings', 'Manage bookings'),\n description: t(\n 'ggnomad.dashboard.next.bookingsDesc',\n 'Track and cancel reservations in real time.'\n ),\n icon: <CalendarCheck className=\"size-4\" />,\n onClick: () => navigate('bookings'),\n },\n ]}\n />\n\n <section className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <StatCard\n hero\n label={t('ggnomad.dashboard.stats.monthlyRevenue', 'Monthly Revenue')}\n value={`$${Number(stats?.monthlyRevenue ?? 0).toLocaleString()}`}\n icon={<DollarSign />}\n />\n <StatCard\n label={t('ggnomad.dashboard.stats.users', 'Users')}\n value={Number(stats?.users ?? 0).toLocaleString()}\n icon={<Users />}\n />\n <StatCard\n label={t('ggnomad.dashboard.stats.listings', 'Listings')}\n value={Number(stats?.listings ?? 0).toLocaleString()}\n icon={<Building />}\n />\n <StatCard\n label={t('ggnomad.dashboard.stats.bookings', 'Bookings')}\n value={Number(stats?.bookings ?? 0).toLocaleString()}\n icon={<CalendarCheck />}\n />\n </section>\n\n <EmphasisPanel>\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('ggnomad.dashboard.inventory.properties', 'Properties')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {properties.data?.ggnomadProperties?.length ?? 0}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('ggnomad.dashboard.inventory.tours', 'Tours')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {tours.data?.ggnomadTours?.length ?? 0}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('ggnomad.dashboard.inventory.events', 'Events')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {events.data?.ggnomadEvents?.length ?? 0}\n </p>\n </div>\n </div>\n <p className=\"mt-4 text-sm text-text-secondary\">\n {t(\n 'ggnomad.dashboard.inventory.liveDataNotice',\n 'Data is live from `wspace-ggnomad-svc` GraphQL APIs.'\n )}\n </p>\n </EmphasisPanel>\n\n <SectionCard title={t('ggnomad.dashboard.sections.recentBookings', 'Recent bookings')}>\n {recentBookings.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('ggnomad.dashboard.recentBookings.emptyTitle', 'No recent bookings')}\n description={t(\n 'ggnomad.dashboard.recentBookings.emptyDescription',\n 'New bookings across travel, hospitality and tourism will appear here.'\n )}\n />\n ) : (\n <ul className=\"space-y-2 text-sm\">\n {recentBookings.map((booking) => (\n <li\n key={booking.id}\n className=\"flex items-center justify-between gap-3 rounded-lg border border-border-seam bg-bg-surface/40 p-3\"\n >\n <span className=\"min-w-0 truncate text-text-primary\">\n {booking.referenceCode} — {booking.itemName}\n </span>\n <StatusBadge status={booking.status} />\n </li>\n ))}\n </ul>\n )}\n </SectionCard>\n </PageShell>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/ggnomad/pages/DashboardPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { useQuery } from '@apollo/client/react';\nimport type { TypedDocumentNode } from '@apollo/client';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Building, CalendarCheck, Compass, DollarSign, Hotel, Search, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n EmphasisPanel,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n GGNOMAD_OVERVIEW_QUERY,\n GGNOMAD_BOOKINGS_QUERY,\n GGNOMAD_PROPERTIES_QUERY,\n GGNOMAD_TOURS_QUERY,\n GGNOMAD_EVENTS_QUERY,\n} from '../graphql';\nimport { PageShell } from './PageShell';\nimport { SectionCard, StatCard, StatusBadge } from '../components';\n\nconst CHART_COLORS = [\n 'var(--color-chart-1)',\n 'var(--color-chart-2)',\n 'var(--color-chart-3)',\n 'var(--color-chart-4)',\n 'var(--color-chart-5)',\n];\n\nconst humanizeCategory = (key: string): string =>\n key\n .replace(/[_-]+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (char) => char.toUpperCase()) || key;\n\nexport function DashboardPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const overview = useQuery(\n GGNOMAD_OVERVIEW_QUERY as TypedDocumentNode<\n {\n ggnomadOverviewStats: {\n users: number;\n listings: number;\n bookings: number;\n monthlyRevenue: number;\n };\n ggnomadAnalytics: {\n totalRevenue: number;\n totalBookings: number;\n totalUsers: number;\n conversionRate: number;\n revenueByCategory: Record<string, unknown>;\n };\n },\n Record<string, never>\n >\n );\n const bookings = useQuery(\n GGNOMAD_BOOKINGS_QUERY as TypedDocumentNode<\n {\n ggnomadBookings: Array<{\n id: string;\n referenceCode: string;\n itemName: string;\n status: string;\n }>;\n },\n { first: number; skip: number }\n >,\n {\n variables: { first: 5, skip: 0 },\n }\n );\n const properties = useQuery(\n GGNOMAD_PROPERTIES_QUERY as TypedDocumentNode<\n { ggnomadProperties: Array<{ id: string }> },\n { first: number; skip: number }\n >,\n { variables: { first: 4, skip: 0 } }\n );\n const tours = useQuery(\n GGNOMAD_TOURS_QUERY as TypedDocumentNode<\n { ggnomadTours: Array<{ id: string }> },\n { first: number; skip: number }\n >,\n {\n variables: { first: 4, skip: 0 },\n }\n );\n const events = useQuery(\n GGNOMAD_EVENTS_QUERY as TypedDocumentNode<\n { ggnomadEvents: Array<{ id: string }> },\n { first: number; skip: number }\n >,\n {\n variables: { first: 4, skip: 0 },\n }\n );\n\n const stats = overview.data?.ggnomadOverviewStats;\n const analytics = overview.data?.ggnomadAnalytics;\n const recentBookings = bookings.data?.ggnomadBookings ?? [];\n\n const categories = useMemo(() => {\n const raw = analytics?.revenueByCategory ?? {};\n return Object.entries(raw)\n .map(([key, value]) => ({ label: humanizeCategory(key), value: Number(value) }))\n .filter((entry) => Number.isFinite(entry.value) && entry.value > 0)\n .sort((a, b) => b.value - a.value);\n }, [analytics?.revenueByCategory]);\n\n const maxCategory = categories.length > 0 ? categories[0].value : 0;\n\n return (\n <PageShell\n hero\n title={t('ggnomad.dashboard.title', 'GGNomad Dashboard')}\n titleAccent={t('ggnomad.dashboard.title.accent', 'GGNomad')}\n subtitle={t(\n 'ggnomad.dashboard.subtitle',\n 'Unified travel, hospitality, tourism and entertainment operations'\n )}\n >\n <PagePurpose icon={<Compass className=\"size-4\" />}>\n {t(\n 'ggnomad.dashboard.purpose',\n 'Your command centre for the whole GGNomad marketplace — see live revenue, users, listings and bookings across travel, hospitality, tourism and entertainment in one place, and jump straight into the area you want to work on.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"ggnomad-dashboard\"\n steps={[\n {\n id: 'search',\n label: t('ggnomad.dashboard.next.search', 'Search the catalogue'),\n description: t(\n 'ggnomad.dashboard.next.searchDesc',\n 'Find inventory across every domain at once.'\n ),\n icon: <Search className=\"size-4\" />,\n onClick: () => navigate('search'),\n },\n {\n id: 'stays',\n label: t('ggnomad.dashboard.next.stays', 'Browse places to stay'),\n description: t(\n 'ggnomad.dashboard.next.staysDesc',\n 'Explore hospitality listings and open a property.'\n ),\n icon: <Hotel className=\"size-4\" />,\n onClick: () => navigate('hospitality'),\n },\n {\n id: 'tourism',\n label: t('ggnomad.dashboard.next.tourism', 'Discover tours & activities'),\n description: t(\n 'ggnomad.dashboard.next.tourismDesc',\n 'Plan what to do at each destination.'\n ),\n icon: <Compass className=\"size-4\" />,\n onClick: () => navigate('tourism'),\n },\n {\n id: 'bookings',\n label: t('ggnomad.dashboard.next.bookings', 'Manage bookings'),\n description: t(\n 'ggnomad.dashboard.next.bookingsDesc',\n 'Track and cancel reservations in real time.'\n ),\n icon: <CalendarCheck className=\"size-4\" />,\n onClick: () => navigate('bookings'),\n },\n ]}\n />\n\n <section className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <StatCard\n hero\n label={t('ggnomad.dashboard.stats.monthlyRevenue', 'Monthly Revenue')}\n value={`$${Number(stats?.monthlyRevenue ?? 0).toLocaleString()}`}\n icon={<DollarSign />}\n />\n <StatCard\n label={t('ggnomad.dashboard.stats.users', 'Users')}\n value={Number(stats?.users ?? 0).toLocaleString()}\n icon={<Users />}\n />\n <StatCard\n label={t('ggnomad.dashboard.stats.listings', 'Listings')}\n value={Number(stats?.listings ?? 0).toLocaleString()}\n icon={<Building />}\n />\n <StatCard\n label={t('ggnomad.dashboard.stats.bookings', 'Bookings')}\n value={Number(stats?.bookings ?? 0).toLocaleString()}\n icon={<CalendarCheck />}\n />\n </section>\n\n <EmphasisPanel>\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('ggnomad.dashboard.inventory.properties', 'Properties')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {properties.data?.ggnomadProperties?.length ?? 0}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('ggnomad.dashboard.inventory.tours', 'Tours')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {tours.data?.ggnomadTours?.length ?? 0}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('ggnomad.dashboard.inventory.events', 'Events')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {events.data?.ggnomadEvents?.length ?? 0}\n </p>\n </div>\n </div>\n <p className=\"mt-4 text-sm text-text-secondary\">\n {t(\n 'ggnomad.dashboard.inventory.liveDataNotice',\n 'Data is live from `wspace-ggnomad-svc` GraphQL APIs.'\n )}\n </p>\n </EmphasisPanel>\n\n <SectionCard title={t('ggnomad.dashboard.sections.recentBookings', 'Recent bookings')}>\n {recentBookings.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('ggnomad.dashboard.recentBookings.emptyTitle', 'No recent bookings')}\n description={t(\n 'ggnomad.dashboard.recentBookings.emptyDescription',\n 'New bookings across travel, hospitality and tourism will appear here.'\n )}\n />\n ) : (\n <ul className=\"space-y-2 text-sm\">\n {recentBookings.map((booking) => (\n <li\n key={booking.id}\n className=\"flex items-center justify-between gap-3 rounded-lg border border-border-seam bg-bg-surface/40 p-3\"\n >\n <span className=\"min-w-0 truncate text-text-primary\">\n {booking.referenceCode} — {booking.itemName}\n </span>\n <StatusBadge status={booking.status} />\n </li>\n ))}\n </ul>\n )}\n </SectionCard>\n\n <SectionCard title={t('ggnomad.dashboard.sections.revenueByCategory', 'Revenue by category')}>\n {categories.length === 0 ? (\n <div className=\"flex flex-col items-center gap-2 py-8 text-center\">\n <span className=\"flex size-10 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-secondary\">\n <DollarSign className=\"size-5\" />\n </span>\n <p className=\"text-sm font-medium text-text-primary\">\n {t('ggnomad.dashboard.empty.title', 'Revenue data coming soon')}\n </p>\n <p className=\"max-w-sm text-sm text-text-secondary\">\n {t(\n 'ggnomad.dashboard.empty.description',\n 'Revenue by category appears here as bookings come in across stays, tours and events.'\n )}\n </p>\n </div>\n ) : (\n <ul className=\"flex flex-col gap-4\">\n {categories.map((category, index) => {\n const pct = maxCategory > 0 ? Math.max((category.value / maxCategory) * 100, 2) : 0;\n return (\n <li key={category.label}>\n <div className=\"flex items-baseline justify-between gap-3\">\n <span className=\"truncate text-sm font-medium text-text-primary\">\n {category.label}\n </span>\n <span className=\"flex-shrink-0 text-sm tabular-nums text-text-secondary\">\n ${category.value.toLocaleString()}\n </span>\n </div>\n <div className=\"mt-1.5 h-2.5 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full transition-[width] duration-500 ease-out\"\n style={{\n width: `${pct}%`,\n backgroundColor: CHART_COLORS[index % CHART_COLORS.length],\n }}\n />\n </div>\n </li>\n );\n })}\n </ul>\n )}\n </SectionCard>\n </PageShell>\n );\n}\n"],"mappings":"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"}