@burdenoff/microfe-brainyrich 2026.720.1 → 2026.731.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/hooks/useBrainyRichApi.d.ts +37 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.d.ts.map +1 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.js +125 -46
- package/dist/brainyrich/hooks/useBrainyRichApi.js.map +1 -1
- package/dist/brainyrich/pages/RiskPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/RiskPage.js +682 -332
- package/dist/brainyrich/pages/RiskPage.js.map +1 -1
- package/dist/brainyrich/types/bra.d.ts +50 -0
- package/dist/brainyrich/types/bra.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { useAcknowledgeInsight as e, useCreateRebalanceProposal as t, useDismissInsight as n,
|
|
2
|
-
import { LoadMore as
|
|
3
|
-
import { ConfirmDialog as
|
|
4
|
-
import { ActorName as
|
|
5
|
-
import { DonutChart as
|
|
1
|
+
import { useAcknowledgeInsight as e, useCreateRebalanceProposal as t, useDismissInsight as n, useGenerateRiskInsights as r, useHarvestTaxLossInsights as i, usePagedInsights as a, usePortfolioRiskSignals as o, usePortfolioRiskSummary as s, usePortfolios as ee, useRebalanceProposals as te, useResolveInsight as ne, useTaxLossOpportunities as re, useTransitionRebalanceProposal as ie } from "../hooks/useBrainyRichApi.js";
|
|
2
|
+
import { LoadMore as ae } from "../components/LoadMore.js";
|
|
3
|
+
import { ConfirmDialog as oe } from "../components/ConfirmDialog.js";
|
|
4
|
+
import { ActorName as c } from "../components/ActorName.js";
|
|
5
|
+
import { DonutChart as se, FadeIn as l, GlassCard as ce, LifecycleStepper as le, StatTile as u } from "../components/viz.js";
|
|
6
6
|
import "../components/index.js";
|
|
7
|
-
import { EmptyState as
|
|
8
|
-
import { CommentThread as
|
|
9
|
-
import { useMemo as
|
|
10
|
-
import { Activity as
|
|
11
|
-
import { Fragment as
|
|
12
|
-
import { Badge as
|
|
7
|
+
import { EmptyState as d, ErrorState as f, LoadingState as p, SectionShell as ue, formatDate as m, formatMoney as h, formatPct as g, statusBadgeVariant as _ } from "./_shared.js";
|
|
8
|
+
import { CommentThread as de } from "../components/reuse/CommentThread.js";
|
|
9
|
+
import { useMemo as v, useState as y } from "react";
|
|
10
|
+
import { Activity as fe, AlertTriangle as pe, ArrowRight as me, Check as he, Eye as ge, Gauge as b, Layers as _e, MoreHorizontal as ve, Plus as ye, RefreshCw as be, Scale as x, Scissors as S, ShieldAlert as C, ShieldCheck as w, Sparkles as xe, TrendingUp as Se, X as T } from "lucide-react";
|
|
11
|
+
import { Fragment as Ce, jsx as E, jsxs as D } from "react/jsx-runtime";
|
|
12
|
+
import { Badge as O, Button as k, Card as A, CardContent as j, CardDescription as M, CardHeader as N, CardTitle as P, Dialog as we, DialogClose as Te, DialogContent as Ee, DialogDescription as De, DialogFooter as Oe, DialogHeader as ke, DialogTitle as Ae, DropdownMenu as je, DropdownMenuContent as Me, DropdownMenuItem as F, DropdownMenuLabel as Ne, DropdownMenuSeparator as Pe, DropdownMenuTrigger as Fe, Input as Ie, Label as I, Select as Le, SelectContent as Re, SelectItem as ze, SelectTrigger as Be, SelectValue as Ve, Table as He, TableBody as Ue, TableCell as L, TableHead as R, TableHeader as We, TableRow as z, Textarea as Ge } from "@burdenoff/fe-libs/ui";
|
|
13
13
|
//#region src/brainyrich/pages/RiskPage.tsx
|
|
14
|
-
var
|
|
14
|
+
var Ke = {
|
|
15
15
|
DRAFT: ["PROPOSED", "CANCELLED"],
|
|
16
16
|
PROPOSED: [
|
|
17
17
|
"APPROVED",
|
|
@@ -22,49 +22,49 @@ var He = {
|
|
|
22
22
|
REJECTED: [],
|
|
23
23
|
EXECUTED: [],
|
|
24
24
|
CANCELLED: []
|
|
25
|
-
},
|
|
25
|
+
}, qe = new Set([
|
|
26
26
|
"DRIFT",
|
|
27
27
|
"CONCENTRATION_RISK",
|
|
28
28
|
"REBALANCE_DUE",
|
|
29
29
|
"CASH_DRAG",
|
|
30
30
|
"FEE_ANOMALY"
|
|
31
31
|
]);
|
|
32
|
-
function
|
|
32
|
+
function B(e) {
|
|
33
33
|
return e.toLowerCase().split("_").map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join(" ");
|
|
34
34
|
}
|
|
35
|
-
var
|
|
35
|
+
var V = [
|
|
36
36
|
"Draft",
|
|
37
37
|
"Proposed",
|
|
38
38
|
"Approved",
|
|
39
39
|
"Executed"
|
|
40
|
-
],
|
|
40
|
+
], Je = {
|
|
41
41
|
DRAFT: "neutral",
|
|
42
42
|
PROPOSED: "warning",
|
|
43
43
|
APPROVED: "blue",
|
|
44
44
|
EXECUTED: "success",
|
|
45
45
|
REJECTED: "error",
|
|
46
46
|
CANCELLED: "neutral"
|
|
47
|
-
},
|
|
47
|
+
}, Ye = [
|
|
48
48
|
"PROPOSED",
|
|
49
49
|
"DRAFT",
|
|
50
50
|
"APPROVED",
|
|
51
51
|
"EXECUTED",
|
|
52
52
|
"REJECTED",
|
|
53
53
|
"CANCELLED"
|
|
54
|
-
],
|
|
54
|
+
], Xe = {
|
|
55
55
|
CRITICAL: "error",
|
|
56
56
|
HIGH: "warning",
|
|
57
57
|
MEDIUM: "info",
|
|
58
58
|
LOW: "teal",
|
|
59
59
|
INFO: "neutral"
|
|
60
|
-
},
|
|
60
|
+
}, Ze = [
|
|
61
61
|
"CRITICAL",
|
|
62
62
|
"HIGH",
|
|
63
63
|
"MEDIUM",
|
|
64
64
|
"LOW",
|
|
65
65
|
"INFO"
|
|
66
66
|
];
|
|
67
|
-
function
|
|
67
|
+
function Qe(e) {
|
|
68
68
|
if (!Array.isArray(e) || e.length === 0) return null;
|
|
69
69
|
let t = [];
|
|
70
70
|
for (let n of e) {
|
|
@@ -101,11 +101,14 @@ function Je(e) {
|
|
|
101
101
|
}
|
|
102
102
|
return t;
|
|
103
103
|
}
|
|
104
|
-
function
|
|
104
|
+
function H(e) {
|
|
105
|
+
return e == null ? "—" : typeof e == "number" ? Number.isInteger(e) ? e.toLocaleString() : e.toLocaleString(void 0, { maximumFractionDigits: 2 }) : typeof e == "boolean" ? e ? "Yes" : "No" : typeof e == "string" ? e : JSON.stringify(e);
|
|
106
|
+
}
|
|
107
|
+
function U(e) {
|
|
105
108
|
let t = (e ?? "").toUpperCase();
|
|
106
109
|
return t.includes("BUY") || t.includes("ADD") ? "text-status-success-text" : t.includes("SELL") || t.includes("TRIM") || t.includes("REDUCE") ? "text-status-error-text" : "text-text-secondary";
|
|
107
110
|
}
|
|
108
|
-
function
|
|
111
|
+
function $e(e) {
|
|
109
112
|
if (e == null) return "—";
|
|
110
113
|
if (Array.isArray(e)) return `${e.length} trade${e.length === 1 ? "" : "s"}`;
|
|
111
114
|
if (typeof e == "object") {
|
|
@@ -114,133 +117,133 @@ function Xe(e) {
|
|
|
114
117
|
}
|
|
115
118
|
return String(e);
|
|
116
119
|
}
|
|
117
|
-
var
|
|
120
|
+
var et = {
|
|
118
121
|
portfolioId: "",
|
|
119
122
|
driftPct: "",
|
|
120
123
|
rationale: "",
|
|
121
124
|
trades: ""
|
|
122
125
|
};
|
|
123
|
-
function
|
|
126
|
+
function tt(e) {
|
|
124
127
|
if (e.trim() === "") return;
|
|
125
128
|
let t = Number(e);
|
|
126
129
|
return Number.isFinite(t) ? t : void 0;
|
|
127
130
|
}
|
|
128
|
-
function
|
|
129
|
-
let { data:
|
|
131
|
+
function W() {
|
|
132
|
+
let { data: c, isLoading: le, isError: de, refetch: he } = te(), { data: V } = ee(), [Qe, H] = y(void 0), U = Qe ?? V[0]?.id ?? "", { data: W, isLoading: ot, isError: st, refetch: ct } = o(U || void 0), G = r(), { data: K, isFetching: lt, refetch: ut } = s(U || void 0), { data: q, isLoading: dt, isError: ft, refetch: pt } = re(U || void 0), mt = i(), { items: ht, hasMore: gt, loadMore: _t, isLoading: vt, isFetchingNextPage: yt, isError: bt, refetch: xt } = a(), St = t(), J = ie(), Ct = e(), wt = n(), Tt = ne(), [Et, Dt] = y(!1), [Y, X] = y(et), [Ot, kt] = y(null), [At, jt] = y(null), [Z, Mt] = y(null), Q = v(() => {
|
|
130
133
|
let e = /* @__PURE__ */ new Map();
|
|
131
|
-
for (let t of
|
|
134
|
+
for (let t of V) e.set(t.id, t);
|
|
132
135
|
return e;
|
|
133
|
-
}, [
|
|
134
|
-
let t =
|
|
136
|
+
}, [V]), Nt = v(() => ht.filter((e) => qe.has(e.type)), [ht]), Pt = c.filter((e) => e.status === "DRAFT" || e.status === "PROPOSED" || e.status === "APPROVED"), $ = Nt.filter((e) => e.status === "OPEN"), Ft = c.length > 0 ? c.reduce((e, t) => e + (t.driftPct ?? 0), 0) / c.length : null, It = v(() => c.filter((e) => {
|
|
137
|
+
let t = Q.get(e.portfolioId)?.driftThresholdPct;
|
|
135
138
|
return t != null && Number.isFinite(t) && e.driftPct >= t;
|
|
136
|
-
}).length, [
|
|
139
|
+
}).length, [c, Q]), Lt = v(() => [...c].sort((e, t) => new Date(e.createdAt).getTime() - new Date(t.createdAt).getTime()).map((e) => e.driftPct).filter((e) => Number.isFinite(e)), [c]), Rt = v(() => {
|
|
137
140
|
let e = /* @__PURE__ */ new Map();
|
|
138
|
-
for (let t of
|
|
139
|
-
return
|
|
140
|
-
label:
|
|
141
|
+
for (let t of c) e.set(t.status, (e.get(t.status) ?? 0) + 1);
|
|
142
|
+
return Ye.filter((t) => (e.get(t) ?? 0) > 0).map((t) => ({
|
|
143
|
+
label: B(t),
|
|
141
144
|
value: e.get(t) ?? 0,
|
|
142
|
-
tone:
|
|
145
|
+
tone: Je[t]
|
|
143
146
|
}));
|
|
144
|
-
}, [
|
|
147
|
+
}, [c]), zt = v(() => {
|
|
145
148
|
let e = /* @__PURE__ */ new Map();
|
|
146
|
-
for (let t of
|
|
147
|
-
return
|
|
148
|
-
label:
|
|
149
|
+
for (let t of $) e.set(t.severity, (e.get(t.severity) ?? 0) + 1);
|
|
150
|
+
return Ze.filter((t) => (e.get(t) ?? 0) > 0).map((t) => ({
|
|
151
|
+
label: B(t),
|
|
149
152
|
value: e.get(t) ?? 0,
|
|
150
|
-
tone:
|
|
153
|
+
tone: Xe[t]
|
|
151
154
|
}));
|
|
152
|
-
}, [
|
|
153
|
-
function
|
|
154
|
-
|
|
155
|
+
}, [$]), Bt = V.length > 0;
|
|
156
|
+
function Vt() {
|
|
157
|
+
X(et), kt(null), Dt(!0);
|
|
155
158
|
}
|
|
156
|
-
function
|
|
157
|
-
if (!
|
|
159
|
+
function Ht() {
|
|
160
|
+
if (!Y.portfolioId) return;
|
|
158
161
|
let e;
|
|
159
|
-
if (
|
|
160
|
-
e = JSON.parse(
|
|
162
|
+
if (Y.trades.trim() !== "") try {
|
|
163
|
+
e = JSON.parse(Y.trades);
|
|
161
164
|
} catch {
|
|
162
|
-
|
|
165
|
+
kt("Trades must be valid JSON.");
|
|
163
166
|
return;
|
|
164
167
|
}
|
|
165
|
-
let t =
|
|
166
|
-
|
|
167
|
-
portfolioId:
|
|
168
|
+
let t = Q.get(Y.portfolioId);
|
|
169
|
+
St.mutate({
|
|
170
|
+
portfolioId: Y.portfolioId,
|
|
168
171
|
householdId: t?.householdId ?? null,
|
|
169
|
-
driftPct:
|
|
170
|
-
rationale:
|
|
172
|
+
driftPct: tt(Y.driftPct),
|
|
173
|
+
rationale: Y.rationale.trim() || null,
|
|
171
174
|
...e === void 0 ? {} : { trades: e }
|
|
172
|
-
}, { onSuccess: () =>
|
|
175
|
+
}, { onSuccess: () => Dt(!1) });
|
|
173
176
|
}
|
|
174
|
-
function
|
|
177
|
+
function Ut(e, t) {
|
|
175
178
|
if (t === "REJECTED" || t === "CANCELLED") {
|
|
176
|
-
|
|
179
|
+
Mt({
|
|
177
180
|
proposal: e,
|
|
178
181
|
status: t
|
|
179
182
|
});
|
|
180
183
|
return;
|
|
181
184
|
}
|
|
182
|
-
|
|
185
|
+
J.mutate({
|
|
183
186
|
id: e.id,
|
|
184
187
|
status: t
|
|
185
188
|
});
|
|
186
189
|
}
|
|
187
|
-
function
|
|
188
|
-
let t =
|
|
190
|
+
function Wt(e) {
|
|
191
|
+
let t = Q.get(e.portfolioId)?.driftThresholdPct;
|
|
189
192
|
return t != null && Number.isFinite(t) && e.driftPct >= t;
|
|
190
193
|
}
|
|
191
|
-
return /* @__PURE__ */
|
|
194
|
+
return /* @__PURE__ */ D(ue, {
|
|
192
195
|
title: "Risk & Rebalancing",
|
|
193
196
|
description: "Review drift-driven rebalance proposals and act on portfolio risk insights.",
|
|
194
|
-
badges: [`${
|
|
197
|
+
badges: [`${Pt.length} active`, `${$.length} open insight${$.length === 1 ? "" : "s"}`],
|
|
195
198
|
actionLabel: "New proposal",
|
|
196
|
-
onAction:
|
|
199
|
+
onAction: Vt,
|
|
197
200
|
children: [
|
|
198
|
-
/* @__PURE__ */
|
|
201
|
+
/* @__PURE__ */ D("div", {
|
|
199
202
|
className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-4",
|
|
200
203
|
children: [
|
|
201
|
-
/* @__PURE__ */
|
|
204
|
+
/* @__PURE__ */ E(l, {
|
|
202
205
|
index: 0,
|
|
203
|
-
children: /* @__PURE__ */
|
|
206
|
+
children: /* @__PURE__ */ E(u, {
|
|
204
207
|
label: "Average drift",
|
|
205
|
-
value:
|
|
206
|
-
spark:
|
|
207
|
-
sparkTone:
|
|
208
|
+
value: Ft === null ? "—" : g(Ft),
|
|
209
|
+
spark: Lt.length > 1 ? Lt : void 0,
|
|
210
|
+
sparkTone: It > 0 ? "error" : "brand",
|
|
208
211
|
glow: !0,
|
|
209
|
-
icon: /* @__PURE__ */
|
|
212
|
+
icon: /* @__PURE__ */ E(b, {
|
|
210
213
|
className: "size-4",
|
|
211
214
|
"aria-hidden": "true"
|
|
212
215
|
})
|
|
213
216
|
})
|
|
214
217
|
}),
|
|
215
|
-
/* @__PURE__ */
|
|
218
|
+
/* @__PURE__ */ E(l, {
|
|
216
219
|
index: 1,
|
|
217
|
-
children: /* @__PURE__ */
|
|
220
|
+
children: /* @__PURE__ */ E(u, {
|
|
218
221
|
label: "Active proposals",
|
|
219
|
-
value: String(
|
|
220
|
-
icon: /* @__PURE__ */
|
|
222
|
+
value: String(Pt.length),
|
|
223
|
+
icon: /* @__PURE__ */ E(fe, {
|
|
221
224
|
className: "size-4",
|
|
222
225
|
"aria-hidden": "true"
|
|
223
226
|
})
|
|
224
227
|
})
|
|
225
228
|
}),
|
|
226
|
-
/* @__PURE__ */
|
|
229
|
+
/* @__PURE__ */ E(l, {
|
|
227
230
|
index: 2,
|
|
228
|
-
children: /* @__PURE__ */
|
|
231
|
+
children: /* @__PURE__ */ E(u, {
|
|
229
232
|
label: "Total proposals",
|
|
230
|
-
value: String(
|
|
231
|
-
icon: /* @__PURE__ */
|
|
233
|
+
value: String(c.length),
|
|
234
|
+
icon: /* @__PURE__ */ E(_e, {
|
|
232
235
|
className: "size-4",
|
|
233
236
|
"aria-hidden": "true"
|
|
234
237
|
})
|
|
235
238
|
})
|
|
236
239
|
}),
|
|
237
|
-
/* @__PURE__ */
|
|
240
|
+
/* @__PURE__ */ E(l, {
|
|
238
241
|
index: 3,
|
|
239
|
-
children: /* @__PURE__ */
|
|
242
|
+
children: /* @__PURE__ */ E(u, {
|
|
240
243
|
label: "Open risk insights",
|
|
241
|
-
value: String(
|
|
242
|
-
deltaTone:
|
|
243
|
-
icon: /* @__PURE__ */
|
|
244
|
+
value: String($.length),
|
|
245
|
+
deltaTone: $.length > 0 ? "negative" : "neutral",
|
|
246
|
+
icon: /* @__PURE__ */ E(C, {
|
|
244
247
|
className: "size-4",
|
|
245
248
|
"aria-hidden": "true"
|
|
246
249
|
})
|
|
@@ -248,53 +251,53 @@ function $e() {
|
|
|
248
251
|
})
|
|
249
252
|
]
|
|
250
253
|
}),
|
|
251
|
-
(
|
|
254
|
+
(Rt.length > 0 || zt.length > 0) && !le ? /* @__PURE__ */ D("div", {
|
|
252
255
|
className: "grid gap-4 lg:grid-cols-2",
|
|
253
|
-
children: [/* @__PURE__ */
|
|
256
|
+
children: [/* @__PURE__ */ E(l, {
|
|
254
257
|
index: 0,
|
|
255
|
-
children: /* @__PURE__ */
|
|
258
|
+
children: /* @__PURE__ */ D(ce, {
|
|
256
259
|
glow: !0,
|
|
257
260
|
className: "h-full",
|
|
258
|
-
children: [/* @__PURE__ */
|
|
261
|
+
children: [/* @__PURE__ */ D("div", {
|
|
259
262
|
className: "mb-3 flex items-center gap-2",
|
|
260
|
-
children: [/* @__PURE__ */
|
|
263
|
+
children: [/* @__PURE__ */ E(Se, {
|
|
261
264
|
className: "size-4 text-text-secondary",
|
|
262
265
|
"aria-hidden": "true"
|
|
263
|
-
}), /* @__PURE__ */
|
|
266
|
+
}), /* @__PURE__ */ E("h2", {
|
|
264
267
|
className: "text-sm font-semibold text-text-primary",
|
|
265
268
|
children: "Proposal pipeline"
|
|
266
269
|
})]
|
|
267
|
-
}), /* @__PURE__ */
|
|
268
|
-
data:
|
|
269
|
-
centerValue: String(
|
|
270
|
+
}), /* @__PURE__ */ E(se, {
|
|
271
|
+
data: Rt,
|
|
272
|
+
centerValue: String(c.length),
|
|
270
273
|
centerLabel: "proposals",
|
|
271
274
|
height: 200
|
|
272
275
|
})]
|
|
273
276
|
})
|
|
274
|
-
}), /* @__PURE__ */
|
|
277
|
+
}), /* @__PURE__ */ E(l, {
|
|
275
278
|
index: 1,
|
|
276
|
-
children: /* @__PURE__ */
|
|
279
|
+
children: /* @__PURE__ */ D(ce, {
|
|
277
280
|
className: "h-full",
|
|
278
|
-
children: [/* @__PURE__ */
|
|
281
|
+
children: [/* @__PURE__ */ D("div", {
|
|
279
282
|
className: "mb-3 flex items-center gap-2",
|
|
280
|
-
children: [/* @__PURE__ */
|
|
283
|
+
children: [/* @__PURE__ */ E(C, {
|
|
281
284
|
className: "size-4 text-text-secondary",
|
|
282
285
|
"aria-hidden": "true"
|
|
283
|
-
}), /* @__PURE__ */
|
|
286
|
+
}), /* @__PURE__ */ E("h2", {
|
|
284
287
|
className: "text-sm font-semibold text-text-primary",
|
|
285
288
|
children: "Open risk signals"
|
|
286
289
|
})]
|
|
287
|
-
}),
|
|
288
|
-
data:
|
|
289
|
-
centerValue: String(
|
|
290
|
+
}), zt.length > 0 ? /* @__PURE__ */ E(se, {
|
|
291
|
+
data: zt,
|
|
292
|
+
centerValue: String($.length),
|
|
290
293
|
centerLabel: "open",
|
|
291
294
|
height: 200
|
|
292
|
-
}) : /* @__PURE__ */
|
|
295
|
+
}) : /* @__PURE__ */ D("div", {
|
|
293
296
|
className: "flex h-[200px] flex-col items-center justify-center gap-2 text-center",
|
|
294
|
-
children: [/* @__PURE__ */ w
|
|
297
|
+
children: [/* @__PURE__ */ E(w, {
|
|
295
298
|
className: "size-8 text-status-success-text",
|
|
296
299
|
"aria-hidden": "true"
|
|
297
|
-
}), /* @__PURE__ */
|
|
300
|
+
}), /* @__PURE__ */ E("p", {
|
|
298
301
|
className: "text-sm text-text-secondary",
|
|
299
302
|
children: "No open risk signals."
|
|
300
303
|
})]
|
|
@@ -302,75 +305,318 @@ function $e() {
|
|
|
302
305
|
})
|
|
303
306
|
})]
|
|
304
307
|
}) : null,
|
|
305
|
-
/* @__PURE__ */
|
|
308
|
+
/* @__PURE__ */ D(A, { children: [/* @__PURE__ */ D(N, { children: [/* @__PURE__ */ D(P, {
|
|
309
|
+
className: "flex items-center gap-2",
|
|
310
|
+
children: [/* @__PURE__ */ E(b, {
|
|
311
|
+
className: "h-5 w-5",
|
|
312
|
+
"aria-hidden": "true"
|
|
313
|
+
}), "Portfolio risk signals"]
|
|
314
|
+
}), /* @__PURE__ */ E(M, { children: "Real, explainable signals computed live from this portfolio's own holdings and target allocation — every signal below shows the real inputs and formula/threshold behind it. Informational only, never a buy/sell recommendation." })] }), /* @__PURE__ */ D(j, {
|
|
315
|
+
className: "space-y-4",
|
|
316
|
+
children: [/* @__PURE__ */ D("div", {
|
|
317
|
+
className: "flex flex-wrap items-center gap-3",
|
|
318
|
+
children: [
|
|
319
|
+
/* @__PURE__ */ D("div", {
|
|
320
|
+
className: "min-w-[220px] space-y-1.5",
|
|
321
|
+
children: [/* @__PURE__ */ E(I, {
|
|
322
|
+
htmlFor: "risk-portfolio",
|
|
323
|
+
children: "Portfolio"
|
|
324
|
+
}), /* @__PURE__ */ D(Le, {
|
|
325
|
+
value: U,
|
|
326
|
+
onValueChange: H,
|
|
327
|
+
children: [/* @__PURE__ */ E(Be, {
|
|
328
|
+
id: "risk-portfolio",
|
|
329
|
+
children: /* @__PURE__ */ E(Ve, { placeholder: "Select a portfolio" })
|
|
330
|
+
}), /* @__PURE__ */ E(Re, { children: V.map((e) => /* @__PURE__ */ E(ze, {
|
|
331
|
+
value: e.id,
|
|
332
|
+
children: e.name
|
|
333
|
+
}, e.id)) })]
|
|
334
|
+
})]
|
|
335
|
+
}),
|
|
336
|
+
/* @__PURE__ */ D(k, {
|
|
337
|
+
variant: "outline",
|
|
338
|
+
size: "sm",
|
|
339
|
+
className: "mt-auto",
|
|
340
|
+
disabled: !U || ot,
|
|
341
|
+
onClick: () => ct(),
|
|
342
|
+
children: [/* @__PURE__ */ E(be, {
|
|
343
|
+
className: "size-4",
|
|
344
|
+
"aria-hidden": "true"
|
|
345
|
+
}), "Recompute"]
|
|
346
|
+
}),
|
|
347
|
+
/* @__PURE__ */ D(k, {
|
|
348
|
+
variant: "outline",
|
|
349
|
+
size: "sm",
|
|
350
|
+
className: "mt-auto",
|
|
351
|
+
disabled: !U || (W?.signals.length ?? 0) === 0 || G.isPending,
|
|
352
|
+
onClick: () => G.mutate(U),
|
|
353
|
+
children: [/* @__PURE__ */ E(C, {
|
|
354
|
+
className: "size-4",
|
|
355
|
+
"aria-hidden": "true"
|
|
356
|
+
}), G.isPending ? "Saving…" : "Save as insights"]
|
|
357
|
+
})
|
|
358
|
+
]
|
|
359
|
+
}), V.length === 0 ? /* @__PURE__ */ E(d, {
|
|
360
|
+
icon: /* @__PURE__ */ E(b, {
|
|
361
|
+
className: "size-6",
|
|
362
|
+
"aria-hidden": "true"
|
|
363
|
+
}),
|
|
364
|
+
title: "No portfolios yet",
|
|
365
|
+
description: "Create a portfolio to compute real risk signals from its holdings."
|
|
366
|
+
}) : ot ? /* @__PURE__ */ E(p, {}) : st ? /* @__PURE__ */ E(f, { onRetry: () => ct() }) : W ? /* @__PURE__ */ D("div", {
|
|
367
|
+
className: "space-y-4",
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ D("div", {
|
|
370
|
+
className: "grid gap-3 sm:grid-cols-3",
|
|
371
|
+
children: [
|
|
372
|
+
/* @__PURE__ */ E(u, {
|
|
373
|
+
label: "Portfolio value",
|
|
374
|
+
value: h(W.totalValue),
|
|
375
|
+
icon: /* @__PURE__ */ E(_e, {
|
|
376
|
+
className: "size-4",
|
|
377
|
+
"aria-hidden": "true"
|
|
378
|
+
})
|
|
379
|
+
}),
|
|
380
|
+
/* @__PURE__ */ E(u, {
|
|
381
|
+
label: "Holdings considered",
|
|
382
|
+
value: String(W.holdingsConsidered),
|
|
383
|
+
icon: /* @__PURE__ */ E(fe, {
|
|
384
|
+
className: "size-4",
|
|
385
|
+
"aria-hidden": "true"
|
|
386
|
+
})
|
|
387
|
+
}),
|
|
388
|
+
/* @__PURE__ */ E(u, {
|
|
389
|
+
label: "Signals breached",
|
|
390
|
+
value: String(W.signals.length),
|
|
391
|
+
deltaTone: W.signals.length > 0 ? "negative" : "neutral",
|
|
392
|
+
icon: /* @__PURE__ */ E(C, {
|
|
393
|
+
className: "size-4",
|
|
394
|
+
"aria-hidden": "true"
|
|
395
|
+
})
|
|
396
|
+
})
|
|
397
|
+
]
|
|
398
|
+
}),
|
|
399
|
+
W.signals.length === 0 ? /* @__PURE__ */ E(d, {
|
|
400
|
+
icon: /* @__PURE__ */ E(w, {
|
|
401
|
+
className: "size-6",
|
|
402
|
+
"aria-hidden": "true"
|
|
403
|
+
}),
|
|
404
|
+
title: "No configured threshold was breached",
|
|
405
|
+
description: "This portfolio's concentration, cash, drift and unrealized-loss metrics are all within their configured thresholds."
|
|
406
|
+
}) : /* @__PURE__ */ E("ul", {
|
|
407
|
+
className: "space-y-3",
|
|
408
|
+
children: W.signals.map((e, t) => /* @__PURE__ */ E(rt, { signal: e }, `${e.kind}-${t}`))
|
|
409
|
+
}),
|
|
410
|
+
/* @__PURE__ */ D("div", {
|
|
411
|
+
className: "rounded-xl border border-border-subtle bg-bg-surface p-4",
|
|
412
|
+
children: [/* @__PURE__ */ D("div", {
|
|
413
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
414
|
+
children: [/* @__PURE__ */ D("div", {
|
|
415
|
+
className: "flex items-center gap-2",
|
|
416
|
+
children: [
|
|
417
|
+
/* @__PURE__ */ E(xe, {
|
|
418
|
+
className: "size-4 text-text-secondary",
|
|
419
|
+
"aria-hidden": "true"
|
|
420
|
+
}),
|
|
421
|
+
/* @__PURE__ */ E("h3", {
|
|
422
|
+
className: "text-sm font-semibold text-text-primary",
|
|
423
|
+
children: "AI summary"
|
|
424
|
+
}),
|
|
425
|
+
/* @__PURE__ */ E("span", {
|
|
426
|
+
className: "text-xs text-text-muted",
|
|
427
|
+
children: "(optional — plain-language restatement of the signals above; never a source of numbers)"
|
|
428
|
+
})
|
|
429
|
+
]
|
|
430
|
+
}), /* @__PURE__ */ D(k, {
|
|
431
|
+
variant: "outline",
|
|
432
|
+
size: "sm",
|
|
433
|
+
disabled: !U || lt,
|
|
434
|
+
onClick: () => ut(),
|
|
435
|
+
children: [/* @__PURE__ */ E(xe, {
|
|
436
|
+
className: "size-4",
|
|
437
|
+
"aria-hidden": "true"
|
|
438
|
+
}), lt ? "Generating…" : "Generate AI summary"]
|
|
439
|
+
})]
|
|
440
|
+
}), lt ? /* @__PURE__ */ E("p", {
|
|
441
|
+
className: "mt-2 text-sm text-text-secondary",
|
|
442
|
+
children: "Asking the AI provider…"
|
|
443
|
+
}) : K?.generated ? /* @__PURE__ */ D("div", {
|
|
444
|
+
className: "mt-2 space-y-1",
|
|
445
|
+
children: [/* @__PURE__ */ E("p", {
|
|
446
|
+
className: "text-sm text-text-primary",
|
|
447
|
+
children: K.summary
|
|
448
|
+
}), /* @__PURE__ */ D("p", {
|
|
449
|
+
className: "text-xs text-text-muted",
|
|
450
|
+
children: [
|
|
451
|
+
"AI-generated commentary",
|
|
452
|
+
K.provider ? ` · ${K.provider}` : "",
|
|
453
|
+
" · based on",
|
|
454
|
+
" ",
|
|
455
|
+
K.signalsConsidered,
|
|
456
|
+
" computed signal",
|
|
457
|
+
K.signalsConsidered === 1 ? "" : "s",
|
|
458
|
+
" above"
|
|
459
|
+
]
|
|
460
|
+
})]
|
|
461
|
+
}) : K && !K.generated ? /* @__PURE__ */ D("p", {
|
|
462
|
+
className: "mt-2 text-sm text-text-secondary",
|
|
463
|
+
children: [
|
|
464
|
+
"AI summary unavailable — ",
|
|
465
|
+
K.reason ?? "no provider configured",
|
|
466
|
+
". The deterministic signals above are unaffected."
|
|
467
|
+
]
|
|
468
|
+
}) : /* @__PURE__ */ E("p", {
|
|
469
|
+
className: "mt-2 text-sm text-text-muted",
|
|
470
|
+
children: "Not generated yet. The deterministic signals above always work without this."
|
|
471
|
+
})]
|
|
472
|
+
})
|
|
473
|
+
]
|
|
474
|
+
}) : /* @__PURE__ */ E(d, {
|
|
475
|
+
icon: /* @__PURE__ */ E(b, {
|
|
476
|
+
className: "size-6",
|
|
477
|
+
"aria-hidden": "true"
|
|
478
|
+
}),
|
|
479
|
+
title: "Select a portfolio",
|
|
480
|
+
description: "Choose a portfolio above to compute its real risk signals."
|
|
481
|
+
})]
|
|
482
|
+
})] }),
|
|
483
|
+
/* @__PURE__ */ D(A, { children: [/* @__PURE__ */ D(N, { children: [/* @__PURE__ */ D(P, {
|
|
306
484
|
className: "flex items-center gap-2",
|
|
307
|
-
children: [/* @__PURE__ */
|
|
485
|
+
children: [/* @__PURE__ */ E(S, {
|
|
486
|
+
className: "h-5 w-5",
|
|
487
|
+
"aria-hidden": "true"
|
|
488
|
+
}), "Tax-loss-harvesting opportunities"]
|
|
489
|
+
}), /* @__PURE__ */ E(M, { children: "Real unrealized-loss detection for the selected portfolio, using configurable dollar/percent thresholds and a wash-sale caution flag from your recorded transactions. Detection only — this never places a trade, and it is not tax advice." })] }), /* @__PURE__ */ D(j, {
|
|
490
|
+
className: "space-y-4",
|
|
491
|
+
children: [/* @__PURE__ */ D("div", {
|
|
492
|
+
className: "flex flex-wrap items-center gap-3",
|
|
493
|
+
children: [
|
|
494
|
+
/* @__PURE__ */ D(k, {
|
|
495
|
+
variant: "outline",
|
|
496
|
+
size: "sm",
|
|
497
|
+
disabled: !U || dt,
|
|
498
|
+
onClick: () => pt(),
|
|
499
|
+
children: [/* @__PURE__ */ E(be, {
|
|
500
|
+
className: "size-4",
|
|
501
|
+
"aria-hidden": "true"
|
|
502
|
+
}), "Recompute"]
|
|
503
|
+
}),
|
|
504
|
+
/* @__PURE__ */ D(k, {
|
|
505
|
+
variant: "outline",
|
|
506
|
+
size: "sm",
|
|
507
|
+
disabled: !U || (q?.opportunities.length ?? 0) === 0 || mt.isPending,
|
|
508
|
+
onClick: () => mt.mutate({ portfolioId: U }),
|
|
509
|
+
children: [/* @__PURE__ */ E(C, {
|
|
510
|
+
className: "size-4",
|
|
511
|
+
"aria-hidden": "true"
|
|
512
|
+
}), mt.isPending ? "Saving…" : "Save as insights"]
|
|
513
|
+
}),
|
|
514
|
+
q ? /* @__PURE__ */ D("span", {
|
|
515
|
+
className: "text-xs text-text-muted",
|
|
516
|
+
children: [
|
|
517
|
+
"Thresholds: ≥",
|
|
518
|
+
h(q.thresholds.minLossAmount),
|
|
519
|
+
" or ≥",
|
|
520
|
+
g(q.thresholds.minLossPct),
|
|
521
|
+
" of portfolio value"
|
|
522
|
+
]
|
|
523
|
+
}) : null
|
|
524
|
+
]
|
|
525
|
+
}), V.length === 0 ? /* @__PURE__ */ E(d, {
|
|
526
|
+
icon: /* @__PURE__ */ E(S, {
|
|
527
|
+
className: "size-6",
|
|
528
|
+
"aria-hidden": "true"
|
|
529
|
+
}),
|
|
530
|
+
title: "No portfolios yet",
|
|
531
|
+
description: "Create a portfolio to detect real tax-loss-harvesting opportunities from its holdings."
|
|
532
|
+
}) : dt ? /* @__PURE__ */ E(p, {}) : ft ? /* @__PURE__ */ E(f, { onRetry: () => pt() }) : q && q.opportunities.length > 0 ? /* @__PURE__ */ E("ul", {
|
|
533
|
+
className: "space-y-3",
|
|
534
|
+
children: q.opportunities.map((e) => /* @__PURE__ */ E(it, { opportunity: e }, e.symbol))
|
|
535
|
+
}) : q ? /* @__PURE__ */ E(d, {
|
|
536
|
+
icon: /* @__PURE__ */ E(w, {
|
|
537
|
+
className: "size-6",
|
|
538
|
+
"aria-hidden": "true"
|
|
539
|
+
}),
|
|
540
|
+
title: "No opportunities at the current thresholds",
|
|
541
|
+
description: "No symbol's unrealized loss clears the configured dollar/percent thresholds."
|
|
542
|
+
}) : /* @__PURE__ */ E(d, {
|
|
543
|
+
icon: /* @__PURE__ */ E(S, {
|
|
544
|
+
className: "size-6",
|
|
545
|
+
"aria-hidden": "true"
|
|
546
|
+
}),
|
|
547
|
+
title: "Select a portfolio",
|
|
548
|
+
description: "Choose a portfolio above to detect real tax-loss opportunities."
|
|
549
|
+
})]
|
|
550
|
+
})] }),
|
|
551
|
+
/* @__PURE__ */ D(A, { children: [/* @__PURE__ */ D(N, { children: [/* @__PURE__ */ D(P, {
|
|
552
|
+
className: "flex items-center gap-2",
|
|
553
|
+
children: [/* @__PURE__ */ E(x, {
|
|
308
554
|
className: "h-5 w-5",
|
|
309
555
|
"aria-hidden": "true"
|
|
310
556
|
}), "Rebalance proposals"]
|
|
311
|
-
}), /* @__PURE__ */
|
|
312
|
-
icon: /* @__PURE__ */
|
|
557
|
+
}), /* @__PURE__ */ E(M, { children: "Drift against target allocation, with lifecycle actions per proposal." })] }), /* @__PURE__ */ E(j, { children: le ? /* @__PURE__ */ E(p, {}) : de ? /* @__PURE__ */ E(f, { onRetry: () => he() }) : c.length === 0 ? /* @__PURE__ */ E(d, {
|
|
558
|
+
icon: /* @__PURE__ */ E(x, {
|
|
313
559
|
className: "size-6",
|
|
314
560
|
"aria-hidden": "true"
|
|
315
561
|
}),
|
|
316
562
|
title: "No rebalance proposals",
|
|
317
|
-
description:
|
|
318
|
-
action:
|
|
563
|
+
description: Bt ? "Create a proposal when a portfolio drifts from its target allocation." : "Create a portfolio first, then propose a rebalance when it drifts.",
|
|
564
|
+
action: Bt ? /* @__PURE__ */ D(k, {
|
|
319
565
|
size: "sm",
|
|
320
|
-
onClick:
|
|
321
|
-
children: [/* @__PURE__ */
|
|
566
|
+
onClick: Vt,
|
|
567
|
+
children: [/* @__PURE__ */ E(ye, {
|
|
322
568
|
className: "size-4",
|
|
323
569
|
"aria-hidden": "true"
|
|
324
570
|
}), "New proposal"]
|
|
325
571
|
}) : void 0
|
|
326
|
-
}) : /* @__PURE__ */
|
|
572
|
+
}) : /* @__PURE__ */ E("div", {
|
|
327
573
|
className: "overflow-x-auto",
|
|
328
|
-
children: /* @__PURE__ */
|
|
329
|
-
/* @__PURE__ */
|
|
330
|
-
/* @__PURE__ */
|
|
574
|
+
children: /* @__PURE__ */ D(He, { children: [/* @__PURE__ */ E(We, { children: /* @__PURE__ */ D(z, { children: [
|
|
575
|
+
/* @__PURE__ */ E(R, { children: "Portfolio" }),
|
|
576
|
+
/* @__PURE__ */ E(R, {
|
|
331
577
|
className: "text-right",
|
|
332
578
|
children: "Drift"
|
|
333
579
|
}),
|
|
334
|
-
/* @__PURE__ */
|
|
335
|
-
/* @__PURE__ */
|
|
336
|
-
/* @__PURE__ */
|
|
337
|
-
/* @__PURE__ */
|
|
338
|
-
/* @__PURE__ */
|
|
580
|
+
/* @__PURE__ */ E(R, { children: "Status" }),
|
|
581
|
+
/* @__PURE__ */ E(R, { children: "Rationale" }),
|
|
582
|
+
/* @__PURE__ */ E(R, { children: "Trades" }),
|
|
583
|
+
/* @__PURE__ */ E(R, { children: "Created" }),
|
|
584
|
+
/* @__PURE__ */ E(R, {
|
|
339
585
|
className: "w-12 text-right",
|
|
340
586
|
children: "Actions"
|
|
341
587
|
})
|
|
342
|
-
] }) }), /* @__PURE__ */
|
|
343
|
-
let t =
|
|
344
|
-
return /* @__PURE__ */
|
|
345
|
-
onClick: () =>
|
|
588
|
+
] }) }), /* @__PURE__ */ E(Ue, { children: c.map((e) => {
|
|
589
|
+
let t = Q.get(e.portfolioId), n = Wt(e), r = Ke[e.status], i = t?.driftThresholdPct, a = i != null && i > 0 ? Math.min(100, e.driftPct / i * 100) : null;
|
|
590
|
+
return /* @__PURE__ */ D(z, {
|
|
591
|
+
onClick: () => jt(e),
|
|
346
592
|
className: "cursor-pointer transition-colors motion-safe:hover:bg-bg-elevated",
|
|
347
593
|
children: [
|
|
348
|
-
/* @__PURE__ */
|
|
594
|
+
/* @__PURE__ */ D(L, { children: [/* @__PURE__ */ E("p", {
|
|
349
595
|
className: "font-medium text-text-primary",
|
|
350
596
|
children: t?.name ?? "Unknown portfolio"
|
|
351
|
-
}), /* @__PURE__ */
|
|
597
|
+
}), /* @__PURE__ */ D("p", {
|
|
352
598
|
className: "text-xs text-text-secondary",
|
|
353
|
-
children: [t?.baseCurrency ?? "—", i == null ? "" : ` · threshold ${
|
|
599
|
+
children: [t?.baseCurrency ?? "—", i == null ? "" : ` · threshold ${g(i)}`]
|
|
354
600
|
})] }),
|
|
355
|
-
/* @__PURE__ */
|
|
601
|
+
/* @__PURE__ */ D(L, {
|
|
356
602
|
className: "text-right",
|
|
357
|
-
children: [/* @__PURE__ */
|
|
603
|
+
children: [/* @__PURE__ */ D("span", {
|
|
358
604
|
className: `inline-flex items-center justify-end gap-1 font-semibold tabular-nums ${n ? "text-status-error-text" : "text-text-primary"}`,
|
|
359
|
-
children: [n ? /* @__PURE__ */
|
|
605
|
+
children: [n ? /* @__PURE__ */ E(pe, {
|
|
360
606
|
className: "size-4",
|
|
361
607
|
"aria-hidden": "true"
|
|
362
|
-
}) : null,
|
|
363
|
-
}), a == null ? n ? /* @__PURE__ */
|
|
608
|
+
}) : null, g(e.driftPct)]
|
|
609
|
+
}), a == null ? n ? /* @__PURE__ */ E("p", {
|
|
364
610
|
className: "text-xs text-status-error-text",
|
|
365
611
|
children: "Over threshold"
|
|
366
|
-
}) : null : /* @__PURE__ */
|
|
612
|
+
}) : null : /* @__PURE__ */ E("div", {
|
|
367
613
|
className: "ml-auto mt-1 h-1.5 w-24 overflow-hidden rounded-full bg-bg-sunken",
|
|
368
614
|
role: "progressbar",
|
|
369
615
|
"aria-valuenow": Math.round(a),
|
|
370
616
|
"aria-valuemin": 0,
|
|
371
617
|
"aria-valuemax": 100,
|
|
372
618
|
"aria-label": `Drift vs threshold for ${t?.name ?? "portfolio"}`,
|
|
373
|
-
children: /* @__PURE__ */
|
|
619
|
+
children: /* @__PURE__ */ E("div", {
|
|
374
620
|
className: "h-full rounded-full",
|
|
375
621
|
style: {
|
|
376
622
|
width: `${a}%`,
|
|
@@ -379,60 +625,60 @@ function $e() {
|
|
|
379
625
|
})
|
|
380
626
|
})]
|
|
381
627
|
}),
|
|
382
|
-
/* @__PURE__ */
|
|
383
|
-
variant:
|
|
384
|
-
children:
|
|
628
|
+
/* @__PURE__ */ E(L, { children: /* @__PURE__ */ E(O, {
|
|
629
|
+
variant: _(e.status),
|
|
630
|
+
children: B(e.status)
|
|
385
631
|
}) }),
|
|
386
|
-
/* @__PURE__ */
|
|
632
|
+
/* @__PURE__ */ E(L, {
|
|
387
633
|
className: "max-w-xs",
|
|
388
|
-
children: /* @__PURE__ */
|
|
634
|
+
children: /* @__PURE__ */ E("p", {
|
|
389
635
|
className: "truncate text-sm text-text-secondary",
|
|
390
636
|
children: e.rationale ?? "—"
|
|
391
637
|
})
|
|
392
638
|
}),
|
|
393
|
-
/* @__PURE__ */
|
|
639
|
+
/* @__PURE__ */ E(L, {
|
|
394
640
|
className: "text-sm text-text-secondary",
|
|
395
|
-
children:
|
|
641
|
+
children: $e(e.trades)
|
|
396
642
|
}),
|
|
397
|
-
/* @__PURE__ */
|
|
643
|
+
/* @__PURE__ */ E(L, {
|
|
398
644
|
className: "text-sm text-text-secondary",
|
|
399
645
|
children: m(e.createdAt)
|
|
400
646
|
}),
|
|
401
|
-
/* @__PURE__ */
|
|
647
|
+
/* @__PURE__ */ E(L, {
|
|
402
648
|
className: "text-right",
|
|
403
649
|
onClick: (e) => e.stopPropagation(),
|
|
404
|
-
children: /* @__PURE__ */
|
|
650
|
+
children: /* @__PURE__ */ D(je, { children: [/* @__PURE__ */ E(Fe, {
|
|
405
651
|
asChild: !0,
|
|
406
|
-
children: /* @__PURE__ */
|
|
652
|
+
children: /* @__PURE__ */ E(k, {
|
|
407
653
|
variant: "ghost",
|
|
408
654
|
size: "sm",
|
|
409
655
|
"aria-label": `Actions for ${t?.name ?? "proposal"}`,
|
|
410
|
-
children: /* @__PURE__ */
|
|
656
|
+
children: /* @__PURE__ */ E(ve, {
|
|
411
657
|
className: "size-4",
|
|
412
658
|
"aria-hidden": "true"
|
|
413
659
|
})
|
|
414
660
|
})
|
|
415
|
-
}), /* @__PURE__ */
|
|
661
|
+
}), /* @__PURE__ */ D(Me, {
|
|
416
662
|
align: "end",
|
|
417
|
-
children: [/* @__PURE__ */
|
|
418
|
-
onClick: () =>
|
|
419
|
-
children: [/* @__PURE__ */
|
|
663
|
+
children: [/* @__PURE__ */ D(F, {
|
|
664
|
+
onClick: () => jt(e),
|
|
665
|
+
children: [/* @__PURE__ */ E(ge, {
|
|
420
666
|
className: "size-4",
|
|
421
667
|
"aria-hidden": "true"
|
|
422
668
|
}), "View details"]
|
|
423
|
-
}), r.length > 0 ? /* @__PURE__ */
|
|
424
|
-
/* @__PURE__ */
|
|
425
|
-
/* @__PURE__ */
|
|
669
|
+
}), r.length > 0 ? /* @__PURE__ */ D(Ce, { children: [
|
|
670
|
+
/* @__PURE__ */ E(Pe, {}),
|
|
671
|
+
/* @__PURE__ */ E(Ne, { children: "Advance to" }),
|
|
426
672
|
r.map((t) => {
|
|
427
673
|
let n = t === "REJECTED" || t === "CANCELLED";
|
|
428
|
-
return /* @__PURE__ */
|
|
429
|
-
disabled:
|
|
674
|
+
return /* @__PURE__ */ D(F, {
|
|
675
|
+
disabled: J.isPending,
|
|
430
676
|
className: n ? "text-status-error-text" : void 0,
|
|
431
|
-
onClick: () =>
|
|
432
|
-
children: [
|
|
677
|
+
onClick: () => Ut(e, t),
|
|
678
|
+
children: [E(n ? T : me, {
|
|
433
679
|
className: "size-4",
|
|
434
680
|
"aria-hidden": "true"
|
|
435
|
-
}),
|
|
681
|
+
}), B(t)]
|
|
436
682
|
}, t);
|
|
437
683
|
})
|
|
438
684
|
] }) : null]
|
|
@@ -442,79 +688,79 @@ function $e() {
|
|
|
442
688
|
}, e.id);
|
|
443
689
|
}) })] })
|
|
444
690
|
}) })] }),
|
|
445
|
-
/* @__PURE__ */
|
|
691
|
+
/* @__PURE__ */ D(A, { children: [/* @__PURE__ */ D(N, { children: [/* @__PURE__ */ D(P, {
|
|
446
692
|
className: "flex items-center gap-2",
|
|
447
|
-
children: [/* @__PURE__ */
|
|
693
|
+
children: [/* @__PURE__ */ E(C, {
|
|
448
694
|
className: "h-5 w-5",
|
|
449
695
|
"aria-hidden": "true"
|
|
450
696
|
}), "Risk insights"]
|
|
451
|
-
}), /* @__PURE__ */
|
|
452
|
-
icon: /* @__PURE__ */ w
|
|
697
|
+
}), /* @__PURE__ */ E(M, { children: "Drift, concentration, cash-drag and fee-anomaly signals detected across your portfolios." })] }), /* @__PURE__ */ E(j, { children: vt ? /* @__PURE__ */ E(p, {}) : bt ? /* @__PURE__ */ E(f, { onRetry: () => xt() }) : Nt.length === 0 ? /* @__PURE__ */ E(d, {
|
|
698
|
+
icon: /* @__PURE__ */ E(w, {
|
|
453
699
|
className: "size-6",
|
|
454
700
|
"aria-hidden": "true"
|
|
455
701
|
}),
|
|
456
702
|
title: "No risk insights",
|
|
457
703
|
description: "No drift, concentration, cash-drag or fee-anomaly signals are open right now."
|
|
458
|
-
}) : /* @__PURE__ */
|
|
704
|
+
}) : /* @__PURE__ */ D("div", {
|
|
459
705
|
className: "space-y-3",
|
|
460
|
-
children: [
|
|
706
|
+
children: [Nt.map((e, t) => /* @__PURE__ */ E(l, {
|
|
461
707
|
index: t,
|
|
462
|
-
children: /* @__PURE__ */
|
|
708
|
+
children: /* @__PURE__ */ E(at, {
|
|
463
709
|
insight: e,
|
|
464
|
-
onAcknowledge: () =>
|
|
465
|
-
onResolve: () =>
|
|
466
|
-
onDismiss: () =>
|
|
467
|
-
actionPending:
|
|
710
|
+
onAcknowledge: () => Ct.mutate(e.id),
|
|
711
|
+
onResolve: () => Tt.mutate(e.id),
|
|
712
|
+
onDismiss: () => wt.mutate(e.id),
|
|
713
|
+
actionPending: Ct.isPending || Tt.isPending || wt.isPending
|
|
468
714
|
})
|
|
469
|
-
}, e.id)), /* @__PURE__ */
|
|
470
|
-
hasMore:
|
|
471
|
-
onClick:
|
|
472
|
-
loading:
|
|
715
|
+
}, e.id)), /* @__PURE__ */ E(ae, {
|
|
716
|
+
hasMore: gt,
|
|
717
|
+
onClick: _t,
|
|
718
|
+
loading: yt,
|
|
473
719
|
label: "Load more insights"
|
|
474
720
|
})]
|
|
475
721
|
}) })] }),
|
|
476
|
-
/* @__PURE__ */
|
|
477
|
-
open:
|
|
478
|
-
onOpenChange:
|
|
479
|
-
children: /* @__PURE__ */
|
|
480
|
-
/* @__PURE__ */
|
|
481
|
-
|
|
722
|
+
/* @__PURE__ */ E(we, {
|
|
723
|
+
open: Et,
|
|
724
|
+
onOpenChange: Dt,
|
|
725
|
+
children: /* @__PURE__ */ D(Ee, { children: [
|
|
726
|
+
/* @__PURE__ */ D(ke, { children: [/* @__PURE__ */ E(Ae, { children: "New rebalance proposal" }), /* @__PURE__ */ E(De, { children: "Propose a rebalance for a portfolio that has drifted from its target allocation." })] }),
|
|
727
|
+
Bt ? /* @__PURE__ */ D("div", {
|
|
482
728
|
className: "grid gap-4",
|
|
483
729
|
children: [
|
|
484
|
-
/* @__PURE__ */
|
|
730
|
+
/* @__PURE__ */ D("div", {
|
|
485
731
|
className: "grid gap-4 sm:grid-cols-2",
|
|
486
|
-
children: [/* @__PURE__ */
|
|
732
|
+
children: [/* @__PURE__ */ D("div", {
|
|
487
733
|
className: "space-y-2",
|
|
488
|
-
children: [/* @__PURE__ */
|
|
734
|
+
children: [/* @__PURE__ */ D(I, {
|
|
489
735
|
htmlFor: "prop-portfolio",
|
|
490
|
-
children: ["Portfolio ", /* @__PURE__ */
|
|
736
|
+
children: ["Portfolio ", /* @__PURE__ */ E("span", {
|
|
491
737
|
className: "text-status-error-text",
|
|
492
738
|
children: "*"
|
|
493
739
|
})]
|
|
494
|
-
}), /* @__PURE__ */
|
|
495
|
-
value:
|
|
496
|
-
onValueChange: (e) =>
|
|
740
|
+
}), /* @__PURE__ */ D(Le, {
|
|
741
|
+
value: Y.portfolioId,
|
|
742
|
+
onValueChange: (e) => X((t) => ({
|
|
497
743
|
...t,
|
|
498
744
|
portfolioId: e
|
|
499
745
|
})),
|
|
500
|
-
children: [/* @__PURE__ */
|
|
746
|
+
children: [/* @__PURE__ */ E(Be, {
|
|
501
747
|
id: "prop-portfolio",
|
|
502
|
-
children: /* @__PURE__ */
|
|
503
|
-
}), /* @__PURE__ */
|
|
748
|
+
children: /* @__PURE__ */ E(Ve, { placeholder: "Select a portfolio" })
|
|
749
|
+
}), /* @__PURE__ */ E(Re, { children: V.map((e) => /* @__PURE__ */ E(ze, {
|
|
504
750
|
value: e.id,
|
|
505
751
|
children: e.name
|
|
506
752
|
}, e.id)) })]
|
|
507
753
|
})]
|
|
508
|
-
}), /* @__PURE__ */
|
|
754
|
+
}), /* @__PURE__ */ D("div", {
|
|
509
755
|
className: "space-y-2",
|
|
510
|
-
children: [/* @__PURE__ */
|
|
756
|
+
children: [/* @__PURE__ */ E(I, {
|
|
511
757
|
htmlFor: "prop-drift",
|
|
512
758
|
children: "Drift %"
|
|
513
|
-
}), /* @__PURE__ */
|
|
759
|
+
}), /* @__PURE__ */ E(Ie, {
|
|
514
760
|
id: "prop-drift",
|
|
515
761
|
type: "number",
|
|
516
|
-
value:
|
|
517
|
-
onChange: (e) =>
|
|
762
|
+
value: Y.driftPct,
|
|
763
|
+
onChange: (e) => X((t) => ({
|
|
518
764
|
...t,
|
|
519
765
|
driftPct: e.target.value
|
|
520
766
|
})),
|
|
@@ -522,294 +768,294 @@ function $e() {
|
|
|
522
768
|
})]
|
|
523
769
|
})]
|
|
524
770
|
}),
|
|
525
|
-
/* @__PURE__ */
|
|
771
|
+
/* @__PURE__ */ D("div", {
|
|
526
772
|
className: "space-y-2",
|
|
527
|
-
children: [/* @__PURE__ */
|
|
773
|
+
children: [/* @__PURE__ */ E(I, {
|
|
528
774
|
htmlFor: "prop-rationale",
|
|
529
775
|
children: "Rationale"
|
|
530
|
-
}), /* @__PURE__ */
|
|
776
|
+
}), /* @__PURE__ */ E(Ge, {
|
|
531
777
|
id: "prop-rationale",
|
|
532
|
-
value:
|
|
533
|
-
onChange: (e) =>
|
|
778
|
+
value: Y.rationale,
|
|
779
|
+
onChange: (e) => X((t) => ({
|
|
534
780
|
...t,
|
|
535
781
|
rationale: e.target.value
|
|
536
782
|
})),
|
|
537
783
|
placeholder: "Why is this rebalance needed?"
|
|
538
784
|
})]
|
|
539
785
|
}),
|
|
540
|
-
/* @__PURE__ */
|
|
786
|
+
/* @__PURE__ */ D("div", {
|
|
541
787
|
className: "space-y-2",
|
|
542
788
|
children: [
|
|
543
|
-
/* @__PURE__ */
|
|
789
|
+
/* @__PURE__ */ E(I, {
|
|
544
790
|
htmlFor: "prop-trades",
|
|
545
791
|
children: "Trades (JSON, optional)"
|
|
546
792
|
}),
|
|
547
|
-
/* @__PURE__ */
|
|
793
|
+
/* @__PURE__ */ E(Ge, {
|
|
548
794
|
id: "prop-trades",
|
|
549
795
|
className: "font-mono text-xs",
|
|
550
|
-
value:
|
|
796
|
+
value: Y.trades,
|
|
551
797
|
onChange: (e) => {
|
|
552
|
-
|
|
798
|
+
kt(null), X((t) => ({
|
|
553
799
|
...t,
|
|
554
800
|
trades: e.target.value
|
|
555
801
|
}));
|
|
556
802
|
},
|
|
557
803
|
placeholder: "e.g. [{\"symbol\":\"VOO\",\"action\":\"SELL\",\"quantity\":10}]"
|
|
558
804
|
}),
|
|
559
|
-
|
|
805
|
+
Ot ? /* @__PURE__ */ E("p", {
|
|
560
806
|
className: "text-xs text-status-error-text",
|
|
561
|
-
children:
|
|
807
|
+
children: Ot
|
|
562
808
|
}) : null
|
|
563
809
|
]
|
|
564
810
|
})
|
|
565
811
|
]
|
|
566
|
-
}) : /* @__PURE__ */
|
|
567
|
-
icon: /* @__PURE__ */
|
|
812
|
+
}) : /* @__PURE__ */ E(d, {
|
|
813
|
+
icon: /* @__PURE__ */ E(x, {
|
|
568
814
|
className: "size-6",
|
|
569
815
|
"aria-hidden": "true"
|
|
570
816
|
}),
|
|
571
817
|
title: "Create a portfolio first",
|
|
572
818
|
description: "A rebalance proposal targets a portfolio. Add a portfolio on the Portfolios page, then return here to propose a rebalance."
|
|
573
819
|
}),
|
|
574
|
-
/* @__PURE__ */
|
|
820
|
+
/* @__PURE__ */ D(Oe, { children: [/* @__PURE__ */ E(Te, {
|
|
575
821
|
asChild: !0,
|
|
576
|
-
children: /* @__PURE__ */
|
|
822
|
+
children: /* @__PURE__ */ E(k, {
|
|
577
823
|
variant: "outline",
|
|
578
824
|
children: "Cancel"
|
|
579
825
|
})
|
|
580
|
-
}), /* @__PURE__ */
|
|
581
|
-
onClick:
|
|
582
|
-
disabled: !
|
|
583
|
-
children:
|
|
826
|
+
}), /* @__PURE__ */ E(k, {
|
|
827
|
+
onClick: Ht,
|
|
828
|
+
disabled: !Y.portfolioId || St.isPending,
|
|
829
|
+
children: St.isPending ? "Creating…" : "Create proposal"
|
|
584
830
|
})] })
|
|
585
831
|
] })
|
|
586
832
|
}),
|
|
587
833
|
(() => {
|
|
588
|
-
let e =
|
|
589
|
-
return /* @__PURE__ */
|
|
834
|
+
let e = At ? c.find((e) => e.id === At.id) ?? At : null, t = e ? ht.filter((t) => t.subjectId === e.portfolioId) : [];
|
|
835
|
+
return /* @__PURE__ */ E(nt, {
|
|
590
836
|
proposal: e,
|
|
591
|
-
portfolio: e ?
|
|
837
|
+
portfolio: e ? Q.get(e.portfolioId) ?? null : null,
|
|
592
838
|
relatedInsights: t,
|
|
593
|
-
nextStatuses: e ?
|
|
594
|
-
transitionPending:
|
|
839
|
+
nextStatuses: e ? Ke[e.status] : [],
|
|
840
|
+
transitionPending: J.isPending,
|
|
595
841
|
onTransition: (t) => {
|
|
596
|
-
e &&
|
|
842
|
+
e && Ut(e, t);
|
|
597
843
|
},
|
|
598
844
|
onOpenChange: (e) => {
|
|
599
|
-
e ||
|
|
845
|
+
e || jt(null);
|
|
600
846
|
}
|
|
601
847
|
});
|
|
602
848
|
})(),
|
|
603
|
-
/* @__PURE__ */
|
|
604
|
-
open:
|
|
849
|
+
/* @__PURE__ */ E(oe, {
|
|
850
|
+
open: Z !== null,
|
|
605
851
|
onOpenChange: (e) => {
|
|
606
|
-
e ||
|
|
852
|
+
e || Mt(null);
|
|
607
853
|
},
|
|
608
|
-
title:
|
|
609
|
-
description:
|
|
610
|
-
confirmLabel:
|
|
854
|
+
title: Z?.status === "REJECTED" ? "Reject this proposal?" : "Cancel this proposal?",
|
|
855
|
+
description: Z ? `This moves the rebalance proposal for ${Q.get(Z.proposal.portfolioId)?.name ?? "this portfolio"} to ${B(Z.status)}. This cannot be undone.` : void 0,
|
|
856
|
+
confirmLabel: Z?.status === "REJECTED" ? "Reject" : "Cancel proposal",
|
|
611
857
|
cancelLabel: "Keep",
|
|
612
858
|
destructive: !0,
|
|
613
|
-
pending:
|
|
859
|
+
pending: J.isPending,
|
|
614
860
|
onConfirm: () => {
|
|
615
|
-
|
|
616
|
-
id:
|
|
617
|
-
status:
|
|
618
|
-
}, { onSuccess: () =>
|
|
861
|
+
Z && J.mutate({
|
|
862
|
+
id: Z.proposal.id,
|
|
863
|
+
status: Z.status
|
|
864
|
+
}, { onSuccess: () => Mt(null) });
|
|
619
865
|
}
|
|
620
866
|
})
|
|
621
867
|
]
|
|
622
868
|
});
|
|
623
869
|
}
|
|
624
|
-
function
|
|
625
|
-
let s = e ?
|
|
626
|
-
return /* @__PURE__ */
|
|
870
|
+
function nt({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, transitionPending: i, onTransition: a, onOpenChange: o }) {
|
|
871
|
+
let s = e ? Qe(e.trades) : null, ee = e != null && t?.driftThresholdPct != null && Number.isFinite(t.driftThresholdPct) && e.driftPct >= t.driftThresholdPct;
|
|
872
|
+
return /* @__PURE__ */ E(we, {
|
|
627
873
|
open: e !== null,
|
|
628
874
|
onOpenChange: o,
|
|
629
|
-
children: /* @__PURE__ */
|
|
875
|
+
children: /* @__PURE__ */ E(Ee, {
|
|
630
876
|
className: "max-h-[88vh] max-w-3xl overflow-y-auto",
|
|
631
|
-
children: e ? /* @__PURE__ */
|
|
632
|
-
/* @__PURE__ */
|
|
633
|
-
/* @__PURE__ */
|
|
877
|
+
children: e ? /* @__PURE__ */ D(Ce, { children: [
|
|
878
|
+
/* @__PURE__ */ D(ke, { children: [
|
|
879
|
+
/* @__PURE__ */ E("p", {
|
|
634
880
|
className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
635
881
|
children: "Detail"
|
|
636
882
|
}),
|
|
637
|
-
/* @__PURE__ */
|
|
883
|
+
/* @__PURE__ */ D(Ae, {
|
|
638
884
|
className: "flex flex-wrap items-center gap-2 text-xl",
|
|
639
885
|
children: [
|
|
640
886
|
t?.name ?? "Rebalance proposal",
|
|
641
|
-
/* @__PURE__ */
|
|
887
|
+
/* @__PURE__ */ E("span", {
|
|
642
888
|
className: "text-text-secondary",
|
|
643
889
|
children: "— Rebalance proposal"
|
|
644
890
|
}),
|
|
645
|
-
/* @__PURE__ */
|
|
646
|
-
variant:
|
|
647
|
-
children:
|
|
891
|
+
/* @__PURE__ */ E(O, {
|
|
892
|
+
variant: _(e.status),
|
|
893
|
+
children: B(e.status)
|
|
648
894
|
})
|
|
649
895
|
]
|
|
650
896
|
}),
|
|
651
|
-
/* @__PURE__ */
|
|
897
|
+
/* @__PURE__ */ D(De, { children: [
|
|
652
898
|
"Created ",
|
|
653
899
|
m(e.createdAt),
|
|
654
900
|
e.executedAt ? ` · executed ${m(e.executedAt)}` : ""
|
|
655
901
|
] })
|
|
656
902
|
] }),
|
|
657
|
-
/* @__PURE__ */
|
|
903
|
+
/* @__PURE__ */ E("div", {
|
|
658
904
|
className: "rounded-xl border border-border-subtle bg-bg-surface p-4",
|
|
659
|
-
children: /* @__PURE__ */
|
|
660
|
-
steps:
|
|
661
|
-
current:
|
|
905
|
+
children: /* @__PURE__ */ E(le, {
|
|
906
|
+
steps: V,
|
|
907
|
+
current: B(e.status)
|
|
662
908
|
})
|
|
663
909
|
}),
|
|
664
|
-
/* @__PURE__ */
|
|
910
|
+
/* @__PURE__ */ D("div", {
|
|
665
911
|
className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4",
|
|
666
912
|
children: [
|
|
667
|
-
/* @__PURE__ */
|
|
913
|
+
/* @__PURE__ */ E(u, {
|
|
668
914
|
label: "Drift",
|
|
669
|
-
value:
|
|
670
|
-
deltaTone:
|
|
671
|
-
glow:
|
|
672
|
-
icon: /* @__PURE__ */
|
|
915
|
+
value: g(e.driftPct),
|
|
916
|
+
deltaTone: ee ? "negative" : "neutral",
|
|
917
|
+
glow: ee,
|
|
918
|
+
icon: /* @__PURE__ */ E(b, {
|
|
673
919
|
className: "size-4",
|
|
674
920
|
"aria-hidden": "true"
|
|
675
921
|
})
|
|
676
922
|
}),
|
|
677
|
-
/* @__PURE__ */
|
|
923
|
+
/* @__PURE__ */ E(u, {
|
|
678
924
|
label: "Threshold",
|
|
679
|
-
value: t?.driftThresholdPct == null ? "—" :
|
|
925
|
+
value: t?.driftThresholdPct == null ? "—" : g(t.driftThresholdPct)
|
|
680
926
|
}),
|
|
681
|
-
/* @__PURE__ */
|
|
927
|
+
/* @__PURE__ */ D("div", {
|
|
682
928
|
className: "rounded-xl border border-border-subtle bg-bg-surface p-4",
|
|
683
|
-
children: [/* @__PURE__ */
|
|
929
|
+
children: [/* @__PURE__ */ E("p", {
|
|
684
930
|
className: "text-xs text-text-secondary",
|
|
685
931
|
children: "Proposed by"
|
|
686
|
-
}), /* @__PURE__ */
|
|
932
|
+
}), /* @__PURE__ */ E("p", {
|
|
687
933
|
className: "mt-1 truncate text-sm font-medium text-text-primary",
|
|
688
|
-
children: e.proposedById ? /* @__PURE__ */
|
|
934
|
+
children: e.proposedById ? /* @__PURE__ */ E(c, { id: e.proposedById }) : "—"
|
|
689
935
|
})]
|
|
690
936
|
}),
|
|
691
|
-
/* @__PURE__ */
|
|
937
|
+
/* @__PURE__ */ D("div", {
|
|
692
938
|
className: "rounded-xl border border-border-subtle bg-bg-surface p-4",
|
|
693
|
-
children: [/* @__PURE__ */
|
|
939
|
+
children: [/* @__PURE__ */ E("p", {
|
|
694
940
|
className: "text-xs text-text-secondary",
|
|
695
941
|
children: "Approved by"
|
|
696
|
-
}), /* @__PURE__ */
|
|
942
|
+
}), /* @__PURE__ */ E("p", {
|
|
697
943
|
className: "mt-1 truncate text-sm font-medium text-text-primary",
|
|
698
|
-
children: e.approvedById ? /* @__PURE__ */
|
|
944
|
+
children: e.approvedById ? /* @__PURE__ */ E(c, { id: e.approvedById }) : "—"
|
|
699
945
|
})]
|
|
700
946
|
})
|
|
701
947
|
]
|
|
702
948
|
}),
|
|
703
|
-
/* @__PURE__ */
|
|
949
|
+
/* @__PURE__ */ D("div", {
|
|
704
950
|
className: "space-y-2",
|
|
705
|
-
children: [/* @__PURE__ */
|
|
951
|
+
children: [/* @__PURE__ */ E("h3", {
|
|
706
952
|
className: "text-sm font-semibold text-text-primary",
|
|
707
953
|
children: "Proposed trades"
|
|
708
|
-
}), s && s.length > 0 ? /* @__PURE__ */
|
|
954
|
+
}), s && s.length > 0 ? /* @__PURE__ */ E("div", {
|
|
709
955
|
className: "overflow-x-auto rounded-lg border border-border-subtle",
|
|
710
|
-
children: /* @__PURE__ */
|
|
711
|
-
/* @__PURE__ */
|
|
712
|
-
/* @__PURE__ */
|
|
713
|
-
/* @__PURE__ */
|
|
956
|
+
children: /* @__PURE__ */ D(He, { children: [/* @__PURE__ */ E(We, { children: /* @__PURE__ */ D(z, { children: [
|
|
957
|
+
/* @__PURE__ */ E(R, { children: "Action" }),
|
|
958
|
+
/* @__PURE__ */ E(R, { children: "Symbol" }),
|
|
959
|
+
/* @__PURE__ */ E(R, {
|
|
714
960
|
className: "text-right",
|
|
715
961
|
children: "Quantity"
|
|
716
962
|
}),
|
|
717
|
-
/* @__PURE__ */
|
|
963
|
+
/* @__PURE__ */ E(R, {
|
|
718
964
|
className: "text-right",
|
|
719
965
|
children: "Est. value"
|
|
720
966
|
})
|
|
721
|
-
] }) }), /* @__PURE__ */
|
|
722
|
-
/* @__PURE__ */
|
|
723
|
-
className: `font-semibold ${
|
|
967
|
+
] }) }), /* @__PURE__ */ E(Ue, { children: s.map((e, n) => /* @__PURE__ */ D(z, { children: [
|
|
968
|
+
/* @__PURE__ */ E(L, {
|
|
969
|
+
className: `font-semibold ${U(e.action)}`,
|
|
724
970
|
children: e.action ? e.action.toUpperCase() : "—"
|
|
725
971
|
}),
|
|
726
|
-
/* @__PURE__ */
|
|
972
|
+
/* @__PURE__ */ E(L, {
|
|
727
973
|
className: "font-medium text-text-primary",
|
|
728
974
|
children: e.symbol ?? "—"
|
|
729
975
|
}),
|
|
730
|
-
/* @__PURE__ */
|
|
976
|
+
/* @__PURE__ */ E(L, {
|
|
731
977
|
className: "text-right tabular-nums text-text-secondary",
|
|
732
978
|
children: e.quantity == null ? "—" : e.quantity.toLocaleString()
|
|
733
979
|
}),
|
|
734
|
-
/* @__PURE__ */
|
|
980
|
+
/* @__PURE__ */ E(L, {
|
|
735
981
|
className: "text-right tabular-nums text-text-secondary",
|
|
736
|
-
children: e.value == null ? "—" :
|
|
982
|
+
children: e.value == null ? "—" : h(e.value, t?.baseCurrency ?? "USD")
|
|
737
983
|
})
|
|
738
984
|
] }, n)) })] })
|
|
739
|
-
}) : /* @__PURE__ */
|
|
985
|
+
}) : /* @__PURE__ */ D("p", {
|
|
740
986
|
className: "text-sm text-text-secondary",
|
|
741
|
-
children: [
|
|
987
|
+
children: [$e(e.trades), " — no structured trade breakdown available."]
|
|
742
988
|
})]
|
|
743
989
|
}),
|
|
744
|
-
/* @__PURE__ */
|
|
990
|
+
/* @__PURE__ */ D("div", {
|
|
745
991
|
className: "space-y-1",
|
|
746
|
-
children: [/* @__PURE__ */
|
|
992
|
+
children: [/* @__PURE__ */ E("h3", {
|
|
747
993
|
className: "text-sm font-semibold text-text-primary",
|
|
748
994
|
children: "Rationale"
|
|
749
|
-
}), /* @__PURE__ */
|
|
995
|
+
}), /* @__PURE__ */ E("p", {
|
|
750
996
|
className: "text-sm text-text-secondary",
|
|
751
997
|
children: e.rationale ?? "—"
|
|
752
998
|
})]
|
|
753
999
|
}),
|
|
754
|
-
r.length > 0 ? /* @__PURE__ */
|
|
1000
|
+
r.length > 0 ? /* @__PURE__ */ E("div", {
|
|
755
1001
|
className: "flex flex-wrap gap-2",
|
|
756
1002
|
children: r.map((e) => {
|
|
757
1003
|
let t = e === "REJECTED" || e === "CANCELLED";
|
|
758
|
-
return /* @__PURE__ */
|
|
1004
|
+
return /* @__PURE__ */ D(k, {
|
|
759
1005
|
variant: t ? "outline" : "default",
|
|
760
1006
|
size: "sm",
|
|
761
1007
|
disabled: i,
|
|
762
1008
|
className: t ? "text-status-error-text" : void 0,
|
|
763
1009
|
onClick: () => a(e),
|
|
764
|
-
children: [
|
|
1010
|
+
children: [E(t ? T : me, {
|
|
765
1011
|
className: "size-4",
|
|
766
1012
|
"aria-hidden": "true"
|
|
767
|
-
}),
|
|
1013
|
+
}), B(e)]
|
|
768
1014
|
}, e);
|
|
769
1015
|
})
|
|
770
1016
|
}) : null,
|
|
771
|
-
n.length > 0 ? /* @__PURE__ */
|
|
1017
|
+
n.length > 0 ? /* @__PURE__ */ D("div", {
|
|
772
1018
|
className: "space-y-2 border-t border-border-subtle pt-4",
|
|
773
|
-
children: [/* @__PURE__ */
|
|
1019
|
+
children: [/* @__PURE__ */ D("h3", {
|
|
774
1020
|
className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
775
|
-
children: [/* @__PURE__ */
|
|
1021
|
+
children: [/* @__PURE__ */ E(C, {
|
|
776
1022
|
className: "size-4",
|
|
777
1023
|
"aria-hidden": "true"
|
|
778
1024
|
}), "Risk insights"]
|
|
779
|
-
}), /* @__PURE__ */
|
|
1025
|
+
}), /* @__PURE__ */ E("ul", {
|
|
780
1026
|
className: "space-y-2",
|
|
781
|
-
children: n.map((e) => /* @__PURE__ */
|
|
1027
|
+
children: n.map((e) => /* @__PURE__ */ D("li", {
|
|
782
1028
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-3",
|
|
783
|
-
children: [/* @__PURE__ */
|
|
1029
|
+
children: [/* @__PURE__ */ D("div", {
|
|
784
1030
|
className: "flex flex-wrap items-center gap-2",
|
|
785
1031
|
children: [
|
|
786
|
-
/* @__PURE__ */
|
|
1032
|
+
/* @__PURE__ */ E("span", {
|
|
787
1033
|
className: "text-sm font-medium text-text-primary",
|
|
788
1034
|
children: e.title
|
|
789
1035
|
}),
|
|
790
|
-
/* @__PURE__ */
|
|
791
|
-
variant:
|
|
792
|
-
children:
|
|
1036
|
+
/* @__PURE__ */ E(O, {
|
|
1037
|
+
variant: _(e.severity),
|
|
1038
|
+
children: B(e.severity)
|
|
793
1039
|
}),
|
|
794
|
-
/* @__PURE__ */
|
|
1040
|
+
/* @__PURE__ */ E(O, {
|
|
795
1041
|
variant: "outline",
|
|
796
|
-
children:
|
|
1042
|
+
children: B(e.type)
|
|
797
1043
|
}),
|
|
798
|
-
/* @__PURE__ */
|
|
799
|
-
variant:
|
|
800
|
-
children:
|
|
1044
|
+
/* @__PURE__ */ E(O, {
|
|
1045
|
+
variant: _(e.status),
|
|
1046
|
+
children: B(e.status)
|
|
801
1047
|
})
|
|
802
1048
|
]
|
|
803
|
-
}), e.detail ? /* @__PURE__ */
|
|
1049
|
+
}), e.detail ? /* @__PURE__ */ E("p", {
|
|
804
1050
|
className: "mt-1 text-xs text-text-secondary",
|
|
805
1051
|
children: e.detail
|
|
806
1052
|
}) : null]
|
|
807
1053
|
}, e.id))
|
|
808
1054
|
})]
|
|
809
1055
|
}) : null,
|
|
810
|
-
/* @__PURE__ */
|
|
1056
|
+
/* @__PURE__ */ E("div", {
|
|
811
1057
|
className: "border-t border-border-subtle pt-4",
|
|
812
|
-
children: /* @__PURE__ */
|
|
1058
|
+
children: /* @__PURE__ */ E(de, {
|
|
813
1059
|
entityType: "brainyrich-rebalance",
|
|
814
1060
|
entityId: e.id,
|
|
815
1061
|
heading: "Discussion"
|
|
@@ -819,79 +1065,183 @@ function et({ proposal: e, portfolio: t, relatedInsights: n, nextStatuses: r, tr
|
|
|
819
1065
|
})
|
|
820
1066
|
});
|
|
821
1067
|
}
|
|
822
|
-
function
|
|
1068
|
+
function rt({ signal: e }) {
|
|
1069
|
+
let t = Object.entries(e.metrics ?? {});
|
|
1070
|
+
return /* @__PURE__ */ D("li", {
|
|
1071
|
+
className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
1072
|
+
children: [
|
|
1073
|
+
/* @__PURE__ */ D("div", {
|
|
1074
|
+
className: "flex flex-wrap items-center gap-2",
|
|
1075
|
+
children: [
|
|
1076
|
+
/* @__PURE__ */ E("p", {
|
|
1077
|
+
className: "font-medium text-text-primary",
|
|
1078
|
+
children: e.title
|
|
1079
|
+
}),
|
|
1080
|
+
/* @__PURE__ */ E(O, {
|
|
1081
|
+
variant: _(e.severity),
|
|
1082
|
+
children: B(e.severity)
|
|
1083
|
+
}),
|
|
1084
|
+
/* @__PURE__ */ E(O, {
|
|
1085
|
+
variant: "outline",
|
|
1086
|
+
children: B(e.kind)
|
|
1087
|
+
})
|
|
1088
|
+
]
|
|
1089
|
+
}),
|
|
1090
|
+
e.detail ? /* @__PURE__ */ E("p", {
|
|
1091
|
+
className: "mt-1 text-sm text-text-secondary",
|
|
1092
|
+
children: e.detail
|
|
1093
|
+
}) : null,
|
|
1094
|
+
t.length > 0 ? /* @__PURE__ */ E("dl", {
|
|
1095
|
+
className: "mt-3 grid grid-cols-2 gap-x-4 gap-y-1 sm:grid-cols-3 lg:grid-cols-4",
|
|
1096
|
+
children: t.map(([e, t]) => /* @__PURE__ */ D("div", {
|
|
1097
|
+
className: "min-w-0",
|
|
1098
|
+
children: [/* @__PURE__ */ E("dt", {
|
|
1099
|
+
className: "truncate text-[11px] uppercase tracking-wide text-text-muted",
|
|
1100
|
+
children: B(e)
|
|
1101
|
+
}), /* @__PURE__ */ E("dd", {
|
|
1102
|
+
className: "truncate text-sm font-medium tabular-nums text-text-primary",
|
|
1103
|
+
children: H(t)
|
|
1104
|
+
})]
|
|
1105
|
+
}, e))
|
|
1106
|
+
}) : null
|
|
1107
|
+
]
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
function it({ opportunity: e }) {
|
|
1111
|
+
let t = Object.entries(e.metrics ?? {});
|
|
1112
|
+
return /* @__PURE__ */ D("li", {
|
|
1113
|
+
className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
1114
|
+
children: [
|
|
1115
|
+
/* @__PURE__ */ D("div", {
|
|
1116
|
+
className: "flex flex-wrap items-center gap-2",
|
|
1117
|
+
children: [
|
|
1118
|
+
/* @__PURE__ */ D("p", {
|
|
1119
|
+
className: "font-medium text-text-primary",
|
|
1120
|
+
children: [
|
|
1121
|
+
e.symbol,
|
|
1122
|
+
" — unrealized loss ",
|
|
1123
|
+
h(e.unrealizedLoss)
|
|
1124
|
+
]
|
|
1125
|
+
}),
|
|
1126
|
+
/* @__PURE__ */ E(O, {
|
|
1127
|
+
variant: _(e.severity),
|
|
1128
|
+
children: B(e.severity)
|
|
1129
|
+
}),
|
|
1130
|
+
e.washSaleRisk ? /* @__PURE__ */ D(O, {
|
|
1131
|
+
variant: "outline",
|
|
1132
|
+
className: "text-status-error-text",
|
|
1133
|
+
children: [/* @__PURE__ */ E(pe, {
|
|
1134
|
+
className: "mr-1 size-3",
|
|
1135
|
+
"aria-hidden": "true"
|
|
1136
|
+
}), "Wash-sale caution"]
|
|
1137
|
+
}) : null
|
|
1138
|
+
]
|
|
1139
|
+
}),
|
|
1140
|
+
/* @__PURE__ */ D("p", {
|
|
1141
|
+
className: "mt-1 text-sm text-text-secondary",
|
|
1142
|
+
children: [
|
|
1143
|
+
"Market value ",
|
|
1144
|
+
h(e.marketValue),
|
|
1145
|
+
" vs. cost basis ",
|
|
1146
|
+
h(e.costBasis),
|
|
1147
|
+
" · ",
|
|
1148
|
+
g(e.lossPctOfPortfolio),
|
|
1149
|
+
" of portfolio value"
|
|
1150
|
+
]
|
|
1151
|
+
}),
|
|
1152
|
+
e.washSaleReason ? /* @__PURE__ */ E("p", {
|
|
1153
|
+
className: "mt-1 text-xs text-status-error-text",
|
|
1154
|
+
children: e.washSaleReason
|
|
1155
|
+
}) : null,
|
|
1156
|
+
t.length > 0 ? /* @__PURE__ */ E("dl", {
|
|
1157
|
+
className: "mt-3 grid grid-cols-2 gap-x-4 gap-y-1 sm:grid-cols-3 lg:grid-cols-4",
|
|
1158
|
+
children: t.filter(([e]) => e !== "formula").map(([e, t]) => /* @__PURE__ */ D("div", {
|
|
1159
|
+
className: "min-w-0",
|
|
1160
|
+
children: [/* @__PURE__ */ E("dt", {
|
|
1161
|
+
className: "truncate text-[11px] uppercase tracking-wide text-text-muted",
|
|
1162
|
+
children: B(e)
|
|
1163
|
+
}), /* @__PURE__ */ E("dd", {
|
|
1164
|
+
className: "truncate text-sm font-medium tabular-nums text-text-primary",
|
|
1165
|
+
children: H(t)
|
|
1166
|
+
})]
|
|
1167
|
+
}, e))
|
|
1168
|
+
}) : null
|
|
1169
|
+
]
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
function at({ insight: e, onAcknowledge: t, onResolve: n, onDismiss: r, actionPending: i }) {
|
|
823
1173
|
let a = e.status === "RESOLVED" || e.status === "DISMISSED";
|
|
824
|
-
return /* @__PURE__ */
|
|
1174
|
+
return /* @__PURE__ */ D("div", {
|
|
825
1175
|
className: "flex items-start justify-between gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4 transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))]",
|
|
826
|
-
children: [/* @__PURE__ */
|
|
1176
|
+
children: [/* @__PURE__ */ D("div", {
|
|
827
1177
|
className: "min-w-0 space-y-1",
|
|
828
1178
|
children: [
|
|
829
|
-
/* @__PURE__ */
|
|
1179
|
+
/* @__PURE__ */ D("div", {
|
|
830
1180
|
className: "flex flex-wrap items-center gap-2",
|
|
831
1181
|
children: [
|
|
832
|
-
/* @__PURE__ */
|
|
1182
|
+
/* @__PURE__ */ E("p", {
|
|
833
1183
|
className: "font-medium text-text-primary",
|
|
834
1184
|
children: e.title
|
|
835
1185
|
}),
|
|
836
|
-
/* @__PURE__ */
|
|
837
|
-
variant:
|
|
838
|
-
children:
|
|
1186
|
+
/* @__PURE__ */ E(O, {
|
|
1187
|
+
variant: _(e.severity),
|
|
1188
|
+
children: B(e.severity)
|
|
839
1189
|
}),
|
|
840
|
-
/* @__PURE__ */
|
|
1190
|
+
/* @__PURE__ */ E(O, {
|
|
841
1191
|
variant: "outline",
|
|
842
|
-
children:
|
|
1192
|
+
children: B(e.type)
|
|
843
1193
|
}),
|
|
844
|
-
/* @__PURE__ */
|
|
845
|
-
variant:
|
|
846
|
-
children:
|
|
1194
|
+
/* @__PURE__ */ E(O, {
|
|
1195
|
+
variant: _(e.status),
|
|
1196
|
+
children: B(e.status)
|
|
847
1197
|
})
|
|
848
1198
|
]
|
|
849
1199
|
}),
|
|
850
|
-
e.detail ? /* @__PURE__ */
|
|
1200
|
+
e.detail ? /* @__PURE__ */ E("p", {
|
|
851
1201
|
className: "text-sm text-text-secondary",
|
|
852
1202
|
children: e.detail
|
|
853
1203
|
}) : null,
|
|
854
|
-
/* @__PURE__ */
|
|
1204
|
+
/* @__PURE__ */ D("p", {
|
|
855
1205
|
className: "text-xs text-text-muted",
|
|
856
1206
|
children: ["Detected ", m(e.createdAt)]
|
|
857
1207
|
})
|
|
858
1208
|
]
|
|
859
|
-
}), a ? /* @__PURE__ */
|
|
1209
|
+
}), a ? /* @__PURE__ */ E("span", {
|
|
860
1210
|
className: "mt-1 text-xs text-text-muted",
|
|
861
1211
|
children: "Closed"
|
|
862
|
-
}) : /* @__PURE__ */
|
|
1212
|
+
}) : /* @__PURE__ */ D(je, { children: [/* @__PURE__ */ E(Fe, {
|
|
863
1213
|
asChild: !0,
|
|
864
|
-
children: /* @__PURE__ */
|
|
1214
|
+
children: /* @__PURE__ */ E(k, {
|
|
865
1215
|
variant: "ghost",
|
|
866
1216
|
size: "sm",
|
|
867
1217
|
"aria-label": `Actions for ${e.title}`,
|
|
868
1218
|
disabled: i,
|
|
869
|
-
children: /* @__PURE__ */
|
|
1219
|
+
children: /* @__PURE__ */ E(ve, {
|
|
870
1220
|
className: "size-4",
|
|
871
1221
|
"aria-hidden": "true"
|
|
872
1222
|
})
|
|
873
1223
|
})
|
|
874
|
-
}), /* @__PURE__ */
|
|
1224
|
+
}), /* @__PURE__ */ D(Me, {
|
|
875
1225
|
align: "end",
|
|
876
1226
|
children: [
|
|
877
|
-
e.status === "OPEN" ? /* @__PURE__ */
|
|
1227
|
+
e.status === "OPEN" ? /* @__PURE__ */ D(F, {
|
|
878
1228
|
onClick: t,
|
|
879
|
-
children: [/* @__PURE__ */
|
|
1229
|
+
children: [/* @__PURE__ */ E(he, {
|
|
880
1230
|
className: "size-4",
|
|
881
1231
|
"aria-hidden": "true"
|
|
882
1232
|
}), "Acknowledge"]
|
|
883
1233
|
}) : null,
|
|
884
|
-
/* @__PURE__ */
|
|
1234
|
+
/* @__PURE__ */ D(F, {
|
|
885
1235
|
onClick: n,
|
|
886
|
-
children: [/* @__PURE__ */ w
|
|
1236
|
+
children: [/* @__PURE__ */ E(w, {
|
|
887
1237
|
className: "size-4",
|
|
888
1238
|
"aria-hidden": "true"
|
|
889
1239
|
}), "Resolve"]
|
|
890
1240
|
}),
|
|
891
|
-
/* @__PURE__ */
|
|
1241
|
+
/* @__PURE__ */ D(F, {
|
|
892
1242
|
className: "text-status-error-text",
|
|
893
1243
|
onClick: r,
|
|
894
|
-
children: [/* @__PURE__ */
|
|
1244
|
+
children: [/* @__PURE__ */ E(T, {
|
|
895
1245
|
className: "size-4",
|
|
896
1246
|
"aria-hidden": "true"
|
|
897
1247
|
}), "Dismiss"]
|
|
@@ -901,6 +1251,6 @@ function tt({ insight: e, onAcknowledge: t, onResolve: n, onDismiss: r, actionPe
|
|
|
901
1251
|
});
|
|
902
1252
|
}
|
|
903
1253
|
//#endregion
|
|
904
|
-
export {
|
|
1254
|
+
export { W as RiskPage };
|
|
905
1255
|
|
|
906
1256
|
//# sourceMappingURL=RiskPage.js.map
|