@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.
- package/dist/brainyrich/BrainyRichRoot.js +55 -90
- package/dist/brainyrich/BrainyRichRoot.js.map +1 -1
- package/dist/brainyrich/BrainyRichRoutes.js +15 -35
- package/dist/brainyrich/BrainyRichRoutes.js.map +1 -1
- package/dist/brainyrich/components/ActorName.js +38 -0
- package/dist/brainyrich/components/ActorName.js.map +1 -0
- package/dist/brainyrich/components/ConfirmDialog.js +25 -0
- package/dist/brainyrich/components/ConfirmDialog.js.map +1 -0
- package/dist/brainyrich/components/LoadMore.js +24 -0
- package/dist/brainyrich/components/LoadMore.js.map +1 -0
- package/dist/brainyrich/components/index.js +5 -0
- package/dist/brainyrich/components/notify.js +38 -0
- package/dist/brainyrich/components/notify.js.map +1 -0
- package/dist/brainyrich/components/pickers.js +232 -0
- package/dist/brainyrich/components/pickers.js.map +1 -0
- package/dist/brainyrich/components/reuse/CommentThread.js +208 -0
- package/dist/brainyrich/components/reuse/CommentThread.js.map +1 -0
- package/dist/brainyrich/components/reuse/DocumentsPanel.js +237 -0
- package/dist/brainyrich/components/reuse/DocumentsPanel.js.map +1 -0
- package/dist/brainyrich/components/reuse/TagField.js +206 -0
- package/dist/brainyrich/components/reuse/TagField.js.map +1 -0
- package/dist/brainyrich/components/reuse/transport.js +24 -0
- package/dist/brainyrich/components/reuse/transport.js.map +1 -0
- package/dist/brainyrich/hooks/useBrainyRichApi.js +815 -0
- package/dist/brainyrich/hooks/useBrainyRichApi.js.map +1 -0
- package/dist/brainyrich/index.js +0 -1
- package/dist/brainyrich/pages/AccountsPage.js +743 -160
- package/dist/brainyrich/pages/AccountsPage.js.map +1 -1
- package/dist/brainyrich/pages/AiAssistantPage.js +556 -363
- package/dist/brainyrich/pages/AiAssistantPage.js.map +1 -1
- package/dist/brainyrich/pages/AnalyticsPage.js +601 -268
- package/dist/brainyrich/pages/AnalyticsPage.js.map +1 -1
- package/dist/brainyrich/pages/DashboardPage.js +375 -231
- package/dist/brainyrich/pages/DashboardPage.js.map +1 -1
- package/dist/brainyrich/pages/FamilyPage.js +599 -337
- package/dist/brainyrich/pages/FamilyPage.js.map +1 -1
- package/dist/brainyrich/pages/GoalsPage.js +810 -141
- package/dist/brainyrich/pages/GoalsPage.js.map +1 -1
- package/dist/brainyrich/pages/InvestmentsPage.js +410 -311
- package/dist/brainyrich/pages/InvestmentsPage.js.map +1 -1
- package/dist/brainyrich/pages/PortfoliosPage.js +867 -156
- package/dist/brainyrich/pages/PortfoliosPage.js.map +1 -1
- package/dist/brainyrich/pages/ReportsPage.js +421 -251
- package/dist/brainyrich/pages/ReportsPage.js.map +1 -1
- package/dist/brainyrich/pages/RiskPage.js +557 -194
- package/dist/brainyrich/pages/RiskPage.js.map +1 -1
- package/dist/brainyrich/pages/TaxPage.js +655 -221
- package/dist/brainyrich/pages/TaxPage.js.map +1 -1
- package/dist/brainyrich/pages/_shared.js +222 -41
- package/dist/brainyrich/pages/_shared.js.map +1 -1
- package/dist/index.js +2 -3
- package/dist/node_modules/sonner/dist/index.js +163 -0
- package/dist/node_modules/sonner/dist/index.js.map +1 -0
- package/package.json +3 -2
- package/dist/brainyrich/pages/AdvisorsPage.js +0 -375
- package/dist/brainyrich/pages/AdvisorsPage.js.map +0 -1
- package/dist/brainyrich/pages/AssistantPage.js +0 -332
- package/dist/brainyrich/pages/AssistantPage.js.map +0 -1
- package/dist/brainyrich/pages/EstatePage.js +0 -269
- package/dist/brainyrich/pages/EstatePage.js.map +0 -1
- package/dist/brainyrich/pages/InsurancePage.js +0 -181
- package/dist/brainyrich/pages/InsurancePage.js.map +0 -1
- package/dist/brainyrich/pages/MarketplacePage.js +0 -450
- package/dist/brainyrich/pages/MarketplacePage.js.map +0 -1
- package/dist/brainyrich/store/brainyrichStore.js +0 -272
- package/dist/brainyrich/store/brainyrichStore.js.map +0 -1
|
@@ -1,222 +1,585 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
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
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
badges: [`${
|
|
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__ */
|
|
105
|
+
/* @__PURE__ */ m(oe, { items: [
|
|
88
106
|
{
|
|
89
|
-
label: "
|
|
90
|
-
value:
|
|
91
|
-
trend: "Moderate Risk"
|
|
107
|
+
label: "Total proposals",
|
|
108
|
+
value: String(a.length)
|
|
92
109
|
},
|
|
93
110
|
{
|
|
94
|
-
label: "
|
|
95
|
-
value:
|
|
96
|
-
trend: "95% confidence, 1-day"
|
|
111
|
+
label: "Active proposals",
|
|
112
|
+
value: String(Qe.length)
|
|
97
113
|
},
|
|
98
114
|
{
|
|
99
|
-
label: "
|
|
100
|
-
value: "
|
|
101
|
-
trend: "Risk-adjusted return"
|
|
115
|
+
label: "Average drift",
|
|
116
|
+
value: $e === null ? "—" : c($e)
|
|
102
117
|
},
|
|
103
118
|
{
|
|
104
|
-
label: "
|
|
105
|
-
value:
|
|
106
|
-
trend: "Overall grade"
|
|
119
|
+
label: "Open risk insights",
|
|
120
|
+
value: String(Z.length)
|
|
107
121
|
}
|
|
108
122
|
] }),
|
|
109
|
-
/* @__PURE__ */
|
|
110
|
-
className: "
|
|
111
|
-
children: [/* @__PURE__ */
|
|
112
|
-
className: "
|
|
113
|
-
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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__ */
|
|
127
|
-
|
|
128
|
-
children:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
}),
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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__ */
|
|
169
|
-
className: "
|
|
170
|
-
children: "
|
|
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__ */
|
|
173
|
-
className: "
|
|
174
|
-
children:
|
|
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
|
-
] })
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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__ */
|
|
186
|
-
className: "text-
|
|
187
|
-
children:
|
|
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__ */
|
|
190
|
-
className: "text-
|
|
191
|
-
|
|
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
|
-
]
|
|
194
|
-
|
|
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 {
|
|
583
|
+
export { Ie as RiskPage };
|
|
221
584
|
|
|
222
585
|
//# sourceMappingURL=RiskPage.js.map
|