@burdenoff/microfe-brainyrich 2026.525.1 → 2026.706.1

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.
Files changed (66) hide show
  1. package/dist/brainyrich/BrainyRichRoot.js +55 -90
  2. package/dist/brainyrich/BrainyRichRoot.js.map +1 -1
  3. package/dist/brainyrich/BrainyRichRoutes.js +15 -35
  4. package/dist/brainyrich/BrainyRichRoutes.js.map +1 -1
  5. package/dist/brainyrich/components/ActorName.js +38 -0
  6. package/dist/brainyrich/components/ActorName.js.map +1 -0
  7. package/dist/brainyrich/components/ConfirmDialog.js +25 -0
  8. package/dist/brainyrich/components/ConfirmDialog.js.map +1 -0
  9. package/dist/brainyrich/components/LoadMore.js +24 -0
  10. package/dist/brainyrich/components/LoadMore.js.map +1 -0
  11. package/dist/brainyrich/components/index.js +5 -0
  12. package/dist/brainyrich/components/notify.js +38 -0
  13. package/dist/brainyrich/components/notify.js.map +1 -0
  14. package/dist/brainyrich/components/pickers.js +232 -0
  15. package/dist/brainyrich/components/pickers.js.map +1 -0
  16. package/dist/brainyrich/components/reuse/CommentThread.js +208 -0
  17. package/dist/brainyrich/components/reuse/CommentThread.js.map +1 -0
  18. package/dist/brainyrich/components/reuse/DocumentsPanel.js +237 -0
  19. package/dist/brainyrich/components/reuse/DocumentsPanel.js.map +1 -0
  20. package/dist/brainyrich/components/reuse/TagField.js +206 -0
  21. package/dist/brainyrich/components/reuse/TagField.js.map +1 -0
  22. package/dist/brainyrich/components/reuse/transport.js +24 -0
  23. package/dist/brainyrich/components/reuse/transport.js.map +1 -0
  24. package/dist/brainyrich/hooks/useBrainyRichApi.js +815 -0
  25. package/dist/brainyrich/hooks/useBrainyRichApi.js.map +1 -0
  26. package/dist/brainyrich/index.js +0 -1
  27. package/dist/brainyrich/pages/AccountsPage.js +743 -160
  28. package/dist/brainyrich/pages/AccountsPage.js.map +1 -1
  29. package/dist/brainyrich/pages/AiAssistantPage.js +556 -363
  30. package/dist/brainyrich/pages/AiAssistantPage.js.map +1 -1
  31. package/dist/brainyrich/pages/AnalyticsPage.js +601 -268
  32. package/dist/brainyrich/pages/AnalyticsPage.js.map +1 -1
  33. package/dist/brainyrich/pages/DashboardPage.js +375 -231
  34. package/dist/brainyrich/pages/DashboardPage.js.map +1 -1
  35. package/dist/brainyrich/pages/FamilyPage.js +599 -337
  36. package/dist/brainyrich/pages/FamilyPage.js.map +1 -1
  37. package/dist/brainyrich/pages/GoalsPage.js +810 -141
  38. package/dist/brainyrich/pages/GoalsPage.js.map +1 -1
  39. package/dist/brainyrich/pages/InvestmentsPage.js +410 -311
  40. package/dist/brainyrich/pages/InvestmentsPage.js.map +1 -1
  41. package/dist/brainyrich/pages/PortfoliosPage.js +867 -156
  42. package/dist/brainyrich/pages/PortfoliosPage.js.map +1 -1
  43. package/dist/brainyrich/pages/ReportsPage.js +421 -251
  44. package/dist/brainyrich/pages/ReportsPage.js.map +1 -1
  45. package/dist/brainyrich/pages/RiskPage.js +557 -194
  46. package/dist/brainyrich/pages/RiskPage.js.map +1 -1
  47. package/dist/brainyrich/pages/TaxPage.js +655 -221
  48. package/dist/brainyrich/pages/TaxPage.js.map +1 -1
  49. package/dist/brainyrich/pages/_shared.js +222 -41
  50. package/dist/brainyrich/pages/_shared.js.map +1 -1
  51. package/dist/index.js +2 -3
  52. package/dist/node_modules/sonner/dist/index.js +163 -0
  53. package/dist/node_modules/sonner/dist/index.js.map +1 -0
  54. package/package.json +3 -2
  55. package/dist/brainyrich/pages/AdvisorsPage.js +0 -375
  56. package/dist/brainyrich/pages/AdvisorsPage.js.map +0 -1
  57. package/dist/brainyrich/pages/AssistantPage.js +0 -332
  58. package/dist/brainyrich/pages/AssistantPage.js.map +0 -1
  59. package/dist/brainyrich/pages/EstatePage.js +0 -269
  60. package/dist/brainyrich/pages/EstatePage.js.map +0 -1
  61. package/dist/brainyrich/pages/InsurancePage.js +0 -181
  62. package/dist/brainyrich/pages/InsurancePage.js.map +0 -1
  63. package/dist/brainyrich/pages/MarketplacePage.js +0 -450
  64. package/dist/brainyrich/pages/MarketplacePage.js.map +0 -1
  65. package/dist/brainyrich/store/brainyrichStore.js +0 -272
  66. package/dist/brainyrich/store/brainyrichStore.js.map +0 -1
@@ -1,316 +1,649 @@
1
- import { useBrainyRichStore as e } from "../store/brainyrichStore.js";
2
- import { KpiGrid as t, SectionShell as n, formatMoney as r } from "./_shared.js";
3
- import { BarChart3 as i, Download as a } from "lucide-react";
4
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
5
- import { Button as c, Card as l, CardContent as u, CardDescription as d, CardHeader as f, CardTitle as p, Tabs as m, TabsContent as h, TabsList as g, TabsTrigger as _ } from "@burdenoff/fe-libs/ui";
1
+ import { useAccounts as e, useAllTransactions as t, useHoldings as n, useNetWorthSummary as r, useRecordTransaction as i } from "../hooks/useBrainyRichApi.js";
2
+ import { AllocationBars as a, EmptyState as o, ErrorState as ee, KpiGrid as te, LoadingState as s, SectionShell as ne, formatDate as re, formatMoney as c, formatPct as ie } from "./_shared.js";
3
+ import { useMemo as l, useState as ae } from "react";
4
+ import { ArrowDownRight as oe, ArrowUpRight as se, BarChart3 as u, Minus as d, PieChart as ce, Plus as le, Wallet as f } from "lucide-react";
5
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
6
+ import { Badge as ue, Button as h, Card as g, CardContent as _, CardDescription as v, CardHeader as y, CardTitle as b, Dialog as de, DialogContent as fe, DialogDescription as pe, DialogFooter as me, DialogHeader as he, DialogTitle as ge, DialogTrigger as _e, Input as x, Label as S, Select as C, SelectContent as w, SelectItem as T, SelectTrigger as E, SelectValue as D, Table as O, TableBody as k, TableCell as A, TableHead as j, TableHeader as M, TableRow as N, Tabs as ve, TabsContent as P, TabsList as ye, TabsTrigger as F, Textarea as be } from "@burdenoff/fe-libs/ui";
6
7
  //#region src/brainyrich/pages/AnalyticsPage.tsx
7
- var v = [
8
- {
9
- month: "Jan",
10
- portfolio: 91e4,
11
- benchmark: 895e3
12
- },
13
- {
14
- month: "Feb",
15
- portfolio: 928e3,
16
- benchmark: 91e4
17
- },
18
- {
19
- month: "Mar",
20
- portfolio: 922e3,
21
- benchmark: 905e3
22
- },
23
- {
24
- month: "Apr",
25
- portfolio: 945e3,
26
- benchmark: 92e4
27
- },
28
- {
29
- month: "May",
30
- portfolio: 948e3,
31
- benchmark: 925e3
32
- },
33
- {
34
- month: "Jun",
35
- portfolio: 97e4,
36
- benchmark: 94e4
8
+ var I = (e) => e.toLowerCase().split("_").map((e) => e && e[0].toUpperCase() + e.slice(1)).join(" "), L = [
9
+ "DEPOSIT",
10
+ "DIVIDEND",
11
+ "INTEREST",
12
+ "SELL"
13
+ ], R = [
14
+ "WITHDRAWAL",
15
+ "FEE",
16
+ "BUY"
17
+ ], z = (e) => L.includes(e) ? "in" : R.includes(e) ? "out" : "neutral", xe = (e) => {
18
+ let t = new Date(e);
19
+ return Number.isNaN(t.getTime()) ? null : {
20
+ key: `${t.getFullYear()}-${String(t.getMonth() + 1).padStart(2, "0")}`,
21
+ label: new Intl.DateTimeFormat("en-US", {
22
+ month: "short",
23
+ year: "numeric"
24
+ }).format(t)
25
+ };
26
+ }, Se = (e) => {
27
+ let t = /* @__PURE__ */ new Map();
28
+ for (let n of e) {
29
+ let e = xe(n.tradeDate);
30
+ if (!e) continue;
31
+ let r = z(n.type);
32
+ if (r === "neutral") continue;
33
+ let i = Math.abs(n.amount), a = t.get(e.key) ?? {
34
+ key: e.key,
35
+ label: e.label,
36
+ inflow: 0,
37
+ outflow: 0
38
+ };
39
+ r === "in" ? a.inflow += i : a.outflow += i, t.set(e.key, a);
37
40
  }
38
- ], y = [
39
- {
40
- month: "Jan",
41
- income: 185e3,
42
- expenses: 92e3,
43
- savings: 93e3
44
- },
45
- {
46
- month: "Feb",
47
- income: 185e3,
48
- expenses: 98e3,
49
- savings: 87e3
50
- },
51
- {
52
- month: "Mar",
53
- income: 195e3,
54
- expenses: 88e3,
55
- savings: 107e3
56
- },
57
- {
58
- month: "Apr",
59
- income: 185e3,
60
- expenses: 95e3,
61
- savings: 9e4
62
- },
63
- {
64
- month: "May",
65
- income: 185e3,
66
- expenses: 91e3,
67
- savings: 94e3
68
- },
69
- {
70
- month: "Jun",
71
- income: 2e5,
72
- expenses: 99e3,
73
- savings: 101e3
74
- }
75
- ], b = Math.max(...v.map((e) => e.portfolio)), x = Math.max(...y.map((e) => e.income));
76
- function S() {
77
- let { portfolios: S, holdings: C } = e(), w = S.reduce((e, t) => e + t.value, 0);
78
- return /* @__PURE__ */ s(n, {
41
+ return Array.from(t.values()).sort((e, t) => e.key.localeCompare(t.key));
42
+ }, Ce = (e) => {
43
+ let t = /* @__PURE__ */ new Map();
44
+ for (let n of e) t.set(n.type, (t.get(n.type) ?? 0) + Math.abs(n.amount));
45
+ return Array.from(t.entries()).map(([e, t]) => ({
46
+ type: e,
47
+ total: t,
48
+ dir: z(e)
49
+ })).sort((e, t) => t.total - e.total);
50
+ };
51
+ function we({ value: e, currency: t }) {
52
+ let n = e > 0, r = e < 0, i = n ? se : r ? oe : d, a = n ? "text-status-success-text" : r ? "text-status-error-text" : "text-text-secondary", o = n ? "+" : r ? "-" : "";
53
+ return /* @__PURE__ */ m("span", {
54
+ className: `inline-flex items-center justify-end gap-1 font-medium ${a}`,
55
+ children: [
56
+ /* @__PURE__ */ p(i, {
57
+ className: "size-3.5",
58
+ "aria-hidden": "true"
59
+ }),
60
+ o,
61
+ c(Math.abs(e), t)
62
+ ]
63
+ });
64
+ }
65
+ var Te = {
66
+ accountId: "",
67
+ type: "DEPOSIT",
68
+ amount: "",
69
+ symbol: "",
70
+ tradeDate: "",
71
+ notes: ""
72
+ }, Ee = [
73
+ "DEPOSIT",
74
+ "WITHDRAWAL",
75
+ "DIVIDEND",
76
+ "INTEREST",
77
+ "FEE",
78
+ "BUY",
79
+ "SELL",
80
+ "TRANSFER"
81
+ ];
82
+ function B() {
83
+ let d = r(), L = t(), R = e(), [z, xe] = ae(void 0), B = R.data, De = z ?? B[0]?.id, V = n({ accountId: De }), H = i(), [Oe, U] = ae(!1), [W, G] = ae(Te), K = d.data, q = K?.currency ?? "USD", J = L.data, ke = l(() => !K || K.totalMarketValue <= 0 ? [] : K.byAssetClass.filter((e) => e.marketValue !== 0).map((e) => ({
84
+ label: I(e.assetClass),
85
+ value: e.marketValue / K.totalMarketValue * 100,
86
+ caption: c(e.marketValue, q),
87
+ tone: "accent"
88
+ })).sort((e, t) => t.value - e.value), [K, q]), Ae = l(() => {
89
+ if (!K) return [];
90
+ let e = K.totalMarketValue + K.totalCash;
91
+ return e <= 0 ? [] : [{
92
+ label: "Invested (Market Value)",
93
+ value: K.totalMarketValue / e * 100,
94
+ caption: c(K.totalMarketValue, q),
95
+ tone: "default"
96
+ }, {
97
+ label: "Cash",
98
+ value: K.totalCash / e * 100,
99
+ caption: c(K.totalCash, q),
100
+ tone: "warning"
101
+ }];
102
+ }, [K, q]), Y = l(() => Se(J), [J]), je = l(() => Ce(J), [J]), X = l(() => {
103
+ let e = 0, t = 0;
104
+ for (let n of Y) e += n.inflow, t += n.outflow;
105
+ return {
106
+ inflow: e,
107
+ outflow: t,
108
+ net: e - t
109
+ };
110
+ }, [Y]), Z = l(() => Math.max(1, ...Y.map((e) => Math.max(e.inflow, e.outflow))), [Y]), Me = V.data, Q = l(() => {
111
+ let e = Me.map((e) => ({
112
+ holding: e,
113
+ unrealized: e.marketValue - e.costBasis
114
+ })).sort((e, t) => t.unrealized - e.unrealized);
115
+ return {
116
+ rows: e,
117
+ totalUnrealized: e.reduce((e, t) => e + t.unrealized, 0),
118
+ totalCost: Me.reduce((e, t) => e + t.costBasis, 0)
119
+ };
120
+ }, [Me]);
121
+ if (d.isLoading) return /* @__PURE__ */ p(ne, {
122
+ title: "Wealth Analytics",
123
+ description: "Allocation, cash flow, and holdings performance derived from your real accounts.",
124
+ children: /* @__PURE__ */ p(s, { rows: 5 })
125
+ });
126
+ if (d.isError || !K) return /* @__PURE__ */ p(ne, {
127
+ title: "Wealth Analytics",
128
+ description: "Allocation, cash flow, and holdings performance derived from your real accounts.",
129
+ children: /* @__PURE__ */ p(ee, {
130
+ title: "Could not load analytics",
131
+ description: "We couldn't reach the wealth service. Please retry.",
132
+ onRetry: () => d.refetch()
133
+ })
134
+ });
135
+ let $ = Number(W.amount), Ne = !!W.accountId && !!W.tradeDate && W.amount.trim() !== "" && Number.isFinite($) && $ > 0 && !H.isPending, Pe = /* @__PURE__ */ m(de, {
136
+ open: Oe,
137
+ onOpenChange: (e) => {
138
+ U(e), e || G(Te);
139
+ },
140
+ children: [/* @__PURE__ */ p(_e, {
141
+ asChild: !0,
142
+ children: /* @__PURE__ */ m(h, {
143
+ size: "sm",
144
+ children: [/* @__PURE__ */ p(le, {
145
+ className: "mr-1 size-4",
146
+ "aria-hidden": "true"
147
+ }), "Record Transaction"]
148
+ })
149
+ }), /* @__PURE__ */ m(fe, { children: [
150
+ /* @__PURE__ */ m(he, { children: [/* @__PURE__ */ p(ge, { children: "Record Transaction" }), /* @__PURE__ */ p(pe, { children: "Log a real cash flow or trade. It updates your cash-flow analytics immediately." })] }),
151
+ B.length === 0 ? /* @__PURE__ */ p(o, {
152
+ icon: /* @__PURE__ */ p(f, {
153
+ className: "size-6",
154
+ "aria-hidden": "true"
155
+ }),
156
+ title: "Create an account first",
157
+ description: "You need at least one account before you can record a transaction. Open the Accounts page to add one, then come back here."
158
+ }) : /* @__PURE__ */ m("div", {
159
+ className: "space-y-4",
160
+ children: [
161
+ /* @__PURE__ */ m("div", {
162
+ className: "space-y-1.5",
163
+ children: [/* @__PURE__ */ p(S, {
164
+ htmlFor: "tx-account",
165
+ children: "Account"
166
+ }), /* @__PURE__ */ m(C, {
167
+ value: W.accountId,
168
+ onValueChange: (e) => G((t) => ({
169
+ ...t,
170
+ accountId: e
171
+ })),
172
+ children: [/* @__PURE__ */ p(E, {
173
+ id: "tx-account",
174
+ children: /* @__PURE__ */ p(D, { placeholder: "Select an account" })
175
+ }), /* @__PURE__ */ p(w, { children: B.map((e) => /* @__PURE__ */ p(T, {
176
+ value: e.id,
177
+ children: e.name
178
+ }, e.id)) })]
179
+ })]
180
+ }),
181
+ /* @__PURE__ */ m("div", {
182
+ className: "grid grid-cols-2 gap-4",
183
+ children: [/* @__PURE__ */ m("div", {
184
+ className: "space-y-1.5",
185
+ children: [/* @__PURE__ */ p(S, {
186
+ htmlFor: "tx-type",
187
+ children: "Type"
188
+ }), /* @__PURE__ */ m(C, {
189
+ value: W.type,
190
+ onValueChange: (e) => G((t) => ({
191
+ ...t,
192
+ type: e
193
+ })),
194
+ children: [/* @__PURE__ */ p(E, {
195
+ id: "tx-type",
196
+ children: /* @__PURE__ */ p(D, {})
197
+ }), /* @__PURE__ */ p(w, { children: Ee.map((e) => /* @__PURE__ */ p(T, {
198
+ value: e,
199
+ children: I(e)
200
+ }, e)) })]
201
+ })]
202
+ }), /* @__PURE__ */ m("div", {
203
+ className: "space-y-1.5",
204
+ children: [/* @__PURE__ */ m(S, {
205
+ htmlFor: "tx-amount",
206
+ children: [
207
+ "Amount (",
208
+ q,
209
+ ")"
210
+ ]
211
+ }), /* @__PURE__ */ p(x, {
212
+ id: "tx-amount",
213
+ type: "number",
214
+ min: "0",
215
+ step: "0.01",
216
+ inputMode: "decimal",
217
+ placeholder: "0.00",
218
+ value: W.amount,
219
+ onChange: (e) => G((t) => ({
220
+ ...t,
221
+ amount: e.target.value
222
+ }))
223
+ })]
224
+ })]
225
+ }),
226
+ /* @__PURE__ */ m("div", {
227
+ className: "grid grid-cols-2 gap-4",
228
+ children: [/* @__PURE__ */ m("div", {
229
+ className: "space-y-1.5",
230
+ children: [/* @__PURE__ */ p(S, {
231
+ htmlFor: "tx-date",
232
+ children: "Trade date"
233
+ }), /* @__PURE__ */ p(x, {
234
+ id: "tx-date",
235
+ type: "date",
236
+ value: W.tradeDate,
237
+ onChange: (e) => G((t) => ({
238
+ ...t,
239
+ tradeDate: e.target.value
240
+ }))
241
+ })]
242
+ }), /* @__PURE__ */ m("div", {
243
+ className: "space-y-1.5",
244
+ children: [/* @__PURE__ */ p(S, {
245
+ htmlFor: "tx-symbol",
246
+ children: "Symbol (optional)"
247
+ }), /* @__PURE__ */ p(x, {
248
+ id: "tx-symbol",
249
+ placeholder: "e.g. AAPL",
250
+ value: W.symbol,
251
+ onChange: (e) => G((t) => ({
252
+ ...t,
253
+ symbol: e.target.value
254
+ }))
255
+ })]
256
+ })]
257
+ }),
258
+ /* @__PURE__ */ m("div", {
259
+ className: "space-y-1.5",
260
+ children: [/* @__PURE__ */ p(S, {
261
+ htmlFor: "tx-notes",
262
+ children: "Notes (optional)"
263
+ }), /* @__PURE__ */ p(be, {
264
+ id: "tx-notes",
265
+ rows: 2,
266
+ placeholder: "Context for this transaction",
267
+ value: W.notes,
268
+ onChange: (e) => G((t) => ({
269
+ ...t,
270
+ notes: e.target.value
271
+ }))
272
+ })]
273
+ }),
274
+ H.isError ? /* @__PURE__ */ p("p", {
275
+ className: "text-sm text-status-error-text",
276
+ children: H.error instanceof Error ? H.error.message : "Could not record transaction."
277
+ }) : null
278
+ ]
279
+ }),
280
+ /* @__PURE__ */ m(me, { children: [/* @__PURE__ */ p(h, {
281
+ variant: "outline",
282
+ onClick: () => U(!1),
283
+ children: B.length === 0 ? "Close" : "Cancel"
284
+ }), B.length > 0 ? /* @__PURE__ */ p(h, {
285
+ onClick: () => {
286
+ Ne && H.mutate({
287
+ accountId: W.accountId,
288
+ type: W.type,
289
+ amount: $,
290
+ symbol: W.symbol.trim() ? W.symbol.trim() : void 0,
291
+ tradeDate: new Date(W.tradeDate).toISOString(),
292
+ notes: W.notes.trim() ? W.notes.trim() : void 0
293
+ }, { onSuccess: () => {
294
+ U(!1), G(Te);
295
+ } });
296
+ },
297
+ disabled: !Ne,
298
+ children: H.isPending ? "Recording…" : "Record"
299
+ }) : null] })
300
+ ] })]
301
+ });
302
+ return /* @__PURE__ */ m(ne, {
79
303
  title: "Wealth Analytics",
80
- description: "Comprehensive insights into your wealth performance and financial flows",
81
- actionLabel: "Export PDF",
82
- badges: ["Live Analytics"],
83
- children: [/* @__PURE__ */ o(t, { items: [
304
+ description: "Allocation, cash flow, and holdings performance derived from your real accounts.",
305
+ badges: [`${K.accountCount} accounts`],
306
+ actions: Pe,
307
+ children: [/* @__PURE__ */ p(te, { items: [
84
308
  {
85
- label: "Total Returns",
86
- value: "+12.4%",
87
- trend: "+2.3% vs last month"
309
+ label: "Net Worth",
310
+ value: c(K.totalNetWorth, q)
88
311
  },
89
312
  {
90
- label: "Portfolio Value",
91
- value: r(w),
92
- trend: "+$85K YTD"
313
+ label: "Invested Value",
314
+ value: c(K.totalMarketValue, q)
93
315
  },
94
316
  {
95
- label: "Monthly Savings",
96
- value: r(94e3),
97
- trend: "51% savings rate"
317
+ label: "Cash",
318
+ value: c(K.totalCash, q)
98
319
  },
99
320
  {
100
- label: "Goals Progress",
101
- value: "68%",
102
- trend: "+7.4% this quarter"
321
+ label: "Net Cash Flow",
322
+ value: c(X.net, q),
323
+ deltaTone: X.net > 0 ? "positive" : X.net < 0 ? "negative" : "neutral",
324
+ trend: J.length > 0 ? `${c(X.inflow, q)} in · ${c(X.outflow, q)} out` : "No transactions yet"
103
325
  }
104
- ] }), /* @__PURE__ */ s(m, {
105
- defaultValue: "performance",
326
+ ] }), /* @__PURE__ */ m(ve, {
327
+ defaultValue: "allocation",
106
328
  className: "space-y-4",
107
329
  children: [
108
- /* @__PURE__ */ s(g, {
330
+ /* @__PURE__ */ m(ye, {
109
331
  className: "grid w-full grid-cols-3",
110
332
  children: [
111
- /* @__PURE__ */ o(_, {
112
- value: "performance",
113
- children: "Performance"
114
- }),
115
- /* @__PURE__ */ o(_, {
333
+ /* @__PURE__ */ p(F, {
116
334
  value: "allocation",
117
335
  children: "Allocation"
118
336
  }),
119
- /* @__PURE__ */ o(_, {
337
+ /* @__PURE__ */ p(F, {
120
338
  value: "cashflow",
121
339
  children: "Cash Flow"
340
+ }),
341
+ /* @__PURE__ */ p(F, {
342
+ value: "performance",
343
+ children: "Performance"
122
344
  })
123
345
  ]
124
346
  }),
125
- /* @__PURE__ */ s(h, {
126
- value: "performance",
347
+ /* @__PURE__ */ m(P, {
348
+ value: "allocation",
349
+ className: "space-y-4",
350
+ children: [/* @__PURE__ */ m(g, { children: [/* @__PURE__ */ m(y, { children: [/* @__PURE__ */ m(b, {
351
+ className: "flex items-center gap-2",
352
+ children: [/* @__PURE__ */ p(ce, {
353
+ className: "size-5",
354
+ "aria-hidden": "true"
355
+ }), "Asset Allocation"]
356
+ }), /* @__PURE__ */ p(v, { children: "Share of invested value by asset class, from your holdings." })] }), /* @__PURE__ */ p(_, { children: ke.length === 0 ? /* @__PURE__ */ p(o, {
357
+ icon: /* @__PURE__ */ p(ce, {
358
+ className: "size-6",
359
+ "aria-hidden": "true"
360
+ }),
361
+ title: "No invested holdings yet",
362
+ description: "Add holdings to your accounts to see an asset-class breakdown here."
363
+ }) : /* @__PURE__ */ m("div", {
364
+ className: "space-y-4",
365
+ children: [/* @__PURE__ */ p(a, { data: ke }), /* @__PURE__ */ m(O, { children: [/* @__PURE__ */ p(M, { children: /* @__PURE__ */ m(N, { children: [
366
+ /* @__PURE__ */ p(j, { children: "Asset class" }),
367
+ /* @__PURE__ */ p(j, {
368
+ className: "text-right",
369
+ children: "Market value"
370
+ }),
371
+ /* @__PURE__ */ p(j, {
372
+ className: "text-right",
373
+ children: "Weight"
374
+ })
375
+ ] }) }), /* @__PURE__ */ p(k, { children: ke.map((e) => /* @__PURE__ */ m(N, { children: [
376
+ /* @__PURE__ */ p(A, {
377
+ className: "font-medium text-text-primary",
378
+ children: e.label
379
+ }),
380
+ /* @__PURE__ */ p(A, {
381
+ className: "text-right",
382
+ children: e.caption
383
+ }),
384
+ /* @__PURE__ */ p(A, {
385
+ className: "text-right text-text-secondary",
386
+ children: ie(e.value)
387
+ })
388
+ ] }, e.label)) })] })]
389
+ }) })] }), /* @__PURE__ */ m(g, { children: [/* @__PURE__ */ m(y, { children: [/* @__PURE__ */ m(b, {
390
+ className: "flex items-center gap-2",
391
+ children: [/* @__PURE__ */ p(f, {
392
+ className: "size-5",
393
+ "aria-hidden": "true"
394
+ }), "Net Worth Composition"]
395
+ }), /* @__PURE__ */ p(v, { children: "Invested value versus liquid cash." })] }), /* @__PURE__ */ p(_, { children: Ae.length === 0 ? /* @__PURE__ */ p(o, {
396
+ icon: /* @__PURE__ */ p(f, {
397
+ className: "size-6",
398
+ "aria-hidden": "true"
399
+ }),
400
+ title: "No balances yet",
401
+ description: "Add accounts with balances or holdings to see your composition."
402
+ }) : /* @__PURE__ */ p(a, { data: Ae }) })] })]
403
+ }),
404
+ /* @__PURE__ */ m(P, {
405
+ value: "cashflow",
127
406
  className: "space-y-4",
128
- children: [/* @__PURE__ */ s(l, { children: [/* @__PURE__ */ s(f, {
129
- className: "flex flex-row items-center justify-between",
130
- children: [/* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o(p, { children: "Portfolio vs Benchmark" }), /* @__PURE__ */ o(d, { children: "6-month performance comparison (CSS bar chart)" })] }), /* @__PURE__ */ s(c, {
131
- variant: "outline",
407
+ children: [/* @__PURE__ */ m(g, { children: [/* @__PURE__ */ m(y, { children: [/* @__PURE__ */ m(b, {
408
+ className: "flex items-center gap-2",
409
+ children: [/* @__PURE__ */ p(u, {
410
+ className: "size-5",
411
+ "aria-hidden": "true"
412
+ }), "Inflows vs Outflows"]
413
+ }), /* @__PURE__ */ m(v, { children: ["Monthly cash flow aggregated from your recorded transactions.", J.length > 0 ? /* @__PURE__ */ m("span", {
414
+ className: "mt-0.5 block text-xs text-text-secondary",
415
+ children: [
416
+ "Based on ",
417
+ J.length.toLocaleString(),
418
+ " ",
419
+ J.length === 1 ? "transaction" : "transactions",
420
+ "."
421
+ ]
422
+ }) : null] })] }), /* @__PURE__ */ p(_, { children: L.isLoading ? /* @__PURE__ */ p(s, { rows: 4 }) : L.isError ? /* @__PURE__ */ p(ee, { onRetry: () => L.refetch() }) : Y.length === 0 ? /* @__PURE__ */ p(o, {
423
+ icon: /* @__PURE__ */ p(u, {
424
+ className: "size-6",
425
+ "aria-hidden": "true"
426
+ }),
427
+ title: "No cash flow to analyze yet",
428
+ description: "Record deposits, withdrawals, or trades to build a cash-flow history.",
429
+ action: /* @__PURE__ */ m(h, {
132
430
  size: "sm",
133
- children: [/* @__PURE__ */ o(a, { className: "mr-1 h-4 w-4" }), "Export"]
134
- })]
135
- }), /* @__PURE__ */ s(u, {
136
- className: "space-y-3",
137
- children: [v.map((e) => /* @__PURE__ */ s("div", {
138
- className: "space-y-1",
139
- children: [/* @__PURE__ */ s("div", {
140
- className: "flex items-center justify-between text-xs text-muted-foreground",
141
- children: [/* @__PURE__ */ o("span", {
142
- className: "w-8 font-medium",
143
- children: e.month
144
- }), /* @__PURE__ */ s("span", { children: [
145
- "Portfolio: ",
146
- r(e.portfolio),
147
- " | Benchmark: ",
148
- r(e.benchmark)
149
- ] })]
150
- }), /* @__PURE__ */ s("div", {
151
- className: "relative h-5 bg-muted rounded overflow-hidden",
152
- children: [/* @__PURE__ */ o("div", {
153
- className: "absolute h-5 bg-blue-400/60 rounded",
154
- style: { width: `${e.benchmark / b * 100}%` }
155
- }), /* @__PURE__ */ o("div", {
156
- className: "absolute h-5 bg-blue-600 rounded",
157
- style: {
158
- width: `${e.portfolio / b * 100}%`,
159
- opacity: .8
160
- }
161
- })]
162
- })]
163
- }, e.month)), /* @__PURE__ */ s("div", {
164
- className: "flex gap-4 text-xs pt-2",
165
- children: [/* @__PURE__ */ s("span", {
166
- className: "flex items-center gap-1",
167
- children: [/* @__PURE__ */ o("span", { className: "h-2 w-4 bg-blue-600 rounded inline-block" }), " Portfolio"]
168
- }), /* @__PURE__ */ s("span", {
169
- className: "flex items-center gap-1",
170
- children: [/* @__PURE__ */ o("span", { className: "h-2 w-4 bg-blue-400/60 rounded inline-block" }), " Benchmark"]
171
- })]
172
- })]
173
- })] }), /* @__PURE__ */ s(l, { children: [/* @__PURE__ */ s(f, { children: [/* @__PURE__ */ o(p, { children: "Net Worth Trend" }), /* @__PURE__ */ o(d, { children: "Growth trajectory over the past 6 months" })] }), /* @__PURE__ */ o(u, {
174
- className: "space-y-2",
175
- children: v.map((e) => /* @__PURE__ */ s("div", {
176
- className: "flex items-center gap-3",
431
+ onClick: () => U(!0),
432
+ children: [/* @__PURE__ */ p(le, {
433
+ className: "mr-1 size-4",
434
+ "aria-hidden": "true"
435
+ }), "Record Transaction"]
436
+ })
437
+ }) : /* @__PURE__ */ m("div", {
438
+ className: "space-y-4",
439
+ children: [Y.map((e) => /* @__PURE__ */ m("div", {
440
+ className: "space-y-1.5",
177
441
  children: [
178
- /* @__PURE__ */ o("span", {
179
- className: "w-8 text-xs text-muted-foreground",
180
- children: e.month
442
+ /* @__PURE__ */ m("div", {
443
+ className: "flex items-center justify-between text-xs",
444
+ children: [/* @__PURE__ */ p("span", {
445
+ className: "font-medium text-text-primary",
446
+ children: e.label
447
+ }), /* @__PURE__ */ m("span", {
448
+ className: "flex gap-3",
449
+ children: [/* @__PURE__ */ m("span", {
450
+ className: "text-status-success-text",
451
+ children: [/* @__PURE__ */ p(se, {
452
+ className: "mr-0.5 inline size-3",
453
+ "aria-hidden": "true"
454
+ }), c(e.inflow, q)]
455
+ }), /* @__PURE__ */ m("span", {
456
+ className: "text-status-error-text",
457
+ children: [/* @__PURE__ */ p(oe, {
458
+ className: "mr-0.5 inline size-3",
459
+ "aria-hidden": "true"
460
+ }), c(e.outflow, q)]
461
+ })]
462
+ })]
181
463
  }),
182
- /* @__PURE__ */ o("div", {
183
- className: "flex-1 h-4 bg-muted rounded overflow-hidden",
184
- children: /* @__PURE__ */ o("div", {
185
- className: "h-4 bg-emerald-500 rounded",
186
- style: { width: `${e.portfolio / b * 100}%` }
464
+ /* @__PURE__ */ p("div", {
465
+ className: "h-2 w-full overflow-hidden rounded-full bg-bg-sunken",
466
+ role: "progressbar",
467
+ "aria-label": `${e.label} inflow`,
468
+ "aria-valuenow": Math.round(e.inflow / Z * 100),
469
+ "aria-valuemin": 0,
470
+ "aria-valuemax": 100,
471
+ children: /* @__PURE__ */ p("div", {
472
+ className: "h-full rounded-full bg-status-success-bg motion-safe:transition-[width] motion-safe:duration-200",
473
+ style: { width: `${e.inflow / Z * 100}%` }
187
474
  })
188
475
  }),
189
- /* @__PURE__ */ o("span", {
190
- className: "text-xs font-medium w-20 text-right",
191
- children: r(e.portfolio)
476
+ /* @__PURE__ */ p("div", {
477
+ className: "h-2 w-full overflow-hidden rounded-full bg-bg-sunken",
478
+ role: "progressbar",
479
+ "aria-label": `${e.label} outflow`,
480
+ "aria-valuenow": Math.round(e.outflow / Z * 100),
481
+ "aria-valuemin": 0,
482
+ "aria-valuemax": 100,
483
+ children: /* @__PURE__ */ p("div", {
484
+ className: "h-full rounded-full bg-status-error-bg motion-safe:transition-[width] motion-safe:duration-200",
485
+ style: { width: `${e.outflow / Z * 100}%` }
486
+ })
192
487
  })
193
488
  ]
194
- }, e.month))
195
- })] })]
196
- }),
197
- /* @__PURE__ */ s(h, {
198
- value: "allocation",
199
- className: "space-y-4",
200
- children: [/* @__PURE__ */ s(l, { children: [/* @__PURE__ */ s(f, { children: [/* @__PURE__ */ o(p, { children: "Asset Allocation" }), /* @__PURE__ */ o(d, { children: "Current distribution by portfolio strategy" })] }), /* @__PURE__ */ o(u, {
201
- className: "space-y-4",
202
- children: S.map((e) => {
203
- let t = Math.round(e.value / w * 100);
204
- return /* @__PURE__ */ s("div", {
205
- className: "space-y-1",
206
- children: [/* @__PURE__ */ s("div", {
207
- className: "flex justify-between text-sm",
208
- children: [/* @__PURE__ */ o("span", {
209
- className: "font-medium",
210
- children: e.name
211
- }), /* @__PURE__ */ s("span", { children: [
212
- r(e.value),
213
- " (",
214
- t,
215
- "%)"
216
- ] })]
217
- }), /* @__PURE__ */ o("div", {
218
- className: "h-4 rounded bg-muted overflow-hidden",
219
- children: /* @__PURE__ */ o("div", {
220
- className: "h-4 rounded bg-primary",
221
- style: { width: `${t}%` }
222
- })
223
- })]
224
- }, e.id);
225
- })
226
- })] }), /* @__PURE__ */ s(l, { children: [/* @__PURE__ */ s(f, { children: [/* @__PURE__ */ o(p, { children: "Sector Exposure" }), /* @__PURE__ */ o(d, { children: "Breakdown by sector from holdings" })] }), /* @__PURE__ */ o(u, { children: /* @__PURE__ */ o("div", {
227
- className: "grid gap-3 md:grid-cols-2",
228
- children: C.map((e) => /* @__PURE__ */ s("div", {
229
- className: "flex items-center justify-between rounded-lg border p-3",
230
- children: [/* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("p", {
231
- className: "text-sm font-medium",
232
- children: e.symbol
233
- }), /* @__PURE__ */ o("p", {
234
- className: "text-xs text-muted-foreground",
235
- children: e.sector
236
- })] }), /* @__PURE__ */ o("span", {
237
- className: "text-sm font-semibold",
238
- children: r(e.marketValue)
489
+ }, e.key)), /* @__PURE__ */ m("div", {
490
+ className: "flex flex-wrap gap-4 pt-1 text-xs text-text-secondary",
491
+ children: [/* @__PURE__ */ m("span", {
492
+ className: "inline-flex items-center gap-1.5",
493
+ children: [/* @__PURE__ */ p("span", { className: "inline-block size-2.5 rounded-full bg-status-success-bg" }), "Inflow"]
494
+ }), /* @__PURE__ */ m("span", {
495
+ className: "inline-flex items-center gap-1.5",
496
+ children: [/* @__PURE__ */ p("span", { className: "inline-block size-2.5 rounded-full bg-status-error-bg" }), "Outflow"]
239
497
  })]
240
- }, e.symbol))
241
- }) })] })]
498
+ })]
499
+ }) })] }), je.length > 0 ? /* @__PURE__ */ m(g, { children: [/* @__PURE__ */ m(y, { children: [/* @__PURE__ */ p(b, { children: "By Transaction Type" }), /* @__PURE__ */ p(v, { children: "Total value moved per transaction type." })] }), /* @__PURE__ */ p(_, { children: /* @__PURE__ */ m(O, { children: [/* @__PURE__ */ p(M, { children: /* @__PURE__ */ m(N, { children: [
500
+ /* @__PURE__ */ p(j, { children: "Type" }),
501
+ /* @__PURE__ */ p(j, { children: "Direction" }),
502
+ /* @__PURE__ */ p(j, {
503
+ className: "text-right",
504
+ children: "Total"
505
+ })
506
+ ] }) }), /* @__PURE__ */ p(k, { children: je.map((e) => /* @__PURE__ */ m(N, { children: [
507
+ /* @__PURE__ */ p(A, {
508
+ className: "font-medium text-text-primary",
509
+ children: I(e.type)
510
+ }),
511
+ /* @__PURE__ */ p(A, { children: /* @__PURE__ */ p(ue, {
512
+ variant: e.dir === "in" ? "default" : e.dir === "out" ? "destructive" : "secondary",
513
+ children: e.dir === "in" ? "Inflow" : e.dir === "out" ? "Outflow" : "Neutral"
514
+ }) }),
515
+ /* @__PURE__ */ p(A, {
516
+ className: "text-right font-medium",
517
+ children: c(e.total, q)
518
+ })
519
+ ] }, e.type)) })] }) })] }) : null]
242
520
  }),
243
- /* @__PURE__ */ o(h, {
244
- value: "cashflow",
521
+ /* @__PURE__ */ p(P, {
522
+ value: "performance",
245
523
  className: "space-y-4",
246
- children: /* @__PURE__ */ s(l, { children: [/* @__PURE__ */ s(f, { children: [/* @__PURE__ */ s(p, {
247
- className: "flex items-center gap-2",
248
- children: [/* @__PURE__ */ o(i, { className: "h-5 w-5" }), "Income vs Expenses"]
249
- }), /* @__PURE__ */ o(d, { children: "Monthly financial flow analysis" })] }), /* @__PURE__ */ s(u, {
250
- className: "space-y-4",
251
- children: [y.map((e) => /* @__PURE__ */ s("div", {
252
- className: "space-y-1",
253
- children: [/* @__PURE__ */ s("div", {
254
- className: "flex items-center justify-between text-xs",
255
- children: [
256
- /* @__PURE__ */ o("span", {
257
- className: "font-medium w-8",
258
- children: e.month
259
- }),
260
- /* @__PURE__ */ s("span", {
261
- className: "text-emerald-600",
262
- children: ["Income: ", r(e.income)]
263
- }),
264
- /* @__PURE__ */ s("span", {
265
- className: "text-red-500",
266
- children: ["Expenses: ", r(e.expenses)]
267
- }),
268
- /* @__PURE__ */ s("span", {
269
- className: "text-blue-600",
270
- children: ["Saved: ", r(e.savings)]
271
- })
272
- ]
273
- }), /* @__PURE__ */ s("div", {
274
- className: "flex gap-1",
275
- children: [
276
- /* @__PURE__ */ o("div", {
277
- className: "h-3 rounded bg-emerald-500",
278
- style: { width: `${e.income / x * 50}%` }
279
- }),
280
- /* @__PURE__ */ o("div", {
281
- className: "h-3 rounded bg-red-400",
282
- style: { width: `${e.expenses / x * 50}%` }
283
- }),
284
- /* @__PURE__ */ o("div", {
285
- className: "h-3 rounded bg-blue-500",
286
- style: { width: `${e.savings / x * 50}%` }
287
- })
288
- ]
524
+ children: /* @__PURE__ */ m(g, { children: [/* @__PURE__ */ m(y, {
525
+ className: "flex flex-col gap-3 md:flex-row md:items-start md:justify-between",
526
+ children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p(b, { children: "Holdings Performance" }), /* @__PURE__ */ p(v, { children: "Unrealized gain or loss — market value versus cost basis." })] }), B.length > 0 ? /* @__PURE__ */ m("div", {
527
+ className: "w-full md:w-56",
528
+ children: [/* @__PURE__ */ p(S, {
529
+ htmlFor: "perf-account",
530
+ className: "sr-only",
531
+ children: "Account"
532
+ }), /* @__PURE__ */ m(C, {
533
+ value: De ?? "",
534
+ onValueChange: (e) => xe(e),
535
+ children: [/* @__PURE__ */ p(E, {
536
+ id: "perf-account",
537
+ children: /* @__PURE__ */ p(D, { placeholder: "Select account" })
538
+ }), /* @__PURE__ */ p(w, { children: B.map((e) => /* @__PURE__ */ p(T, {
539
+ value: e.id,
540
+ children: e.name
541
+ }, e.id)) })]
289
542
  })]
290
- }, e.month)), /* @__PURE__ */ s("div", {
291
- className: "flex gap-4 text-xs pt-2",
543
+ }) : null]
544
+ }), /* @__PURE__ */ p(_, { children: R.isLoading ? /* @__PURE__ */ p(s, { rows: 3 }) : B.length === 0 ? /* @__PURE__ */ p(o, {
545
+ icon: /* @__PURE__ */ p(f, {
546
+ className: "size-6",
547
+ "aria-hidden": "true"
548
+ }),
549
+ title: "No accounts yet",
550
+ description: "Create an account and add holdings to analyze performance."
551
+ }) : V.isLoading ? /* @__PURE__ */ p(s, { rows: 3 }) : V.isError ? /* @__PURE__ */ p(ee, { onRetry: () => V.refetch() }) : Q.rows.length === 0 ? /* @__PURE__ */ p(o, {
552
+ icon: /* @__PURE__ */ p(u, {
553
+ className: "size-6",
554
+ "aria-hidden": "true"
555
+ }),
556
+ title: "No holdings in this account",
557
+ description: "Add holdings to this account to see unrealized gains and losses."
558
+ }) : /* @__PURE__ */ m("div", {
559
+ className: "space-y-4",
560
+ children: [/* @__PURE__ */ m("div", {
561
+ className: "grid gap-4 sm:grid-cols-3",
292
562
  children: [
293
- /* @__PURE__ */ s("span", {
294
- className: "flex items-center gap-1",
295
- children: [/* @__PURE__ */ o("span", { className: "h-2 w-4 bg-emerald-500 rounded inline-block" }), " Income"]
563
+ /* @__PURE__ */ m("div", {
564
+ className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
565
+ children: [/* @__PURE__ */ p("p", {
566
+ className: "text-xs text-text-secondary",
567
+ children: "Total unrealized"
568
+ }), /* @__PURE__ */ p("p", {
569
+ className: "mt-1 text-xl font-semibold",
570
+ children: /* @__PURE__ */ p(we, {
571
+ value: Q.totalUnrealized,
572
+ currency: q
573
+ })
574
+ })]
296
575
  }),
297
- /* @__PURE__ */ s("span", {
298
- className: "flex items-center gap-1",
299
- children: [/* @__PURE__ */ o("span", { className: "h-2 w-4 bg-red-400 rounded inline-block" }), " Expenses"]
576
+ /* @__PURE__ */ m("div", {
577
+ className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
578
+ children: [/* @__PURE__ */ p("p", {
579
+ className: "text-xs text-text-secondary",
580
+ children: "Cost basis"
581
+ }), /* @__PURE__ */ p("p", {
582
+ className: "mt-1 text-xl font-semibold text-text-primary",
583
+ children: c(Q.totalCost, q)
584
+ })]
300
585
  }),
301
- /* @__PURE__ */ s("span", {
302
- className: "flex items-center gap-1",
303
- children: [/* @__PURE__ */ o("span", { className: "h-2 w-4 bg-blue-500 rounded inline-block" }), " Savings"]
586
+ /* @__PURE__ */ m("div", {
587
+ className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
588
+ children: [/* @__PURE__ */ p("p", {
589
+ className: "text-xs text-text-secondary",
590
+ children: "Return on cost"
591
+ }), /* @__PURE__ */ p("p", {
592
+ className: "mt-1 text-xl font-semibold text-text-primary",
593
+ children: ie(Q.totalCost > 0 ? Q.totalUnrealized / Q.totalCost * 100 : null)
594
+ })]
304
595
  })
305
596
  ]
306
- })]
307
- })] })
597
+ }), /* @__PURE__ */ m(O, { children: [/* @__PURE__ */ p(M, { children: /* @__PURE__ */ m(N, { children: [
598
+ /* @__PURE__ */ p(j, { children: "Holding" }),
599
+ /* @__PURE__ */ p(j, {
600
+ className: "text-right",
601
+ children: "Market value"
602
+ }),
603
+ /* @__PURE__ */ p(j, {
604
+ className: "text-right",
605
+ children: "Cost basis"
606
+ }),
607
+ /* @__PURE__ */ p(j, {
608
+ className: "text-right",
609
+ children: "Unrealized"
610
+ })
611
+ ] }) }), /* @__PURE__ */ p(k, { children: Q.rows.map(({ holding: e, unrealized: t }) => /* @__PURE__ */ m(N, { children: [
612
+ /* @__PURE__ */ m(A, { children: [/* @__PURE__ */ p("div", {
613
+ className: "font-medium text-text-primary",
614
+ children: e.symbol
615
+ }), /* @__PURE__ */ m("div", {
616
+ className: "text-xs text-text-secondary",
617
+ children: [
618
+ e.name ?? I(e.assetClass),
619
+ " · as of",
620
+ " ",
621
+ re(e.asOf)
622
+ ]
623
+ })] }),
624
+ /* @__PURE__ */ p(A, {
625
+ className: "text-right",
626
+ children: c(e.marketValue, e.currency)
627
+ }),
628
+ /* @__PURE__ */ p(A, {
629
+ className: "text-right text-text-secondary",
630
+ children: c(e.costBasis, e.currency)
631
+ }),
632
+ /* @__PURE__ */ p(A, {
633
+ className: "text-right",
634
+ children: /* @__PURE__ */ p(we, {
635
+ value: t,
636
+ currency: e.currency
637
+ })
638
+ })
639
+ ] }, e.id)) })] })]
640
+ }) })] })
308
641
  })
309
642
  ]
310
643
  })]
311
644
  });
312
645
  }
313
646
  //#endregion
314
- export { S as AnalyticsPage };
647
+ export { B as AnalyticsPage };
315
648
 
316
649
  //# sourceMappingURL=AnalyticsPage.js.map