@mx-cartographer/experiences 9.4.20 → 9.4.21
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/CHANGELOG.md +5 -0
- package/dist/core/utils/InvestmentUtil.d.ts +9 -0
- package/dist/core/utils/InvestmentUtil.es.js +68 -50
- package/dist/core/utils/InvestmentUtil.es.js.map +1 -1
- package/dist/investments/components/HoldingDrawer.d.ts +3 -0
- package/dist/investments/components/HoldingDrawer.es.js +33 -29
- package/dist/investments/components/HoldingDrawer.es.js.map +1 -1
- package/dist/investments/components/HoldingTable.d.ts +3 -0
- package/dist/investments/components/HoldingTable.es.js +37 -33
- package/dist/investments/components/HoldingTable.es.js.map +1 -1
- package/dist/investments/components/Overview.es.js +163 -134
- package/dist/investments/components/Overview.es.js.map +1 -1
- package/dist/investments/components/allocation/InvestmentsAllocationChart.d.ts +1 -0
- package/dist/investments/components/allocation/InvestmentsAllocationChart.es.js +16 -16
- package/dist/investments/components/allocation/InvestmentsAllocationChart.es.js.map +1 -1
- package/dist/investments/components/allocation/util/createInvestementsAllocationData.d.ts +1 -0
- package/dist/investments/components/allocation/util/createInvestementsAllocationData.es.js +58 -54
- package/dist/investments/components/allocation/util/createInvestementsAllocationData.es.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## [9.4.21] - 09-15-2026
|
|
2
|
+
|
|
3
|
+
- **FIXED** - Investments widget showed a false 100% gain on holdings with a null `cost_basis` (exposed once MEW-4073 enriched `market_value`), because gain/loss treated an unknown basis as `0`. Basis now resolves via a shared helper (`getHoldingGainLoss`): `cost_basis` when set (including a real `0`), else `purchase_price`, else "—" instead of a fabricated 0/100% — applied to the holding rows, Cost Basis column, account rollup, the Overview total-portfolio gain/loss, and the Allocation donut (including its center) so an all-unknown-basis portfolio shows "—" rather than a fabricated $0.00. The inline editor still seeds from the raw `cost_basis` so an untouched edit never persists `purchase_price` back to Abacus, and editing a basis on mobile now re-derives the drawer's gain/loss instead of leaving it stale (MEW-3791)
|
|
4
|
+
- **ADDED** - `getHoldingMarketValue`, `getHoldingCostBasis`, and `getHoldingGainLoss` helpers in `core/utils/InvestmentUtil` as the single source of truth for holding valuation and gain/loss, with unit coverage (MEW-3791)
|
|
5
|
+
|
|
1
6
|
## [9.4.20] - 09-15-2026
|
|
2
7
|
|
|
3
8
|
- **ADDED** - DataDog RUM for Pulse and MDB
|
|
@@ -5,6 +5,15 @@ export declare const isMeaningfulNumber: (value: unknown) => boolean;
|
|
|
5
5
|
export declare const isValidClassification: (value: unknown) => boolean;
|
|
6
6
|
export declare const holdingHasStyleData: (holding: Holding) => boolean;
|
|
7
7
|
export declare const holdingHasAllocationData: (holding: Holding) => boolean;
|
|
8
|
+
export declare const getHoldingMarketValue: (holding: Holding) => number;
|
|
9
|
+
export declare const getHoldingCostBasis: (holding: Holding) => number | null;
|
|
10
|
+
export interface HoldingGainLoss {
|
|
11
|
+
available: boolean;
|
|
12
|
+
basis: number;
|
|
13
|
+
gainLoss: number;
|
|
14
|
+
gainLossPercentage: number;
|
|
15
|
+
}
|
|
16
|
+
export declare const getHoldingGainLoss: (holding: Holding) => HoldingGainLoss;
|
|
8
17
|
export declare const createGroups: (classificationObj: Record<number, string>, groupSize?: number) => string[][];
|
|
9
18
|
export declare const bondGroups: string[][];
|
|
10
19
|
export declare const stockGroups: string[][];
|
|
@@ -1,92 +1,110 @@
|
|
|
1
|
-
import { ALLOCATION_KEYS as
|
|
1
|
+
import { ALLOCATION_KEYS as O, AnalysisType as V, EquityClassificationTypes as A, EquityClassificationValues as m, FixedIncomeClassificationTypes as G, FixedIncomeClassificationValues as f, STYLE_WEIGHT_KEYS as T } from "../constants/Investments.es.js";
|
|
2
2
|
import W from "numeral";
|
|
3
|
-
var
|
|
3
|
+
var C = 80, H = 120, d = (e) => e > C && e < H, S = (e) => {
|
|
4
4
|
const t = Number(e);
|
|
5
5
|
return Number.isFinite(t) && t !== 0;
|
|
6
|
-
},
|
|
6
|
+
}, p = (e) => {
|
|
7
7
|
const t = Number(e);
|
|
8
8
|
return Number.isFinite(t) && t >= 1 && t <= 9;
|
|
9
|
-
},
|
|
9
|
+
}, K = (e) => {
|
|
10
10
|
const t = T.reduce((r, s) => r + (Number(e[s]) || 0), 0);
|
|
11
|
-
return
|
|
12
|
-
},
|
|
11
|
+
return d(t) || t === 0 && (p(e.equity_classification) || p(e.fixed_income_classification));
|
|
12
|
+
}, U = (e) => O.some((t) => S(e[t])), x = (e) => e.calculated_market_value ?? e.market_value ?? 0, I = (e) => Number.isFinite(e.cost_basis) ? e.cost_basis : Number.isFinite(e.purchase_price) ? e.purchase_price : null, Y = (e) => {
|
|
13
|
+
const t = I(e);
|
|
14
|
+
if (t === null) return {
|
|
15
|
+
available: !1,
|
|
16
|
+
basis: 0,
|
|
17
|
+
gainLoss: 0,
|
|
18
|
+
gainLossPercentage: 0
|
|
19
|
+
};
|
|
20
|
+
const r = x(e) - t;
|
|
21
|
+
return {
|
|
22
|
+
available: !0,
|
|
23
|
+
basis: t,
|
|
24
|
+
gainLoss: r,
|
|
25
|
+
gainLossPercentage: t === 0 ? 0 : r / t * 100
|
|
26
|
+
};
|
|
27
|
+
}, E = (e, t = 3) => {
|
|
13
28
|
const r = Object.keys(e).map(Number).filter((a) => a !== 0).sort((a, i) => a - i), s = [];
|
|
14
29
|
for (let a = 0; a < r.length; a += t) s.push(r.slice(a, a + t).map((i) => e[i]));
|
|
15
30
|
return s;
|
|
16
|
-
},
|
|
17
|
-
const t =
|
|
18
|
-
const o = a.reduce((n, c) => n +
|
|
19
|
-
const
|
|
20
|
-
return Object.keys(
|
|
31
|
+
}, D = E(f), M = E(m), B = (e) => {
|
|
32
|
+
const t = b(e, k), r = b(e, h), s = (a, i) => {
|
|
33
|
+
const o = a.reduce((n, c) => n + w(c), 0), l = a.reduce((n, c) => {
|
|
34
|
+
const u = i(c);
|
|
35
|
+
return Object.keys(u).forEach((_) => n[_] = (n[_] || 0) + u[_]), n;
|
|
21
36
|
}, {});
|
|
22
|
-
return Object.fromEntries(Object.entries(
|
|
37
|
+
return Object.fromEntries(Object.entries(l).map(([n, c]) => [n, c / o * 100]));
|
|
23
38
|
};
|
|
24
39
|
return {
|
|
25
|
-
stocks: s(t,
|
|
26
|
-
bonds: s(r,
|
|
40
|
+
stocks: s(t, y),
|
|
41
|
+
bonds: s(r, L)
|
|
27
42
|
};
|
|
28
|
-
},
|
|
29
|
-
const t = e.filter((a) => !isNaN(a.equity_classification)), r = e.filter((a) => !isNaN(a.fixed_income_classification)), s = (a, i, o) => a.reduce((
|
|
43
|
+
}, P = (e) => {
|
|
44
|
+
const t = e.filter((a) => !isNaN(a.equity_classification)), r = e.filter((a) => !isNaN(a.fixed_income_classification)), s = (a, i, o) => a.reduce((l, n) => {
|
|
30
45
|
const c = i(n);
|
|
31
|
-
return Object.keys(o).forEach((
|
|
32
|
-
u
|
|
33
|
-
}),
|
|
46
|
+
return Object.keys(o).forEach((u) => {
|
|
47
|
+
l[u] = (l[u] || 0) + (c[u] || 0);
|
|
48
|
+
}), l;
|
|
34
49
|
}, {});
|
|
35
50
|
return {
|
|
36
|
-
stocks: s(t,
|
|
37
|
-
bonds: s(r,
|
|
51
|
+
stocks: s(t, y, A),
|
|
52
|
+
bonds: s(r, L, G)
|
|
38
53
|
};
|
|
39
|
-
},
|
|
54
|
+
}, j = (e, t) => Object.fromEntries(Object.entries(e).map(([r, s]) => [r, s * t / 100])), L = (e) => N(e, h, f), h = (e) => {
|
|
40
55
|
const t = e.fixed_income_classification;
|
|
41
56
|
return { [f[t]]: 100 };
|
|
42
|
-
},
|
|
43
|
-
const { large_core_weight: t, large_growth_weight: r, large_value_weight: s, mid_core_weight: a, mid_growth_weight: i, mid_value_weight: o, small_core_weight:
|
|
57
|
+
}, y = (e) => N(e, k, m), k = (e) => {
|
|
58
|
+
const { large_core_weight: t, large_growth_weight: r, large_value_weight: s, mid_core_weight: a, mid_growth_weight: i, mid_value_weight: o, small_core_weight: l, small_growth_weight: n, small_value_weight: c, unknown_weight: u, equity_classification: _ } = e, g = {
|
|
44
59
|
LARGE_CORE: t ?? 0,
|
|
45
60
|
LARGE_GROWTH: r ?? 0,
|
|
46
61
|
LARGE_VALUE: s ?? 0,
|
|
47
62
|
MID_CORE: a ?? 0,
|
|
48
63
|
MID_GROWTH: i ?? 0,
|
|
49
64
|
MID_VALUE: o ?? 0,
|
|
50
|
-
SMALL_CORE:
|
|
65
|
+
SMALL_CORE: l ?? 0,
|
|
51
66
|
SMALL_GROWTH: n ?? 0,
|
|
52
67
|
SMALL_VALUE: c ?? 0,
|
|
53
|
-
UNKNOWN:
|
|
68
|
+
UNKNOWN: u ?? 0
|
|
54
69
|
};
|
|
55
70
|
return v(g) === 0 && _ !== void 0 ? { [m[_]]: 100 } : g;
|
|
56
|
-
},
|
|
57
|
-
const s = t(e), a =
|
|
71
|
+
}, N = (e, t, r) => {
|
|
72
|
+
const s = t(e), a = w(e), i = j(s, a);
|
|
58
73
|
if (v(i) === 0) {
|
|
59
74
|
const o = String(e.equity_classification ?? e.fixed_income_classification);
|
|
60
75
|
if (o in r) return { [r[o]]: a };
|
|
61
76
|
console.error(`Invalid classification key: ${o}`);
|
|
62
77
|
}
|
|
63
78
|
return i;
|
|
64
|
-
},
|
|
79
|
+
}, $ = (e) => e.split("_").map((t) => t.charAt(0).toUpperCase() + t.slice(1).toLowerCase()).join(" "), F = (e) => e >= 1 ? `${W(e).format("0")}%` : "< 1%", w = (e) => e.calculated_market_value ?? e.market_value, b = (e, t) => e.filter((r) => {
|
|
65
80
|
const s = t(r);
|
|
66
|
-
return
|
|
67
|
-
}),
|
|
68
|
-
const r = t ===
|
|
69
|
-
return !s || Object.keys(s).length === 0 ? r.map((a) => a.map(() => "0%")) : r.map((a) => a.map((i) =>
|
|
81
|
+
return d(v(s));
|
|
82
|
+
}), X = (e, t) => {
|
|
83
|
+
const r = t === V.Stocks ? M : D, s = e[t];
|
|
84
|
+
return !s || Object.keys(s).length === 0 ? r.map((a) => a.map(() => "0%")) : r.map((a) => a.map((i) => F(s[i] ?? 0)));
|
|
70
85
|
}, v = (e) => Object.values(e).reduce((t, r) => t + r, 0);
|
|
71
86
|
export {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
87
|
+
B as analysisChartData,
|
|
88
|
+
P as analysisDetailsData,
|
|
89
|
+
D as bondGroups,
|
|
90
|
+
j as calculateWeightedValue,
|
|
76
91
|
E as createGroups,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
h as extractBondWeight,
|
|
93
|
+
k as extractStockWeight,
|
|
94
|
+
N as extractValueFromWeight,
|
|
95
|
+
$ as formatKey,
|
|
96
|
+
F as formatPercent,
|
|
97
|
+
I as getHoldingCostBasis,
|
|
98
|
+
Y as getHoldingGainLoss,
|
|
99
|
+
x as getHoldingMarketValue,
|
|
100
|
+
w as getHoldingValue,
|
|
101
|
+
b as getValidHoldings,
|
|
102
|
+
U as holdingHasAllocationData,
|
|
103
|
+
K as holdingHasStyleData,
|
|
104
|
+
S as isMeaningfulNumber,
|
|
105
|
+
p as isValidClassification,
|
|
106
|
+
X as mapDataToPercentageGrid,
|
|
107
|
+
M as stockGroups,
|
|
90
108
|
v as sumValues
|
|
91
109
|
};
|
|
92
110
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InvestmentUtil.es.js","names":[],"sources":["../../../src/core/utils/InvestmentUtil.ts"],"sourcesContent":["import numeral from 'numeral'\n\nimport type { Holding } from '../types'\n\nimport {\n ALLOCATION_KEYS,\n AnalysisType,\n EquityClassificationTypes,\n EquityClassificationValues,\n FixedIncomeClassificationTypes,\n FixedIncomeClassificationValues,\n STYLE_WEIGHT_KEYS,\n} from '../constants/Investments'\n\ntype WeightMap = Record<string, number>\n\n// The render band getValidHoldings keeps; the analysis gate reuses it so the\n// tab never enables onto an all-zero grid.\nconst STYLE_WEIGHT_MIN = 80\nconst STYLE_WEIGHT_MAX = 120\nconst isInStyleWeightBand = (total: number): boolean =>\n total > STYLE_WEIGHT_MIN && total < STYLE_WEIGHT_MAX\n\n// Coerces so a stringified number counts; null/\"\"/\"0\"/NaN/0 all mean \"no data\".\nexport const isMeaningfulNumber = (value: unknown): boolean => {\n const n = Number(value)\n return Number.isFinite(n) && n !== 0\n}\n\n// Classification 0 is UNKNOWN; only 1..9 represent real data.\nexport const isValidClassification = (value: unknown): boolean => {\n const n = Number(value)\n return Number.isFinite(n) && n >= 1 && n <= 9\n}\n\n// Classification only counts when style weights sum to 0, matching\n// extractWeight's fallback — otherwise a partial (out-of-band) total that\n// getValidHoldings drops would wrongly enable the tab onto an empty grid.\nexport const holdingHasStyleData = (holding: Holding): boolean => {\n const styleTotal = STYLE_WEIGHT_KEYS.reduce((sum, key) => sum + (Number(holding[key]) || 0), 0)\n return (\n isInStyleWeightBand(styleTotal) ||\n (styleTotal === 0 &&\n (isValidClassification(holding.equity_classification) ||\n isValidClassification(holding.fixed_income_classification)))\n )\n}\n\nexport const holdingHasAllocationData = (holding: Holding): boolean =>\n ALLOCATION_KEYS.some((key) => isMeaningfulNumber(holding[key]))\n\nexport const createGroups = (classificationObj: Record<number, string>, groupSize = 3) => {\n const keys = Object.keys(classificationObj)\n .map(Number)\n .filter((k) => k !== 0)\n .sort((a, b) => a - b)\n\n const groups = []\n for (let i = 0; i < keys.length; i += groupSize) {\n groups.push(keys.slice(i, i + groupSize).map((key) => classificationObj[key]))\n }\n return groups\n}\n\nexport const bondGroups = createGroups(FixedIncomeClassificationValues)\nexport const stockGroups = createGroups(EquityClassificationValues)\n\nexport const analysisChartData = (holdings: Holding[]) => {\n const stocks = getValidHoldings(holdings, extractStockWeight)\n const bonds = getValidHoldings(holdings, extractBondWeight)\n\n const processGroupData = (group: Holding[], extractValueFn: (holding: Holding) => WeightMap) => {\n const totalValue = group.reduce((acc, holding) => acc + getHoldingValue(holding), 0)\n const groupValues = group.reduce((acc, holding) => {\n const value = extractValueFn(holding)\n Object.keys(value).forEach((key) => (acc[key] = (acc[key] || 0) + value[key]))\n return acc\n }, {} as WeightMap)\n\n return Object.fromEntries(\n Object.entries(groupValues).map(([key, value]) => [key, (value / totalValue) * 100]),\n )\n }\n\n const data = {\n stocks: processGroupData(stocks, extractStockValueFromWeight),\n bonds: processGroupData(bonds, extractBondValueFromWeight),\n }\n\n return data\n}\n\nexport const analysisDetailsData = (holdings: Holding[]) => {\n const stocks = holdings.filter((holding) => !isNaN(holding.equity_classification))\n const bonds = holdings.filter((holding) => !isNaN(holding.fixed_income_classification))\n\n const aggregateValues = (\n holdings: Holding[],\n extractValueFn: (holding: Holding) => WeightMap,\n classificationTypes: Record<string, number>,\n ) => {\n return holdings.reduce((acc, holding) => {\n const values = extractValueFn(holding)\n Object.keys(classificationTypes).forEach((sector) => {\n acc[sector] = (acc[sector] || 0) + (values[sector] || 0)\n })\n return acc\n }, {} as WeightMap)\n }\n\n return {\n stocks: aggregateValues(stocks, extractStockValueFromWeight, EquityClassificationTypes),\n bonds: aggregateValues(bonds, extractBondValueFromWeight, FixedIncomeClassificationTypes),\n }\n}\n\nexport const calculateWeightedValue = (weights: WeightMap, value: number): WeightMap => {\n return Object.fromEntries(\n Object.entries(weights).map(([key, weight]) => [key, (weight * value) / 100]),\n )\n}\n\nconst extractBondValueFromWeight = (bond: Holding) =>\n extractValueFromWeight(bond, extractBondWeight, FixedIncomeClassificationValues)\n\nexport const extractBondWeight = (bond: Holding): WeightMap => {\n const classificationKey = bond.fixed_income_classification\n return {\n [FixedIncomeClassificationValues[\n classificationKey as keyof typeof FixedIncomeClassificationValues\n ]]: 100,\n }\n}\n\nconst extractStockValueFromWeight = (stock: Holding) =>\n extractValueFromWeight(stock, extractStockWeight, EquityClassificationValues)\n\nexport const extractStockWeight = (stock: Holding): WeightMap => {\n const {\n large_core_weight,\n large_growth_weight,\n large_value_weight,\n mid_core_weight,\n mid_growth_weight,\n mid_value_weight,\n small_core_weight,\n small_growth_weight,\n small_value_weight,\n unknown_weight,\n equity_classification,\n } = stock\n\n const data: WeightMap = {\n LARGE_CORE: large_core_weight ?? 0,\n LARGE_GROWTH: large_growth_weight ?? 0,\n LARGE_VALUE: large_value_weight ?? 0,\n MID_CORE: mid_core_weight ?? 0,\n MID_GROWTH: mid_growth_weight ?? 0,\n MID_VALUE: mid_value_weight ?? 0,\n SMALL_CORE: small_core_weight ?? 0,\n SMALL_GROWTH: small_growth_weight ?? 0,\n SMALL_VALUE: small_value_weight ?? 0,\n UNKNOWN: unknown_weight ?? 0,\n }\n\n if (sumValues(data) === 0 && equity_classification !== undefined) {\n const key =\n EquityClassificationValues[equity_classification as keyof typeof EquityClassificationValues]\n return { [key]: 100 }\n }\n\n return data\n}\n\nexport const extractValueFromWeight = (\n holding: Holding,\n extractWeightFn: (h: Holding) => WeightMap,\n classificationValues: Record<string, string>,\n): WeightMap => {\n const weights = extractWeightFn(holding)\n const value = getHoldingValue(holding)\n const weightedValues = calculateWeightedValue(weights, value)\n\n if (sumValues(weightedValues) === 0) {\n const classificationKey = String(\n holding.equity_classification ?? holding.fixed_income_classification,\n )\n\n if (classificationKey in classificationValues) {\n return { [classificationValues[classificationKey]]: value }\n } else {\n console.error(`Invalid classification key: ${classificationKey}`)\n }\n }\n\n return weightedValues\n}\n\nexport const formatKey = (key: string): string =>\n key\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ')\n\nexport const formatPercent = (value: number): string =>\n value >= 1 ? `${numeral(value).format('0')}%` : '< 1%'\n\nexport const getHoldingValue = (holding: Holding): number =>\n holding.calculated_market_value ?? holding.market_value\n\nexport const getValidHoldings = (\n holdings: Holding[],\n extractWeightFn: (holding: Holding) => WeightMap,\n): Holding[] => {\n return holdings.filter((holding) => {\n const weight = extractWeightFn(holding)\n return isInStyleWeightBand(sumValues(weight))\n })\n}\n\nexport const mapDataToPercentageGrid = (\n data: Record<AnalysisType, Record<string, number>>,\n analysisType: AnalysisType,\n): string[][] => {\n const groups = analysisType === AnalysisType.Stocks ? stockGroups : bondGroups\n\n const selected = data[analysisType]\n if (!selected || Object.keys(selected).length === 0)\n return groups.map((group) => group.map(() => '0%'))\n\n return groups.map((group) => group.map((key) => formatPercent(selected[key] ?? 0)))\n}\n\nexport const sumValues = (obj: WeightMap): number =>\n Object.values(obj).reduce((acc, val) => acc + val, 0)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InvestmentUtil.es.js","names":[],"sources":["../../../src/core/utils/InvestmentUtil.ts"],"sourcesContent":["import numeral from 'numeral'\n\nimport type { Holding } from '../types'\n\nimport {\n ALLOCATION_KEYS,\n AnalysisType,\n EquityClassificationTypes,\n EquityClassificationValues,\n FixedIncomeClassificationTypes,\n FixedIncomeClassificationValues,\n STYLE_WEIGHT_KEYS,\n} from '../constants/Investments'\n\ntype WeightMap = Record<string, number>\n\n// The render band getValidHoldings keeps; the analysis gate reuses it so the\n// tab never enables onto an all-zero grid.\nconst STYLE_WEIGHT_MIN = 80\nconst STYLE_WEIGHT_MAX = 120\nconst isInStyleWeightBand = (total: number): boolean =>\n total > STYLE_WEIGHT_MIN && total < STYLE_WEIGHT_MAX\n\n// Coerces so a stringified number counts; null/\"\"/\"0\"/NaN/0 all mean \"no data\".\nexport const isMeaningfulNumber = (value: unknown): boolean => {\n const n = Number(value)\n return Number.isFinite(n) && n !== 0\n}\n\n// Classification 0 is UNKNOWN; only 1..9 represent real data.\nexport const isValidClassification = (value: unknown): boolean => {\n const n = Number(value)\n return Number.isFinite(n) && n >= 1 && n <= 9\n}\n\n// Classification only counts when style weights sum to 0, matching\n// extractWeight's fallback — otherwise a partial (out-of-band) total that\n// getValidHoldings drops would wrongly enable the tab onto an empty grid.\nexport const holdingHasStyleData = (holding: Holding): boolean => {\n const styleTotal = STYLE_WEIGHT_KEYS.reduce((sum, key) => sum + (Number(holding[key]) || 0), 0)\n return (\n isInStyleWeightBand(styleTotal) ||\n (styleTotal === 0 &&\n (isValidClassification(holding.equity_classification) ||\n isValidClassification(holding.fixed_income_classification)))\n )\n}\n\nexport const holdingHasAllocationData = (holding: Holding): boolean =>\n ALLOCATION_KEYS.some((key) => isMeaningfulNumber(holding[key]))\n\n// Enriched market value from Custodian; falls back to the raw feed value.\nexport const getHoldingMarketValue = (holding: Holding): number =>\n holding.calculated_market_value ?? holding.market_value ?? 0\n\n// The cost basis to measure gain/loss against. `cost_basis` is user-edited and\n// persists in Abacus; it is null until someone sets it. `purchase_price` is the\n// cumulative feed cost for all shares and is a valid stand-in. A basis of 0 is a\n// real value (e.g. a gifted holding) and must be kept, so only null/undefined/\n// non-finite is treated as \"no basis known\".\n//\n// Returns null when neither value is known — callers must NOT coerce that to 0,\n// which would fabricate a 100% gain (the MEW-4073 symptom: market_value became\n// enriched/non-zero while cost_basis stayed null).\nexport const getHoldingCostBasis = (holding: Holding): number | null => {\n if (Number.isFinite(holding.cost_basis)) return holding.cost_basis\n if (Number.isFinite(holding.purchase_price)) return holding.purchase_price\n return null\n}\n\nexport interface HoldingGainLoss {\n available: boolean\n basis: number\n gainLoss: number\n gainLossPercentage: number\n}\n\n// Single source of truth for a holding's gain/loss. When no cost basis is known,\n// `available` is false and callers should render \"—\" rather than a fake 0/100%.\nexport const getHoldingGainLoss = (holding: Holding): HoldingGainLoss => {\n const basis = getHoldingCostBasis(holding)\n if (basis === null) {\n return { available: false, basis: 0, gainLoss: 0, gainLossPercentage: 0 }\n }\n const gainLoss = getHoldingMarketValue(holding) - basis\n return {\n available: true,\n basis,\n gainLoss,\n gainLossPercentage: basis === 0 ? 0 : (gainLoss / basis) * 100,\n }\n}\n\nexport const createGroups = (classificationObj: Record<number, string>, groupSize = 3) => {\n const keys = Object.keys(classificationObj)\n .map(Number)\n .filter((k) => k !== 0)\n .sort((a, b) => a - b)\n\n const groups = []\n for (let i = 0; i < keys.length; i += groupSize) {\n groups.push(keys.slice(i, i + groupSize).map((key) => classificationObj[key]))\n }\n return groups\n}\n\nexport const bondGroups = createGroups(FixedIncomeClassificationValues)\nexport const stockGroups = createGroups(EquityClassificationValues)\n\nexport const analysisChartData = (holdings: Holding[]) => {\n const stocks = getValidHoldings(holdings, extractStockWeight)\n const bonds = getValidHoldings(holdings, extractBondWeight)\n\n const processGroupData = (group: Holding[], extractValueFn: (holding: Holding) => WeightMap) => {\n const totalValue = group.reduce((acc, holding) => acc + getHoldingValue(holding), 0)\n const groupValues = group.reduce((acc, holding) => {\n const value = extractValueFn(holding)\n Object.keys(value).forEach((key) => (acc[key] = (acc[key] || 0) + value[key]))\n return acc\n }, {} as WeightMap)\n\n return Object.fromEntries(\n Object.entries(groupValues).map(([key, value]) => [key, (value / totalValue) * 100]),\n )\n }\n\n const data = {\n stocks: processGroupData(stocks, extractStockValueFromWeight),\n bonds: processGroupData(bonds, extractBondValueFromWeight),\n }\n\n return data\n}\n\nexport const analysisDetailsData = (holdings: Holding[]) => {\n const stocks = holdings.filter((holding) => !isNaN(holding.equity_classification))\n const bonds = holdings.filter((holding) => !isNaN(holding.fixed_income_classification))\n\n const aggregateValues = (\n holdings: Holding[],\n extractValueFn: (holding: Holding) => WeightMap,\n classificationTypes: Record<string, number>,\n ) => {\n return holdings.reduce((acc, holding) => {\n const values = extractValueFn(holding)\n Object.keys(classificationTypes).forEach((sector) => {\n acc[sector] = (acc[sector] || 0) + (values[sector] || 0)\n })\n return acc\n }, {} as WeightMap)\n }\n\n return {\n stocks: aggregateValues(stocks, extractStockValueFromWeight, EquityClassificationTypes),\n bonds: aggregateValues(bonds, extractBondValueFromWeight, FixedIncomeClassificationTypes),\n }\n}\n\nexport const calculateWeightedValue = (weights: WeightMap, value: number): WeightMap => {\n return Object.fromEntries(\n Object.entries(weights).map(([key, weight]) => [key, (weight * value) / 100]),\n )\n}\n\nconst extractBondValueFromWeight = (bond: Holding) =>\n extractValueFromWeight(bond, extractBondWeight, FixedIncomeClassificationValues)\n\nexport const extractBondWeight = (bond: Holding): WeightMap => {\n const classificationKey = bond.fixed_income_classification\n return {\n [FixedIncomeClassificationValues[\n classificationKey as keyof typeof FixedIncomeClassificationValues\n ]]: 100,\n }\n}\n\nconst extractStockValueFromWeight = (stock: Holding) =>\n extractValueFromWeight(stock, extractStockWeight, EquityClassificationValues)\n\nexport const extractStockWeight = (stock: Holding): WeightMap => {\n const {\n large_core_weight,\n large_growth_weight,\n large_value_weight,\n mid_core_weight,\n mid_growth_weight,\n mid_value_weight,\n small_core_weight,\n small_growth_weight,\n small_value_weight,\n unknown_weight,\n equity_classification,\n } = stock\n\n const data: WeightMap = {\n LARGE_CORE: large_core_weight ?? 0,\n LARGE_GROWTH: large_growth_weight ?? 0,\n LARGE_VALUE: large_value_weight ?? 0,\n MID_CORE: mid_core_weight ?? 0,\n MID_GROWTH: mid_growth_weight ?? 0,\n MID_VALUE: mid_value_weight ?? 0,\n SMALL_CORE: small_core_weight ?? 0,\n SMALL_GROWTH: small_growth_weight ?? 0,\n SMALL_VALUE: small_value_weight ?? 0,\n UNKNOWN: unknown_weight ?? 0,\n }\n\n if (sumValues(data) === 0 && equity_classification !== undefined) {\n const key =\n EquityClassificationValues[equity_classification as keyof typeof EquityClassificationValues]\n return { [key]: 100 }\n }\n\n return data\n}\n\nexport const extractValueFromWeight = (\n holding: Holding,\n extractWeightFn: (h: Holding) => WeightMap,\n classificationValues: Record<string, string>,\n): WeightMap => {\n const weights = extractWeightFn(holding)\n const value = getHoldingValue(holding)\n const weightedValues = calculateWeightedValue(weights, value)\n\n if (sumValues(weightedValues) === 0) {\n const classificationKey = String(\n holding.equity_classification ?? holding.fixed_income_classification,\n )\n\n if (classificationKey in classificationValues) {\n return { [classificationValues[classificationKey]]: value }\n } else {\n console.error(`Invalid classification key: ${classificationKey}`)\n }\n }\n\n return weightedValues\n}\n\nexport const formatKey = (key: string): string =>\n key\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ')\n\nexport const formatPercent = (value: number): string =>\n value >= 1 ? `${numeral(value).format('0')}%` : '< 1%'\n\nexport const getHoldingValue = (holding: Holding): number =>\n holding.calculated_market_value ?? holding.market_value\n\nexport const getValidHoldings = (\n holdings: Holding[],\n extractWeightFn: (holding: Holding) => WeightMap,\n): Holding[] => {\n return holdings.filter((holding) => {\n const weight = extractWeightFn(holding)\n return isInStyleWeightBand(sumValues(weight))\n })\n}\n\nexport const mapDataToPercentageGrid = (\n data: Record<AnalysisType, Record<string, number>>,\n analysisType: AnalysisType,\n): string[][] => {\n const groups = analysisType === AnalysisType.Stocks ? stockGroups : bondGroups\n\n const selected = data[analysisType]\n if (!selected || Object.keys(selected).length === 0)\n return groups.map((group) => group.map(() => '0%'))\n\n return groups.map((group) => group.map((key) => formatPercent(selected[key] ?? 0)))\n}\n\nexport const sumValues = (obj: WeightMap): number =>\n Object.values(obj).reduce((acc, val) => acc + val, 0)\n"],"mappings":"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"}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { useGlobalCopyStore as D } from "../../common/context/hooks.es.js";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { observer as
|
|
5
|
-
import { InstitutionLogo as
|
|
2
|
+
import L from "../../common/components/drawer/Drawer.es.js";
|
|
3
|
+
import S from "react";
|
|
4
|
+
import { observer as C } from "mobx-react-lite";
|
|
5
|
+
import { InstitutionLogo as W, Text as r } from "@mxenabled/mxui";
|
|
6
6
|
import { Icon as d } from "@mxenabled/mx-icons";
|
|
7
|
-
import { jsx as t, jsxs as i } from "react/jsx-runtime";
|
|
8
|
-
import
|
|
9
|
-
import
|
|
7
|
+
import { Fragment as I, jsx as t, jsxs as i } from "react/jsx-runtime";
|
|
8
|
+
import _ from "@mui/material/IconButton";
|
|
9
|
+
import k from "@mui/material/TextField";
|
|
10
10
|
import n from "@mui/system/Stack";
|
|
11
|
-
import
|
|
11
|
+
import F from "@mui/material/Accordion";
|
|
12
12
|
import G from "@mui/material/AccordionDetails";
|
|
13
13
|
import B from "@mui/material/AccordionSummary";
|
|
14
|
-
var
|
|
15
|
-
const { investments: a } = D(), [s,
|
|
16
|
-
|
|
14
|
+
var A = ({ accountHoldingsData: o, currentEditedCostBasis: x, editingHoldingId: p, handleCostBasisBlur: u, handleCostBasisClick: y, handleCostBasisChange: v, handleCostBasisKeyDown: f, isOpen: h, onClose: b }) => {
|
|
15
|
+
const { investments: a } = D(), [s, w] = S.useState({}), g = (e) => (c, l) => {
|
|
16
|
+
w((m) => ({
|
|
17
17
|
...m,
|
|
18
18
|
[e]: l
|
|
19
19
|
}));
|
|
20
20
|
};
|
|
21
|
-
return /* @__PURE__ */ i(
|
|
21
|
+
return /* @__PURE__ */ i(L, {
|
|
22
22
|
ariaLabelClose: a.overview.close_investment_drawer,
|
|
23
|
-
isOpen:
|
|
24
|
-
onClose:
|
|
23
|
+
isOpen: h,
|
|
24
|
+
onClose: b,
|
|
25
25
|
title: a.overview.investment_details,
|
|
26
26
|
children: [
|
|
27
27
|
/* @__PURE__ */ i(n, {
|
|
@@ -30,7 +30,7 @@ var F = ({ accountHoldingsData: o, currentEditedCostBasis: x, editingHoldingId:
|
|
|
30
30
|
p: 24
|
|
31
31
|
},
|
|
32
32
|
children: [
|
|
33
|
-
/* @__PURE__ */ t(
|
|
33
|
+
/* @__PURE__ */ t(W, {
|
|
34
34
|
alt: o.accounts.institutionName || "",
|
|
35
35
|
institutionGuid: o.accounts.institution_guid || "",
|
|
36
36
|
size: 64
|
|
@@ -100,7 +100,7 @@ var F = ({ accountHoldingsData: o, currentEditedCostBasis: x, editingHoldingId:
|
|
|
100
100
|
}),
|
|
101
101
|
o.holdings?.map((e, c) => {
|
|
102
102
|
const l = p === e.id;
|
|
103
|
-
return /* @__PURE__ */ i(
|
|
103
|
+
return /* @__PURE__ */ i(F, {
|
|
104
104
|
disableGutters: !0,
|
|
105
105
|
expanded: s[e.id] === !0,
|
|
106
106
|
onChange: e ? g(e?.id) : () => {
|
|
@@ -189,13 +189,13 @@ var F = ({ accountHoldingsData: o, currentEditedCostBasis: x, editingHoldingId:
|
|
|
189
189
|
minimumFractionDigits: 2,
|
|
190
190
|
style: "currency"
|
|
191
191
|
})
|
|
192
|
-
}), /* @__PURE__ */
|
|
192
|
+
}), /* @__PURE__ */ t(n, {
|
|
193
193
|
sx: {
|
|
194
194
|
alignItems: "center",
|
|
195
195
|
gap: 2,
|
|
196
196
|
flexDirection: "row"
|
|
197
197
|
},
|
|
198
|
-
children: [
|
|
198
|
+
children: e.gainLossAvailable ? /* @__PURE__ */ i(I, { children: [
|
|
199
199
|
e.totalGainLoss !== 0 && /* @__PURE__ */ t(d, {
|
|
200
200
|
name: e.totalGainLoss >= 0 ? "trending_up" : "trending_down",
|
|
201
201
|
size: 12,
|
|
@@ -211,7 +211,7 @@ var F = ({ accountHoldingsData: o, currentEditedCostBasis: x, editingHoldingId:
|
|
|
211
211
|
fontWeight: e.totalGainLoss <= 0 ? 400 : 700
|
|
212
212
|
},
|
|
213
213
|
variant: "caption",
|
|
214
|
-
children: e.
|
|
214
|
+
children: e.gainLossBasis ? `${(e.totalGainLoss / e.gainLossBasis * 100).toFixed(2)}%` : "0.00%"
|
|
215
215
|
}),
|
|
216
216
|
/* @__PURE__ */ t(r, {
|
|
217
217
|
sx: { color: "grey.700" },
|
|
@@ -231,7 +231,11 @@ var F = ({ accountHoldingsData: o, currentEditedCostBasis: x, editingHoldingId:
|
|
|
231
231
|
style: "currency"
|
|
232
232
|
})
|
|
233
233
|
})
|
|
234
|
-
]
|
|
234
|
+
] }) : /* @__PURE__ */ t(r, {
|
|
235
|
+
sx: { color: "grey.700" },
|
|
236
|
+
variant: "caption",
|
|
237
|
+
children: "—"
|
|
238
|
+
})
|
|
235
239
|
})] }), /* @__PURE__ */ t(d, {
|
|
236
240
|
name: s[e.id] ? "expand_less" : "expand_more",
|
|
237
241
|
size: 20
|
|
@@ -285,11 +289,11 @@ var F = ({ accountHoldingsData: o, currentEditedCostBasis: x, editingHoldingId:
|
|
|
285
289
|
alignItems: "center",
|
|
286
290
|
gap: 4
|
|
287
291
|
},
|
|
288
|
-
children: [l ? /* @__PURE__ */ t(
|
|
292
|
+
children: [l ? /* @__PURE__ */ t(k, {
|
|
289
293
|
autoFocus: !0,
|
|
290
294
|
onBlur: () => u(e.id),
|
|
291
|
-
onChange:
|
|
292
|
-
onKeyDown: (m) =>
|
|
295
|
+
onChange: v,
|
|
296
|
+
onKeyDown: (m) => f(m, e.id),
|
|
293
297
|
size: "small",
|
|
294
298
|
sx: {
|
|
295
299
|
fontSize: 14,
|
|
@@ -309,14 +313,14 @@ var F = ({ accountHoldingsData: o, currentEditedCostBasis: x, editingHoldingId:
|
|
|
309
313
|
width: 58
|
|
310
314
|
},
|
|
311
315
|
variant: "body2",
|
|
312
|
-
children: e.costBasis?.toLocaleString("en-US", {
|
|
316
|
+
children: e.gainLossAvailable ? e.costBasis?.toLocaleString("en-US", {
|
|
313
317
|
currency: "USD",
|
|
314
318
|
maximumFractionDigits: 2,
|
|
315
319
|
minimumFractionDigits: 2,
|
|
316
320
|
style: "currency"
|
|
317
|
-
})
|
|
318
|
-
}), /* @__PURE__ */ t(
|
|
319
|
-
onClick: () => y(e.id, e.
|
|
321
|
+
}) : "—"
|
|
322
|
+
}), /* @__PURE__ */ t(_, {
|
|
323
|
+
onClick: () => y(e.id, e.rawCostBasis),
|
|
320
324
|
sx: {
|
|
321
325
|
minWidth: 16,
|
|
322
326
|
minHeight: 16
|
|
@@ -335,9 +339,9 @@ var F = ({ accountHoldingsData: o, currentEditedCostBasis: x, editingHoldingId:
|
|
|
335
339
|
})
|
|
336
340
|
]
|
|
337
341
|
});
|
|
338
|
-
},
|
|
342
|
+
}, J = C(A);
|
|
339
343
|
export {
|
|
340
|
-
|
|
344
|
+
J as default
|
|
341
345
|
};
|
|
342
346
|
|
|
343
347
|
//# sourceMappingURL=HoldingDrawer.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoldingDrawer.es.js","names":[],"sources":["../../../src/investments/components/HoldingDrawer.tsx"],"sourcesContent":["import React from 'react'\n\nimport { observer } from 'mobx-react-lite'\n\nimport Accordion from '@mui/material/Accordion'\nimport AccordionDetails from '@mui/material/AccordionDetails'\nimport AccordionSummary from '@mui/material/AccordionSummary'\nimport IconButton from '@mui/material/IconButton'\nimport TextField from '@mui/material/TextField'\nimport Stack from '@mui/system/Stack'\n\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport { InstitutionLogo, Text } from '@mxenabled/mxui'\n\nimport { Drawer } from '../../common'\nimport { useGlobalCopyStore } from '../../common'\n\ninterface HoldingDetail {\n id: string\n description: string\n qty: number\n holding: string\n costBasis: number\n totalGainLoss: number\n marketValue: number\n}\n\ninterface InvestmentDetailsDrawerProps {\n accountHoldingsData: {\n accounts: any\n holdings: HoldingDetail[]\n }\n currentEditedCostBasis: string\n editingHoldingId: string | null\n handleCostBasisBlur: (id: string) => void\n handleCostBasisChange: (event: React.ChangeEvent<HTMLInputElement>) => void\n handleCostBasisClick: (holdingId: string, currentCostBasis: number) => void\n handleCostBasisKeyDown: (event: React.KeyboardEvent<HTMLInputElement>, id: string) => void\n isOpen: boolean\n onClose: () => void\n}\n\nconst InvestmentDetailsDrawer: React.FC<InvestmentDetailsDrawerProps> = ({\n accountHoldingsData,\n currentEditedCostBasis,\n editingHoldingId,\n handleCostBasisBlur,\n handleCostBasisClick,\n handleCostBasisChange,\n handleCostBasisKeyDown,\n isOpen,\n onClose,\n}) => {\n const { investments: copy } = useGlobalCopyStore()\n const [expandedStates, setExpandedStates] = React.useState<Record<string, boolean>>({})\n\n const handleAccordionChange =\n (holdingId: string) => (_event: React.SyntheticEvent, isExpanded: boolean) => {\n setExpandedStates((prevStates) => ({\n ...prevStates,\n [holdingId]: isExpanded,\n }))\n }\n\n return (\n <Drawer\n ariaLabelClose={copy.overview.close_investment_drawer}\n isOpen={isOpen}\n onClose={onClose}\n title={copy.overview.investment_details}\n >\n <Stack sx={{ gap: 8, p: 24 }}>\n <InstitutionLogo\n alt={accountHoldingsData.accounts.institutionName || ''}\n institutionGuid={accountHoldingsData.accounts.institution_guid || ''}\n size={64}\n />\n <Text sx={{ color: 'text.primary' }} variant=\"body2\">\n {accountHoldingsData.accounts.memberName}\n </Text>\n <Text sx={{ color: 'text.primary' }} variant=\"h2\">\n {accountHoldingsData.accounts.user_name || accountHoldingsData.accounts.name}\n </Text>\n\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', justifyContent: 'space-between' }}>\n <Text sx={{ color: 'text.primary', fontWeight: 600 }} variant=\"body1\">\n {copy.overview.current_balance}\n </Text>\n\n <Text sx={{ color: 'text.primary', fontWeight: 600 }} variant=\"body1\">\n {accountHoldingsData.accounts.balance?.toLocaleString('en-US', {\n currency: 'USD',\n maximumFractionDigits: 2,\n minimumFractionDigits: 2,\n style: 'currency',\n })}\n </Text>\n </Stack>\n </Stack>\n\n <Stack\n sx={{\n bgcolor: 'background.default',\n flexDirection: 'row',\n justifyContent: 'space-between',\n px: 24,\n py: 10,\n }}\n >\n <Text sx={{ color: 'text.primary', fontWeight: 700 }} variant=\"caption\">\n {copy.overview.holding}\n </Text>\n <Text sx={{ color: 'text.primary', fontWeight: 700 }} variant=\"caption\">\n {copy.overview.market_value}\n </Text>\n </Stack>\n {accountHoldingsData.holdings?.map((holding, index) => {\n const isCurrentlyEditing = editingHoldingId === holding.id\n return (\n <Accordion\n disableGutters={true}\n expanded={expandedStates[holding.id] === true}\n key={holding.id}\n onChange={holding ? handleAccordionChange(holding?.id) : () => {}}\n sx={{\n ':before': index === 0 ? { opacity: 0 } : {},\n '.MuiAccordionDetails-root': { p: 0 },\n }}\n >\n <AccordionSummary\n aria-controls=\"panel1a-content\"\n id=\"panel1a-header\"\n sx={[\n { height: 64 },\n expandedStates[holding.id] &&\n index > 0 && {\n borderTop: 1,\n borderColor: 'divider',\n },\n ]}\n >\n <Stack sx={{ flexDirection: 'row', width: '100%' }}>\n <div style={{ width: 24 }} />\n <Stack\n sx={[\n {\n alignItems: 'center',\n flexDirection: 'row',\n justifyContent: 'space-between',\n pr: 24,\n py: 14,\n width: '100%',\n },\n expandedStates[holding.id] && {\n borderBottom: 1,\n borderColor: 'divider',\n },\n ]}\n >\n <Stack\n sx={{\n alignItems: 'center',\n flex: 1,\n flexDirection: 'row',\n gap: 12,\n minWidth: 0,\n }}\n >\n <Stack sx={{ minWidth: 0, overflow: 'hidden' }}>\n <Text\n sx={{\n fontWeight: 600,\n display: '-webkit-box',\n WebkitBoxOrient: 'vertical',\n WebkitLineClamp: 1,\n overflow: 'hidden',\n overflowWrap: 'anywhere',\n }}\n variant=\"body1\"\n >\n {holding.holding}\n </Text>\n <Text\n sx={{\n display: '-webkit-box',\n WebkitBoxOrient: 'vertical',\n WebkitLineClamp: 2,\n overflow: 'hidden',\n overflowWrap: 'anywhere',\n }}\n variant=\"caption\"\n >\n {holding.description}\n </Text>\n </Stack>\n </Stack>\n\n <Stack\n sx={{\n alignItems: 'center',\n flexShrink: 0,\n flexDirection: 'row',\n gap: 12,\n justifyContent: 'flex-end',\n }}\n >\n <Stack>\n <Text sx={{ fontWeight: 600, textAlign: 'right' }} variant={'body1'}>\n {holding.marketValue?.toLocaleString('en-US', {\n currency: 'USD',\n maximumFractionDigits: 2,\n minimumFractionDigits: 2,\n style: 'currency',\n })}\n </Text>\n <Stack sx={{ alignItems: 'center', gap: 2, flexDirection: 'row' }}>\n {holding.totalGainLoss !== 0 && (\n <Icon\n name={holding.totalGainLoss >= 0 ? 'trending_up' : 'trending_down'}\n size={12}\n sx={{\n verticalAlign: 'middle',\n mr: 1,\n color: holding.totalGainLoss >= 0 ? 'success.main' : 'grey.700',\n }}\n />\n )}\n <Text\n sx={{\n color: holding.totalGainLoss <= 0 ? 'grey.700' : 'success.main',\n fontWeight: holding.totalGainLoss <= 0 ? 400 : 700,\n }}\n variant=\"caption\"\n >\n {holding.costBasis\n ? `${((holding.totalGainLoss / holding.costBasis) * 100).toFixed(2)}%`\n : '0.00%'}\n </Text>\n <Text sx={{ color: 'grey.700' }} variant=\"caption\">\n |\n </Text>\n <Text\n sx={{\n color: holding.totalGainLoss <= 0 ? 'grey.700' : 'success.main',\n fontWeight: holding.totalGainLoss <= 0 ? 400 : 700,\n }}\n variant=\"caption\"\n >\n {Math.abs(holding.totalGainLoss).toLocaleString('en-US', {\n currency: 'USD',\n maximumFractionDigits: 2,\n minimumFractionDigits: 2,\n style: 'currency',\n })}\n </Text>\n </Stack>\n </Stack>\n\n <Icon\n name={expandedStates[holding.id] ? 'expand_less' : 'expand_more'}\n size={20}\n />\n </Stack>\n </Stack>\n </Stack>\n </AccordionSummary>\n <AccordionDetails>\n <Stack\n sx={{\n alignItems: 'center',\n bgcolor: 'background.default',\n flexDirection: 'row',\n pl: 24,\n }}\n >\n <Stack sx={{ width: 32 }} />\n <Stack sx={{ flex: 1 }}>\n <Stack\n sx={{\n alignItems: 'center',\n borderBottom: 1,\n borderColor: 'divider',\n flexDirection: 'row',\n height: 48,\n justifyContent: 'space-between',\n pr: 24,\n }}\n >\n <Text sx={{ color: 'text.primary' }} variant=\"body1\">\n {copy.overview.quantity}\n </Text>\n <Text sx={{ color: 'text.primary' }} variant=\"body2\">\n {holding.qty}\n </Text>\n </Stack>\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n height: 48,\n justifyContent: 'space-between',\n pr: 24,\n }}\n >\n <Text sx={{ color: 'text.primary' }} variant=\"body1\">\n {copy.overview.cost_basis_header}\n </Text>\n\n <Stack\n direction=\"row\"\n sx={{\n alignItems: 'center',\n gap: 4,\n }}\n >\n {isCurrentlyEditing ? (\n <TextField\n autoFocus={true}\n onBlur={() => handleCostBasisBlur(holding.id)}\n onChange={handleCostBasisChange}\n onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) =>\n handleCostBasisKeyDown(e, holding.id)\n }\n size=\"small\"\n sx={{\n fontSize: 14,\n width: 58,\n '& .MuiInputBase-input': {\n padding: '4px 0',\n textAlign: 'center',\n fontWeight: 600,\n color: 'text.primary',\n },\n '& .MuiOutlinedInput-notchedOutline': {\n border: 'none',\n },\n }}\n value={currentEditedCostBasis}\n />\n ) : (\n <Text sx={{ fontSize: 14, width: 58 }} variant=\"body2\">\n {holding.costBasis?.toLocaleString('en-US', {\n currency: 'USD',\n maximumFractionDigits: 2,\n minimumFractionDigits: 2,\n style: 'currency',\n })}\n </Text>\n )}\n\n <IconButton\n onClick={() => handleCostBasisClick(holding.id, holding.costBasis)}\n sx={{ minWidth: 16, minHeight: 16 }}\n >\n <Icon name={'stylus'} size={16} sx={{ color: 'grey.700' }} />\n </IconButton>\n </Stack>\n </Stack>\n </Stack>\n </Stack>\n </AccordionDetails>\n </Accordion>\n )\n })}\n </Drawer>\n )\n}\n\nexport default observer(InvestmentDetailsDrawer)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HoldingDrawer.es.js","names":[],"sources":["../../../src/investments/components/HoldingDrawer.tsx"],"sourcesContent":["import React from 'react'\n\nimport { observer } from 'mobx-react-lite'\n\nimport Accordion from '@mui/material/Accordion'\nimport AccordionDetails from '@mui/material/AccordionDetails'\nimport AccordionSummary from '@mui/material/AccordionSummary'\nimport IconButton from '@mui/material/IconButton'\nimport TextField from '@mui/material/TextField'\nimport Stack from '@mui/system/Stack'\n\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport { InstitutionLogo, Text } from '@mxenabled/mxui'\n\nimport { Drawer } from '../../common'\nimport { useGlobalCopyStore } from '../../common'\n\ninterface HoldingDetail {\n id: string\n description: string\n qty: number\n holding: string\n costBasis: number\n rawCostBasis: number\n totalGainLoss: number\n gainLossAvailable: boolean\n gainLossBasis: number\n marketValue: number\n}\n\ninterface InvestmentDetailsDrawerProps {\n accountHoldingsData: {\n accounts: any\n holdings: HoldingDetail[]\n }\n currentEditedCostBasis: string\n editingHoldingId: string | null\n handleCostBasisBlur: (id: string) => void\n handleCostBasisChange: (event: React.ChangeEvent<HTMLInputElement>) => void\n handleCostBasisClick: (holdingId: string, currentCostBasis: number) => void\n handleCostBasisKeyDown: (event: React.KeyboardEvent<HTMLInputElement>, id: string) => void\n isOpen: boolean\n onClose: () => void\n}\n\nconst InvestmentDetailsDrawer: React.FC<InvestmentDetailsDrawerProps> = ({\n accountHoldingsData,\n currentEditedCostBasis,\n editingHoldingId,\n handleCostBasisBlur,\n handleCostBasisClick,\n handleCostBasisChange,\n handleCostBasisKeyDown,\n isOpen,\n onClose,\n}) => {\n const { investments: copy } = useGlobalCopyStore()\n const [expandedStates, setExpandedStates] = React.useState<Record<string, boolean>>({})\n\n const handleAccordionChange =\n (holdingId: string) => (_event: React.SyntheticEvent, isExpanded: boolean) => {\n setExpandedStates((prevStates) => ({\n ...prevStates,\n [holdingId]: isExpanded,\n }))\n }\n\n return (\n <Drawer\n ariaLabelClose={copy.overview.close_investment_drawer}\n isOpen={isOpen}\n onClose={onClose}\n title={copy.overview.investment_details}\n >\n <Stack sx={{ gap: 8, p: 24 }}>\n <InstitutionLogo\n alt={accountHoldingsData.accounts.institutionName || ''}\n institutionGuid={accountHoldingsData.accounts.institution_guid || ''}\n size={64}\n />\n <Text sx={{ color: 'text.primary' }} variant=\"body2\">\n {accountHoldingsData.accounts.memberName}\n </Text>\n <Text sx={{ color: 'text.primary' }} variant=\"h2\">\n {accountHoldingsData.accounts.user_name || accountHoldingsData.accounts.name}\n </Text>\n\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', justifyContent: 'space-between' }}>\n <Text sx={{ color: 'text.primary', fontWeight: 600 }} variant=\"body1\">\n {copy.overview.current_balance}\n </Text>\n\n <Text sx={{ color: 'text.primary', fontWeight: 600 }} variant=\"body1\">\n {accountHoldingsData.accounts.balance?.toLocaleString('en-US', {\n currency: 'USD',\n maximumFractionDigits: 2,\n minimumFractionDigits: 2,\n style: 'currency',\n })}\n </Text>\n </Stack>\n </Stack>\n\n <Stack\n sx={{\n bgcolor: 'background.default',\n flexDirection: 'row',\n justifyContent: 'space-between',\n px: 24,\n py: 10,\n }}\n >\n <Text sx={{ color: 'text.primary', fontWeight: 700 }} variant=\"caption\">\n {copy.overview.holding}\n </Text>\n <Text sx={{ color: 'text.primary', fontWeight: 700 }} variant=\"caption\">\n {copy.overview.market_value}\n </Text>\n </Stack>\n {accountHoldingsData.holdings?.map((holding, index) => {\n const isCurrentlyEditing = editingHoldingId === holding.id\n return (\n <Accordion\n disableGutters={true}\n expanded={expandedStates[holding.id] === true}\n key={holding.id}\n onChange={holding ? handleAccordionChange(holding?.id) : () => {}}\n sx={{\n ':before': index === 0 ? { opacity: 0 } : {},\n '.MuiAccordionDetails-root': { p: 0 },\n }}\n >\n <AccordionSummary\n aria-controls=\"panel1a-content\"\n id=\"panel1a-header\"\n sx={[\n { height: 64 },\n expandedStates[holding.id] &&\n index > 0 && {\n borderTop: 1,\n borderColor: 'divider',\n },\n ]}\n >\n <Stack sx={{ flexDirection: 'row', width: '100%' }}>\n <div style={{ width: 24 }} />\n <Stack\n sx={[\n {\n alignItems: 'center',\n flexDirection: 'row',\n justifyContent: 'space-between',\n pr: 24,\n py: 14,\n width: '100%',\n },\n expandedStates[holding.id] && {\n borderBottom: 1,\n borderColor: 'divider',\n },\n ]}\n >\n <Stack\n sx={{\n alignItems: 'center',\n flex: 1,\n flexDirection: 'row',\n gap: 12,\n minWidth: 0,\n }}\n >\n <Stack sx={{ minWidth: 0, overflow: 'hidden' }}>\n <Text\n sx={{\n fontWeight: 600,\n display: '-webkit-box',\n WebkitBoxOrient: 'vertical',\n WebkitLineClamp: 1,\n overflow: 'hidden',\n overflowWrap: 'anywhere',\n }}\n variant=\"body1\"\n >\n {holding.holding}\n </Text>\n <Text\n sx={{\n display: '-webkit-box',\n WebkitBoxOrient: 'vertical',\n WebkitLineClamp: 2,\n overflow: 'hidden',\n overflowWrap: 'anywhere',\n }}\n variant=\"caption\"\n >\n {holding.description}\n </Text>\n </Stack>\n </Stack>\n\n <Stack\n sx={{\n alignItems: 'center',\n flexShrink: 0,\n flexDirection: 'row',\n gap: 12,\n justifyContent: 'flex-end',\n }}\n >\n <Stack>\n <Text sx={{ fontWeight: 600, textAlign: 'right' }} variant={'body1'}>\n {holding.marketValue?.toLocaleString('en-US', {\n currency: 'USD',\n maximumFractionDigits: 2,\n minimumFractionDigits: 2,\n style: 'currency',\n })}\n </Text>\n <Stack sx={{ alignItems: 'center', gap: 2, flexDirection: 'row' }}>\n {!holding.gainLossAvailable ? (\n <Text sx={{ color: 'grey.700' }} variant=\"caption\">\n —\n </Text>\n ) : (\n <>\n {holding.totalGainLoss !== 0 && (\n <Icon\n name={holding.totalGainLoss >= 0 ? 'trending_up' : 'trending_down'}\n size={12}\n sx={{\n verticalAlign: 'middle',\n mr: 1,\n color: holding.totalGainLoss >= 0 ? 'success.main' : 'grey.700',\n }}\n />\n )}\n <Text\n sx={{\n color: holding.totalGainLoss <= 0 ? 'grey.700' : 'success.main',\n fontWeight: holding.totalGainLoss <= 0 ? 400 : 700,\n }}\n variant=\"caption\"\n >\n {holding.gainLossBasis\n ? `${((holding.totalGainLoss / holding.gainLossBasis) * 100).toFixed(2)}%`\n : '0.00%'}\n </Text>\n <Text sx={{ color: 'grey.700' }} variant=\"caption\">\n |\n </Text>\n <Text\n sx={{\n color: holding.totalGainLoss <= 0 ? 'grey.700' : 'success.main',\n fontWeight: holding.totalGainLoss <= 0 ? 400 : 700,\n }}\n variant=\"caption\"\n >\n {Math.abs(holding.totalGainLoss).toLocaleString('en-US', {\n currency: 'USD',\n maximumFractionDigits: 2,\n minimumFractionDigits: 2,\n style: 'currency',\n })}\n </Text>\n </>\n )}\n </Stack>\n </Stack>\n\n <Icon\n name={expandedStates[holding.id] ? 'expand_less' : 'expand_more'}\n size={20}\n />\n </Stack>\n </Stack>\n </Stack>\n </AccordionSummary>\n <AccordionDetails>\n <Stack\n sx={{\n alignItems: 'center',\n bgcolor: 'background.default',\n flexDirection: 'row',\n pl: 24,\n }}\n >\n <Stack sx={{ width: 32 }} />\n <Stack sx={{ flex: 1 }}>\n <Stack\n sx={{\n alignItems: 'center',\n borderBottom: 1,\n borderColor: 'divider',\n flexDirection: 'row',\n height: 48,\n justifyContent: 'space-between',\n pr: 24,\n }}\n >\n <Text sx={{ color: 'text.primary' }} variant=\"body1\">\n {copy.overview.quantity}\n </Text>\n <Text sx={{ color: 'text.primary' }} variant=\"body2\">\n {holding.qty}\n </Text>\n </Stack>\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n height: 48,\n justifyContent: 'space-between',\n pr: 24,\n }}\n >\n <Text sx={{ color: 'text.primary' }} variant=\"body1\">\n {copy.overview.cost_basis_header}\n </Text>\n\n <Stack\n direction=\"row\"\n sx={{\n alignItems: 'center',\n gap: 4,\n }}\n >\n {isCurrentlyEditing ? (\n <TextField\n autoFocus={true}\n onBlur={() => handleCostBasisBlur(holding.id)}\n onChange={handleCostBasisChange}\n onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) =>\n handleCostBasisKeyDown(e, holding.id)\n }\n size=\"small\"\n sx={{\n fontSize: 14,\n width: 58,\n '& .MuiInputBase-input': {\n padding: '4px 0',\n textAlign: 'center',\n fontWeight: 600,\n color: 'text.primary',\n },\n '& .MuiOutlinedInput-notchedOutline': {\n border: 'none',\n },\n }}\n value={currentEditedCostBasis}\n />\n ) : (\n <Text sx={{ fontSize: 14, width: 58 }} variant=\"body2\">\n {holding.gainLossAvailable\n ? holding.costBasis?.toLocaleString('en-US', {\n currency: 'USD',\n maximumFractionDigits: 2,\n minimumFractionDigits: 2,\n style: 'currency',\n })\n : '—'}\n </Text>\n )}\n\n <IconButton\n onClick={() => handleCostBasisClick(holding.id, holding.rawCostBasis)}\n sx={{ minWidth: 16, minHeight: 16 }}\n >\n <Icon name={'stylus'} size={16} sx={{ color: 'grey.700' }} />\n </IconButton>\n </Stack>\n </Stack>\n </Stack>\n </Stack>\n </AccordionDetails>\n </Accordion>\n )\n })}\n </Drawer>\n )\n}\n\nexport default observer(InvestmentDetailsDrawer)\n"],"mappings":"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"}
|