@burdenoff/microfe-brainyrich 2026.825.1 → 2026.827.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/components/reuse/DocumentsPanel.d.ts +4 -0
- package/dist/brainyrich/components/reuse/DocumentsPanel.d.ts.map +1 -1
- package/dist/brainyrich/components/reuse/DocumentsPanel.js +150 -99
- package/dist/brainyrich/components/reuse/DocumentsPanel.js.map +1 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.d.ts +176 -0
- package/dist/brainyrich/hooks/useBrainyRichApi.d.ts.map +1 -1
- package/dist/brainyrich/hooks/useBrainyRichApi.js +96 -82
- package/dist/brainyrich/hooks/useBrainyRichApi.js.map +1 -1
- package/dist/brainyrich/pages/AdminFirmPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/AdminFirmPage.js +115 -83
- package/dist/brainyrich/pages/AdminFirmPage.js.map +1 -1
- package/dist/brainyrich/pages/AiAssistantPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/AiAssistantPage.js +251 -230
- package/dist/brainyrich/pages/AiAssistantPage.js.map +1 -1
- package/dist/brainyrich/pages/FirmPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/FirmPage.js +148 -116
- package/dist/brainyrich/pages/FirmPage.js.map +1 -1
- package/dist/brainyrich/pages/PortfoliosPage.d.ts +14 -0
- package/dist/brainyrich/pages/PortfoliosPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/PortfoliosPage.js +530 -353
- package/dist/brainyrich/pages/PortfoliosPage.js.map +1 -1
- package/dist/brainyrich/pages/RiskPage.d.ts.map +1 -1
- package/dist/brainyrich/pages/RiskPage.js +381 -396
- package/dist/brainyrich/pages/RiskPage.js.map +1 -1
- package/dist/brainyrich/pages/_shared.d.ts +21 -0
- package/dist/brainyrich/pages/_shared.d.ts.map +1 -1
- package/dist/brainyrich/pages/_shared.js +66 -31
- package/dist/brainyrich/pages/_shared.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { LoadMore as
|
|
3
|
-
import { ConfirmDialog as
|
|
4
|
-
import { DonutChart as
|
|
5
|
-
import { AccountPicker as
|
|
1
|
+
import { useAllHoldings as e, useArchivePortfolio as t, useCreateHolding as n, useCreatePortfolio as r, useDeleteHolding as i, useHouseholds as a, useModelPortfolios as o, usePagedPortfolios as s, usePortfolio as c, useUpdateHolding as l, useUpdatePortfolio as u } from "../hooks/useBrainyRichApi.js";
|
|
2
|
+
import { LoadMore as d } from "../components/LoadMore.js";
|
|
3
|
+
import { ConfirmDialog as f } from "../components/ConfirmDialog.js";
|
|
4
|
+
import { DonutChart as p, FadeIn as m, GlassCard as h, StatTile as g } from "../components/viz.js";
|
|
5
|
+
import { AccountPicker as _ } from "../components/pickers.js";
|
|
6
6
|
import "../components/index.js";
|
|
7
|
-
import { AllocationBars as
|
|
8
|
-
import { hapticSuccess as
|
|
9
|
-
import { useTrackBrainyRichPageView as
|
|
10
|
-
import { TagField as
|
|
11
|
-
import { CommentThread as
|
|
12
|
-
import { useMemo as
|
|
13
|
-
import { ArrowDownRight as
|
|
14
|
-
import { Fragment as
|
|
15
|
-
import { Badge as N, Button as P, Card as F, CardContent as I, CardDescription as
|
|
7
|
+
import { AllocationBars as ee, EmptyState as te, ErrorState as ne, LoadingState as re, SectionShell as ie, deltaToneClass as v, formatCompact as y, formatMoney as b, formatPct as x, statusBadgeVariant as S } from "./_shared.js";
|
|
8
|
+
import { hapticSuccess as C, showToast as w } from "../utils/nativeControls.js";
|
|
9
|
+
import { useTrackBrainyRichPageView as T } from "../hooks/useBrainyRichAnalytics.js";
|
|
10
|
+
import { TagField as ae } from "../components/reuse/TagField.js";
|
|
11
|
+
import { CommentThread as oe } from "../components/reuse/CommentThread.js";
|
|
12
|
+
import { useMemo as E, useState as D } from "react";
|
|
13
|
+
import { ArrowDownRight as O, ArrowUpRight as k, Briefcase as A, MoreHorizontal as se, Pencil as ce, Plus as le, Trash2 as ue } from "lucide-react";
|
|
14
|
+
import { Fragment as de, jsx as j, jsxs as M } from "react/jsx-runtime";
|
|
15
|
+
import { Badge as N, Button as P, Card as F, CardContent as I, CardDescription as L, CardHeader as R, CardTitle as z, Dialog as B, DialogContent as V, DialogDescription as fe, DialogFooter as H, DialogHeader as U, DialogTitle as W, DropdownMenu as pe, DropdownMenuContent as me, DropdownMenuItem as G, DropdownMenuLabel as he, DropdownMenuSeparator as ge, DropdownMenuTrigger as _e, Input as K, Label as q, Select as ve, SelectContent as ye, SelectItem as J, SelectTrigger as be, SelectValue as xe, Sheet as Se, SheetContent as Ce, SheetDescription as we, SheetHeader as Te, SheetTitle as Ee, Table as De, TableBody as Oe, TableCell as Y, TableHead as X, TableHeader as ke, TableRow as Ae, Textarea as je } from "@burdenoff/fe-libs/ui";
|
|
16
16
|
//#region src/brainyrich/pages/PortfoliosPage.tsx
|
|
17
|
-
var
|
|
17
|
+
var Me = [
|
|
18
18
|
"EQUITY",
|
|
19
19
|
"FIXED_INCOME",
|
|
20
20
|
"CASH",
|
|
@@ -22,7 +22,7 @@ var Ae = [
|
|
|
22
22
|
"COMMODITY",
|
|
23
23
|
"CRYPTO",
|
|
24
24
|
"ALTERNATIVE"
|
|
25
|
-
],
|
|
25
|
+
], Ne = [
|
|
26
26
|
"DRAFT",
|
|
27
27
|
"ACTIVE",
|
|
28
28
|
"ARCHIVED"
|
|
@@ -30,7 +30,7 @@ var Ae = [
|
|
|
30
30
|
if (e.trim() === "") return;
|
|
31
31
|
let t = Number(e);
|
|
32
32
|
return Number.isFinite(t) ? t : void 0;
|
|
33
|
-
},
|
|
33
|
+
}, Pe = {
|
|
34
34
|
EQUITY: "brand",
|
|
35
35
|
FIXED_INCOME: "blue",
|
|
36
36
|
CASH: "teal",
|
|
@@ -38,29 +38,72 @@ var Ae = [
|
|
|
38
38
|
COMMODITY: "warning",
|
|
39
39
|
CRYPTO: "indigo",
|
|
40
40
|
ALTERNATIVE: "info"
|
|
41
|
-
},
|
|
42
|
-
function
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
}, Fe = (e) => Pe[e.toUpperCase()] ?? "neutral";
|
|
42
|
+
function Ie(e) {
|
|
43
|
+
return Array.isArray(e) ? e.flatMap((e) => {
|
|
44
|
+
if (!e || typeof e != "object") return [];
|
|
45
|
+
let { assetClass: t, targetPct: n } = e;
|
|
46
|
+
if (typeof t != "string") return [];
|
|
47
|
+
let r = Number(n);
|
|
48
|
+
return Number.isFinite(r) ? [{
|
|
49
|
+
assetClass: t,
|
|
50
|
+
targetPct: r
|
|
51
|
+
}] : [];
|
|
52
|
+
}) : e && typeof e == "object" ? Object.entries(e).flatMap(([e, t]) => {
|
|
53
|
+
let n = Number(t);
|
|
54
|
+
return Number.isFinite(n) ? [{
|
|
55
|
+
assetClass: e,
|
|
56
|
+
targetPct: n
|
|
57
|
+
}] : [];
|
|
58
|
+
}) : [];
|
|
59
|
+
}
|
|
60
|
+
function Le(e) {
|
|
61
|
+
return Ie(e).map((e) => ({
|
|
62
|
+
label: Q(e.assetClass),
|
|
63
|
+
value: e.targetPct,
|
|
49
64
|
tone: "accent"
|
|
50
65
|
}));
|
|
51
66
|
}
|
|
52
|
-
function
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
value:
|
|
56
|
-
|
|
57
|
-
label: Q(e.key),
|
|
58
|
-
value: e.value,
|
|
59
|
-
tone: Ne(e.key)
|
|
67
|
+
function Re(e) {
|
|
68
|
+
return Ie(e).filter((e) => e.targetPct > 0).sort((e, t) => t.targetPct - e.targetPct).map((e) => ({
|
|
69
|
+
label: Q(e.assetClass),
|
|
70
|
+
value: e.targetPct,
|
|
71
|
+
tone: Fe(e.assetClass)
|
|
60
72
|
}));
|
|
61
73
|
}
|
|
62
|
-
|
|
63
|
-
|
|
74
|
+
var ze = {
|
|
75
|
+
marketValue: 0,
|
|
76
|
+
costBasis: 0,
|
|
77
|
+
unrealizedGain: 0,
|
|
78
|
+
gainPct: null,
|
|
79
|
+
holdingCount: 0,
|
|
80
|
+
maxDriftPct: null,
|
|
81
|
+
driftAssetClass: null
|
|
82
|
+
};
|
|
83
|
+
function Be(e, t) {
|
|
84
|
+
if (e.length === 0) return ze;
|
|
85
|
+
let n = 0, r = 0, i = /* @__PURE__ */ new Map();
|
|
86
|
+
for (let t of e) n += t.marketValue, r += t.costBasis, i.set(t.assetClass, (i.get(t.assetClass) ?? 0) + t.marketValue);
|
|
87
|
+
let a = n - r, o = Ie(t), s = null, c = null;
|
|
88
|
+
if (o.length > 0 && n > 0) {
|
|
89
|
+
let e = new Set([...i.keys(), ...o.map((e) => e.assetClass)]);
|
|
90
|
+
for (let t of e) {
|
|
91
|
+
let e = (i.get(t) ?? 0) / n * 100 - (o.find((e) => e.assetClass === t)?.targetPct ?? 0);
|
|
92
|
+
(s === null || Math.abs(e) > Math.abs(s)) && (s = e, c = t);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
marketValue: n,
|
|
97
|
+
costBasis: r,
|
|
98
|
+
unrealizedGain: a,
|
|
99
|
+
gainPct: r > 0 ? a / r * 100 : null,
|
|
100
|
+
holdingCount: e.length,
|
|
101
|
+
maxDriftPct: s,
|
|
102
|
+
driftAssetClass: c
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function Ve({ value: e, currency: t }) {
|
|
106
|
+
let n = e > 0, r = e < 0, i = n ? "text-status-success-text" : r ? "text-status-error-text" : "text-text-secondary", a = n ? k : r ? O : null;
|
|
64
107
|
return /* @__PURE__ */ M("span", {
|
|
65
108
|
className: `inline-flex items-center justify-end gap-1 font-medium ${i}`,
|
|
66
109
|
children: [
|
|
@@ -69,11 +112,11 @@ function Ie({ value: e, currency: t }) {
|
|
|
69
112
|
"aria-hidden": "true"
|
|
70
113
|
}) : null,
|
|
71
114
|
n ? "+" : "",
|
|
72
|
-
|
|
115
|
+
b(e, t)
|
|
73
116
|
]
|
|
74
117
|
});
|
|
75
118
|
}
|
|
76
|
-
function
|
|
119
|
+
function He() {
|
|
77
120
|
return {
|
|
78
121
|
name: "",
|
|
79
122
|
baseCurrency: "USD",
|
|
@@ -84,34 +127,34 @@ function Le() {
|
|
|
84
127
|
householdId: Z
|
|
85
128
|
};
|
|
86
129
|
}
|
|
87
|
-
function
|
|
88
|
-
let { data:
|
|
89
|
-
e && p !== h && (m(h), f(
|
|
90
|
-
name:
|
|
91
|
-
baseCurrency:
|
|
92
|
-
description:
|
|
93
|
-
driftThresholdPct: String(
|
|
94
|
-
status:
|
|
95
|
-
modelPortfolioId:
|
|
96
|
-
householdId:
|
|
97
|
-
} :
|
|
98
|
-
let g = c.isPending ||
|
|
99
|
-
return /* @__PURE__ */ j(
|
|
130
|
+
function Ue({ open: e, onOpenChange: t, editing: n }) {
|
|
131
|
+
let { data: i } = o(), { data: s } = a(), c = r(), l = u(), [d, f] = D(He), [p, m] = D(null), h = n?.id ?? "new";
|
|
132
|
+
e && p !== h && (m(h), f(n ? {
|
|
133
|
+
name: n.name,
|
|
134
|
+
baseCurrency: n.baseCurrency,
|
|
135
|
+
description: n.description ?? "",
|
|
136
|
+
driftThresholdPct: String(n.driftThresholdPct),
|
|
137
|
+
status: n.status,
|
|
138
|
+
modelPortfolioId: n.modelPortfolioId ?? Z,
|
|
139
|
+
householdId: n.householdId ?? Z
|
|
140
|
+
} : He())), !e && p !== null && m(null);
|
|
141
|
+
let g = c.isPending || l.isPending, _ = d.name.trim().length > 0;
|
|
142
|
+
return /* @__PURE__ */ j(B, {
|
|
100
143
|
open: e,
|
|
101
144
|
onOpenChange: t,
|
|
102
|
-
children: /* @__PURE__ */ M(
|
|
145
|
+
children: /* @__PURE__ */ M(V, {
|
|
103
146
|
className: "max-h-[90vh] overflow-y-auto sm:max-w-lg",
|
|
104
147
|
children: [
|
|
105
|
-
/* @__PURE__ */ M(
|
|
148
|
+
/* @__PURE__ */ M(U, { children: [/* @__PURE__ */ j(W, { children: n ? "Edit portfolio" : "New portfolio" }), /* @__PURE__ */ j(fe, { children: n ? "Update this portfolio’s strategy settings." : "Create an investment portfolio to organize and rebalance holdings." })] }),
|
|
106
149
|
/* @__PURE__ */ M("div", {
|
|
107
150
|
className: "space-y-4 py-2",
|
|
108
151
|
children: [
|
|
109
152
|
/* @__PURE__ */ M("div", {
|
|
110
153
|
className: "space-y-1.5",
|
|
111
|
-
children: [/* @__PURE__ */ j(
|
|
154
|
+
children: [/* @__PURE__ */ j(q, {
|
|
112
155
|
htmlFor: "pf-name",
|
|
113
156
|
children: "Name"
|
|
114
|
-
}), /* @__PURE__ */ j(
|
|
157
|
+
}), /* @__PURE__ */ j(K, {
|
|
115
158
|
id: "pf-name",
|
|
116
159
|
value: d.name,
|
|
117
160
|
onChange: (e) => f((t) => ({
|
|
@@ -126,10 +169,10 @@ function Re({ open: e, onOpenChange: t, editing: r }) {
|
|
|
126
169
|
className: "grid grid-cols-2 gap-4",
|
|
127
170
|
children: [/* @__PURE__ */ M("div", {
|
|
128
171
|
className: "space-y-1.5",
|
|
129
|
-
children: [/* @__PURE__ */ j(
|
|
172
|
+
children: [/* @__PURE__ */ j(q, {
|
|
130
173
|
htmlFor: "pf-currency",
|
|
131
174
|
children: "Base currency"
|
|
132
|
-
}), /* @__PURE__ */ j(
|
|
175
|
+
}), /* @__PURE__ */ j(K, {
|
|
133
176
|
id: "pf-currency",
|
|
134
177
|
value: d.baseCurrency,
|
|
135
178
|
onChange: (e) => f((t) => ({
|
|
@@ -141,10 +184,10 @@ function Re({ open: e, onOpenChange: t, editing: r }) {
|
|
|
141
184
|
})]
|
|
142
185
|
}), /* @__PURE__ */ M("div", {
|
|
143
186
|
className: "space-y-1.5",
|
|
144
|
-
children: [/* @__PURE__ */ j(
|
|
187
|
+
children: [/* @__PURE__ */ j(q, {
|
|
145
188
|
htmlFor: "pf-drift",
|
|
146
189
|
children: "Drift threshold %"
|
|
147
|
-
}), /* @__PURE__ */ j(
|
|
190
|
+
}), /* @__PURE__ */ j(K, {
|
|
148
191
|
id: "pf-drift",
|
|
149
192
|
type: "number",
|
|
150
193
|
min: 0,
|
|
@@ -157,21 +200,21 @@ function Re({ open: e, onOpenChange: t, editing: r }) {
|
|
|
157
200
|
})]
|
|
158
201
|
})]
|
|
159
202
|
}),
|
|
160
|
-
|
|
203
|
+
n ? /* @__PURE__ */ M("div", {
|
|
161
204
|
className: "space-y-1.5",
|
|
162
|
-
children: [/* @__PURE__ */ j(
|
|
205
|
+
children: [/* @__PURE__ */ j(q, {
|
|
163
206
|
htmlFor: "pf-status",
|
|
164
207
|
children: "Status"
|
|
165
|
-
}), /* @__PURE__ */ M(
|
|
208
|
+
}), /* @__PURE__ */ M(ve, {
|
|
166
209
|
value: d.status,
|
|
167
210
|
onValueChange: (e) => f((t) => ({
|
|
168
211
|
...t,
|
|
169
212
|
status: e
|
|
170
213
|
})),
|
|
171
|
-
children: [/* @__PURE__ */ j(
|
|
214
|
+
children: [/* @__PURE__ */ j(be, {
|
|
172
215
|
id: "pf-status",
|
|
173
|
-
children: /* @__PURE__ */ j(
|
|
174
|
-
}), /* @__PURE__ */ j(
|
|
216
|
+
children: /* @__PURE__ */ j(xe, {})
|
|
217
|
+
}), /* @__PURE__ */ j(ye, { children: Ne.map((e) => /* @__PURE__ */ j(J, {
|
|
175
218
|
value: e,
|
|
176
219
|
children: Q(e)
|
|
177
220
|
}, e)) })]
|
|
@@ -179,45 +222,45 @@ function Re({ open: e, onOpenChange: t, editing: r }) {
|
|
|
179
222
|
}) : null,
|
|
180
223
|
/* @__PURE__ */ M("div", {
|
|
181
224
|
className: "space-y-1.5",
|
|
182
|
-
children: [/* @__PURE__ */ j(
|
|
225
|
+
children: [/* @__PURE__ */ j(q, {
|
|
183
226
|
htmlFor: "pf-model",
|
|
184
227
|
children: "Model portfolio"
|
|
185
|
-
}), /* @__PURE__ */ M(
|
|
228
|
+
}), /* @__PURE__ */ M(ve, {
|
|
186
229
|
value: d.modelPortfolioId,
|
|
187
230
|
onValueChange: (e) => f((t) => ({
|
|
188
231
|
...t,
|
|
189
232
|
modelPortfolioId: e
|
|
190
233
|
})),
|
|
191
|
-
children: [/* @__PURE__ */ j(
|
|
234
|
+
children: [/* @__PURE__ */ j(be, {
|
|
192
235
|
id: "pf-model",
|
|
193
|
-
children: /* @__PURE__ */ j(
|
|
194
|
-
}), /* @__PURE__ */ M(
|
|
236
|
+
children: /* @__PURE__ */ j(xe, { placeholder: "None" })
|
|
237
|
+
}), /* @__PURE__ */ M(ye, { children: [/* @__PURE__ */ j(J, {
|
|
195
238
|
value: Z,
|
|
196
239
|
children: "None"
|
|
197
|
-
}),
|
|
240
|
+
}), i.map((e) => /* @__PURE__ */ j(J, {
|
|
198
241
|
value: e.id,
|
|
199
242
|
children: e.name
|
|
200
243
|
}, e.id))] })]
|
|
201
244
|
})]
|
|
202
245
|
}),
|
|
203
|
-
|
|
246
|
+
n ? null : /* @__PURE__ */ M("div", {
|
|
204
247
|
className: "space-y-1.5",
|
|
205
|
-
children: [/* @__PURE__ */ j(
|
|
248
|
+
children: [/* @__PURE__ */ j(q, {
|
|
206
249
|
htmlFor: "pf-household",
|
|
207
250
|
children: "Household"
|
|
208
|
-
}), /* @__PURE__ */ M(
|
|
251
|
+
}), /* @__PURE__ */ M(ve, {
|
|
209
252
|
value: d.householdId,
|
|
210
253
|
onValueChange: (e) => f((t) => ({
|
|
211
254
|
...t,
|
|
212
255
|
householdId: e
|
|
213
256
|
})),
|
|
214
|
-
children: [/* @__PURE__ */ j(
|
|
257
|
+
children: [/* @__PURE__ */ j(be, {
|
|
215
258
|
id: "pf-household",
|
|
216
|
-
children: /* @__PURE__ */ j(
|
|
217
|
-
}), /* @__PURE__ */ M(
|
|
259
|
+
children: /* @__PURE__ */ j(xe, { placeholder: "None" })
|
|
260
|
+
}), /* @__PURE__ */ M(ye, { children: [/* @__PURE__ */ j(J, {
|
|
218
261
|
value: Z,
|
|
219
262
|
children: "None"
|
|
220
|
-
}), s.map((e) => /* @__PURE__ */ j(
|
|
263
|
+
}), s.map((e) => /* @__PURE__ */ j(J, {
|
|
221
264
|
value: e.id,
|
|
222
265
|
children: e.name
|
|
223
266
|
}, e.id))] })]
|
|
@@ -225,10 +268,10 @@ function Re({ open: e, onOpenChange: t, editing: r }) {
|
|
|
225
268
|
}),
|
|
226
269
|
/* @__PURE__ */ M("div", {
|
|
227
270
|
className: "space-y-1.5",
|
|
228
|
-
children: [/* @__PURE__ */ j(
|
|
271
|
+
children: [/* @__PURE__ */ j(q, {
|
|
229
272
|
htmlFor: "pf-desc",
|
|
230
273
|
children: "Description"
|
|
231
|
-
}), /* @__PURE__ */ j(
|
|
274
|
+
}), /* @__PURE__ */ j(je, {
|
|
232
275
|
id: "pf-desc",
|
|
233
276
|
value: d.description,
|
|
234
277
|
onChange: (e) => f((t) => ({
|
|
@@ -241,7 +284,7 @@ function Re({ open: e, onOpenChange: t, editing: r }) {
|
|
|
241
284
|
})
|
|
242
285
|
]
|
|
243
286
|
}),
|
|
244
|
-
/* @__PURE__ */ M(
|
|
287
|
+
/* @__PURE__ */ M(H, { children: [/* @__PURE__ */ j(P, {
|
|
245
288
|
variant: "outline",
|
|
246
289
|
onClick: () => t(!1),
|
|
247
290
|
disabled: g,
|
|
@@ -249,38 +292,38 @@ function Re({ open: e, onOpenChange: t, editing: r }) {
|
|
|
249
292
|
}), /* @__PURE__ */ j(P, {
|
|
250
293
|
onClick: () => {
|
|
251
294
|
if (!_) return;
|
|
252
|
-
let e = $(d.driftThresholdPct),
|
|
253
|
-
|
|
254
|
-
id:
|
|
295
|
+
let e = $(d.driftThresholdPct), r = d.modelPortfolioId === Z ? null : d.modelPortfolioId, i = d.householdId === Z ? null : d.householdId;
|
|
296
|
+
n ? l.mutate({
|
|
297
|
+
id: n.id,
|
|
255
298
|
input: {
|
|
256
299
|
name: d.name.trim(),
|
|
257
300
|
baseCurrency: d.baseCurrency.trim() || "USD",
|
|
258
301
|
description: d.description.trim() || null,
|
|
259
302
|
driftThresholdPct: e,
|
|
260
303
|
status: d.status,
|
|
261
|
-
modelPortfolioId:
|
|
304
|
+
modelPortfolioId: r
|
|
262
305
|
}
|
|
263
306
|
}, { onSuccess: () => {
|
|
264
|
-
|
|
307
|
+
C(), w("Portfolio saved"), t(!1);
|
|
265
308
|
} }) : c.mutate({
|
|
266
309
|
name: d.name.trim(),
|
|
267
310
|
baseCurrency: d.baseCurrency.trim() || "USD",
|
|
268
311
|
description: d.description.trim() || null,
|
|
269
312
|
driftThresholdPct: e,
|
|
270
|
-
modelPortfolioId:
|
|
313
|
+
modelPortfolioId: r,
|
|
271
314
|
householdId: i
|
|
272
315
|
}, { onSuccess: () => {
|
|
273
|
-
|
|
316
|
+
C(), w("Portfolio created"), t(!1);
|
|
274
317
|
} });
|
|
275
318
|
},
|
|
276
319
|
disabled: !_ || g,
|
|
277
|
-
children: g ? "Saving…" :
|
|
320
|
+
children: g ? "Saving…" : n ? "Save changes" : "Create portfolio"
|
|
278
321
|
})] })
|
|
279
322
|
]
|
|
280
323
|
})
|
|
281
324
|
});
|
|
282
325
|
}
|
|
283
|
-
function
|
|
326
|
+
function We() {
|
|
284
327
|
return {
|
|
285
328
|
accountId: "",
|
|
286
329
|
symbol: "",
|
|
@@ -291,9 +334,9 @@ function ze() {
|
|
|
291
334
|
costBasis: "0"
|
|
292
335
|
};
|
|
293
336
|
}
|
|
294
|
-
function
|
|
295
|
-
let a =
|
|
296
|
-
e && u !== f && (d(f),
|
|
337
|
+
function Ge({ open: e, onOpenChange: t, portfolioId: r, editing: i }) {
|
|
338
|
+
let a = n(), o = l(), [s, c] = D(We), [u, d] = D(null), f = i?.id ?? "new";
|
|
339
|
+
e && u !== f && (d(f), c(i ? {
|
|
297
340
|
accountId: i.accountId,
|
|
298
341
|
symbol: i.symbol,
|
|
299
342
|
name: i.name ?? "",
|
|
@@ -301,22 +344,22 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
301
344
|
quantity: String(i.quantity),
|
|
302
345
|
lastPrice: String(i.lastPrice),
|
|
303
346
|
costBasis: String(i.costBasis)
|
|
304
|
-
} :
|
|
305
|
-
let p = a.isPending || o.isPending, m = s.symbol.trim().length > 0, h = i ? !0 : s.accountId.trim().length > 0,
|
|
306
|
-
return /* @__PURE__ */ j(
|
|
347
|
+
} : We())), !e && u !== null && d(null);
|
|
348
|
+
let p = a.isPending || o.isPending, m = s.symbol.trim().length > 0, h = i ? !0 : s.accountId.trim().length > 0, g = m && h && !p;
|
|
349
|
+
return /* @__PURE__ */ j(B, {
|
|
307
350
|
open: e,
|
|
308
|
-
onOpenChange:
|
|
309
|
-
children: /* @__PURE__ */ M(
|
|
351
|
+
onOpenChange: t,
|
|
352
|
+
children: /* @__PURE__ */ M(V, {
|
|
310
353
|
className: "max-h-[90vh] overflow-y-auto sm:max-w-lg",
|
|
311
354
|
children: [
|
|
312
|
-
/* @__PURE__ */ M(
|
|
355
|
+
/* @__PURE__ */ M(U, { children: [/* @__PURE__ */ j(W, { children: i ? "Edit holding" : "Add holding" }), /* @__PURE__ */ j(fe, { children: i ? "Update the position details for this holding." : "Add a position to this portfolio from one of your accounts." })] }),
|
|
313
356
|
/* @__PURE__ */ M("div", {
|
|
314
357
|
className: "space-y-4 py-2",
|
|
315
358
|
children: [
|
|
316
|
-
i ? null : /* @__PURE__ */ j(
|
|
359
|
+
i ? null : /* @__PURE__ */ j(_, {
|
|
317
360
|
id: "h-account",
|
|
318
361
|
value: s.accountId,
|
|
319
|
-
onChange: (e) =>
|
|
362
|
+
onChange: (e) => c((t) => ({
|
|
320
363
|
...t,
|
|
321
364
|
accountId: e
|
|
322
365
|
})),
|
|
@@ -326,13 +369,13 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
326
369
|
className: "grid grid-cols-2 gap-4",
|
|
327
370
|
children: [/* @__PURE__ */ M("div", {
|
|
328
371
|
className: "space-y-1.5",
|
|
329
|
-
children: [/* @__PURE__ */ j(
|
|
372
|
+
children: [/* @__PURE__ */ j(q, {
|
|
330
373
|
htmlFor: "h-symbol",
|
|
331
374
|
children: "Symbol"
|
|
332
|
-
}), /* @__PURE__ */ j(
|
|
375
|
+
}), /* @__PURE__ */ j(K, {
|
|
333
376
|
id: "h-symbol",
|
|
334
377
|
value: s.symbol,
|
|
335
|
-
onChange: (e) =>
|
|
378
|
+
onChange: (e) => c((t) => ({
|
|
336
379
|
...t,
|
|
337
380
|
symbol: e.target.value
|
|
338
381
|
})),
|
|
@@ -342,19 +385,19 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
342
385
|
})]
|
|
343
386
|
}), /* @__PURE__ */ M("div", {
|
|
344
387
|
className: "space-y-1.5",
|
|
345
|
-
children: [/* @__PURE__ */ j(
|
|
388
|
+
children: [/* @__PURE__ */ j(q, {
|
|
346
389
|
htmlFor: "h-class",
|
|
347
390
|
children: "Asset class"
|
|
348
|
-
}), /* @__PURE__ */ M(
|
|
391
|
+
}), /* @__PURE__ */ M(ve, {
|
|
349
392
|
value: s.assetClass,
|
|
350
|
-
onValueChange: (e) =>
|
|
393
|
+
onValueChange: (e) => c((t) => ({
|
|
351
394
|
...t,
|
|
352
395
|
assetClass: e
|
|
353
396
|
})),
|
|
354
|
-
children: [/* @__PURE__ */ j(
|
|
397
|
+
children: [/* @__PURE__ */ j(be, {
|
|
355
398
|
id: "h-class",
|
|
356
|
-
children: /* @__PURE__ */ j(
|
|
357
|
-
}), /* @__PURE__ */ j(
|
|
399
|
+
children: /* @__PURE__ */ j(xe, {})
|
|
400
|
+
}), /* @__PURE__ */ j(ye, { children: Me.map((e) => /* @__PURE__ */ j(J, {
|
|
358
401
|
value: e,
|
|
359
402
|
children: Q(e)
|
|
360
403
|
}, e)) })]
|
|
@@ -363,13 +406,13 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
363
406
|
}),
|
|
364
407
|
/* @__PURE__ */ M("div", {
|
|
365
408
|
className: "space-y-1.5",
|
|
366
|
-
children: [/* @__PURE__ */ j(
|
|
409
|
+
children: [/* @__PURE__ */ j(q, {
|
|
367
410
|
htmlFor: "h-name",
|
|
368
411
|
children: "Name"
|
|
369
|
-
}), /* @__PURE__ */ j(
|
|
412
|
+
}), /* @__PURE__ */ j(K, {
|
|
370
413
|
id: "h-name",
|
|
371
414
|
value: s.name,
|
|
372
|
-
onChange: (e) =>
|
|
415
|
+
onChange: (e) => c((t) => ({
|
|
373
416
|
...t,
|
|
374
417
|
name: e.target.value
|
|
375
418
|
})),
|
|
@@ -381,15 +424,15 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
381
424
|
children: [
|
|
382
425
|
/* @__PURE__ */ M("div", {
|
|
383
426
|
className: "space-y-1.5",
|
|
384
|
-
children: [/* @__PURE__ */ j(
|
|
427
|
+
children: [/* @__PURE__ */ j(q, {
|
|
385
428
|
htmlFor: "h-qty",
|
|
386
429
|
children: "Quantity"
|
|
387
|
-
}), /* @__PURE__ */ j(
|
|
430
|
+
}), /* @__PURE__ */ j(K, {
|
|
388
431
|
id: "h-qty",
|
|
389
432
|
type: "number",
|
|
390
433
|
step: "any",
|
|
391
434
|
value: s.quantity,
|
|
392
|
-
onChange: (e) =>
|
|
435
|
+
onChange: (e) => c((t) => ({
|
|
393
436
|
...t,
|
|
394
437
|
quantity: e.target.value
|
|
395
438
|
}))
|
|
@@ -397,15 +440,15 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
397
440
|
}),
|
|
398
441
|
/* @__PURE__ */ M("div", {
|
|
399
442
|
className: "space-y-1.5",
|
|
400
|
-
children: [/* @__PURE__ */ j(
|
|
443
|
+
children: [/* @__PURE__ */ j(q, {
|
|
401
444
|
htmlFor: "h-price",
|
|
402
445
|
children: "Last price"
|
|
403
|
-
}), /* @__PURE__ */ j(
|
|
446
|
+
}), /* @__PURE__ */ j(K, {
|
|
404
447
|
id: "h-price",
|
|
405
448
|
type: "number",
|
|
406
449
|
step: "any",
|
|
407
450
|
value: s.lastPrice,
|
|
408
|
-
onChange: (e) =>
|
|
451
|
+
onChange: (e) => c((t) => ({
|
|
409
452
|
...t,
|
|
410
453
|
lastPrice: e.target.value
|
|
411
454
|
}))
|
|
@@ -413,15 +456,15 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
413
456
|
}),
|
|
414
457
|
/* @__PURE__ */ M("div", {
|
|
415
458
|
className: "space-y-1.5",
|
|
416
|
-
children: [/* @__PURE__ */ j(
|
|
459
|
+
children: [/* @__PURE__ */ j(q, {
|
|
417
460
|
htmlFor: "h-cost",
|
|
418
461
|
children: "Cost basis"
|
|
419
|
-
}), /* @__PURE__ */ j(
|
|
462
|
+
}), /* @__PURE__ */ j(K, {
|
|
420
463
|
id: "h-cost",
|
|
421
464
|
type: "number",
|
|
422
465
|
step: "any",
|
|
423
466
|
value: s.costBasis,
|
|
424
|
-
onChange: (e) =>
|
|
467
|
+
onChange: (e) => c((t) => ({
|
|
425
468
|
...t,
|
|
426
469
|
costBasis: e.target.value
|
|
427
470
|
}))
|
|
@@ -431,9 +474,9 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
431
474
|
})
|
|
432
475
|
]
|
|
433
476
|
}),
|
|
434
|
-
/* @__PURE__ */ M(
|
|
477
|
+
/* @__PURE__ */ M(H, { children: [/* @__PURE__ */ j(P, {
|
|
435
478
|
variant: "outline",
|
|
436
|
-
onClick: () =>
|
|
479
|
+
onClick: () => t(!1),
|
|
437
480
|
disabled: p,
|
|
438
481
|
children: "Cancel"
|
|
439
482
|
}), /* @__PURE__ */ j(P, {
|
|
@@ -448,7 +491,7 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
448
491
|
costBasis: $(s.costBasis)
|
|
449
492
|
}
|
|
450
493
|
}, { onSuccess: () => {
|
|
451
|
-
|
|
494
|
+
C(), w("Holding saved"), t(!1);
|
|
452
495
|
} }) : a.mutate({
|
|
453
496
|
accountId: s.accountId,
|
|
454
497
|
portfolioId: r,
|
|
@@ -459,96 +502,98 @@ function Be({ open: e, onOpenChange: n, portfolioId: r, editing: i }) {
|
|
|
459
502
|
lastPrice: $(s.lastPrice),
|
|
460
503
|
costBasis: $(s.costBasis)
|
|
461
504
|
}, { onSuccess: () => {
|
|
462
|
-
|
|
505
|
+
C(), w("Holding added"), t(!1);
|
|
463
506
|
} }));
|
|
464
507
|
},
|
|
465
|
-
disabled: !
|
|
508
|
+
disabled: !g,
|
|
466
509
|
children: p ? "Saving…" : i ? "Save changes" : "Add holding"
|
|
467
510
|
})] })
|
|
468
511
|
]
|
|
469
512
|
})
|
|
470
513
|
});
|
|
471
514
|
}
|
|
472
|
-
function
|
|
473
|
-
let { data:
|
|
474
|
-
if (
|
|
515
|
+
function Ke({ portfolioId: t, onOpenChange: n }) {
|
|
516
|
+
let { data: r, isLoading: a, isError: o, refetch: s } = c(t ?? void 0), l = e({ portfolioId: t ?? void 0 }, { enabled: t !== null }), u = i(), [d, _] = D(!1), [ie, v] = D(null), [C, w] = D(null), T = t ? l.data : [], O = r?.baseCurrency ?? "USD", k = T.reduce((e, t) => e + t.marketValue, 0), B = T.reduce((e, t) => e + t.costBasis, 0), V = k - B, fe = B > 0 ? V / B * 100 : 0, H = E(() => {
|
|
517
|
+
if (T.length === 0 || k <= 0) return [];
|
|
475
518
|
let e = /* @__PURE__ */ new Map();
|
|
476
|
-
return
|
|
519
|
+
return T.forEach((t) => e.set(t.assetClass, (e.get(t.assetClass) ?? 0) + t.marketValue)), Array.from(e.entries()).map(([e, t]) => ({
|
|
477
520
|
label: Q(e),
|
|
478
521
|
value: t,
|
|
479
|
-
tone:
|
|
522
|
+
tone: Fe(e)
|
|
480
523
|
})).sort((e, t) => t.value - e.value);
|
|
481
|
-
}, [
|
|
524
|
+
}, [T, k]), U = E(() => {
|
|
482
525
|
let e = /* @__PURE__ */ new Map();
|
|
483
|
-
return
|
|
484
|
-
}, [
|
|
485
|
-
let t =
|
|
526
|
+
return k <= 0 || T.forEach((t) => e.set(Q(t.assetClass), (e.get(Q(t.assetClass)) ?? 0) + t.marketValue / k * 100)), e;
|
|
527
|
+
}, [T, k]), W = E(() => Le(r?.targetAllocation).map((e) => {
|
|
528
|
+
let t = U.get(e.label) ?? 0;
|
|
486
529
|
return {
|
|
487
530
|
label: e.label,
|
|
488
531
|
value: e.value,
|
|
489
532
|
tone: "accent",
|
|
490
|
-
caption: `${
|
|
533
|
+
caption: `${x(e.value, 0)} target · ${x(t, 0)} actual`
|
|
491
534
|
};
|
|
492
|
-
}), [
|
|
493
|
-
|
|
494
|
-
},
|
|
495
|
-
|
|
535
|
+
}), [r?.targetAllocation, U]), K = () => {
|
|
536
|
+
v(null), _(!0);
|
|
537
|
+
}, q = (e) => {
|
|
538
|
+
v(e), _(!0);
|
|
496
539
|
};
|
|
497
|
-
return /* @__PURE__ */ j(
|
|
498
|
-
open:
|
|
499
|
-
onOpenChange:
|
|
500
|
-
children: /* @__PURE__ */ j(
|
|
540
|
+
return /* @__PURE__ */ j(Se, {
|
|
541
|
+
open: t !== null,
|
|
542
|
+
onOpenChange: n,
|
|
543
|
+
children: /* @__PURE__ */ j(Ce, {
|
|
501
544
|
className: "flex w-full flex-col gap-0 overflow-y-auto p-0 sm:max-w-2xl",
|
|
502
|
-
children:
|
|
545
|
+
children: a || t !== null && l.isPending ? /* @__PURE__ */ j("div", {
|
|
503
546
|
className: "p-6",
|
|
504
|
-
children: /* @__PURE__ */ j(
|
|
505
|
-
}) :
|
|
547
|
+
children: /* @__PURE__ */ j(re, { rows: 5 })
|
|
548
|
+
}) : o || l.isError ? /* @__PURE__ */ j("div", {
|
|
506
549
|
className: "p-6",
|
|
507
|
-
children: /* @__PURE__ */ j(
|
|
508
|
-
|
|
509
|
-
|
|
550
|
+
children: /* @__PURE__ */ j(ne, { onRetry: () => {
|
|
551
|
+
s(), l.refetch();
|
|
552
|
+
} })
|
|
553
|
+
}) : r ? /* @__PURE__ */ M(de, { children: [
|
|
554
|
+
/* @__PURE__ */ M(Te, {
|
|
510
555
|
className: "border-b border-border-subtle p-6",
|
|
511
556
|
children: [/* @__PURE__ */ M("div", {
|
|
512
557
|
className: "flex items-center gap-2",
|
|
513
|
-
children: [/* @__PURE__ */ j(
|
|
558
|
+
children: [/* @__PURE__ */ j(Ee, {
|
|
514
559
|
className: "text-xl",
|
|
515
|
-
children:
|
|
560
|
+
children: r.name
|
|
516
561
|
}), /* @__PURE__ */ j(N, {
|
|
517
|
-
variant:
|
|
518
|
-
children: Q(
|
|
562
|
+
variant: S(r.status),
|
|
563
|
+
children: Q(r.status)
|
|
519
564
|
})]
|
|
520
|
-
}), /* @__PURE__ */ j(
|
|
565
|
+
}), /* @__PURE__ */ j(we, { children: r.description?.trim() ? r.description : `${r.baseCurrency} · Drift threshold ${x(r.driftThresholdPct)}` })]
|
|
521
566
|
}),
|
|
522
567
|
/* @__PURE__ */ M("div", {
|
|
523
568
|
className: "space-y-6 p-6",
|
|
524
569
|
children: [
|
|
525
|
-
/* @__PURE__ */ M(
|
|
570
|
+
/* @__PURE__ */ M(m, {
|
|
526
571
|
className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
|
|
527
572
|
children: [
|
|
528
|
-
/* @__PURE__ */ j(
|
|
573
|
+
/* @__PURE__ */ j(g, {
|
|
529
574
|
label: "Market value",
|
|
530
|
-
value:
|
|
575
|
+
value: b(k, O),
|
|
531
576
|
glow: !0
|
|
532
577
|
}),
|
|
533
|
-
/* @__PURE__ */ j(
|
|
578
|
+
/* @__PURE__ */ j(g, {
|
|
534
579
|
label: "Unrealized gain",
|
|
535
|
-
value:
|
|
536
|
-
delta:
|
|
537
|
-
deltaTone:
|
|
580
|
+
value: b(V, O),
|
|
581
|
+
delta: B > 0 ? fe : void 0,
|
|
582
|
+
deltaTone: V > 0 ? "positive" : V < 0 ? "negative" : "neutral"
|
|
538
583
|
}),
|
|
539
|
-
/* @__PURE__ */ j(
|
|
584
|
+
/* @__PURE__ */ j(g, {
|
|
540
585
|
label: "Holdings",
|
|
541
|
-
value: String(
|
|
586
|
+
value: String(T.length)
|
|
542
587
|
}),
|
|
543
|
-
/* @__PURE__ */ j(
|
|
588
|
+
/* @__PURE__ */ j(g, {
|
|
544
589
|
label: "Drift threshold",
|
|
545
|
-
value:
|
|
590
|
+
value: x(r.driftThresholdPct)
|
|
546
591
|
})
|
|
547
592
|
]
|
|
548
593
|
}),
|
|
549
|
-
/* @__PURE__ */ j(
|
|
594
|
+
/* @__PURE__ */ j(m, {
|
|
550
595
|
index: 1,
|
|
551
|
-
children: /* @__PURE__ */ M(
|
|
596
|
+
children: /* @__PURE__ */ M(h, {
|
|
552
597
|
glow: !0,
|
|
553
598
|
className: "space-y-5",
|
|
554
599
|
children: [/* @__PURE__ */ M("div", {
|
|
@@ -558,7 +603,7 @@ function Ve({ portfolioId: e, onOpenChange: t }) {
|
|
|
558
603
|
children: "Target vs actual allocation"
|
|
559
604
|
}), /* @__PURE__ */ j(N, {
|
|
560
605
|
variant: "outline",
|
|
561
|
-
children:
|
|
606
|
+
children: O
|
|
562
607
|
})]
|
|
563
608
|
}), /* @__PURE__ */ M("div", {
|
|
564
609
|
className: "grid gap-6 md:grid-cols-2",
|
|
@@ -567,11 +612,11 @@ function Ve({ portfolioId: e, onOpenChange: t }) {
|
|
|
567
612
|
children: [/* @__PURE__ */ j("p", {
|
|
568
613
|
className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
569
614
|
children: "Actual — by market value"
|
|
570
|
-
}),
|
|
571
|
-
data:
|
|
572
|
-
centerValue:
|
|
615
|
+
}), H.length > 0 ? /* @__PURE__ */ j(p, {
|
|
616
|
+
data: H,
|
|
617
|
+
centerValue: y(k, O),
|
|
573
618
|
centerLabel: "Market value",
|
|
574
|
-
valueFormatter: (e) =>
|
|
619
|
+
valueFormatter: (e) => b(e, O)
|
|
575
620
|
}) : /* @__PURE__ */ j("p", {
|
|
576
621
|
className: "py-8 text-center text-sm text-text-secondary",
|
|
577
622
|
children: "Add holdings to see the live allocation."
|
|
@@ -581,7 +626,7 @@ function Ve({ portfolioId: e, onOpenChange: t }) {
|
|
|
581
626
|
children: [/* @__PURE__ */ j("p", {
|
|
582
627
|
className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
583
628
|
children: "Target — vs live actual"
|
|
584
|
-
}),
|
|
629
|
+
}), W.length > 0 ? /* @__PURE__ */ j(ee, { data: W }) : /* @__PURE__ */ j("p", {
|
|
585
630
|
className: "py-8 text-center text-sm text-text-secondary",
|
|
586
631
|
children: "No target allocation set for this portfolio."
|
|
587
632
|
})]
|
|
@@ -591,26 +636,26 @@ function Ve({ portfolioId: e, onOpenChange: t }) {
|
|
|
591
636
|
}),
|
|
592
637
|
/* @__PURE__ */ j(F, { children: /* @__PURE__ */ j(I, {
|
|
593
638
|
className: "p-4",
|
|
594
|
-
children: /* @__PURE__ */ j(
|
|
639
|
+
children: /* @__PURE__ */ j(ae, {
|
|
595
640
|
entityType: "brainyrich-portfolio",
|
|
596
|
-
entityId:
|
|
641
|
+
entityId: r.id
|
|
597
642
|
})
|
|
598
643
|
}) }),
|
|
599
|
-
/* @__PURE__ */ M(F, { children: [/* @__PURE__ */ M(
|
|
644
|
+
/* @__PURE__ */ M(F, { children: [/* @__PURE__ */ M(R, {
|
|
600
645
|
className: "flex flex-row items-center justify-between",
|
|
601
|
-
children: [/* @__PURE__ */ M("div", { children: [/* @__PURE__ */ j(
|
|
646
|
+
children: [/* @__PURE__ */ M("div", { children: [/* @__PURE__ */ j(z, {
|
|
602
647
|
className: "text-base",
|
|
603
648
|
children: "Holdings"
|
|
604
|
-
}), /* @__PURE__ */ j(
|
|
649
|
+
}), /* @__PURE__ */ j(L, { children: "Positions held in this portfolio" })] }), /* @__PURE__ */ M(P, {
|
|
605
650
|
size: "sm",
|
|
606
|
-
onClick:
|
|
607
|
-
children: [/* @__PURE__ */ j(
|
|
651
|
+
onClick: K,
|
|
652
|
+
children: [/* @__PURE__ */ j(le, {
|
|
608
653
|
className: "size-4",
|
|
609
654
|
"aria-hidden": "true"
|
|
610
655
|
}), "Add holding"]
|
|
611
656
|
})]
|
|
612
|
-
}), /* @__PURE__ */ j(I, { children:
|
|
613
|
-
icon: /* @__PURE__ */ j(
|
|
657
|
+
}), /* @__PURE__ */ j(I, { children: T.length === 0 ? /* @__PURE__ */ j(te, {
|
|
658
|
+
icon: /* @__PURE__ */ j(A, {
|
|
614
659
|
className: "size-6",
|
|
615
660
|
"aria-hidden": "true"
|
|
616
661
|
}),
|
|
@@ -618,15 +663,15 @@ function Ve({ portfolioId: e, onOpenChange: t }) {
|
|
|
618
663
|
description: "Add positions to start tracking this portfolio.",
|
|
619
664
|
action: /* @__PURE__ */ M(P, {
|
|
620
665
|
size: "sm",
|
|
621
|
-
onClick:
|
|
622
|
-
children: [/* @__PURE__ */ j(
|
|
666
|
+
onClick: K,
|
|
667
|
+
children: [/* @__PURE__ */ j(le, {
|
|
623
668
|
className: "size-4",
|
|
624
669
|
"aria-hidden": "true"
|
|
625
670
|
}), "Add holding"]
|
|
626
671
|
})
|
|
627
672
|
}) : /* @__PURE__ */ j("div", {
|
|
628
673
|
className: "overflow-x-auto",
|
|
629
|
-
children: /* @__PURE__ */ M(
|
|
674
|
+
children: /* @__PURE__ */ M(De, { children: [/* @__PURE__ */ j(ke, { children: /* @__PURE__ */ M(Ae, { children: [
|
|
630
675
|
/* @__PURE__ */ j(X, { children: "Symbol" }),
|
|
631
676
|
/* @__PURE__ */ j(X, { children: "Class" }),
|
|
632
677
|
/* @__PURE__ */ j(X, {
|
|
@@ -646,9 +691,9 @@ function Ve({ portfolioId: e, onOpenChange: t }) {
|
|
|
646
691
|
children: "Gain"
|
|
647
692
|
}),
|
|
648
693
|
/* @__PURE__ */ j(X, { className: "w-10" })
|
|
649
|
-
] }) }), /* @__PURE__ */ j(
|
|
694
|
+
] }) }), /* @__PURE__ */ j(Oe, { children: T.map((e) => {
|
|
650
695
|
let t = e.marketValue - e.costBasis, n = e.costBasis > 0 ? t / e.costBasis * 100 : 0;
|
|
651
|
-
return /* @__PURE__ */ M(
|
|
696
|
+
return /* @__PURE__ */ M(Ae, {
|
|
652
697
|
className: "transition-colors motion-safe:hover:bg-bg-sunken/60",
|
|
653
698
|
children: [
|
|
654
699
|
/* @__PURE__ */ M(Y, { children: [/* @__PURE__ */ j("div", {
|
|
@@ -668,53 +713,53 @@ function Ve({ portfolioId: e, onOpenChange: t }) {
|
|
|
668
713
|
}),
|
|
669
714
|
/* @__PURE__ */ j(Y, {
|
|
670
715
|
className: "text-right tabular-nums",
|
|
671
|
-
children:
|
|
716
|
+
children: b(e.lastPrice, e.currency)
|
|
672
717
|
}),
|
|
673
718
|
/* @__PURE__ */ j(Y, {
|
|
674
719
|
className: "text-right font-medium tabular-nums",
|
|
675
|
-
children:
|
|
720
|
+
children: b(e.marketValue, e.currency)
|
|
676
721
|
}),
|
|
677
722
|
/* @__PURE__ */ M(Y, {
|
|
678
723
|
className: "text-right tabular-nums",
|
|
679
|
-
children: [/* @__PURE__ */ j(
|
|
724
|
+
children: [/* @__PURE__ */ j(Ve, {
|
|
680
725
|
value: t,
|
|
681
726
|
currency: e.currency
|
|
682
727
|
}), e.costBasis > 0 ? /* @__PURE__ */ M("div", {
|
|
683
728
|
className: "text-xs text-text-secondary",
|
|
684
|
-
children: [t > 0 ? "+" : "",
|
|
729
|
+
children: [t > 0 ? "+" : "", x(n)]
|
|
685
730
|
}) : null]
|
|
686
731
|
}),
|
|
687
732
|
/* @__PURE__ */ j(Y, {
|
|
688
733
|
className: "text-right",
|
|
689
|
-
children: /* @__PURE__ */ M(
|
|
734
|
+
children: /* @__PURE__ */ M(pe, { children: [/* @__PURE__ */ j(_e, {
|
|
690
735
|
asChild: !0,
|
|
691
736
|
children: /* @__PURE__ */ j(P, {
|
|
692
737
|
variant: "ghost",
|
|
693
738
|
size: "icon",
|
|
694
739
|
className: "size-10",
|
|
695
740
|
"aria-label": `Actions for ${e.symbol}`,
|
|
696
|
-
children: /* @__PURE__ */ j(
|
|
741
|
+
children: /* @__PURE__ */ j(se, {
|
|
697
742
|
className: "size-4",
|
|
698
743
|
"aria-hidden": "true"
|
|
699
744
|
})
|
|
700
745
|
})
|
|
701
|
-
}), /* @__PURE__ */ M(
|
|
746
|
+
}), /* @__PURE__ */ M(me, {
|
|
702
747
|
align: "end",
|
|
703
748
|
children: [
|
|
704
|
-
/* @__PURE__ */ j(
|
|
705
|
-
/* @__PURE__ */ j(
|
|
706
|
-
/* @__PURE__ */ M(
|
|
749
|
+
/* @__PURE__ */ j(he, { children: e.symbol }),
|
|
750
|
+
/* @__PURE__ */ j(ge, {}),
|
|
751
|
+
/* @__PURE__ */ M(G, {
|
|
707
752
|
className: "gap-2",
|
|
708
|
-
onClick: () =>
|
|
709
|
-
children: [/* @__PURE__ */ j(
|
|
753
|
+
onClick: () => q(e),
|
|
754
|
+
children: [/* @__PURE__ */ j(ce, {
|
|
710
755
|
className: "size-4",
|
|
711
756
|
"aria-hidden": "true"
|
|
712
757
|
}), "Edit"]
|
|
713
758
|
}),
|
|
714
|
-
/* @__PURE__ */ M(
|
|
759
|
+
/* @__PURE__ */ M(G, {
|
|
715
760
|
className: "gap-2 text-status-error-text focus:text-status-error-text",
|
|
716
|
-
onClick: () =>
|
|
717
|
-
children: [/* @__PURE__ */ j(
|
|
761
|
+
onClick: () => w(e),
|
|
762
|
+
children: [/* @__PURE__ */ j(ue, {
|
|
718
763
|
className: "size-4",
|
|
719
764
|
"aria-hidden": "true"
|
|
720
765
|
}), "Delete"]
|
|
@@ -726,51 +771,51 @@ function Ve({ portfolioId: e, onOpenChange: t }) {
|
|
|
726
771
|
}, e.id);
|
|
727
772
|
}) })] })
|
|
728
773
|
}) })] }),
|
|
729
|
-
/* @__PURE__ */ M(F, { children: [/* @__PURE__ */ M(
|
|
774
|
+
/* @__PURE__ */ M(F, { children: [/* @__PURE__ */ M(R, {
|
|
730
775
|
className: "pb-3",
|
|
731
|
-
children: [/* @__PURE__ */ j(
|
|
776
|
+
children: [/* @__PURE__ */ j(z, {
|
|
732
777
|
className: "text-sm",
|
|
733
778
|
children: "Tags"
|
|
734
|
-
}), /* @__PURE__ */ j(
|
|
735
|
-
}), /* @__PURE__ */ j(I, { children: /* @__PURE__ */ j(
|
|
779
|
+
}), /* @__PURE__ */ j(L, { children: "Organize and filter this portfolio." })]
|
|
780
|
+
}), /* @__PURE__ */ j(I, { children: /* @__PURE__ */ j(ae, {
|
|
736
781
|
entityType: "brainyrich-portfolio",
|
|
737
|
-
entityId:
|
|
782
|
+
entityId: r.id,
|
|
738
783
|
hideLabel: !0
|
|
739
784
|
}) })] }),
|
|
740
785
|
/* @__PURE__ */ j(F, { children: /* @__PURE__ */ j(I, {
|
|
741
786
|
className: "pt-6",
|
|
742
|
-
children: /* @__PURE__ */ j(
|
|
787
|
+
children: /* @__PURE__ */ j(oe, {
|
|
743
788
|
entityType: "brainyrich-portfolio",
|
|
744
|
-
entityId:
|
|
789
|
+
entityId: r.id
|
|
745
790
|
})
|
|
746
791
|
}) })
|
|
747
792
|
]
|
|
748
793
|
}),
|
|
749
|
-
/* @__PURE__ */ j(
|
|
750
|
-
open:
|
|
751
|
-
onOpenChange:
|
|
752
|
-
portfolioId:
|
|
753
|
-
editing:
|
|
794
|
+
/* @__PURE__ */ j(Ge, {
|
|
795
|
+
open: d,
|
|
796
|
+
onOpenChange: _,
|
|
797
|
+
portfolioId: r.id,
|
|
798
|
+
editing: ie
|
|
754
799
|
}),
|
|
755
|
-
/* @__PURE__ */ j(
|
|
756
|
-
open:
|
|
800
|
+
/* @__PURE__ */ j(f, {
|
|
801
|
+
open: C !== null,
|
|
757
802
|
onOpenChange: (e) => {
|
|
758
|
-
e ||
|
|
803
|
+
e || w(null);
|
|
759
804
|
},
|
|
760
805
|
title: "Delete holding?",
|
|
761
|
-
description:
|
|
806
|
+
description: C ? `Remove ${C.symbol} from this portfolio. This cannot be undone.` : void 0,
|
|
762
807
|
confirmLabel: "Delete",
|
|
763
808
|
pendingLabel: "Deleting…",
|
|
764
809
|
destructive: !0,
|
|
765
|
-
pending:
|
|
810
|
+
pending: u.isPending,
|
|
766
811
|
onConfirm: () => {
|
|
767
|
-
|
|
812
|
+
C && u.mutate(C.id, { onSuccess: () => w(null) });
|
|
768
813
|
}
|
|
769
814
|
})
|
|
770
815
|
] }) : /* @__PURE__ */ j("div", {
|
|
771
816
|
className: "p-6",
|
|
772
|
-
children: /* @__PURE__ */ j(
|
|
773
|
-
icon: /* @__PURE__ */ j(
|
|
817
|
+
children: /* @__PURE__ */ j(te, {
|
|
818
|
+
icon: /* @__PURE__ */ j(A, {
|
|
774
819
|
className: "size-6",
|
|
775
820
|
"aria-hidden": "true"
|
|
776
821
|
}),
|
|
@@ -781,15 +826,47 @@ function Ve({ portfolioId: e, onOpenChange: t }) {
|
|
|
781
826
|
})
|
|
782
827
|
});
|
|
783
828
|
}
|
|
784
|
-
function
|
|
785
|
-
let
|
|
786
|
-
return /* @__PURE__ */
|
|
787
|
-
|
|
829
|
+
function qe({ driftPct: e, thresholdPct: t, assetClass: n }) {
|
|
830
|
+
let r = Math.abs(e), i = t > 0 && r > t, a = !i && t > 0 && r >= t * .75, o = t > 0 ? Math.min(100, r / t * 100) : 0, s = i ? "bg-status-error-bg" : a ? "bg-status-warning-bg" : "bg-accent-teal", c = i ? "text-status-error-text" : a ? "text-status-warning-text" : "text-text-secondary", l = n ? `Widest drift: ${Q(n)} ${e > 0 ? "over" : "under"}-weight by ${x(r)}` : `Widest drift ${x(r)}`;
|
|
831
|
+
return /* @__PURE__ */ M("div", {
|
|
832
|
+
className: "space-y-1",
|
|
833
|
+
children: [/* @__PURE__ */ M("div", {
|
|
834
|
+
className: "flex items-center justify-between gap-2 text-xs",
|
|
835
|
+
children: [/* @__PURE__ */ j("span", {
|
|
836
|
+
className: "text-text-secondary",
|
|
837
|
+
children: "Drift"
|
|
838
|
+
}), /* @__PURE__ */ M("span", {
|
|
839
|
+
className: `font-medium tabular-nums ${c}`,
|
|
840
|
+
children: [
|
|
841
|
+
i ? "⚠ " : "",
|
|
842
|
+
e > 0 ? "+" : "",
|
|
843
|
+
x(e)
|
|
844
|
+
]
|
|
845
|
+
})]
|
|
846
|
+
}), /* @__PURE__ */ j("div", {
|
|
847
|
+
className: "h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken",
|
|
848
|
+
role: "progressbar",
|
|
849
|
+
"aria-valuenow": Math.round(o),
|
|
850
|
+
"aria-valuemin": 0,
|
|
851
|
+
"aria-valuemax": 100,
|
|
852
|
+
"aria-label": l,
|
|
853
|
+
title: l,
|
|
854
|
+
children: /* @__PURE__ */ j("div", {
|
|
855
|
+
className: `h-full rounded-full ${s}`,
|
|
856
|
+
style: { width: `${o}%` }
|
|
857
|
+
})
|
|
858
|
+
})]
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
function Je({ portfolio: e, valuation: t, valuationError: n, index: r, onView: i, onEdit: a, onArchive: o }) {
|
|
862
|
+
let s = E(() => Re(e.targetAllocation), [e.targetAllocation]), c = s[0], l = e.tags ?? [];
|
|
863
|
+
return /* @__PURE__ */ j(m, {
|
|
864
|
+
index: r,
|
|
788
865
|
as: "div",
|
|
789
866
|
className: "h-full",
|
|
790
867
|
children: /* @__PURE__ */ M(F, {
|
|
791
868
|
className: "flex h-full flex-col transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))]",
|
|
792
|
-
children: [/* @__PURE__ */ M(
|
|
869
|
+
children: [/* @__PURE__ */ M(R, {
|
|
793
870
|
className: "pb-3",
|
|
794
871
|
children: [/* @__PURE__ */ M("div", {
|
|
795
872
|
className: "flex items-start justify-between gap-2",
|
|
@@ -798,154 +875,230 @@ function He({ portfolio: e, index: t, onView: n, onEdit: r, onArchive: i }) {
|
|
|
798
875
|
children: [
|
|
799
876
|
/* @__PURE__ */ j("span", {
|
|
800
877
|
className: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-[var(--color-action-primary-bg)]/12 text-[var(--color-action-primary-text)]",
|
|
801
|
-
children: /* @__PURE__ */ j(
|
|
878
|
+
children: /* @__PURE__ */ j(A, {
|
|
802
879
|
className: "size-4",
|
|
803
880
|
"aria-hidden": "true"
|
|
804
881
|
})
|
|
805
882
|
}),
|
|
806
|
-
/* @__PURE__ */ j(
|
|
883
|
+
/* @__PURE__ */ j(z, {
|
|
807
884
|
className: "truncate text-base",
|
|
808
885
|
children: e.name
|
|
809
886
|
}),
|
|
810
887
|
/* @__PURE__ */ j(N, {
|
|
811
|
-
variant:
|
|
888
|
+
variant: S(e.status),
|
|
812
889
|
children: Q(e.status)
|
|
813
890
|
})
|
|
814
891
|
]
|
|
815
|
-
}), /* @__PURE__ */ M(
|
|
892
|
+
}), /* @__PURE__ */ M(pe, { children: [/* @__PURE__ */ j(_e, {
|
|
816
893
|
asChild: !0,
|
|
817
894
|
children: /* @__PURE__ */ j(P, {
|
|
818
895
|
variant: "ghost",
|
|
819
896
|
size: "icon",
|
|
820
897
|
className: "size-9 shrink-0",
|
|
821
898
|
"aria-label": `Actions for ${e.name}`,
|
|
822
|
-
children: /* @__PURE__ */ j(
|
|
899
|
+
children: /* @__PURE__ */ j(se, {
|
|
823
900
|
className: "size-4",
|
|
824
901
|
"aria-hidden": "true"
|
|
825
902
|
})
|
|
826
903
|
})
|
|
827
|
-
}), /* @__PURE__ */ M(
|
|
904
|
+
}), /* @__PURE__ */ M(me, {
|
|
828
905
|
align: "end",
|
|
829
906
|
children: [
|
|
830
|
-
/* @__PURE__ */ j(
|
|
831
|
-
/* @__PURE__ */ j(
|
|
832
|
-
/* @__PURE__ */ M(
|
|
907
|
+
/* @__PURE__ */ j(he, { children: e.name }),
|
|
908
|
+
/* @__PURE__ */ j(ge, {}),
|
|
909
|
+
/* @__PURE__ */ M(G, {
|
|
833
910
|
className: "gap-2",
|
|
834
|
-
onClick:
|
|
835
|
-
children: [/* @__PURE__ */ j(
|
|
911
|
+
onClick: a,
|
|
912
|
+
children: [/* @__PURE__ */ j(ce, {
|
|
836
913
|
className: "size-4",
|
|
837
914
|
"aria-hidden": "true"
|
|
838
915
|
}), "Edit"]
|
|
839
916
|
}),
|
|
840
|
-
/* @__PURE__ */ M(
|
|
917
|
+
/* @__PURE__ */ M(G, {
|
|
841
918
|
className: "gap-2 text-status-error-text focus:text-status-error-text",
|
|
842
919
|
disabled: e.status === "ARCHIVED",
|
|
843
|
-
onClick:
|
|
844
|
-
children: [/* @__PURE__ */ j(
|
|
920
|
+
onClick: o,
|
|
921
|
+
children: [/* @__PURE__ */ j(ue, {
|
|
845
922
|
className: "size-4",
|
|
846
923
|
"aria-hidden": "true"
|
|
847
924
|
}), "Archive"]
|
|
848
925
|
})
|
|
849
926
|
]
|
|
850
927
|
})] })]
|
|
851
|
-
}), e.description?.trim() ? /* @__PURE__ */ j(
|
|
928
|
+
}), e.description?.trim() ? /* @__PURE__ */ j(L, {
|
|
852
929
|
className: "line-clamp-2",
|
|
853
930
|
children: e.description
|
|
854
931
|
}) : null]
|
|
855
932
|
}), /* @__PURE__ */ M(I, {
|
|
856
933
|
className: "flex flex-1 flex-col justify-between gap-4",
|
|
857
|
-
children: [
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
934
|
+
children: [
|
|
935
|
+
n ? /* @__PURE__ */ j("p", {
|
|
936
|
+
className: "text-sm text-text-secondary",
|
|
937
|
+
children: "Valuation unavailable — positions could not be loaded."
|
|
938
|
+
}) : t ? t.holdingCount > 0 ? /* @__PURE__ */ M("div", {
|
|
939
|
+
className: "space-y-2",
|
|
940
|
+
children: [/* @__PURE__ */ M("div", {
|
|
941
|
+
className: "flex flex-wrap items-baseline gap-x-3 gap-y-1",
|
|
942
|
+
children: [
|
|
943
|
+
/* @__PURE__ */ j("span", {
|
|
944
|
+
className: "text-2xl font-semibold tabular-nums text-text-primary",
|
|
945
|
+
children: y(t.marketValue, e.baseCurrency)
|
|
946
|
+
}),
|
|
947
|
+
t.gainPct === null ? null : /* @__PURE__ */ M("span", {
|
|
948
|
+
className: `inline-flex items-center gap-1 text-sm font-medium tabular-nums ${v(t.unrealizedGain)}`,
|
|
949
|
+
children: [
|
|
950
|
+
t.unrealizedGain > 0 ? /* @__PURE__ */ j(k, {
|
|
951
|
+
className: "size-3.5",
|
|
952
|
+
"aria-hidden": "true"
|
|
953
|
+
}) : t.unrealizedGain < 0 ? /* @__PURE__ */ j(O, {
|
|
954
|
+
className: "size-3.5",
|
|
955
|
+
"aria-hidden": "true"
|
|
956
|
+
}) : null,
|
|
957
|
+
t.unrealizedGain > 0 ? "+" : "",
|
|
958
|
+
x(t.gainPct)
|
|
959
|
+
]
|
|
960
|
+
}),
|
|
961
|
+
/* @__PURE__ */ M("span", {
|
|
962
|
+
className: "text-xs text-text-secondary",
|
|
963
|
+
children: [
|
|
964
|
+
t.holdingCount,
|
|
965
|
+
" holding",
|
|
966
|
+
t.holdingCount === 1 ? "" : "s"
|
|
967
|
+
]
|
|
968
|
+
})
|
|
969
|
+
]
|
|
970
|
+
}), t.maxDriftPct === null ? /* @__PURE__ */ j("p", {
|
|
971
|
+
className: "text-xs text-text-secondary",
|
|
972
|
+
children: "Drift needs a target allocation on this portfolio."
|
|
973
|
+
}) : /* @__PURE__ */ j(qe, {
|
|
974
|
+
driftPct: t.maxDriftPct,
|
|
975
|
+
thresholdPct: e.driftThresholdPct,
|
|
976
|
+
assetClass: t.driftAssetClass
|
|
977
|
+
})]
|
|
978
|
+
}) : /* @__PURE__ */ j("p", {
|
|
979
|
+
className: "text-sm text-text-secondary",
|
|
980
|
+
children: "No holdings yet — add positions to value this portfolio."
|
|
869
981
|
}) : /* @__PURE__ */ M("div", {
|
|
870
|
-
className: "
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
]
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
"
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
982
|
+
className: "space-y-2",
|
|
983
|
+
"aria-busy": "true",
|
|
984
|
+
children: [/* @__PURE__ */ j("div", { className: "h-7 w-32 animate-pulse rounded bg-bg-sunken" }), /* @__PURE__ */ j("div", { className: "h-1.5 w-full animate-pulse rounded-full bg-bg-sunken" })]
|
|
985
|
+
}),
|
|
986
|
+
/* @__PURE__ */ M("div", {
|
|
987
|
+
className: "grid grid-cols-[auto_1fr] items-center gap-4",
|
|
988
|
+
children: [s.length > 0 ? /* @__PURE__ */ j("div", {
|
|
989
|
+
className: "w-28 shrink-0",
|
|
990
|
+
children: /* @__PURE__ */ j(p, {
|
|
991
|
+
data: s,
|
|
992
|
+
legend: !1,
|
|
993
|
+
height: 112,
|
|
994
|
+
centerValue: c ? x(c.value, 0) : void 0,
|
|
995
|
+
centerLabel: c?.label,
|
|
996
|
+
valueFormatter: (e) => x(e, 0)
|
|
997
|
+
})
|
|
998
|
+
}) : /* @__PURE__ */ M("div", {
|
|
999
|
+
className: "flex size-28 shrink-0 items-center justify-center rounded-full border border-dashed border-border-subtle text-center text-[10px] leading-tight text-text-secondary",
|
|
1000
|
+
children: [
|
|
1001
|
+
"No target",
|
|
1002
|
+
/* @__PURE__ */ j("br", {}),
|
|
1003
|
+
"allocation"
|
|
1004
|
+
]
|
|
1005
|
+
}), /* @__PURE__ */ M("div", {
|
|
1006
|
+
className: "min-w-0 space-y-2",
|
|
1007
|
+
children: [
|
|
1008
|
+
/* @__PURE__ */ M("div", {
|
|
1009
|
+
className: "flex flex-wrap items-center gap-1.5",
|
|
1010
|
+
children: [/* @__PURE__ */ j(N, {
|
|
1011
|
+
variant: "outline",
|
|
1012
|
+
children: e.baseCurrency
|
|
1013
|
+
}), /* @__PURE__ */ M(N, {
|
|
1014
|
+
variant: "secondary",
|
|
1015
|
+
children: ["Drift ≤ ", x(e.driftThresholdPct)]
|
|
900
1016
|
})]
|
|
901
|
-
},
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
1017
|
+
}),
|
|
1018
|
+
s.length > 0 ? /* @__PURE__ */ j("ul", {
|
|
1019
|
+
className: "space-y-1",
|
|
1020
|
+
"aria-label": "Target allocation",
|
|
1021
|
+
children: s.slice(0, 3).map((e) => /* @__PURE__ */ M("li", {
|
|
1022
|
+
className: "flex items-center gap-1.5 text-xs",
|
|
1023
|
+
children: [/* @__PURE__ */ j("span", {
|
|
1024
|
+
className: "truncate text-text-secondary",
|
|
1025
|
+
children: e.label
|
|
1026
|
+
}), /* @__PURE__ */ j("span", {
|
|
1027
|
+
className: "ml-auto font-medium tabular-nums text-text-primary",
|
|
1028
|
+
children: x(e.value, 0)
|
|
1029
|
+
})]
|
|
1030
|
+
}, e.label))
|
|
1031
|
+
}) : null,
|
|
1032
|
+
l.length > 0 ? /* @__PURE__ */ j("div", {
|
|
1033
|
+
className: "flex flex-wrap gap-1",
|
|
1034
|
+
children: l.slice(0, 3).map((e) => /* @__PURE__ */ j(N, {
|
|
1035
|
+
variant: "outline",
|
|
1036
|
+
className: "text-[10px]",
|
|
1037
|
+
children: e
|
|
1038
|
+
}, e))
|
|
1039
|
+
}) : null
|
|
1040
|
+
]
|
|
1041
|
+
})]
|
|
1042
|
+
}),
|
|
1043
|
+
/* @__PURE__ */ j(P, {
|
|
1044
|
+
variant: "outline",
|
|
1045
|
+
size: "sm",
|
|
1046
|
+
className: "w-full",
|
|
1047
|
+
onClick: i,
|
|
1048
|
+
children: "View holdings"
|
|
1049
|
+
})
|
|
1050
|
+
]
|
|
920
1051
|
})]
|
|
921
1052
|
})
|
|
922
1053
|
});
|
|
923
1054
|
}
|
|
924
|
-
function
|
|
925
|
-
|
|
926
|
-
let { items:
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1055
|
+
function Ye() {
|
|
1056
|
+
T("brainyrich.portfolios.viewed");
|
|
1057
|
+
let { items: n, hasMore: r, loadMore: i, isLoading: a, isFetchingNextPage: o, isError: c, refetch: l } = s(), u = t(), p = e(), h = E(() => {
|
|
1058
|
+
let e = /* @__PURE__ */ new Map();
|
|
1059
|
+
for (let t of p.data) {
|
|
1060
|
+
if (!t.portfolioId) continue;
|
|
1061
|
+
let n = e.get(t.portfolioId);
|
|
1062
|
+
n ? n.push(t) : e.set(t.portfolioId, [t]);
|
|
1063
|
+
}
|
|
1064
|
+
return e;
|
|
1065
|
+
}, [p.data]), _ = E(() => {
|
|
1066
|
+
let e = /* @__PURE__ */ new Map();
|
|
1067
|
+
for (let t of n) e.set(t.id, Be(h.get(t.id) ?? [], t.targetAllocation));
|
|
1068
|
+
return e;
|
|
1069
|
+
}, [n, h]), [ee, v] = D(!1), [b, S] = D(null), [ae, oe] = D(null), [O, k] = D(null), se = n.filter((e) => e.status === "ACTIVE").length, ce = n.filter((e) => e.status === "DRAFT").length, ue = n.length > 0 ? n.reduce((e, t) => e + t.driftThresholdPct, 0) / n.length : 0, N = E(() => {
|
|
1070
|
+
let e = /* @__PURE__ */ new Map();
|
|
1071
|
+
for (let t of n) {
|
|
1072
|
+
let n = _.get(t.id);
|
|
1073
|
+
!n || n.holdingCount === 0 || e.set(t.baseCurrency, (e.get(t.baseCurrency) ?? 0) + n.marketValue);
|
|
1074
|
+
}
|
|
1075
|
+
return e;
|
|
1076
|
+
}, [n, _]), F = Array.from(N.keys()).sort(), I = F.length === 1 ? F[0] : void 0, L = n.filter((e) => {
|
|
1077
|
+
let t = _.get(e.id)?.maxDriftPct;
|
|
1078
|
+
return t == null || e.driftThresholdPct <= 0 ? !1 : Math.abs(t) > e.driftThresholdPct;
|
|
1079
|
+
}).length, R = () => {
|
|
1080
|
+
S(null), v(!0);
|
|
1081
|
+
}, z = (e) => {
|
|
1082
|
+
S(e), v(!0);
|
|
930
1083
|
};
|
|
931
1084
|
return /* @__PURE__ */ j("div", {
|
|
932
1085
|
"data-tour": "brainyrich-page-portfolios",
|
|
933
1086
|
className: "contents",
|
|
934
|
-
children: /* @__PURE__ */ M(
|
|
1087
|
+
children: /* @__PURE__ */ M(ie, {
|
|
935
1088
|
title: "Portfolios",
|
|
936
1089
|
description: "Organize holdings into strategies and keep allocations on target.",
|
|
937
|
-
badges:
|
|
1090
|
+
badges: n.length > 0 ? [`${n.length} total`] : [],
|
|
938
1091
|
actions: /* @__PURE__ */ M(P, {
|
|
939
1092
|
size: "sm",
|
|
940
|
-
onClick:
|
|
941
|
-
children: [/* @__PURE__ */ j(
|
|
1093
|
+
onClick: R,
|
|
1094
|
+
children: [/* @__PURE__ */ j(le, {
|
|
942
1095
|
className: "size-4",
|
|
943
1096
|
"aria-hidden": "true"
|
|
944
1097
|
}), "New portfolio"]
|
|
945
1098
|
}),
|
|
946
1099
|
children: [
|
|
947
|
-
|
|
948
|
-
icon: /* @__PURE__ */ j(
|
|
1100
|
+
a ? /* @__PURE__ */ j(re, { rows: 4 }) : c ? /* @__PURE__ */ j(ne, { onRetry: () => l() }) : n.length === 0 ? /* @__PURE__ */ j(te, {
|
|
1101
|
+
icon: /* @__PURE__ */ j(A, {
|
|
949
1102
|
className: "size-6",
|
|
950
1103
|
"aria-hidden": "true"
|
|
951
1104
|
}),
|
|
@@ -953,76 +1106,100 @@ function Ue() {
|
|
|
953
1106
|
description: "Create your first portfolio to start organizing holdings and tracking drift.",
|
|
954
1107
|
action: /* @__PURE__ */ M(P, {
|
|
955
1108
|
size: "sm",
|
|
956
|
-
onClick:
|
|
957
|
-
children: [/* @__PURE__ */ j(
|
|
1109
|
+
onClick: R,
|
|
1110
|
+
children: [/* @__PURE__ */ j(le, {
|
|
958
1111
|
className: "size-4",
|
|
959
1112
|
"aria-hidden": "true"
|
|
960
1113
|
}), "New portfolio"]
|
|
961
1114
|
})
|
|
962
|
-
}) : /* @__PURE__ */ M(
|
|
963
|
-
/* @__PURE__ */ M(
|
|
964
|
-
className: "grid grid-cols-2 gap-3 lg:grid-cols-
|
|
1115
|
+
}) : /* @__PURE__ */ M(de, { children: [
|
|
1116
|
+
/* @__PURE__ */ M(m, {
|
|
1117
|
+
className: "grid grid-cols-2 gap-3 lg:grid-cols-5",
|
|
965
1118
|
children: [
|
|
966
|
-
/* @__PURE__ */ j(
|
|
1119
|
+
/* @__PURE__ */ j(g, {
|
|
967
1120
|
label: "Portfolios",
|
|
968
|
-
value: String(
|
|
1121
|
+
value: String(n.length),
|
|
969
1122
|
glow: !0
|
|
970
1123
|
}),
|
|
971
|
-
/* @__PURE__ */ j(
|
|
1124
|
+
/* @__PURE__ */ j(g, {
|
|
1125
|
+
label: I ? `Total value (${I})` : "Total value",
|
|
1126
|
+
value: p.isPending ? "…" : p.isError ? "—" : I ? y(N.get(I) ?? 0, I) : F.length === 0 ? "—" : `${F.length} currencies`
|
|
1127
|
+
}),
|
|
1128
|
+
/* @__PURE__ */ j(g, {
|
|
972
1129
|
label: "Active",
|
|
973
|
-
value: String(
|
|
1130
|
+
value: String(se)
|
|
974
1131
|
}),
|
|
975
|
-
/* @__PURE__ */ j(
|
|
1132
|
+
/* @__PURE__ */ j(g, {
|
|
976
1133
|
label: "Drafts",
|
|
977
|
-
value: String(
|
|
1134
|
+
value: String(ce)
|
|
978
1135
|
}),
|
|
979
|
-
/* @__PURE__ */ j(
|
|
980
|
-
label: "
|
|
981
|
-
value:
|
|
1136
|
+
/* @__PURE__ */ j(g, {
|
|
1137
|
+
label: "Past drift threshold",
|
|
1138
|
+
value: p.isPending ? "…" : p.isError ? "—" : String(L)
|
|
982
1139
|
})
|
|
983
1140
|
]
|
|
984
1141
|
}),
|
|
1142
|
+
!p.isPending && !p.isError && F.length > 1 ? /* @__PURE__ */ M("p", {
|
|
1143
|
+
className: "text-xs text-text-secondary",
|
|
1144
|
+
children: [
|
|
1145
|
+
"Market value is not FX-converted:",
|
|
1146
|
+
" ",
|
|
1147
|
+
F.map((e) => y(N.get(e) ?? 0, e)).join(" · "),
|
|
1148
|
+
". Average drift threshold ",
|
|
1149
|
+
x(ue),
|
|
1150
|
+
"."
|
|
1151
|
+
]
|
|
1152
|
+
}) : /* @__PURE__ */ M("p", {
|
|
1153
|
+
className: "text-xs text-text-secondary",
|
|
1154
|
+
children: [
|
|
1155
|
+
"Average drift threshold across these portfolios: ",
|
|
1156
|
+
x(ue),
|
|
1157
|
+
"."
|
|
1158
|
+
]
|
|
1159
|
+
}),
|
|
985
1160
|
/* @__PURE__ */ j("div", {
|
|
986
1161
|
className: "grid gap-4 md:grid-cols-2 xl:grid-cols-3",
|
|
987
|
-
children:
|
|
1162
|
+
children: n.map((e, t) => /* @__PURE__ */ j(Je, {
|
|
988
1163
|
portfolio: e,
|
|
1164
|
+
valuation: p.isPending ? void 0 : _.get(e.id),
|
|
1165
|
+
valuationError: p.isError,
|
|
989
1166
|
index: t,
|
|
990
|
-
onView: () =>
|
|
991
|
-
onEdit: () =>
|
|
992
|
-
onArchive: () =>
|
|
1167
|
+
onView: () => oe(e.id),
|
|
1168
|
+
onEdit: () => z(e),
|
|
1169
|
+
onArchive: () => k(e)
|
|
993
1170
|
}, e.id))
|
|
994
1171
|
}),
|
|
995
|
-
/* @__PURE__ */ j(
|
|
996
|
-
hasMore:
|
|
997
|
-
onClick:
|
|
998
|
-
loading:
|
|
1172
|
+
/* @__PURE__ */ j(d, {
|
|
1173
|
+
hasMore: r,
|
|
1174
|
+
onClick: i,
|
|
1175
|
+
loading: o
|
|
999
1176
|
})
|
|
1000
1177
|
] }),
|
|
1001
|
-
/* @__PURE__ */ j(
|
|
1002
|
-
open:
|
|
1003
|
-
onOpenChange:
|
|
1004
|
-
editing:
|
|
1178
|
+
/* @__PURE__ */ j(Ue, {
|
|
1179
|
+
open: ee,
|
|
1180
|
+
onOpenChange: v,
|
|
1181
|
+
editing: b
|
|
1005
1182
|
}),
|
|
1006
|
-
/* @__PURE__ */ j(
|
|
1007
|
-
portfolioId:
|
|
1183
|
+
/* @__PURE__ */ j(Ke, {
|
|
1184
|
+
portfolioId: ae,
|
|
1008
1185
|
onOpenChange: (e) => {
|
|
1009
|
-
e ||
|
|
1186
|
+
e || oe(null);
|
|
1010
1187
|
}
|
|
1011
1188
|
}),
|
|
1012
|
-
/* @__PURE__ */ j(
|
|
1013
|
-
open:
|
|
1189
|
+
/* @__PURE__ */ j(f, {
|
|
1190
|
+
open: O !== null,
|
|
1014
1191
|
onOpenChange: (e) => {
|
|
1015
|
-
e ||
|
|
1192
|
+
e || k(null);
|
|
1016
1193
|
},
|
|
1017
1194
|
title: "Archive portfolio?",
|
|
1018
|
-
description:
|
|
1195
|
+
description: O ? `Archive “${O.name}”. It will move to archived status and stop appearing in active views.` : void 0,
|
|
1019
1196
|
confirmLabel: "Archive",
|
|
1020
1197
|
pendingLabel: "Archiving…",
|
|
1021
1198
|
destructive: !0,
|
|
1022
|
-
pending:
|
|
1199
|
+
pending: u.isPending,
|
|
1023
1200
|
onConfirm: () => {
|
|
1024
|
-
|
|
1025
|
-
|
|
1201
|
+
O && u.mutate(O.id, { onSuccess: () => {
|
|
1202
|
+
C(), w("Portfolio archived"), k(null);
|
|
1026
1203
|
} });
|
|
1027
1204
|
}
|
|
1028
1205
|
})
|
|
@@ -1031,6 +1208,6 @@ function Ue() {
|
|
|
1031
1208
|
});
|
|
1032
1209
|
}
|
|
1033
1210
|
//#endregion
|
|
1034
|
-
export {
|
|
1211
|
+
export { Ye as PortfoliosPage };
|
|
1035
1212
|
|
|
1036
1213
|
//# sourceMappingURL=PortfoliosPage.js.map
|