@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,222 +1,585 @@
1
- import { useBrainyRichStore as e } from "../store/brainyrichStore.js";
2
- import { KpiGrid as t, SectionShell as n, statusBadgeVariant as r } from "./_shared.js";
3
- import { Activity as i, AlertTriangle as a, BarChart3 as o, ShieldAlert as s } from "lucide-react";
4
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
5
- import { Badge as u, Card as d, CardContent as f, CardDescription as p, CardHeader as m, CardTitle as h, Table as g, TableBody as _, TableCell as v, TableHead as y, TableHeader as b, TableRow as x } from "@burdenoff/fe-libs/ui";
1
+ import { useAcknowledgeInsight as e, useCreateRebalanceProposal as t, useDismissInsight as n, usePagedInsights as r, usePortfolios as i, useRebalanceProposals as ee, useResolveInsight as te, useTransitionRebalanceProposal as ne } from "../hooks/useBrainyRichApi.js";
2
+ import { LoadMore as re } from "../components/LoadMore.js";
3
+ import { ConfirmDialog as ie } from "../components/ConfirmDialog.js";
4
+ import { ActorName as a } from "../components/ActorName.js";
5
+ import "../components/index.js";
6
+ import { EmptyState as o, ErrorState as ae, KpiGrid as oe, LoadingState as se, SectionShell as ce, formatDate as s, formatPct as c, statusBadgeVariant as l } from "./_shared.js";
7
+ import { CommentThread as u } from "../components/reuse/CommentThread.js";
8
+ import { useMemo as d, useState as f } from "react";
9
+ import { AlertTriangle as le, ArrowRight as ue, Check as de, Eye as fe, MoreHorizontal as pe, Plus as me, Scale as p, ShieldAlert as he, ShieldCheck as ge, X as _e } from "lucide-react";
10
+ import { Fragment as ve, jsx as m, jsxs as h } from "react/jsx-runtime";
11
+ import { Badge as g, Button as _, Card as v, CardContent as y, CardDescription as b, CardHeader as x, CardTitle as S, Dialog as C, DialogClose as ye, DialogContent as w, DialogDescription as T, DialogFooter as be, DialogHeader as E, DialogTitle as D, DropdownMenu as O, DropdownMenuContent as k, DropdownMenuItem as A, DropdownMenuLabel as xe, DropdownMenuSeparator as Se, DropdownMenuTrigger as j, Input as Ce, Label as M, Select as we, SelectContent as Te, SelectItem as Ee, SelectTrigger as De, SelectValue as Oe, Table as ke, TableBody as Ae, TableCell as N, TableHead as P, TableHeader as je, TableRow as F, Textarea as I } from "@burdenoff/fe-libs/ui";
6
12
  //#region src/brainyrich/pages/RiskPage.tsx
7
- var S = [
8
- {
9
- metric: "Portfolio Beta",
10
- value: "1.15",
11
- benchmark: "1.0",
12
- status: "Above Market"
13
- },
14
- {
15
- metric: "Value at Risk (95%)",
16
- value: "-8.5%",
17
- benchmark: "-10.0%",
18
- status: "Acceptable"
19
- },
20
- {
21
- metric: "Sharpe Ratio",
22
- value: "1.42",
23
- benchmark: "1.2",
24
- status: "Good"
25
- },
26
- {
27
- metric: "Max Drawdown",
28
- value: "-12.3%",
29
- benchmark: "-15.0%",
30
- status: "Within Limits"
13
+ var Me = {
14
+ DRAFT: ["PROPOSED", "CANCELLED"],
15
+ PROPOSED: [
16
+ "APPROVED",
17
+ "REJECTED",
18
+ "CANCELLED"
19
+ ],
20
+ APPROVED: ["EXECUTED", "CANCELLED"],
21
+ REJECTED: [],
22
+ EXECUTED: [],
23
+ CANCELLED: []
24
+ }, Ne = new Set([
25
+ "DRIFT",
26
+ "CONCENTRATION_RISK",
27
+ "REBALANCE_DUE",
28
+ "CASH_DRAG",
29
+ "FEE_ANOMALY"
30
+ ]);
31
+ function L(e) {
32
+ return e.toLowerCase().split("_").map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join(" ");
33
+ }
34
+ function R(e) {
35
+ if (e == null) return "—";
36
+ if (Array.isArray(e)) return `${e.length} trade${e.length === 1 ? "" : "s"}`;
37
+ if (typeof e == "object") {
38
+ let t = Object.keys(e).length;
39
+ return `${t} field${t === 1 ? "" : "s"}`;
40
+ }
41
+ return String(e);
42
+ }
43
+ var Pe = {
44
+ portfolioId: "",
45
+ driftPct: "",
46
+ rationale: "",
47
+ trades: ""
48
+ };
49
+ function Fe(e) {
50
+ if (e.trim() === "") return;
51
+ let t = Number(e);
52
+ return Number.isFinite(t) ? t : void 0;
53
+ }
54
+ function Ie() {
55
+ let { data: a, isLoading: u, isError: de, refetch: Ie } = ee(), { data: z } = i(), { items: ze, hasMore: Be, loadMore: Ve, isLoading: He, isFetchingNextPage: Ue, isError: We, refetch: Ge } = r(), B = t(), V = ne(), Ke = e(), qe = n(), Je = te(), [Ye, H] = f(!1), [U, W] = f(Pe), [Xe, G] = f(null), [K, Ze] = f(null), [q, J] = f(null), Y = d(() => {
56
+ let e = /* @__PURE__ */ new Map();
57
+ for (let t of z) e.set(t.id, t);
58
+ return e;
59
+ }, [z]), X = d(() => ze.filter((e) => Ne.has(e.type)), [ze]), Qe = a.filter((e) => e.status === "DRAFT" || e.status === "PROPOSED" || e.status === "APPROVED"), Z = X.filter((e) => e.status === "OPEN"), $e = a.length > 0 ? a.reduce((e, t) => e + (t.driftPct ?? 0), 0) / a.length : null, Q = z.length > 0;
60
+ function $() {
61
+ W(Pe), G(null), H(!0);
31
62
  }
32
- ], C = [
33
- {
34
- scenario: "2008 Financial Crisis",
35
- portfolio: -35.2,
36
- market: -37.8,
37
- outperformance: "+2.6%"
38
- },
39
- {
40
- scenario: "COVID-19 Pandemic",
41
- portfolio: -28.1,
42
- market: -33.9,
43
- outperformance: "+5.8%"
44
- },
45
- {
46
- scenario: "Interest Rate Shock",
47
- portfolio: -15.4,
48
- market: -18.2,
49
- outperformance: "+2.8%"
50
- },
51
- {
52
- scenario: "Stagflation Scenario",
53
- portfolio: -12.7,
54
- market: -16.3,
55
- outperformance: "+3.6%"
63
+ function et() {
64
+ if (!U.portfolioId) return;
65
+ let e;
66
+ if (U.trades.trim() !== "") try {
67
+ e = JSON.parse(U.trades);
68
+ } catch {
69
+ G("Trades must be valid JSON.");
70
+ return;
71
+ }
72
+ let t = Y.get(U.portfolioId);
73
+ B.mutate({
74
+ portfolioId: U.portfolioId,
75
+ householdId: t?.householdId ?? null,
76
+ driftPct: Fe(U.driftPct),
77
+ rationale: U.rationale.trim() || null,
78
+ ...e === void 0 ? {} : { trades: e }
79
+ }, { onSuccess: () => H(!1) });
56
80
  }
57
- ], w = [
58
- {
59
- strategy: "Diversification",
60
- status: "Implemented",
61
- effectiveness: "High"
62
- },
63
- {
64
- strategy: "Hedging (Options)",
65
- status: "Partial",
66
- effectiveness: "Medium"
67
- },
68
- {
69
- strategy: "Stop-Loss Orders",
70
- status: "Active",
71
- effectiveness: "Medium"
72
- },
73
- {
74
- strategy: "Quarterly Rebalancing",
75
- status: "Scheduled",
76
- effectiveness: "High"
81
+ function tt(e, t) {
82
+ if (t === "REJECTED" || t === "CANCELLED") {
83
+ J({
84
+ proposal: e,
85
+ status: t
86
+ });
87
+ return;
88
+ }
89
+ V.mutate({
90
+ id: e.id,
91
+ status: t
92
+ });
77
93
  }
78
- ];
79
- function T() {
80
- let { risks: T } = e();
81
- return /* @__PURE__ */ l(n, {
82
- title: "Risk Management",
83
- description: "Monitor portfolio risk exposure, run stress tests, and manage mitigation strategies",
84
- actionLabel: "Run Stress Test",
85
- badges: [`${T.length} Active Alerts`],
94
+ function nt(e) {
95
+ let t = Y.get(e.portfolioId)?.driftThresholdPct;
96
+ return t != null && Number.isFinite(t) && e.driftPct >= t;
97
+ }
98
+ return /* @__PURE__ */ h(ce, {
99
+ title: "Risk & Rebalancing",
100
+ description: "Review drift-driven rebalance proposals and act on portfolio risk insights.",
101
+ badges: [`${Qe.length} active`, `${Z.length} open insight${Z.length === 1 ? "" : "s"}`],
102
+ actionLabel: "New proposal",
103
+ onAction: $,
86
104
  children: [
87
- /* @__PURE__ */ c(t, { items: [
105
+ /* @__PURE__ */ m(oe, { items: [
88
106
  {
89
- label: "Risk Score",
90
- value: "7/10",
91
- trend: "Moderate Risk"
107
+ label: "Total proposals",
108
+ value: String(a.length)
92
109
  },
93
110
  {
94
- label: "Portfolio VaR",
95
- value: "-8.5%",
96
- trend: "95% confidence, 1-day"
111
+ label: "Active proposals",
112
+ value: String(Qe.length)
97
113
  },
98
114
  {
99
- label: "Sharpe Ratio",
100
- value: "1.42",
101
- trend: "Risk-adjusted return"
115
+ label: "Average drift",
116
+ value: $e === null ? "—" : c($e)
102
117
  },
103
118
  {
104
- label: "Risk Rating",
105
- value: "B+",
106
- trend: "Overall grade"
119
+ label: "Open risk insights",
120
+ value: String(Z.length)
107
121
  }
108
122
  ] }),
109
- /* @__PURE__ */ l("div", {
110
- className: "grid gap-4 lg:grid-cols-2",
111
- children: [/* @__PURE__ */ l(d, { children: [/* @__PURE__ */ c(m, { children: /* @__PURE__ */ l(h, {
112
- className: "flex items-center gap-2",
113
- children: [/* @__PURE__ */ c(i, { className: "h-5 w-5" }), "Risk Metrics"]
114
- }) }), /* @__PURE__ */ c(f, {
115
- className: "space-y-3",
116
- children: S.map((e) => /* @__PURE__ */ l("div", {
117
- className: "flex items-center justify-between rounded-lg border p-3",
118
- children: [/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("p", {
119
- className: "font-medium text-sm",
120
- children: e.metric
121
- }), /* @__PURE__ */ l("p", {
122
- className: "text-xs text-muted-foreground",
123
- children: ["Benchmark: ", e.benchmark]
124
- })] }), /* @__PURE__ */ l("div", {
123
+ /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ h(x, { children: [/* @__PURE__ */ h(S, {
124
+ className: "flex items-center gap-2",
125
+ children: [/* @__PURE__ */ m(p, {
126
+ className: "h-5 w-5",
127
+ "aria-hidden": "true"
128
+ }), "Rebalance proposals"]
129
+ }), /* @__PURE__ */ m(b, { children: "Drift against target allocation, with lifecycle actions per proposal." })] }), /* @__PURE__ */ m(y, { children: u ? /* @__PURE__ */ m(se, {}) : de ? /* @__PURE__ */ m(ae, { onRetry: () => Ie() }) : a.length === 0 ? /* @__PURE__ */ m(o, {
130
+ icon: /* @__PURE__ */ m(p, {
131
+ className: "size-6",
132
+ "aria-hidden": "true"
133
+ }),
134
+ title: "No rebalance proposals",
135
+ description: Q ? "Create a proposal when a portfolio drifts from its target allocation." : "Create a portfolio first, then propose a rebalance when it drifts.",
136
+ action: Q ? /* @__PURE__ */ h(_, {
137
+ size: "sm",
138
+ onClick: $,
139
+ children: [/* @__PURE__ */ m(me, {
140
+ className: "size-4",
141
+ "aria-hidden": "true"
142
+ }), "New proposal"]
143
+ }) : void 0
144
+ }) : /* @__PURE__ */ m("div", {
145
+ className: "overflow-x-auto",
146
+ children: /* @__PURE__ */ h(ke, { children: [/* @__PURE__ */ m(je, { children: /* @__PURE__ */ h(F, { children: [
147
+ /* @__PURE__ */ m(P, { children: "Portfolio" }),
148
+ /* @__PURE__ */ m(P, {
149
+ className: "text-right",
150
+ children: "Drift"
151
+ }),
152
+ /* @__PURE__ */ m(P, { children: "Status" }),
153
+ /* @__PURE__ */ m(P, { children: "Rationale" }),
154
+ /* @__PURE__ */ m(P, { children: "Trades" }),
155
+ /* @__PURE__ */ m(P, { children: "Created" }),
156
+ /* @__PURE__ */ m(P, {
157
+ className: "w-12 text-right",
158
+ children: "Actions"
159
+ })
160
+ ] }) }), /* @__PURE__ */ m(Ae, { children: a.map((e) => {
161
+ let t = Y.get(e.portfolioId), n = nt(e), r = Me[e.status];
162
+ return /* @__PURE__ */ h(F, { children: [
163
+ /* @__PURE__ */ h(N, { children: [/* @__PURE__ */ m("p", {
164
+ className: "font-medium text-text-primary",
165
+ children: t?.name ?? "Unknown portfolio"
166
+ }), /* @__PURE__ */ h("p", {
167
+ className: "text-xs text-text-secondary",
168
+ children: [t?.baseCurrency ?? "—", t?.driftThresholdPct == null ? "" : ` · threshold ${c(t.driftThresholdPct)}`]
169
+ })] }),
170
+ /* @__PURE__ */ h(N, {
171
+ className: "text-right",
172
+ children: [/* @__PURE__ */ h("span", {
173
+ className: `inline-flex items-center justify-end gap-1 font-semibold ${n ? "text-status-error-text" : "text-text-primary"}`,
174
+ children: [n ? /* @__PURE__ */ m(le, {
175
+ className: "size-4",
176
+ "aria-hidden": "true"
177
+ }) : null, c(e.driftPct)]
178
+ }), n ? /* @__PURE__ */ m("p", {
179
+ className: "text-xs text-status-error-text",
180
+ children: "Over threshold"
181
+ }) : null]
182
+ }),
183
+ /* @__PURE__ */ m(N, { children: /* @__PURE__ */ m(g, {
184
+ variant: l(e.status),
185
+ children: L(e.status)
186
+ }) }),
187
+ /* @__PURE__ */ m(N, {
188
+ className: "max-w-xs",
189
+ children: /* @__PURE__ */ m("p", {
190
+ className: "truncate text-sm text-text-secondary",
191
+ children: e.rationale ?? "—"
192
+ })
193
+ }),
194
+ /* @__PURE__ */ m(N, {
195
+ className: "text-sm text-text-secondary",
196
+ children: R(e.trades)
197
+ }),
198
+ /* @__PURE__ */ m(N, {
199
+ className: "text-sm text-text-secondary",
200
+ children: s(e.createdAt)
201
+ }),
202
+ /* @__PURE__ */ m(N, {
125
203
  className: "text-right",
126
- children: [/* @__PURE__ */ c("p", {
127
- className: "font-semibold text-sm",
128
- children: e.value
129
- }), /* @__PURE__ */ c(u, {
130
- variant: e.status === "Good" || e.status === "Acceptable" || e.status === "Within Limits" ? "default" : "secondary",
131
- className: "text-[10px]",
132
- children: e.status
204
+ children: /* @__PURE__ */ h(O, { children: [/* @__PURE__ */ m(j, {
205
+ asChild: !0,
206
+ children: /* @__PURE__ */ m(_, {
207
+ variant: "ghost",
208
+ size: "sm",
209
+ "aria-label": `Actions for ${t?.name ?? "proposal"}`,
210
+ children: /* @__PURE__ */ m(pe, {
211
+ className: "size-4",
212
+ "aria-hidden": "true"
213
+ })
214
+ })
215
+ }), /* @__PURE__ */ h(k, {
216
+ align: "end",
217
+ children: [/* @__PURE__ */ h(A, {
218
+ onClick: () => Ze(e),
219
+ children: [/* @__PURE__ */ m(fe, {
220
+ className: "size-4",
221
+ "aria-hidden": "true"
222
+ }), "View details"]
223
+ }), r.length > 0 ? /* @__PURE__ */ h(ve, { children: [
224
+ /* @__PURE__ */ m(Se, {}),
225
+ /* @__PURE__ */ m(xe, { children: "Advance to" }),
226
+ r.map((t) => {
227
+ let n = t === "REJECTED" || t === "CANCELLED";
228
+ return /* @__PURE__ */ h(A, {
229
+ disabled: V.isPending,
230
+ className: n ? "text-status-error-text" : void 0,
231
+ onClick: () => tt(e, t),
232
+ children: [m(n ? _e : ue, {
233
+ className: "size-4",
234
+ "aria-hidden": "true"
235
+ }), L(t)]
236
+ }, t);
237
+ })
238
+ ] }) : null]
239
+ })] })
240
+ })
241
+ ] }, e.id);
242
+ }) })] })
243
+ }) })] }),
244
+ /* @__PURE__ */ h(v, { children: [/* @__PURE__ */ h(x, { children: [/* @__PURE__ */ h(S, {
245
+ className: "flex items-center gap-2",
246
+ children: [/* @__PURE__ */ m(he, {
247
+ className: "h-5 w-5",
248
+ "aria-hidden": "true"
249
+ }), "Risk insights"]
250
+ }), /* @__PURE__ */ m(b, { children: "Drift, concentration, cash-drag and fee-anomaly signals detected across your portfolios." })] }), /* @__PURE__ */ m(y, { children: He ? /* @__PURE__ */ m(se, {}) : We ? /* @__PURE__ */ m(ae, { onRetry: () => Ge() }) : X.length === 0 ? /* @__PURE__ */ m(o, {
251
+ icon: /* @__PURE__ */ m(ge, {
252
+ className: "size-6",
253
+ "aria-hidden": "true"
254
+ }),
255
+ title: "No risk insights",
256
+ description: "No drift, concentration, cash-drag or fee-anomaly signals are open right now."
257
+ }) : /* @__PURE__ */ h("div", {
258
+ className: "space-y-3",
259
+ children: [X.map((e) => /* @__PURE__ */ m(Re, {
260
+ insight: e,
261
+ onAcknowledge: () => Ke.mutate(e.id),
262
+ onResolve: () => Je.mutate(e.id),
263
+ onDismiss: () => qe.mutate(e.id),
264
+ actionPending: Ke.isPending || Je.isPending || qe.isPending
265
+ }, e.id)), /* @__PURE__ */ m(re, {
266
+ hasMore: Be,
267
+ onClick: Ve,
268
+ loading: Ue,
269
+ label: "Load more insights"
270
+ })]
271
+ }) })] }),
272
+ /* @__PURE__ */ m(C, {
273
+ open: Ye,
274
+ onOpenChange: H,
275
+ children: /* @__PURE__ */ h(w, { children: [
276
+ /* @__PURE__ */ h(E, { children: [/* @__PURE__ */ m(D, { children: "New rebalance proposal" }), /* @__PURE__ */ m(T, { children: "Propose a rebalance for a portfolio that has drifted from its target allocation." })] }),
277
+ Q ? /* @__PURE__ */ h("div", {
278
+ className: "grid gap-4",
279
+ children: [
280
+ /* @__PURE__ */ h("div", {
281
+ className: "space-y-2",
282
+ children: [/* @__PURE__ */ m(M, {
283
+ htmlFor: "prop-portfolio",
284
+ children: "Portfolio"
285
+ }), /* @__PURE__ */ h(we, {
286
+ value: U.portfolioId,
287
+ onValueChange: (e) => W((t) => ({
288
+ ...t,
289
+ portfolioId: e
290
+ })),
291
+ children: [/* @__PURE__ */ m(De, {
292
+ id: "prop-portfolio",
293
+ children: /* @__PURE__ */ m(Oe, { placeholder: "Select a portfolio" })
294
+ }), /* @__PURE__ */ m(Te, { children: z.map((e) => /* @__PURE__ */ m(Ee, {
295
+ value: e.id,
296
+ children: e.name
297
+ }, e.id)) })]
298
+ })]
299
+ }),
300
+ /* @__PURE__ */ h("div", {
301
+ className: "space-y-2",
302
+ children: [/* @__PURE__ */ m(M, {
303
+ htmlFor: "prop-drift",
304
+ children: "Drift %"
305
+ }), /* @__PURE__ */ m(Ce, {
306
+ id: "prop-drift",
307
+ type: "number",
308
+ value: U.driftPct,
309
+ onChange: (e) => W((t) => ({
310
+ ...t,
311
+ driftPct: e.target.value
312
+ })),
313
+ placeholder: "e.g. 6.5"
314
+ })]
315
+ }),
316
+ /* @__PURE__ */ h("div", {
317
+ className: "space-y-2",
318
+ children: [/* @__PURE__ */ m(M, {
319
+ htmlFor: "prop-rationale",
320
+ children: "Rationale"
321
+ }), /* @__PURE__ */ m(I, {
322
+ id: "prop-rationale",
323
+ value: U.rationale,
324
+ onChange: (e) => W((t) => ({
325
+ ...t,
326
+ rationale: e.target.value
327
+ })),
328
+ placeholder: "Why is this rebalance needed?"
329
+ })]
330
+ }),
331
+ /* @__PURE__ */ h("div", {
332
+ className: "space-y-2",
333
+ children: [
334
+ /* @__PURE__ */ m(M, {
335
+ htmlFor: "prop-trades",
336
+ children: "Trades (JSON, optional)"
337
+ }),
338
+ /* @__PURE__ */ m(I, {
339
+ id: "prop-trades",
340
+ value: U.trades,
341
+ onChange: (e) => {
342
+ G(null), W((t) => ({
343
+ ...t,
344
+ trades: e.target.value
345
+ }));
346
+ },
347
+ placeholder: "e.g. [{\"symbol\":\"VOO\",\"action\":\"SELL\",\"quantity\":10}]"
348
+ }),
349
+ Xe ? /* @__PURE__ */ m("p", {
350
+ className: "text-xs text-status-error-text",
351
+ children: Xe
352
+ }) : null
353
+ ]
354
+ })
355
+ ]
356
+ }) : /* @__PURE__ */ m(o, {
357
+ icon: /* @__PURE__ */ m(p, {
358
+ className: "size-6",
359
+ "aria-hidden": "true"
360
+ }),
361
+ title: "Create a portfolio first",
362
+ description: "A rebalance proposal targets a portfolio. Add a portfolio on the Portfolios page, then return here to propose a rebalance."
363
+ }),
364
+ /* @__PURE__ */ h(be, { children: [/* @__PURE__ */ m(ye, {
365
+ asChild: !0,
366
+ children: /* @__PURE__ */ m(_, {
367
+ variant: "outline",
368
+ children: "Cancel"
369
+ })
370
+ }), /* @__PURE__ */ m(_, {
371
+ onClick: et,
372
+ disabled: !U.portfolioId || B.isPending,
373
+ children: B.isPending ? "Creating…" : "Create proposal"
374
+ })] })
375
+ ] })
376
+ }),
377
+ /* @__PURE__ */ m(Le, {
378
+ proposal: K,
379
+ portfolio: K ? Y.get(K.portfolioId) ?? null : null,
380
+ onOpenChange: (e) => {
381
+ e || Ze(null);
382
+ }
383
+ }),
384
+ /* @__PURE__ */ m(ie, {
385
+ open: q !== null,
386
+ onOpenChange: (e) => {
387
+ e || J(null);
388
+ },
389
+ title: q?.status === "REJECTED" ? "Reject this proposal?" : "Cancel this proposal?",
390
+ description: q ? `This moves the rebalance proposal for ${Y.get(q.proposal.portfolioId)?.name ?? "this portfolio"} to ${L(q.status)}. This cannot be undone.` : void 0,
391
+ confirmLabel: q?.status === "REJECTED" ? "Reject" : "Cancel proposal",
392
+ cancelLabel: "Keep",
393
+ destructive: !0,
394
+ pending: V.isPending,
395
+ onConfirm: () => {
396
+ q && V.mutate({
397
+ id: q.proposal.id,
398
+ status: q.status
399
+ }, { onSuccess: () => J(null) });
400
+ }
401
+ })
402
+ ]
403
+ });
404
+ }
405
+ function Le({ proposal: e, portfolio: t, onOpenChange: n }) {
406
+ return /* @__PURE__ */ m(C, {
407
+ open: e !== null,
408
+ onOpenChange: n,
409
+ children: /* @__PURE__ */ m(w, {
410
+ className: "max-h-[85vh] overflow-y-auto",
411
+ children: e ? /* @__PURE__ */ h(ve, { children: [
412
+ /* @__PURE__ */ h(E, { children: [/* @__PURE__ */ h(D, {
413
+ className: "flex flex-wrap items-center gap-2",
414
+ children: [t?.name ?? "Rebalance proposal", /* @__PURE__ */ m(g, {
415
+ variant: l(e.status),
416
+ children: L(e.status)
417
+ })]
418
+ }), /* @__PURE__ */ h(T, { children: [
419
+ "Drift ",
420
+ c(e.driftPct),
421
+ t?.driftThresholdPct == null ? "" : ` · threshold ${c(t.driftThresholdPct)}`,
422
+ " · created ",
423
+ s(e.createdAt)
424
+ ] })] }),
425
+ /* @__PURE__ */ h("dl", {
426
+ className: "grid grid-cols-2 gap-4 text-sm",
427
+ children: [
428
+ /* @__PURE__ */ h("div", {
429
+ className: "space-y-1",
430
+ children: [/* @__PURE__ */ m("dt", {
431
+ className: "text-xs font-medium text-text-muted",
432
+ children: "Proposed by"
433
+ }), /* @__PURE__ */ m("dd", {
434
+ className: "text-text-primary",
435
+ children: e.proposedById ? /* @__PURE__ */ m(a, { id: e.proposedById }) : /* @__PURE__ */ m("span", {
436
+ className: "text-text-muted",
437
+ children: "—"
438
+ })
133
439
  })]
134
- })]
135
- }, e.metric))
136
- })] }), /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ c(m, { children: /* @__PURE__ */ l(h, {
137
- className: "flex items-center gap-2",
138
- children: [/* @__PURE__ */ c(a, { className: "h-5 w-5" }), "Active Risk Alerts"]
139
- }) }), /* @__PURE__ */ c(f, {
140
- className: "space-y-3",
141
- children: T.map((e) => /* @__PURE__ */ l("div", {
142
- className: `rounded-lg border p-3 ${e.severity === "High" ? "border-red-200 bg-red-50" : e.severity === "Medium" ? "border-yellow-200 bg-yellow-50" : "border-blue-200 bg-blue-50"}`,
143
- children: [/* @__PURE__ */ l("div", {
144
- className: "flex items-center justify-between mb-1",
145
- children: [/* @__PURE__ */ c("p", {
146
- className: "font-medium text-sm",
147
- children: e.title
148
- }), /* @__PURE__ */ c(u, {
149
- variant: r(e.severity),
150
- children: e.severity
440
+ }),
441
+ /* @__PURE__ */ h("div", {
442
+ className: "space-y-1",
443
+ children: [/* @__PURE__ */ m("dt", {
444
+ className: "text-xs font-medium text-text-muted",
445
+ children: "Approved by"
446
+ }), /* @__PURE__ */ m("dd", {
447
+ className: "text-text-primary",
448
+ children: e.approvedById ? /* @__PURE__ */ m(a, { id: e.approvedById }) : /* @__PURE__ */ m("span", {
449
+ className: "text-text-muted",
450
+ children: "—"
451
+ })
151
452
  })]
152
- }), /* @__PURE__ */ c("p", {
153
- className: "text-xs text-muted-foreground",
154
- children: e.description
155
- })]
156
- }, e.id))
157
- })] })]
158
- }),
159
- /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ l(m, { children: [/* @__PURE__ */ l(h, {
160
- className: "flex items-center gap-2",
161
- children: [/* @__PURE__ */ c(o, { className: "h-5 w-5" }), "Stress Test Results"]
162
- }), /* @__PURE__ */ c(p, { children: "How your portfolio would perform under historical crisis scenarios" })] }), /* @__PURE__ */ c(f, { children: /* @__PURE__ */ l(g, { children: [/* @__PURE__ */ c(b, { children: /* @__PURE__ */ l(x, { children: [
163
- /* @__PURE__ */ c(y, { children: "Scenario" }),
164
- /* @__PURE__ */ c(y, {
165
- className: "text-right",
166
- children: "Your Portfolio"
453
+ }),
454
+ /* @__PURE__ */ h("div", {
455
+ className: "space-y-1",
456
+ children: [/* @__PURE__ */ m("dt", {
457
+ className: "text-xs font-medium text-text-muted",
458
+ children: "Trades"
459
+ }), /* @__PURE__ */ m("dd", {
460
+ className: "text-text-primary",
461
+ children: R(e.trades)
462
+ })]
463
+ }),
464
+ /* @__PURE__ */ h("div", {
465
+ className: "space-y-1",
466
+ children: [/* @__PURE__ */ m("dt", {
467
+ className: "text-xs font-medium text-text-muted",
468
+ children: "Executed"
469
+ }), /* @__PURE__ */ m("dd", {
470
+ className: "text-text-primary",
471
+ children: e.executedAt ? s(e.executedAt) : /* @__PURE__ */ m("span", {
472
+ className: "text-text-muted",
473
+ children: "—"
474
+ })
475
+ })]
476
+ })
477
+ ]
167
478
  }),
168
- /* @__PURE__ */ c(y, {
169
- className: "text-right",
170
- children: "Market Benchmark"
479
+ /* @__PURE__ */ h("div", {
480
+ className: "space-y-1",
481
+ children: [/* @__PURE__ */ m("p", {
482
+ className: "text-xs font-medium text-text-muted",
483
+ children: "Rationale (summary)"
484
+ }), /* @__PURE__ */ m("p", {
485
+ className: "text-sm text-text-secondary",
486
+ children: e.rationale ?? "—"
487
+ })]
171
488
  }),
172
- /* @__PURE__ */ c(y, {
173
- className: "text-right",
174
- children: "Outperformance"
489
+ /* @__PURE__ */ m("div", {
490
+ className: "border-t border-border-subtle pt-4",
491
+ children: /* @__PURE__ */ m(u, {
492
+ entityType: "brainyrich-rebalance",
493
+ entityId: e.id,
494
+ heading: "Discussion"
495
+ })
175
496
  })
176
- ] }) }), /* @__PURE__ */ c(_, { children: C.map((e) => /* @__PURE__ */ l(x, { children: [
177
- /* @__PURE__ */ c(v, {
178
- className: "font-medium",
179
- children: e.scenario
180
- }),
181
- /* @__PURE__ */ l(v, {
182
- className: "text-right text-red-600",
183
- children: [e.portfolio, "%"]
497
+ ] }) : null
498
+ })
499
+ });
500
+ }
501
+ function Re({ insight: e, onAcknowledge: t, onResolve: n, onDismiss: r, actionPending: i }) {
502
+ let ee = e.status === "RESOLVED" || e.status === "DISMISSED";
503
+ return /* @__PURE__ */ h("div", {
504
+ className: "flex items-start justify-between gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4",
505
+ children: [/* @__PURE__ */ h("div", {
506
+ className: "min-w-0 space-y-1",
507
+ children: [
508
+ /* @__PURE__ */ h("div", {
509
+ className: "flex flex-wrap items-center gap-2",
510
+ children: [
511
+ /* @__PURE__ */ m("p", {
512
+ className: "font-medium text-text-primary",
513
+ children: e.title
514
+ }),
515
+ /* @__PURE__ */ m(g, {
516
+ variant: l(e.severity),
517
+ children: L(e.severity)
518
+ }),
519
+ /* @__PURE__ */ m(g, {
520
+ variant: "outline",
521
+ children: L(e.type)
522
+ }),
523
+ /* @__PURE__ */ m(g, {
524
+ variant: l(e.status),
525
+ children: L(e.status)
526
+ })
527
+ ]
184
528
  }),
185
- /* @__PURE__ */ l(v, {
186
- className: "text-right text-red-600",
187
- children: [e.market, "%"]
529
+ e.detail ? /* @__PURE__ */ m("p", {
530
+ className: "text-sm text-text-secondary",
531
+ children: e.detail
532
+ }) : null,
533
+ /* @__PURE__ */ h("p", {
534
+ className: "text-xs text-text-muted",
535
+ children: ["Detected ", s(e.createdAt)]
536
+ })
537
+ ]
538
+ }), ee ? /* @__PURE__ */ m("span", {
539
+ className: "mt-1 text-xs text-text-muted",
540
+ children: "Closed"
541
+ }) : /* @__PURE__ */ h(O, { children: [/* @__PURE__ */ m(j, {
542
+ asChild: !0,
543
+ children: /* @__PURE__ */ m(_, {
544
+ variant: "ghost",
545
+ size: "sm",
546
+ "aria-label": `Actions for ${e.title}`,
547
+ disabled: i,
548
+ children: /* @__PURE__ */ m(pe, {
549
+ className: "size-4",
550
+ "aria-hidden": "true"
551
+ })
552
+ })
553
+ }), /* @__PURE__ */ h(k, {
554
+ align: "end",
555
+ children: [
556
+ e.status === "OPEN" ? /* @__PURE__ */ h(A, {
557
+ onClick: t,
558
+ children: [/* @__PURE__ */ m(de, {
559
+ className: "size-4",
560
+ "aria-hidden": "true"
561
+ }), "Acknowledge"]
562
+ }) : null,
563
+ /* @__PURE__ */ h(A, {
564
+ onClick: n,
565
+ children: [/* @__PURE__ */ m(ge, {
566
+ className: "size-4",
567
+ "aria-hidden": "true"
568
+ }), "Resolve"]
188
569
  }),
189
- /* @__PURE__ */ c(v, {
190
- className: "text-right text-emerald-600 font-medium",
191
- children: e.outperformance
570
+ /* @__PURE__ */ h(A, {
571
+ className: "text-status-error-text",
572
+ onClick: r,
573
+ children: [/* @__PURE__ */ m(_e, {
574
+ className: "size-4",
575
+ "aria-hidden": "true"
576
+ }), "Dismiss"]
192
577
  })
193
- ] }, e.scenario)) })] }) })] }),
194
- /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ l(m, { children: [/* @__PURE__ */ l(h, {
195
- className: "flex items-center gap-2",
196
- children: [/* @__PURE__ */ c(s, { className: "h-5 w-5" }), "Mitigation Strategies"]
197
- }), /* @__PURE__ */ c(p, { children: "Current risk management measures and their effectiveness" })] }), /* @__PURE__ */ c(f, { children: /* @__PURE__ */ c("div", {
198
- className: "grid gap-3 md:grid-cols-2",
199
- children: w.map((e) => /* @__PURE__ */ l("div", {
200
- className: "rounded-lg border p-3",
201
- children: [/* @__PURE__ */ l("div", {
202
- className: "flex items-center justify-between mb-1",
203
- children: [/* @__PURE__ */ c("p", {
204
- className: "font-medium text-sm",
205
- children: e.strategy
206
- }), /* @__PURE__ */ c(u, {
207
- variant: e.status === "Implemented" || e.status === "Active" || e.status === "Scheduled" ? "default" : "secondary",
208
- children: e.status
209
- })]
210
- }), /* @__PURE__ */ l("p", {
211
- className: "text-xs text-muted-foreground",
212
- children: ["Effectiveness: ", e.effectiveness]
213
- })]
214
- }, e.strategy))
215
- }) })] })
216
- ]
578
+ ]
579
+ })] })]
217
580
  });
218
581
  }
219
582
  //#endregion
220
- export { T as RiskPage };
583
+ export { Ie as RiskPage };
221
584
 
222
585
  //# sourceMappingURL=RiskPage.js.map