@mx-cartographer/experiences 9.6.11 → 9.6.13
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 +16 -0
- package/dist/core/stores/InsightsV2Store.d.ts +1 -1
- package/dist/core/stores/InsightsV2Store.es.js.map +1 -1
- package/dist/core/types/Insights.d.ts +24 -1
- package/dist/core/types/Insights.es.js.map +1 -1
- package/dist/core/types/index.d.ts +1 -1
- package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js +21 -21
- package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/AmountInputModalBlock/AmountInputModalBlock.es.js +38 -38
- package/dist/insights-v2/actionBlocks/AmountInputModalBlock/AmountInputModalBlock.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/layout.d.ts +27 -0
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/layout.es.js +14 -0
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/layout.es.js.map +1 -0
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js +5 -5
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.d.ts +6 -2
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js +7 -4
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js +63 -61
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.d.ts +2 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js +59 -38
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/util.d.ts +6 -5
- package/dist/insights-v2/actionBlocks/util.es.js +3 -3
- package/dist/insights-v2/actionBlocks/util.es.js.map +1 -1
- package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js +57 -55
- package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js.map +1 -1
- package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/IconComponent.d.ts +4 -2
- package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/IconComponent.es.js +54 -23
- package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/IconComponent.es.js.map +1 -1
- package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/layout.d.ts +2 -0
- package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/layout.es.js +14 -10
- package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/layout.es.js.map +1 -1
- package/dist/insights-v2/components/BaseLayout.es.js +119 -99
- package/dist/insights-v2/components/BaseLayout.es.js.map +1 -1
- package/dist/insights-v2/components/CompactInsightCard.es.js +34 -24
- package/dist/insights-v2/components/CompactInsightCard.es.js.map +1 -1
- package/dist/insights-v2/components/LogoFromGuid.d.ts +2 -2
- package/dist/insights-v2/components/LogoFromGuid.es.js +44 -32
- package/dist/insights-v2/components/LogoFromGuid.es.js.map +1 -1
- package/dist/insights-v2/components/SubHeader.es.js +3 -2
- package/dist/insights-v2/components/SubHeader.es.js.map +1 -1
- package/dist/insights-v2/components/chartblocks/EmptyBarChart.es.js +4 -4
- package/dist/insights-v2/components/shared/EntityLogo.es.js +31 -21
- package/dist/insights-v2/components/shared/EntityLogo.es.js.map +1 -1
- package/dist/insights-v2/components/shared/images/FeeDetected.es.js +243 -0
- package/dist/insights-v2/components/shared/images/FeeDetected.es.js.map +1 -0
- package/dist/insights-v2/components/statusIcon.d.ts +7 -0
- package/dist/insights-v2/components/statusIcon.es.js +10 -0
- package/dist/insights-v2/components/statusIcon.es.js.map +1 -0
- package/dist/microinsights/cards/InsightCard.es.js +78 -73
- package/dist/microinsights/cards/InsightCard.es.js.map +1 -1
- package/package.json +1 -1
package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTransactionDetailsBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.ts"],"sourcesContent":["import { useActionContext, useInsightsV2Store, useTransactionStore } from '../../../common'\nimport type { Beat, Transaction, DrilldownPayload } from '../../../core'\nimport type { BottomActions, TopActions } from '../../../transactions/constants/Actions'\nimport { getBottomActionsByVariant } from './util'\nimport { resolveTopActions } from './transactionDetailsActions'\n\ninterface TransactionDetailsBlockState {\n bottomActions: BottomActions[]\n /** True while the store is still loading; the block shows a loader instead of an empty state. */\n isLoading: boolean\n topActions: TopActions[]\n /** `undefined` once loading finishes means the transaction could not be resolved. */\n transaction?: Transaction\n}\n\n/**\n * Resolves which transaction this drawer is about, and which inline actions it offers.\n *\n * The subject comes from one of two places:\n * 1. `actionContext.transaction_guid` — set by a parent drawer (e.g. a row tapped in\n * `TransactionHistoryBlock`) when this drawer is opened nested.\n * 2. `insights_payload.primary_transaction_guid` — the ditto contract for every beat whose\n * `primary_cta_block` is `transaction_details_block`.\n *\n * The guid is then looked up in `transactionStore.detailedTransactions` rather than used directly,\n * because `TransactionDetails` needs the *detailed* shape (account + category + taggings joined in)\n * and edits must write through to the same store object the rest of the app renders. `buildDetailed\n * Transactions` inside the store is this repo's equivalent of pulse's `buildTransactionDetails`.\n * A guid the store does not have resolves to `undefined` (the block's error state) rather than to\n * any beat-level snapshot, so inline edits can never be made against a stale copy.\n *\n * Actions are not beat-configurable on the v2 contract: `instance_slot_data` is not part of it (the\n * LargeTransactionV2 payload omits the key entirely), so top actions are always the defaults and\n * bottom actions are derived from the triggering CTA's variant.\n */\nexport const useTransactionDetailsBlock = (beat: Beat): TransactionDetailsBlockState => {\n const { detailedTransactions, isTransactionDataLoaded } = useTransactionStore()\n\n const { actionDrawer } = useInsightsV2Store()\n\n const { transaction_guid } = useActionContext<DrilldownPayload>() ?? {}\n const payload = beat.insights_payload\n\n const guid = transaction_guid ?? payload?.primary_transaction_guid\n\n const transaction = guid\n ? detailedTransactions.find((transaction) => transaction.guid === guid)\n : undefined\n\n const bottomActions = getBottomActionsByVariant(\n actionDrawer,\n payload?.primary_cta,\n payload?.secondary_cta,\n )\n return {\n bottomActions,\n isLoading: !isTransactionDataLoaded,\n topActions: resolveTopActions(),\n transaction,\n }\n}\n"],"mappings":";;;AAmCA,IAAa,IAAA,CAA8B,MAA6C;AACtF,QAAM,EAAE,sBAAA,GAAsB,yBAAA,EAAA,IAA4B,EAAoB,GAExE,EAAE,cAAA,EAAA,IAAiB,EAAmB,GAEtC,EAAE,kBAAA,EAAA,IAAqB,EAAmC,KAAK,CAAC,GAChE,IAAU,EAAK,kBAEf,IAAO,KAAoB,GAAS,0BAEpC,IAAc,IAChB,EAAqB,KAAA,CAAM,MAAgB,EAAY,SAAS,CAAI,IACpE;
|
|
1
|
+
{"version":3,"file":"useTransactionDetailsBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.ts"],"sourcesContent":["import { useActionContext, useInsightsV2Store, useTransactionStore } from '../../../common'\nimport type { Beat, Transaction, DrilldownPayload } from '../../../core'\nimport type { BottomActions, TopActions } from '../../../transactions/constants/Actions'\nimport { getBottomActionsByVariant } from './util'\nimport { resolveTopActions } from './transactionDetailsActions'\n\ninterface TransactionDetailsBlockState {\n bottomActions: BottomActions[]\n /** True while the store is still loading; the block shows a loader instead of an empty state. */\n isLoading: boolean\n topActions: TopActions[]\n /** `undefined` once loading finishes means the transaction could not be resolved. */\n transaction?: Transaction\n}\n\n/**\n * Resolves which transaction this drawer is about, and which inline actions it offers.\n *\n * The subject comes from one of two places:\n * 1. `actionContext.transaction_guid` — set by a parent drawer (e.g. a row tapped in\n * `TransactionHistoryBlock`) when this drawer is opened nested.\n * 2. `insights_payload.primary_transaction_guid` — the ditto contract for every beat whose\n * `primary_cta_block` is `transaction_details_block`.\n *\n * The guid is then looked up in `transactionStore.detailedTransactions` rather than used directly,\n * because `TransactionDetails` needs the *detailed* shape (account + category + taggings joined in)\n * and edits must write through to the same store object the rest of the app renders. `buildDetailed\n * Transactions` inside the store is this repo's equivalent of pulse's `buildTransactionDetails`.\n * A guid the store does not have resolves to `undefined` (the block's error state) rather than to\n * any beat-level snapshot, so inline edits can never be made against a stale copy.\n *\n * Actions are not beat-configurable on the v2 contract: `instance_slot_data` is not part of it (the\n * LargeTransactionV2 payload omits the key entirely), so top actions are always the defaults and\n * bottom actions are derived from the triggering CTA's variant.\n */\nexport const useTransactionDetailsBlock = (beat: Beat): TransactionDetailsBlockState => {\n const { detailedTransactions, isTransactionDataLoaded } = useTransactionStore()\n\n const { actionDrawer } = useInsightsV2Store()\n\n const { transaction_guid } = useActionContext<DrilldownPayload>() ?? {}\n const payload = beat.insights_payload\n\n const guid = transaction_guid ?? payload?.primary_transaction_guid\n\n const transaction = guid\n ? detailedTransactions.find((transaction) => transaction.guid === guid)\n : undefined\n\n const bottomActions = getBottomActionsByVariant(\n actionDrawer,\n payload?.primary_cta,\n payload?.secondary_cta,\n payload?.in_description_cta,\n )\n return {\n bottomActions,\n isLoading: !isTransactionDataLoaded,\n topActions: resolveTopActions(),\n transaction,\n }\n}\n"],"mappings":";;;AAmCA,IAAa,IAAA,CAA8B,MAA6C;AACtF,QAAM,EAAE,sBAAA,GAAsB,yBAAA,EAAA,IAA4B,EAAoB,GAExE,EAAE,cAAA,EAAA,IAAiB,EAAmB,GAEtC,EAAE,kBAAA,EAAA,IAAqB,EAAmC,KAAK,CAAC,GAChE,IAAU,EAAK,kBAEf,IAAO,KAAoB,GAAS,0BAEpC,IAAc,IAChB,EAAqB,KAAA,CAAM,MAAgB,EAAY,SAAS,CAAI,IACpE;AAQJ,SAAO;AAAA,IACL,eAPoB,EACpB,GACA,GAAS,aACT,GAAS,eACT,GAAS,kBAGT;AAAA,IACA,WAAW,CAAC;AAAA,IACZ,YAAY,EAAkB;AAAA,IAC9B,aAAA;AAAA,EACF;AACF"}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import { ActionDrawerState, PrimaryCTA, SecondaryCTA } from '../../../core';
|
|
1
|
+
import { ActionDrawerState, InDescriptionCTA, PrimaryCTA, SecondaryCTA } from '../../../core';
|
|
2
2
|
import { BottomActions } from '../../../transactions/constants/Actions';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Bottom actions for the drawer, driven by the triggering CTA's `variant` via the per-variant
|
|
5
|
+
* config table in `./layout.ts`. Add variant-specific behavior (or styles) there, not here.
|
|
6
|
+
*/
|
|
7
|
+
export declare const getBottomActionsByVariant: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined, in_description_cta?: InDescriptionCTA) => BottomActions[];
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
var
|
|
1
|
+
import { getDynamicCtaBasedOnTriggers as n } from "../util.es.js";
|
|
2
|
+
import { resolveLayoutConfig as e } from "./layout.es.js";
|
|
3
|
+
var c = (t, o, r, a) => {
|
|
4
|
+
const i = n(t, o, r, a);
|
|
5
|
+
return e(i?.variant).bottomActions;
|
|
6
|
+
};
|
|
4
7
|
export {
|
|
5
|
-
|
|
8
|
+
c as getBottomActionsByVariant
|
|
6
9
|
};
|
|
7
10
|
|
|
8
11
|
//# sourceMappingURL=util.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/util.ts"],"sourcesContent":["import type { ActionDrawerState, PrimaryCTA, SecondaryCTA } from '../../../core'\nimport { BottomActions
|
|
1
|
+
{"version":3,"file":"util.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/util.ts"],"sourcesContent":["import type { ActionDrawerState, InDescriptionCTA, PrimaryCTA, SecondaryCTA } from '../../../core'\nimport type { BottomActions } from '../../../transactions/constants/Actions'\nimport { getDynamicCtaBasedOnTriggers } from '../util'\nimport { resolveLayoutConfig } from './layout'\n\n/**\n * Bottom actions for the drawer, driven by the triggering CTA's `variant` via the per-variant\n * config table in `./layout.ts`. Add variant-specific behavior (or styles) there, not here.\n */\nexport const getBottomActionsByVariant = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n in_description_cta?: InDescriptionCTA,\n): BottomActions[] => {\n const cta = getDynamicCtaBasedOnTriggers(\n actionDrawer,\n primary_cta,\n secondary_cta,\n in_description_cta,\n )\n\n return resolveLayoutConfig(cta?.variant).bottomActions\n}\n"],"mappings":";;AASA,IAAa,IAAA,CACX,GACA,GACA,GACA,MACoB;AACpB,QAAM,IAAM,EACV,GACA,GACA,GACA,CACF;AAEA,SAAO,EAAoB,GAAK,OAAO,EAAE;AAC3C"}
|
|
@@ -1,72 +1,74 @@
|
|
|
1
|
-
import { useGlobalCopyStore as
|
|
2
|
-
import { formatCurrency as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { BarChartV2 as
|
|
6
|
-
import { EmptyBarChart as
|
|
7
|
-
import { TransactionDrillDown as
|
|
8
|
-
import { useTransactionHistory as
|
|
9
|
-
import { getDefaultSelection as
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { useGlobalCopyStore as W, useGlobalUiStore as X, useInsightsV2Store as Y } from "../../../common/context/hooks.es.js";
|
|
2
|
+
import { formatCurrency as Z } from "../../../core/utils/NumberFormatting.es.js";
|
|
3
|
+
import tt from "../../../common/components/drawer/Drawer.es.js";
|
|
4
|
+
import et from "../../../common/components/Loader.es.js";
|
|
5
|
+
import { BarChartV2 as at } from "../../components/chartblocks/BarchartV2.es.js";
|
|
6
|
+
import { EmptyBarChart as ot } from "../../components/chartblocks/EmptyBarChart.es.js";
|
|
7
|
+
import { TransactionDrillDown as nt } from "./TransactionDrillDown.es.js";
|
|
8
|
+
import { useTransactionHistory as rt } from "./useTransactionHistory.es.js";
|
|
9
|
+
import { getDefaultSelection as it, getDrillDownConfig as st, getFlattenedDataSeries as lt, toStoreFilter as ct } from "./utils.es.js";
|
|
10
|
+
import { getDynamicCtaBasedOnTriggers as dt } from "../util.es.js";
|
|
11
|
+
import { TransactionDetailsBlock as mt } from "../TransactionDetailsBlock/TransactionDetailsBlock.es.js";
|
|
12
|
+
import { useLayoutEffect as gt, useState as u } from "react";
|
|
13
|
+
import { observer as pt } from "mobx-react-lite";
|
|
14
|
+
import { Fragment as ut, jsx as n, jsxs as ht } from "react/jsx-runtime";
|
|
15
|
+
import { useTheme as bt } from "@mui/material/styles";
|
|
16
|
+
var jt = pt(({ beat: a }) => {
|
|
17
|
+
const h = bt(), { instanceSlotData: e, beatTransactions: l, spendCategoryGuids: b, allAccountGuids: f, categoryName: v, displayedDateRange: g, transactionStore: x } = rt(a), { actionDrawer: y, setActionContext: C } = Y(), { common: B, insights_feed: c } = W(), { isCopyLoaded: F } = X(), [I, T] = u(!1), [G, A] = u(!1), { insights_payload: o } = a, j = dt(y, o?.primary_cta, o?.secondary_cta, o?.in_description_cta)?.variant, { top: r, filterMode: d, header: k, colors: w, filterStrategy: H, tipSection: S } = st(j ?? ""), { dataSeries: m, chartData: i, comparisonBars: O } = lt({
|
|
17
18
|
data: e?.data_series,
|
|
18
19
|
ariaLabel: e?.ariaLabel ?? "",
|
|
19
|
-
top:
|
|
20
|
-
beatTransactions:
|
|
20
|
+
top: r,
|
|
21
|
+
beatTransactions: l,
|
|
21
22
|
payload: e
|
|
22
|
-
}), { chartBarIndex: E, subTabIndex: K } =
|
|
23
|
-
chartTabCount:
|
|
23
|
+
}), { chartBarIndex: E, subTabIndex: K } = it({
|
|
24
|
+
chartTabCount: i.length,
|
|
24
25
|
comparisonTabCount: O.length,
|
|
25
26
|
actionDrawer: y,
|
|
26
27
|
beatGuid: a.guid
|
|
27
|
-
}), [
|
|
28
|
+
}), [s, _] = u(E), D = (t) => H({
|
|
28
29
|
beat: a,
|
|
29
|
-
beatTransactions:
|
|
30
|
-
dataSeries:
|
|
30
|
+
beatTransactions: l,
|
|
31
|
+
dataSeries: m,
|
|
31
32
|
selectedIndex: t,
|
|
32
33
|
subIndex: K,
|
|
33
|
-
isLastTab: t ===
|
|
34
|
+
isLastTab: t === m.length - 1,
|
|
34
35
|
instanceSlotData: e,
|
|
35
36
|
spendCategoryGuids: b,
|
|
36
|
-
displayedDateRange:
|
|
37
|
-
}), V =
|
|
38
|
-
|
|
37
|
+
displayedDateRange: g
|
|
38
|
+
}), V = l.map((t) => t.guid).join(","), R = b.join(","), M = f.join(","), N = r === "list" || m.length > 0, L = () => {
|
|
39
|
+
d !== "store" || !N || x.setFilter(ct(D(s), {
|
|
39
40
|
allAccountGuids: f,
|
|
40
|
-
displayedDateRange:
|
|
41
|
+
displayedDateRange: g
|
|
41
42
|
}));
|
|
42
43
|
};
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
gt(() => {
|
|
45
|
+
L();
|
|
45
46
|
}, [
|
|
46
47
|
a.guid,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
s,
|
|
49
|
+
d,
|
|
50
|
+
m.length,
|
|
50
51
|
e,
|
|
51
|
-
|
|
52
|
+
g,
|
|
52
53
|
R,
|
|
53
54
|
M,
|
|
54
|
-
V
|
|
55
|
+
V,
|
|
56
|
+
r
|
|
55
57
|
]);
|
|
56
58
|
const p = k?.({
|
|
57
|
-
title:
|
|
58
|
-
subHeader:
|
|
59
|
-
categoryName:
|
|
60
|
-
selectedDate:
|
|
61
|
-
}),
|
|
62
|
-
if (!F) return /* @__PURE__ */
|
|
63
|
-
const
|
|
59
|
+
title: o?.title,
|
|
60
|
+
subHeader: o?.sub_title,
|
|
61
|
+
categoryName: v,
|
|
62
|
+
selectedDate: i[s]?.date ?? void 0
|
|
63
|
+
}), P = w(h, e?.category_guid);
|
|
64
|
+
if (!F) return /* @__PURE__ */ n(et, {});
|
|
65
|
+
const U = [c.general.monthly_amount, c.general.trend], [$, q] = e?.legends?.length ? e.legends.map((t) => t.label) : U, z = d === "local" ? (t) => D(t).custom ?? (() => !0) : void 0, J = d === "local" ? l : void 0, Q = r === "singleBar" || r === "upcomingBill" ? i.length ? /* @__PURE__ */ n(at, {
|
|
64
66
|
amounts: {
|
|
65
67
|
average: e?.average_amount,
|
|
66
|
-
formattedAverage:
|
|
68
|
+
formattedAverage: Z(e?.average_amount ?? 0, "0,0.00")
|
|
67
69
|
},
|
|
68
|
-
color:
|
|
69
|
-
data:
|
|
70
|
+
color: P[0] ?? h.palette.primary.main,
|
|
71
|
+
data: i,
|
|
70
72
|
legendPosition: "top",
|
|
71
73
|
heightOverride: 142,
|
|
72
74
|
margin: {
|
|
@@ -75,41 +77,41 @@ var It = mt(({ beat: a }) => {
|
|
|
75
77
|
left: 24,
|
|
76
78
|
right: 24
|
|
77
79
|
},
|
|
78
|
-
monthlyAmountLabel:
|
|
80
|
+
monthlyAmountLabel: $,
|
|
79
81
|
onBarClick: _,
|
|
80
|
-
selectedTabIndex:
|
|
81
|
-
trendAmountLabel:
|
|
82
|
-
}) : /* @__PURE__ */
|
|
83
|
-
return /* @__PURE__ */
|
|
82
|
+
selectedTabIndex: s,
|
|
83
|
+
trendAmountLabel: q
|
|
84
|
+
}) : /* @__PURE__ */ n(ot, {}) : null;
|
|
85
|
+
return /* @__PURE__ */ ht(ut, { children: [/* @__PURE__ */ n(nt, {
|
|
84
86
|
ariaLabel: e?.ariaLabel,
|
|
85
|
-
baseTransactions:
|
|
87
|
+
baseTransactions: J,
|
|
86
88
|
heading: p?.heading,
|
|
87
89
|
icon: p?.icon,
|
|
88
90
|
onSelectionChange: _,
|
|
89
|
-
selectedIndex:
|
|
91
|
+
selectedIndex: s,
|
|
90
92
|
subHeadingText: p?.subHeadingText,
|
|
91
|
-
tabs:
|
|
93
|
+
tabs: i.map((t) => ({
|
|
92
94
|
ariaLabel: t.ariaLabel,
|
|
93
95
|
label: t.label
|
|
94
96
|
})),
|
|
95
|
-
top:
|
|
96
|
-
...S && { tipSection: !G && S(A,
|
|
97
|
-
transactionFilter:
|
|
97
|
+
top: Q,
|
|
98
|
+
...S && { tipSection: !G && S(A, c, o?.sub_title?.text) },
|
|
99
|
+
transactionFilter: z,
|
|
98
100
|
onEachRowClick: (t) => {
|
|
99
101
|
C({ transaction_guid: t }), T(!0);
|
|
100
102
|
}
|
|
101
|
-
}), /* @__PURE__ */
|
|
103
|
+
}), /* @__PURE__ */ n(tt, {
|
|
102
104
|
ariaLabelClose: B.close_aria,
|
|
103
105
|
isOpen: I,
|
|
104
106
|
onClose: () => {
|
|
105
|
-
T(!1), C({ transaction_guid: void 0 }),
|
|
107
|
+
T(!1), C({ transaction_guid: void 0 }), L();
|
|
106
108
|
},
|
|
107
|
-
title:
|
|
108
|
-
children: /* @__PURE__ */
|
|
109
|
+
title: c.general.transaction_details_title,
|
|
110
|
+
children: /* @__PURE__ */ n(mt, { beat: a })
|
|
109
111
|
})] });
|
|
110
112
|
});
|
|
111
113
|
export {
|
|
112
|
-
|
|
114
|
+
jt as TransactionHistoryBlock
|
|
113
115
|
};
|
|
114
116
|
|
|
115
117
|
//# sourceMappingURL=TransactionHistoryBlock.es.js.map
|
package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionHistoryBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.tsx"],"sourcesContent":["import { useLayoutEffect, useState } from 'react'\n\nimport { useTheme } from '@mui/material/styles'\nimport { observer } from 'mobx-react-lite'\n\nimport type { Beat, DataSeries, Transaction } from '../../../core'\nimport { formatCurrency } from '../../../core/utils/NumberFormatting'\nimport { BarChartV2 } from '../../components/chartblocks/BarchartV2'\nimport { EmptyBarChart } from '../../components/chartblocks/EmptyBarChart'\n\nimport { TransactionDrillDown } from './TransactionDrillDown'\nimport { useTransactionHistory } from './useTransactionHistory'\nimport {\n getDefaultSelection,\n getDrillDownConfig,\n getFlattenedDataSeries,\n toStoreFilter,\n} from './utils'\nimport {\n Drawer,\n useInsightsV2Store,\n useGlobalCopyStore,\n useGlobalUiStore,\n Loader,\n} from '../../../common'\nimport { TransactionDetailsBlock } from '../TransactionDetailsBlock'\n\ninterface TransactionHistoryProp {\n beat: Beat\n}\n\nexport const TransactionHistoryBlock = observer(({ beat }: TransactionHistoryProp) => {\n const theme = useTheme()\n const {\n instanceSlotData,\n beatTransactions,\n spendCategoryGuids,\n allAccountGuids,\n categoryName,\n displayedDateRange,\n transactionStore,\n } = useTransactionHistory(beat)\n\n const { actionDrawer, setActionContext } = useInsightsV2Store()\n\n const { common: commonCopy, insights_feed: insightsCopy } = useGlobalCopyStore()\n\n const { isCopyLoaded } = useGlobalUiStore()\n\n const [isTransactionDetailsOpen, setIsTransactionDetailsOpen] = useState(false)\n\n const [closeTipSection, setCloseTipSection] = useState(false)\n\n const { insights_payload } = beat\n\n const dynamicCtaVariant =\n actionDrawer.trigger === 'secondaryCta'\n ? insights_payload?.secondary_cta?.variant\n : insights_payload?.primary_cta?.variant\n\n const { top, filterMode, header, colors, filterStrategy, tipSection } = getDrillDownConfig(\n dynamicCtaVariant ?? '',\n )\n\n const { dataSeries, chartData, comparisonBars } = getFlattenedDataSeries({\n data: instanceSlotData?.data_series as DataSeries,\n ariaLabel: instanceSlotData?.ariaLabel ?? '',\n top,\n beatTransactions,\n payload: instanceSlotData,\n })\n\n const { chartBarIndex, subTabIndex } = getDefaultSelection({\n chartTabCount: chartData.length,\n comparisonTabCount: comparisonBars.length,\n actionDrawer,\n beatGuid: beat.guid,\n })\n\n const [selectedIndex, setSelectedIndex] = useState(chartBarIndex)\n\n const resolveFilter = (index: number) =>\n filterStrategy({\n beat,\n beatTransactions,\n dataSeries,\n selectedIndex: index,\n subIndex: subTabIndex,\n isLastTab: index === dataSeries.length - 1,\n instanceSlotData,\n spendCategoryGuids,\n displayedDateRange,\n })\n\n // Apply the current selection's filter. Store variants route through the store filter; local\n // (upcomingBill) variants filter beatTransactions directly and only backfill the cache when the\n // Stable primitive keys for the collections below: beatTransactions/spendCategoryGuids/\n // allAccountGuids are recomputed (new array identity) every render, so depending on them directly\n // re-fires the effect each render (REVIEW.md MEW-3732). Key on content instead.\n const beatTransactionGuidsKey = beatTransactions.map((transaction) => transaction.guid).join(',')\n const spendCategoryGuidsKey = spendCategoryGuids.join(',')\n const allAccountGuidsKey = allAccountGuids.join(',')\n\n // Re-applies the current selection's filter to the shared transactionStore. Called both by the\n // effect below (on selection change) and when the nested TransactionDetailsBlock drawer closes:\n // AddMerchantBudgetAction (opened from within that drawer) overwrites transactionStore.filter\n // with a merchant_guid-only filter while its own drawer is open, and never restores it — leaving\n // the row list stuck showing only that one merchant's transactions after backing all the way out.\n // Re-running this on close re-derives the filter fresh instead of relying on whatever the nested\n // drawers left behind.\n const applyCurrentSelectionFilter = () => {\n if (filterMode !== 'store' || !dataSeries.length) return\n transactionStore.setFilter(\n toStoreFilter(resolveFilter(selectedIndex), { allAccountGuids, displayedDateRange }),\n )\n }\n\n // store variants route the selection through the shared store filter; local (upcomingBill) variants\n // filter beatTransactions directly, so there's nothing to push to the store for them.\n useLayoutEffect(() => {\n applyCurrentSelectionFilter()\n }, [\n beat.guid,\n selectedIndex,\n filterMode,\n dataSeries.length,\n instanceSlotData,\n displayedDateRange,\n spendCategoryGuidsKey,\n allAccountGuidsKey,\n beatTransactionGuidsKey,\n ])\n\n const headerContent = header?.({\n title: insights_payload?.title,\n subHeader: insights_payload?.sub_title,\n categoryName,\n selectedDate: chartData[selectedIndex]?.date ?? undefined,\n })\n\n const barColors = colors(theme, instanceSlotData?.category_guid)\n\n if (!isCopyLoaded) return <Loader />\n\n // TODO: Temporary fallback while the backend doesn't always send `legends` on every beat/variant.\n // Remove this once the backend guarantees `legends` on the payload.\n const legendFallbackLabels = [insightsCopy.general.monthly_amount, insightsCopy.general.trend]\n\n const [monthlyAmountLabel, trendAmountLabel] = instanceSlotData?.legends?.length\n ? instanceSlotData.legends.map((legend) => legend.label)\n : legendFallbackLabels\n\n const transactionFilter =\n filterMode === 'local'\n ? (index: number) => resolveFilter(index).custom ?? (() => true)\n : undefined\n\n const baseTransactions: Transaction[] | undefined =\n filterMode === 'local' ? beatTransactions : undefined\n\n const isBarTop = top === 'singleBar' || top === 'upcomingBill'\n const chartTop = !isBarTop ? null : chartData.length ? (\n <BarChartV2\n amounts={{\n average: instanceSlotData?.average_amount,\n formattedAverage: formatCurrency(instanceSlotData?.average_amount ?? 0, '0,0.00'),\n }}\n color={barColors[0] ?? theme.palette.primary.main}\n data={chartData}\n legendPosition=\"top\"\n heightOverride={142}\n margin={{\n bottom: 8,\n top: 24,\n left: 24,\n right: 24,\n }}\n monthlyAmountLabel={monthlyAmountLabel}\n onBarClick={setSelectedIndex}\n selectedTabIndex={selectedIndex}\n trendAmountLabel={trendAmountLabel}\n />\n ) : (\n <EmptyBarChart />\n )\n\n return (\n <>\n <TransactionDrillDown\n ariaLabel={instanceSlotData?.ariaLabel}\n baseTransactions={baseTransactions}\n heading={headerContent?.heading}\n icon={headerContent?.icon}\n onSelectionChange={setSelectedIndex}\n selectedIndex={selectedIndex}\n subHeadingText={headerContent?.subHeadingText}\n tabs={chartData.map((bar) => ({\n ariaLabel: bar.ariaLabel,\n label: bar.label,\n }))}\n top={chartTop}\n {...(tipSection && {\n tipSection:\n !closeTipSection &&\n tipSection(setCloseTipSection, insightsCopy, insights_payload?.sub_title?.text),\n })}\n transactionFilter={transactionFilter}\n onEachRowClick={(guid) => {\n setActionContext({ transaction_guid: guid })\n setIsTransactionDetailsOpen(true)\n }}\n />\n <Drawer\n ariaLabelClose={commonCopy.close_aria}\n isOpen={isTransactionDetailsOpen}\n onClose={() => {\n setIsTransactionDetailsOpen(false)\n // Clear only the key this nested drawer owns — setActionContext merges, so an\n // explicit `{}` would be a no-op and leave transaction_guid stuck in the shared\n // context, and the outer drawer's own context (e.g. chartBarIndex) must survive.\n setActionContext({ transaction_guid: undefined })\n // Re-apply this block's own filter: a further-nested AddMerchantBudgetAction drawer may\n // have overwritten transactionStore.filter (merchant_guid-only) without restoring it.\n applyCurrentSelectionFilter()\n }}\n title={insightsCopy.general.transaction_details_title}\n >\n <TransactionDetailsBlock beat={beat} />\n </Drawer>\n </>\n )\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TransactionHistoryBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.tsx"],"sourcesContent":["import { useLayoutEffect, useState } from 'react'\n\nimport { useTheme } from '@mui/material/styles'\nimport { observer } from 'mobx-react-lite'\n\nimport type { Beat, DataSeries, Transaction } from '../../../core'\nimport { formatCurrency } from '../../../core/utils/NumberFormatting'\nimport { BarChartV2 } from '../../components/chartblocks/BarchartV2'\nimport { EmptyBarChart } from '../../components/chartblocks/EmptyBarChart'\n\nimport { TransactionDrillDown } from './TransactionDrillDown'\nimport { useTransactionHistory } from './useTransactionHistory'\nimport {\n getDefaultSelection,\n getDrillDownConfig,\n getFlattenedDataSeries,\n toStoreFilter,\n} from './utils'\nimport {\n Drawer,\n useInsightsV2Store,\n useGlobalCopyStore,\n useGlobalUiStore,\n Loader,\n} from '../../../common'\nimport { TransactionDetailsBlock } from '../TransactionDetailsBlock'\nimport { getDynamicCtaBasedOnTriggers } from '../util'\n\ninterface TransactionHistoryProp {\n beat: Beat\n}\n\nexport const TransactionHistoryBlock = observer(({ beat }: TransactionHistoryProp) => {\n const theme = useTheme()\n const {\n instanceSlotData,\n beatTransactions,\n spendCategoryGuids,\n allAccountGuids,\n categoryName,\n displayedDateRange,\n transactionStore,\n } = useTransactionHistory(beat)\n\n const { actionDrawer, setActionContext } = useInsightsV2Store()\n\n const { common: commonCopy, insights_feed: insightsCopy } = useGlobalCopyStore()\n\n const { isCopyLoaded } = useGlobalUiStore()\n\n const [isTransactionDetailsOpen, setIsTransactionDetailsOpen] = useState(false)\n\n const [closeTipSection, setCloseTipSection] = useState(false)\n\n const { insights_payload } = beat\n\n const dynamicCtaVariant = getDynamicCtaBasedOnTriggers(\n actionDrawer,\n insights_payload?.primary_cta,\n insights_payload?.secondary_cta,\n insights_payload?.in_description_cta,\n )?.variant\n\n const { top, filterMode, header, colors, filterStrategy, tipSection } = getDrillDownConfig(\n dynamicCtaVariant ?? '',\n )\n\n const { dataSeries, chartData, comparisonBars } = getFlattenedDataSeries({\n data: instanceSlotData?.data_series as DataSeries,\n ariaLabel: instanceSlotData?.ariaLabel ?? '',\n top,\n beatTransactions,\n payload: instanceSlotData,\n })\n\n const { chartBarIndex, subTabIndex } = getDefaultSelection({\n chartTabCount: chartData.length,\n comparisonTabCount: comparisonBars.length,\n actionDrawer,\n beatGuid: beat.guid,\n })\n\n const [selectedIndex, setSelectedIndex] = useState(chartBarIndex)\n\n const resolveFilter = (index: number) =>\n filterStrategy({\n beat,\n beatTransactions,\n dataSeries,\n selectedIndex: index,\n subIndex: subTabIndex,\n isLastTab: index === dataSeries.length - 1,\n instanceSlotData,\n spendCategoryGuids,\n displayedDateRange,\n })\n\n // Apply the current selection's filter. Store variants route through the store filter; local\n // (upcomingBill) variants filter beatTransactions directly and only backfill the cache when the\n // Stable primitive keys for the collections below: beatTransactions/spendCategoryGuids/\n // allAccountGuids are recomputed (new array identity) every render, so depending on them directly\n // re-fires the effect each render (REVIEW.md MEW-3732). Key on content instead.\n const beatTransactionGuidsKey = beatTransactions.map((transaction) => transaction.guid).join(',')\n const spendCategoryGuidsKey = spendCategoryGuids.join(',')\n const allAccountGuidsKey = allAccountGuids.join(',')\n\n // Re-applies the current selection's filter to the shared transactionStore. Called both by the\n // effect below (on selection change) and when the nested TransactionDetailsBlock drawer closes:\n // AddMerchantBudgetAction (opened from within that drawer) overwrites transactionStore.filter\n // with a merchant_guid-only filter while its own drawer is open, and never restores it — leaving\n // the row list stuck showing only that one merchant's transactions after backing all the way out.\n // Re-running this on close re-derives the filter fresh instead of relying on whatever the nested\n // drawers left behind.\n // A `list` drawer has no bars: it filters once from the beat alone.\n const canApplyFilter = top === 'list' || dataSeries.length > 0\n const applyCurrentSelectionFilter = () => {\n if (filterMode !== 'store' || !canApplyFilter) return\n transactionStore.setFilter(\n toStoreFilter(resolveFilter(selectedIndex), { allAccountGuids, displayedDateRange }),\n )\n }\n\n // store variants route the selection through the shared store filter; local (upcomingBill) variants\n // filter beatTransactions directly, so there's nothing to push to the store for them.\n useLayoutEffect(() => {\n applyCurrentSelectionFilter()\n }, [\n beat.guid,\n selectedIndex,\n filterMode,\n dataSeries.length,\n instanceSlotData,\n displayedDateRange,\n spendCategoryGuidsKey,\n allAccountGuidsKey,\n beatTransactionGuidsKey,\n top,\n ])\n\n const headerContent = header?.({\n title: insights_payload?.title,\n subHeader: insights_payload?.sub_title,\n categoryName,\n selectedDate: chartData[selectedIndex]?.date ?? undefined,\n })\n\n const barColors = colors(theme, instanceSlotData?.category_guid)\n\n if (!isCopyLoaded) return <Loader />\n\n // TODO: Temporary fallback while the backend doesn't always send `legends` on every beat/variant.\n // Remove this once the backend guarantees `legends` on the payload.\n const legendFallbackLabels = [insightsCopy.general.monthly_amount, insightsCopy.general.trend]\n\n const [monthlyAmountLabel, trendAmountLabel] = instanceSlotData?.legends?.length\n ? instanceSlotData.legends.map((legend) => legend.label)\n : legendFallbackLabels\n\n const transactionFilter =\n filterMode === 'local'\n ? (index: number) => resolveFilter(index).custom ?? (() => true)\n : undefined\n\n const baseTransactions: Transaction[] | undefined =\n filterMode === 'local' ? beatTransactions : undefined\n\n const isBarTop = top === 'singleBar' || top === 'upcomingBill'\n const chartTop = !isBarTop ? null : chartData.length ? (\n <BarChartV2\n amounts={{\n average: instanceSlotData?.average_amount,\n formattedAverage: formatCurrency(instanceSlotData?.average_amount ?? 0, '0,0.00'),\n }}\n color={barColors[0] ?? theme.palette.primary.main}\n data={chartData}\n legendPosition=\"top\"\n heightOverride={142}\n margin={{\n bottom: 8,\n top: 24,\n left: 24,\n right: 24,\n }}\n monthlyAmountLabel={monthlyAmountLabel}\n onBarClick={setSelectedIndex}\n selectedTabIndex={selectedIndex}\n trendAmountLabel={trendAmountLabel}\n />\n ) : (\n <EmptyBarChart />\n )\n\n return (\n <>\n <TransactionDrillDown\n ariaLabel={instanceSlotData?.ariaLabel}\n baseTransactions={baseTransactions}\n heading={headerContent?.heading}\n icon={headerContent?.icon}\n onSelectionChange={setSelectedIndex}\n selectedIndex={selectedIndex}\n subHeadingText={headerContent?.subHeadingText}\n tabs={chartData.map((bar) => ({\n ariaLabel: bar.ariaLabel,\n label: bar.label,\n }))}\n top={chartTop}\n {...(tipSection && {\n tipSection:\n !closeTipSection &&\n tipSection(setCloseTipSection, insightsCopy, insights_payload?.sub_title?.text),\n })}\n transactionFilter={transactionFilter}\n onEachRowClick={(guid) => {\n setActionContext({ transaction_guid: guid })\n setIsTransactionDetailsOpen(true)\n }}\n />\n <Drawer\n ariaLabelClose={commonCopy.close_aria}\n isOpen={isTransactionDetailsOpen}\n onClose={() => {\n setIsTransactionDetailsOpen(false)\n // Clear only the key this nested drawer owns — setActionContext merges, so an\n // explicit `{}` would be a no-op and leave transaction_guid stuck in the shared\n // context, and the outer drawer's own context (e.g. chartBarIndex) must survive.\n setActionContext({ transaction_guid: undefined })\n // Re-apply this block's own filter: a further-nested AddMerchantBudgetAction drawer may\n // have overwritten transactionStore.filter (merchant_guid-only) without restoring it.\n applyCurrentSelectionFilter()\n }}\n title={insightsCopy.general.transaction_details_title}\n >\n <TransactionDetailsBlock beat={beat} />\n </Drawer>\n </>\n )\n})\n"],"mappings":"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"}
|
|
@@ -28,6 +28,7 @@ export declare const DRILLDOWN_VARIANTS: {
|
|
|
28
28
|
readonly COST_OF_LIVING: "cost_living_to_income";
|
|
29
29
|
readonly NON_ESSENTIAL_CATEGORY: "non_essential_category_summary";
|
|
30
30
|
readonly DEPOSIT_SUMMARY: "monthly_deposit_summary";
|
|
31
|
+
readonly LOW_BALANCE: "low_balance";
|
|
31
32
|
};
|
|
32
33
|
export type DrillDownVariant = (typeof DRILLDOWN_VARIANTS)[keyof typeof DRILLDOWN_VARIANTS];
|
|
33
34
|
/**
|
|
@@ -58,7 +59,7 @@ export interface FilterContext {
|
|
|
58
59
|
}
|
|
59
60
|
export type FilterStrategy = (ctx: FilterContext) => TransactionFilter;
|
|
60
61
|
export interface DrillDownVariantConfig {
|
|
61
|
-
top: 'singleBar' | 'upcomingBill' | 'doubleBar' | 'tabsOnly';
|
|
62
|
+
top: 'singleBar' | 'upcomingBill' | 'doubleBar' | 'tabsOnly' | 'list';
|
|
62
63
|
filterStrategy: FilterStrategy;
|
|
63
64
|
colors: ColorKind;
|
|
64
65
|
header?: HeaderKind;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { buildDynamicCopy as p } from "../../../core/utils/Localization.es.js";
|
|
2
|
-
import { DATE_FORMATS_INTL as
|
|
3
|
-
import {
|
|
2
|
+
import { DATE_FORMATS_INTL as y, formatDate as N } from "../../../core/constants/DateFormats.es.js";
|
|
3
|
+
import { fromUnixUTC as d } from "../../../core/utils/DateUtil.es.js";
|
|
4
|
+
import { getCategoryColor as f } from "../../../core/utils/CategoryUtil.es.js";
|
|
4
5
|
import { MerchantLogo as S } from "@mxenabled/mxui";
|
|
5
6
|
import { Icon as O } from "@mxenabled/mx-icons";
|
|
6
7
|
import { jsx as c } from "react/jsx-runtime";
|
|
7
|
-
import { endOfMonth as
|
|
8
|
-
var
|
|
8
|
+
import { endOfMonth as A, startOfMonth as C } from "date-fns";
|
|
9
|
+
var s = {
|
|
9
10
|
TRANSACTION: "not_standard_amount",
|
|
10
11
|
CATEGORY_SPEND: "category_spend",
|
|
11
12
|
MONTHLY_SPEND: "monthly_spend_comparison",
|
|
@@ -16,46 +17,59 @@ var i = {
|
|
|
16
17
|
DEBT_TO_INCOME: "monthly_debt_to_income",
|
|
17
18
|
COST_OF_LIVING: "cost_living_to_income",
|
|
18
19
|
NON_ESSENTIAL_CATEGORY: "non_essential_category_summary",
|
|
19
|
-
DEPOSIT_SUMMARY: "monthly_deposit_summary"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
DEPOSIT_SUMMARY: "monthly_deposit_summary",
|
|
21
|
+
LOW_BALANCE: "low_balance"
|
|
22
|
+
}, l = (e, t) => t && f(t, e) || e.palette.primary.main, _ = (e) => ({
|
|
23
|
+
start: C(new Date(e ?? NaN)),
|
|
24
|
+
end: A(new Date(e ?? NaN))
|
|
25
|
+
}), m = (e) => e?.length ? { accounts: e } : {}, T = ({ beat: e }) => {
|
|
26
|
+
const { account_guid: t, from_date: o, to_date: r } = e.insights_payload?.drilldown_data ?? {};
|
|
27
|
+
return typeof t != "string" || typeof o != "number" || typeof r != "number" || !Number.isFinite(o) || !Number.isFinite(r) || r <= o ? {
|
|
28
|
+
accounts: [],
|
|
29
|
+
custom: () => !1
|
|
30
|
+
} : {
|
|
31
|
+
accounts: [t],
|
|
32
|
+
dateRange: {
|
|
33
|
+
start: d(o),
|
|
34
|
+
end: d(r - 1)
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}, g = ({ beatTransactions: e, dataSeries: t, selectedIndex: o }) => {
|
|
38
|
+
const r = t[o], a = r?.guid, n = e.find((i) => i.guid === a)?.has_been_split;
|
|
25
39
|
return {
|
|
26
|
-
custom: (
|
|
27
|
-
dateRange:
|
|
40
|
+
custom: (i) => i.guid === a,
|
|
41
|
+
dateRange: _(r?.date),
|
|
28
42
|
showSplits: !n
|
|
29
43
|
};
|
|
30
|
-
},
|
|
44
|
+
}, h = ({ dataSeries: e, selectedIndex: t, instanceSlotData: o }) => {
|
|
31
45
|
const r = e[t], a = o.category_guid ?? r?.guid;
|
|
32
46
|
return {
|
|
33
47
|
custom: (n) => n.category_guid === a || n.top_level_category_guid === a,
|
|
34
|
-
dateRange:
|
|
48
|
+
dateRange: _(r?.date)
|
|
35
49
|
};
|
|
36
50
|
}, I = ({ dataSeries: e, selectedIndex: t, spendCategoryGuids: o, instanceSlotData: r }) => {
|
|
37
51
|
const a = e[t];
|
|
38
52
|
return {
|
|
39
53
|
custom: (n) => !!n.top_level_category_guid && o.includes(n.top_level_category_guid),
|
|
40
|
-
dateRange:
|
|
41
|
-
...
|
|
54
|
+
dateRange: _(a?.date),
|
|
55
|
+
...m(r.account_guids)
|
|
42
56
|
};
|
|
43
|
-
},
|
|
44
|
-
const n = t[o], { start:
|
|
57
|
+
}, L = ({ beat: e, dataSeries: t, selectedIndex: o, isLastTab: r, instanceSlotData: a }) => {
|
|
58
|
+
const n = t[o], { start: i, end: u } = _(n?.date);
|
|
45
59
|
return {
|
|
46
60
|
dateRange: {
|
|
47
|
-
start:
|
|
48
|
-
end: r && e.created_at ? new Date(e.created_at) :
|
|
61
|
+
start: i,
|
|
62
|
+
end: r && e.created_at ? new Date(e.created_at) : u
|
|
49
63
|
},
|
|
50
|
-
...
|
|
64
|
+
...m(a.account_guids)
|
|
51
65
|
};
|
|
52
|
-
},
|
|
53
|
-
[
|
|
66
|
+
}, P = {
|
|
67
|
+
[s.TRANSACTION]: {
|
|
54
68
|
top: "singleBar",
|
|
55
69
|
scope: "store",
|
|
56
70
|
filterMode: "store",
|
|
57
71
|
filterStrategy: g,
|
|
58
|
-
colors: (e, t) => [
|
|
72
|
+
colors: (e, t) => [l(e, t)],
|
|
59
73
|
header: (e) => {
|
|
60
74
|
const { title: t, subHeader: o } = e;
|
|
61
75
|
return {
|
|
@@ -74,53 +88,60 @@ var i = {
|
|
|
74
88
|
onDismiss: () => e(!0)
|
|
75
89
|
})
|
|
76
90
|
},
|
|
77
|
-
[
|
|
91
|
+
[s.CATEGORY_SPEND]: {
|
|
78
92
|
top: "singleBar",
|
|
79
|
-
filterStrategy:
|
|
93
|
+
filterStrategy: h,
|
|
80
94
|
scope: "store",
|
|
81
95
|
filterMode: "store",
|
|
82
|
-
colors: (e, t) => [
|
|
96
|
+
colors: (e, t) => [l(e, t)],
|
|
83
97
|
header: (e) => ({
|
|
84
98
|
heading: e.categoryName,
|
|
85
|
-
subHeadingText: e.selectedDate && N(e.selectedDate,
|
|
99
|
+
subHeadingText: e.selectedDate && N(e.selectedDate, y.MONTH_LONG) || "",
|
|
86
100
|
icon: /* @__PURE__ */ c(O, {
|
|
87
101
|
name: "calendar_month",
|
|
88
102
|
size: 16
|
|
89
103
|
})
|
|
90
104
|
})
|
|
91
105
|
},
|
|
92
|
-
[
|
|
106
|
+
[s.MONTHLY_SPEND]: {
|
|
93
107
|
top: "singleBar",
|
|
94
108
|
filterStrategy: I,
|
|
95
109
|
scope: "store",
|
|
96
110
|
filterMode: "store",
|
|
97
111
|
colors: (e) => [e.palette.chart.chart2 ?? e.palette.primary.main]
|
|
98
112
|
},
|
|
99
|
-
[
|
|
113
|
+
[s.ACCOUNT_BALANCE]: {
|
|
100
114
|
top: "singleBar",
|
|
101
|
-
filterStrategy:
|
|
115
|
+
filterStrategy: L,
|
|
102
116
|
scope: "store",
|
|
103
117
|
filterMode: "store",
|
|
104
118
|
colors: (e) => [e.palette.success.main]
|
|
105
119
|
},
|
|
106
|
-
[
|
|
120
|
+
[s.UPCOMING_BILL]: {
|
|
107
121
|
top: "upcomingBill",
|
|
108
122
|
filterStrategy: g,
|
|
109
123
|
scope: "beat",
|
|
110
124
|
filterMode: "local",
|
|
111
|
-
colors: (e, t) => [
|
|
125
|
+
colors: (e, t) => [l(e, t)]
|
|
126
|
+
},
|
|
127
|
+
[s.LOW_BALANCE]: {
|
|
128
|
+
top: "list",
|
|
129
|
+
filterStrategy: T,
|
|
130
|
+
scope: "store",
|
|
131
|
+
filterMode: "store",
|
|
132
|
+
colors: (e) => [e.palette.primary.main]
|
|
112
133
|
}
|
|
113
|
-
},
|
|
134
|
+
}, w = {
|
|
114
135
|
top: "singleBar",
|
|
115
136
|
filterStrategy: g,
|
|
116
137
|
scope: "store",
|
|
117
138
|
filterMode: "store",
|
|
118
|
-
colors: (e, t) => [
|
|
139
|
+
colors: (e, t) => [l(e, t)]
|
|
119
140
|
};
|
|
120
141
|
export {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
142
|
+
s as DRILLDOWN_VARIANTS,
|
|
143
|
+
w as FALLBACK,
|
|
144
|
+
P as layout
|
|
124
145
|
};
|
|
125
146
|
|
|
126
147
|
//# sourceMappingURL=layout.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/layout.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport type { Theme } from '@mui/material/styles'\nimport { endOfMonth, startOfMonth } from 'date-fns'\nimport { getCategoryColor } from '../../../core/utils/CategoryUtil'\nimport {\n type Beat,\n type InsightsFeedCopy,\n type Subtitle,\n type Transaction,\n buildDynamicCopy,\n} from '../../../core'\nimport type { TransactionFilter } from '../../../core/stores/TransactionStore'\nimport type { InsightsInstanceSlotData } from '../../../core/types/InsightsInstanceSlotData'\nimport { MerchantLogo } from '@mxenabled/mxui'\nimport { DATE_FORMATS_INTL, formatDate } from '../../../core/constants'\nimport { Icon } from '@mxenabled/mx-icons'\nimport type { ChartDataSeriesItem } from '../../blocks/ChartBlocks/BarchartBlock/utils'\nimport type { TipSectionProps } from '../../../insights/components/shared/ChartDrawerTemplate/TipSection'\n\nexport interface DrillDownHeader {\n heading?: string\n subHeadingText?: string\n icon?: ReactNode\n}\n\nexport interface DrillDownHeaderContext {\n title?: string\n subHeader?: Subtitle\n categoryName: string\n selectedDate?: string | Date\n}\n\nexport const DRILLDOWN_VARIANTS = {\n TRANSACTION: 'not_standard_amount',\n CATEGORY_SPEND: 'category_spend',\n MONTHLY_SPEND: 'monthly_spend_comparison',\n ACCOUNT_BALANCE: 'account_balance',\n UPCOMING_BILL: 'upcoming_bill',\n SPEND_TO_INCOME: 'monthly_spend_to_income',\n SAVINGS_TO_INCOME: 'monthly_savings_to_income',\n DEBT_TO_INCOME: 'monthly_debt_to_income',\n COST_OF_LIVING: 'cost_living_to_income',\n NON_ESSENTIAL_CATEGORY: 'non_essential_category_summary',\n DEPOSIT_SUMMARY: 'monthly_deposit_summary',\n} as const\n\nexport type DrillDownVariant = (typeof DRILLDOWN_VARIANTS)[keyof typeof DRILLDOWN_VARIANTS]\n\n/**\n * One row of the flattened data_series a filterStrategy indexes into: a single-bar monthly total or a\n * synthesized upcoming-bill bar. Fields are optional because the backend keys each row dynamically\n * from data_series.names and not every variant carries a guid/category. Double-bar comparison rows\n * will extend this in the next MR.\n */\n\n// Resolves the top-chart palette from the theme (and the beat's category, when relevant).\nexport type ColorKind = (theme: Theme, categoryGuid?: string) => string[]\n\n// Resolves the dynamic drawer header (heading/sub-heading/icon JSX) from the selection context.\nexport type HeaderKind = (ctx: DrillDownHeaderContext) => DrillDownHeader\n\n/**\n * Everything a filterStrategy needs to turn the currently-selected bar/sub-tab into a\n * TransactionFilter. Data-only so strategies stay pure and testable.\n */\nexport interface FilterContext {\n beat: Beat\n beatTransactions: Transaction[]\n dataSeries: ChartDataSeriesItem[]\n selectedIndex: number\n subIndex: number\n isLastTab: boolean\n instanceSlotData: InsightsInstanceSlotData\n spendCategoryGuids: string[]\n displayedDateRange: { start: Date; end: Date }\n}\n\n// Resolves the current selection into a TransactionFilter. Carried on each config row so behavior\n// lives next to the variant it belongs to (no separate strategy registry to chase).\nexport type FilterStrategy = (ctx: FilterContext) => TransactionFilter\n\nexport interface DrillDownVariantConfig {\n top: 'singleBar' | 'upcomingBill' | 'doubleBar' | 'tabsOnly'\n filterStrategy: FilterStrategy\n colors: ColorKind\n header?: HeaderKind\n tipSection?: (\n setCloseTipSection: (flag: boolean) => void,\n copy: InsightsFeedCopy,\n merchantName?: string,\n ) => TipSectionProps\n scope: 'store' | 'beat'\n filterMode: 'store' | 'local'\n}\nconst categoryColor = (theme: Theme, categoryGuid?: string): string =>\n (categoryGuid && getCategoryColor(categoryGuid, theme)) || theme.palette.primary.main\n\nconst monthRange = (date: string | number | Date | undefined) => ({\n start: startOfMonth(new Date(date ?? NaN)),\n end: endOfMonth(new Date(date ?? NaN)),\n})\n\n// Scopes a filter to the beat's accounts when the beat carries account_guids; otherwise leaves\n// accounts unset so the store default (all accounts) applies.\nconst accountScope = (accountGuids?: string[]): Pick<TransactionFilter, 'accounts'> =>\n accountGuids?.length ? { accounts: accountGuids } : {}\n\n// ── Single-bar filter strategies (this MR) ────────────────────────────────────────────────────\n\n// BillAmountNotStandard / UpcomingBill — the series carries a transaction (TRN) guid; match a single\n// transaction by guid within its month.\nconst transactionGuidStrategy: FilterStrategy = ({\n beatTransactions,\n dataSeries,\n selectedIndex,\n}) => {\n const seriesItem = dataSeries[selectedIndex]\n const seriesGuid = seriesItem?.guid\n const hasBeenSplit = beatTransactions.find((trn) => trn.guid === seriesGuid)?.has_been_split\n\n return {\n custom: (trn) => trn.guid === seriesGuid,\n dateRange: monthRange(seriesItem?.date),\n showSplits: !hasBeenSplit,\n }\n}\n\n// CategorySpendingV2 — match transactions in the beat's category (or whose top-level category is that\n// guid) within the month.\nconst categoryStrategy: FilterStrategy = ({ dataSeries, selectedIndex, instanceSlotData }) => {\n const seriesItem = dataSeries[selectedIndex]\n const categoryGuid = instanceSlotData.category_guid ?? seriesItem?.guid\n\n return {\n custom: (trn) =>\n trn.category_guid === categoryGuid || trn.top_level_category_guid === categoryGuid,\n dateRange: monthRange(seriesItem?.date),\n }\n}\n\n// MonthlySpendComparisonV2 — no per-bar guid; show all spending-category transactions\n// (income/transfers/investments excluded via spendCategoryGuids) within the month.\nconst spendCategoriesStrategy: FilterStrategy = ({\n dataSeries,\n selectedIndex,\n spendCategoryGuids,\n instanceSlotData,\n}) => {\n const seriesItem = dataSeries[selectedIndex]\n\n return {\n custom: (trn) =>\n !!trn.top_level_category_guid && spendCategoryGuids.includes(trn.top_level_category_guid),\n dateRange: monthRange(seriesItem?.date),\n ...accountScope(instanceSlotData.account_guids),\n }\n}\n\n// SavingsAccountBalancesSummary — balances, not categorized spend. Filter by month only; the most\n// recent month is capped at the beat's creation time to match the snapshot the balance was computed\n// from.\nconst accountDateStrategy: FilterStrategy = ({\n beat,\n dataSeries,\n selectedIndex,\n isLastTab,\n instanceSlotData,\n}) => {\n const seriesItem = dataSeries[selectedIndex]\n const { start, end } = monthRange(seriesItem?.date)\n\n return {\n dateRange: {\n start,\n end: isLastTab && beat.created_at ? new Date(beat.created_at) : end,\n },\n ...accountScope(instanceSlotData.account_guids),\n }\n}\n\n// ── Double-bar + tabsOnly strategies (NEXT MR) ───────────────────────────────────────────────────\n// TODO(next MR — double bar): comparisonAggregatedGuidsStrategy — month × sub-tab membership over the\n// comparison bars' precomputed subGuids. Needs comparisonBars in FilterContext.\n// TODO(next MR — tabsOnly): aggregatedGuids / depositSummary strategies for the donut-drawer beats.\n\nexport const layout: Partial<Record<DrillDownVariant, DrillDownVariantConfig>> = {\n [DRILLDOWN_VARIANTS.TRANSACTION]: {\n top: 'singleBar',\n scope: 'store',\n filterMode: 'store',\n filterStrategy: transactionGuidStrategy,\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n header: (ctx: DrillDownHeaderContext) => {\n const { title, subHeader } = ctx\n return {\n heading: title,\n subHeadingText: subHeader?.text || undefined,\n icon: (\n <MerchantLogo\n alt={subHeader?.text}\n categoryGuid={subHeader?.logo?.category_guid || ''}\n merchantGuid={subHeader?.logo?.merchant_guid || ''}\n size={16}\n />\n ),\n }\n },\n tipSection: (setCloseTipSection, copy, merchantName = '') => {\n return {\n message: buildDynamicCopy(\n copy.general.tip_section_message,\n <strong>{copy.general.tip_section_title}</strong>,\n <strong>{merchantName}</strong>,\n ),\n onDismiss: () => setCloseTipSection(true),\n } as TipSectionProps\n },\n },\n [DRILLDOWN_VARIANTS.CATEGORY_SPEND]: {\n top: 'singleBar',\n filterStrategy: categoryStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n header: (ctx: DrillDownHeaderContext) => {\n return {\n heading: ctx.categoryName,\n subHeadingText: ctx.selectedDate\n ? formatDate(ctx.selectedDate, DATE_FORMATS_INTL.MONTH_LONG) || ''\n : '',\n icon: <Icon name=\"calendar_month\" size={16} />,\n }\n },\n },\n [DRILLDOWN_VARIANTS.MONTHLY_SPEND]: {\n top: 'singleBar',\n filterStrategy: spendCategoriesStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme) => [theme.palette.chart.chart2 ?? theme.palette.primary.main],\n },\n [DRILLDOWN_VARIANTS.ACCOUNT_BALANCE]: {\n top: 'singleBar',\n filterStrategy: accountDateStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme) => [theme.palette.success.main],\n },\n [DRILLDOWN_VARIANTS.UPCOMING_BILL]: {\n top: 'upcomingBill',\n filterStrategy: transactionGuidStrategy,\n scope: 'beat',\n filterMode: 'local',\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n },\n\n // ── NEXT MR: double-bar comparison beats (month tabs + spend/income sub-tabs) ────────────────\n // [DRILLDOWN_VARIANTS.SPEND_TO_INCOME]: comparison('spendVsIncome'),\n // [DRILLDOWN_VARIANTS.SAVINGS_TO_INCOME]: comparison('savingsVsIncome'),\n // [DRILLDOWN_VARIANTS.DEBT_TO_INCOME]: comparison('debtVsIncome'),\n // [DRILLDOWN_VARIANTS.COST_OF_LIVING]: comparison('costOfLiving'),\n //\n // ── NEXT MR: tabsOnly donut-drawer beats (no top chart) ───────────────────────────────────\n // [DRILLDOWN_VARIANTS.NON_ESSENTIAL_CATEGORY]: { top: 'tabsOnly', ... },\n // [DRILLDOWN_VARIANTS.DEPOSIT_SUMMARY]: { top: 'tabsOnly', ... },\n}\n\n// Fallback for a missing/typo'd backend variant: a single-bar, store-scoped drawer filtered by the\n// beat's transaction guid and colored by category, so the drawer still renders instead of crashing.\nexport const FALLBACK: DrillDownVariantConfig = {\n top: 'singleBar',\n filterStrategy: transactionGuidStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"layout.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/layout.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport type { Theme } from '@mui/material/styles'\nimport { endOfMonth, startOfMonth } from 'date-fns'\nimport { getCategoryColor } from '../../../core/utils/CategoryUtil'\nimport {\n type Beat,\n type InsightsFeedCopy,\n type Subtitle,\n type Transaction,\n buildDynamicCopy,\n} from '../../../core'\nimport type { TransactionFilter } from '../../../core/stores/TransactionStore'\nimport type { InsightsInstanceSlotData } from '../../../core/types/InsightsInstanceSlotData'\nimport { MerchantLogo } from '@mxenabled/mxui'\nimport { DATE_FORMATS_INTL, formatDate } from '../../../core/constants'\nimport { fromUnixUTC } from '../../../core/utils/DateUtil'\nimport { Icon } from '@mxenabled/mx-icons'\nimport type { ChartDataSeriesItem } from '../../blocks/ChartBlocks/BarchartBlock/utils'\nimport type { TipSectionProps } from '../../../insights/components/shared/ChartDrawerTemplate/TipSection'\n\nexport interface DrillDownHeader {\n heading?: string\n subHeadingText?: string\n icon?: ReactNode\n}\n\nexport interface DrillDownHeaderContext {\n title?: string\n subHeader?: Subtitle\n categoryName: string\n selectedDate?: string | Date\n}\n\nexport const DRILLDOWN_VARIANTS = {\n TRANSACTION: 'not_standard_amount',\n CATEGORY_SPEND: 'category_spend',\n MONTHLY_SPEND: 'monthly_spend_comparison',\n ACCOUNT_BALANCE: 'account_balance',\n UPCOMING_BILL: 'upcoming_bill',\n SPEND_TO_INCOME: 'monthly_spend_to_income',\n SAVINGS_TO_INCOME: 'monthly_savings_to_income',\n DEBT_TO_INCOME: 'monthly_debt_to_income',\n COST_OF_LIVING: 'cost_living_to_income',\n NON_ESSENTIAL_CATEGORY: 'non_essential_category_summary',\n DEPOSIT_SUMMARY: 'monthly_deposit_summary',\n LOW_BALANCE: 'low_balance',\n} as const\n\nexport type DrillDownVariant = (typeof DRILLDOWN_VARIANTS)[keyof typeof DRILLDOWN_VARIANTS]\n\n/**\n * One row of the flattened data_series a filterStrategy indexes into: a single-bar monthly total or a\n * synthesized upcoming-bill bar. Fields are optional because the backend keys each row dynamically\n * from data_series.names and not every variant carries a guid/category. Double-bar comparison rows\n * will extend this in the next MR.\n */\n\n// Resolves the top-chart palette from the theme (and the beat's category, when relevant).\nexport type ColorKind = (theme: Theme, categoryGuid?: string) => string[]\n\n// Resolves the dynamic drawer header (heading/sub-heading/icon JSX) from the selection context.\nexport type HeaderKind = (ctx: DrillDownHeaderContext) => DrillDownHeader\n\n/**\n * Everything a filterStrategy needs to turn the currently-selected bar/sub-tab into a\n * TransactionFilter. Data-only so strategies stay pure and testable.\n */\nexport interface FilterContext {\n beat: Beat\n beatTransactions: Transaction[]\n dataSeries: ChartDataSeriesItem[]\n selectedIndex: number\n subIndex: number\n isLastTab: boolean\n instanceSlotData: InsightsInstanceSlotData\n spendCategoryGuids: string[]\n displayedDateRange: { start: Date; end: Date }\n}\n\n// Resolves the current selection into a TransactionFilter. Carried on each config row so behavior\n// lives next to the variant it belongs to (no separate strategy registry to chase).\nexport type FilterStrategy = (ctx: FilterContext) => TransactionFilter\n\nexport interface DrillDownVariantConfig {\n // `list`: no chart or tabs above the transaction list (an account's transactions for a window).\n top: 'singleBar' | 'upcomingBill' | 'doubleBar' | 'tabsOnly' | 'list'\n filterStrategy: FilterStrategy\n colors: ColorKind\n header?: HeaderKind\n tipSection?: (\n setCloseTipSection: (flag: boolean) => void,\n copy: InsightsFeedCopy,\n merchantName?: string,\n ) => TipSectionProps\n scope: 'store' | 'beat'\n filterMode: 'store' | 'local'\n}\nconst categoryColor = (theme: Theme, categoryGuid?: string): string =>\n (categoryGuid && getCategoryColor(categoryGuid, theme)) || theme.palette.primary.main\n\nconst monthRange = (date: string | number | Date | undefined) => ({\n start: startOfMonth(new Date(date ?? NaN)),\n end: endOfMonth(new Date(date ?? NaN)),\n})\n\n// Scopes a filter to the beat's accounts when the beat carries account_guids; otherwise leaves\n// accounts unset so the store default (all accounts) applies.\nconst accountScope = (accountGuids?: string[]): Pick<TransactionFilter, 'accounts'> =>\n accountGuids?.length ? { accounts: accountGuids } : {}\n\n// Low Account Balance — `drilldown_data` names one account and a window (epoch seconds at UTC\n// midnight, to_date exclusive). Fails closed: a drawer that cannot name its rows shows none.\nconst accountWindowStrategy: FilterStrategy = ({ beat }) => {\n const { account_guid, from_date, to_date } = beat.insights_payload?.drilldown_data ?? {}\n if (\n typeof account_guid !== 'string' ||\n typeof from_date !== 'number' ||\n typeof to_date !== 'number' ||\n !Number.isFinite(from_date) ||\n !Number.isFinite(to_date) ||\n to_date <= from_date\n ) {\n return { accounts: [], custom: () => false }\n }\n\n return {\n accounts: [account_guid],\n dateRange: { start: fromUnixUTC(from_date), end: fromUnixUTC(to_date - 1) },\n }\n}\n\n// ── Single-bar filter strategies (this MR) ────────────────────────────────────────────────────\n\n// BillAmountNotStandard / UpcomingBill — the series carries a transaction (TRN) guid; match a single\n// transaction by guid within its month.\nconst transactionGuidStrategy: FilterStrategy = ({\n beatTransactions,\n dataSeries,\n selectedIndex,\n}) => {\n const seriesItem = dataSeries[selectedIndex]\n const seriesGuid = seriesItem?.guid\n const hasBeenSplit = beatTransactions.find((trn) => trn.guid === seriesGuid)?.has_been_split\n\n return {\n custom: (trn) => trn.guid === seriesGuid,\n dateRange: monthRange(seriesItem?.date),\n showSplits: !hasBeenSplit,\n }\n}\n\n// CategorySpendingV2 — match transactions in the beat's category (or whose top-level category is that\n// guid) within the month.\nconst categoryStrategy: FilterStrategy = ({ dataSeries, selectedIndex, instanceSlotData }) => {\n const seriesItem = dataSeries[selectedIndex]\n const categoryGuid = instanceSlotData.category_guid ?? seriesItem?.guid\n\n return {\n custom: (trn) =>\n trn.category_guid === categoryGuid || trn.top_level_category_guid === categoryGuid,\n dateRange: monthRange(seriesItem?.date),\n }\n}\n\n// MonthlySpendComparisonV2 — no per-bar guid; show all spending-category transactions\n// (income/transfers/investments excluded via spendCategoryGuids) within the month.\nconst spendCategoriesStrategy: FilterStrategy = ({\n dataSeries,\n selectedIndex,\n spendCategoryGuids,\n instanceSlotData,\n}) => {\n const seriesItem = dataSeries[selectedIndex]\n\n return {\n custom: (trn) =>\n !!trn.top_level_category_guid && spendCategoryGuids.includes(trn.top_level_category_guid),\n dateRange: monthRange(seriesItem?.date),\n ...accountScope(instanceSlotData.account_guids),\n }\n}\n\n// SavingsAccountBalancesSummary — balances, not categorized spend. Filter by month only; the most\n// recent month is capped at the beat's creation time to match the snapshot the balance was computed\n// from.\nconst accountDateStrategy: FilterStrategy = ({\n beat,\n dataSeries,\n selectedIndex,\n isLastTab,\n instanceSlotData,\n}) => {\n const seriesItem = dataSeries[selectedIndex]\n const { start, end } = monthRange(seriesItem?.date)\n\n return {\n dateRange: {\n start,\n end: isLastTab && beat.created_at ? new Date(beat.created_at) : end,\n },\n ...accountScope(instanceSlotData.account_guids),\n }\n}\n\n// ── Double-bar + tabsOnly strategies (NEXT MR) ───────────────────────────────────────────────────\n// TODO(next MR — double bar): comparisonAggregatedGuidsStrategy — month × sub-tab membership over the\n// comparison bars' precomputed subGuids. Needs comparisonBars in FilterContext.\n// TODO(next MR — tabsOnly): aggregatedGuids / depositSummary strategies for the donut-drawer beats.\n\nexport const layout: Partial<Record<DrillDownVariant, DrillDownVariantConfig>> = {\n [DRILLDOWN_VARIANTS.TRANSACTION]: {\n top: 'singleBar',\n scope: 'store',\n filterMode: 'store',\n filterStrategy: transactionGuidStrategy,\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n header: (ctx: DrillDownHeaderContext) => {\n const { title, subHeader } = ctx\n return {\n heading: title,\n subHeadingText: subHeader?.text || undefined,\n icon: (\n <MerchantLogo\n alt={subHeader?.text}\n categoryGuid={subHeader?.logo?.category_guid || ''}\n merchantGuid={subHeader?.logo?.merchant_guid || ''}\n size={16}\n />\n ),\n }\n },\n tipSection: (setCloseTipSection, copy, merchantName = '') => {\n return {\n message: buildDynamicCopy(\n copy.general.tip_section_message,\n <strong>{copy.general.tip_section_title}</strong>,\n <strong>{merchantName}</strong>,\n ),\n onDismiss: () => setCloseTipSection(true),\n } as TipSectionProps\n },\n },\n [DRILLDOWN_VARIANTS.CATEGORY_SPEND]: {\n top: 'singleBar',\n filterStrategy: categoryStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n header: (ctx: DrillDownHeaderContext) => {\n return {\n heading: ctx.categoryName,\n subHeadingText: ctx.selectedDate\n ? formatDate(ctx.selectedDate, DATE_FORMATS_INTL.MONTH_LONG) || ''\n : '',\n icon: <Icon name=\"calendar_month\" size={16} />,\n }\n },\n },\n [DRILLDOWN_VARIANTS.MONTHLY_SPEND]: {\n top: 'singleBar',\n filterStrategy: spendCategoriesStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme) => [theme.palette.chart.chart2 ?? theme.palette.primary.main],\n },\n [DRILLDOWN_VARIANTS.ACCOUNT_BALANCE]: {\n top: 'singleBar',\n filterStrategy: accountDateStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme) => [theme.palette.success.main],\n },\n [DRILLDOWN_VARIANTS.UPCOMING_BILL]: {\n top: 'upcomingBill',\n filterStrategy: transactionGuidStrategy,\n scope: 'beat',\n filterMode: 'local',\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n },\n\n // Low Account Balance's \"Transactions\" link: the account's transactions for the alert's window.\n [DRILLDOWN_VARIANTS.LOW_BALANCE]: {\n top: 'list',\n filterStrategy: accountWindowStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme) => [theme.palette.primary.main],\n },\n\n // ── NEXT MR: double-bar comparison beats (month tabs + spend/income sub-tabs) ────────────────\n // [DRILLDOWN_VARIANTS.SPEND_TO_INCOME]: comparison('spendVsIncome'),\n // [DRILLDOWN_VARIANTS.SAVINGS_TO_INCOME]: comparison('savingsVsIncome'),\n // [DRILLDOWN_VARIANTS.DEBT_TO_INCOME]: comparison('debtVsIncome'),\n // [DRILLDOWN_VARIANTS.COST_OF_LIVING]: comparison('costOfLiving'),\n //\n // ── NEXT MR: tabsOnly donut-drawer beats (no top chart) ───────────────────────────────────\n // [DRILLDOWN_VARIANTS.NON_ESSENTIAL_CATEGORY]: { top: 'tabsOnly', ... },\n // [DRILLDOWN_VARIANTS.DEPOSIT_SUMMARY]: { top: 'tabsOnly', ... },\n}\n\n// Fallback for a missing/typo'd backend variant: a single-bar, store-scoped drawer filtered by the\n// beat's transaction guid and colored by category, so the drawer still renders instead of crashing.\nexport const FALLBACK: DrillDownVariantConfig = {\n top: 'singleBar',\n filterStrategy: transactionGuidStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionDrawerState, PrimaryCTA, SecondaryCTA } from '../../core';
|
|
1
|
+
import { ActionDrawerState, InDescriptionCTA, PrimaryCTA, SecondaryCTA } from '../../core';
|
|
2
2
|
/**
|
|
3
3
|
* A chart-bar drilldown's context carries which block it targets (see BarchartBlock /
|
|
4
4
|
* DoubleBarChartBlock), since either CTA could in principle open the same drawer. Match that
|
|
@@ -6,8 +6,9 @@ import { ActionDrawerState, PrimaryCTA, SecondaryCTA } from '../../core';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare const getCtaForChartBarClick: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined) => PrimaryCTA | SecondaryCTA | undefined;
|
|
8
8
|
/**
|
|
9
|
-
* Resolves which CTA (primary/secondary) drives the currently open drawer's
|
|
10
|
-
* on what triggered it. Falls back to `primary_cta` whenever resolution comes
|
|
11
|
-
* `secondaryCta` trigger with no configured secondary CTA), so callers never have
|
|
9
|
+
* Resolves which CTA (primary/secondary/in-description) drives the currently open drawer's
|
|
10
|
+
* title/variant, based on what triggered it. Falls back to `primary_cta` whenever resolution comes
|
|
11
|
+
* up empty (e.g. a `secondaryCta` trigger with no configured secondary CTA), so callers never have
|
|
12
|
+
* to null-check.
|
|
12
13
|
*/
|
|
13
|
-
export declare const getDynamicCtaBasedOnTriggers: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined) => PrimaryCTA | SecondaryCTA | undefined;
|
|
14
|
+
export declare const getDynamicCtaBasedOnTriggers: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined, in_description_cta?: InDescriptionCTA) => PrimaryCTA | SecondaryCTA | InDescriptionCTA | undefined;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var
|
|
1
|
+
var n = (e, r, t) => e.context?.block === r?.block ? r : t, i = (e, r, t, g) => e.trigger === "inDescriptionCta" ? g : e.trigger === "secondaryCta" ? t ?? r : e.trigger === "primaryCta" ? r : n(e, r, t) ?? r;
|
|
2
2
|
export {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
n as getCtaForChartBarClick,
|
|
4
|
+
i as getDynamicCtaBasedOnTriggers
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
//# sourceMappingURL=util.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.es.js","names":[],"sources":["../../../src/insights-v2/actionBlocks/util.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"util.es.js","names":[],"sources":["../../../src/insights-v2/actionBlocks/util.ts"],"sourcesContent":["import type {\n ActionDrawerState,\n DrilldownPayload,\n InDescriptionCTA,\n PrimaryCTA,\n SecondaryCTA,\n} from '../../core'\n\n/**\n * A chart-bar drilldown's context carries which block it targets (see BarchartBlock /\n * DoubleBarChartBlock), since either CTA could in principle open the same drawer. Match that\n * against `primary_cta.block`; anything else is assumed to be the secondary CTA's block.\n */\nexport const getCtaForChartBarClick = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n): PrimaryCTA | SecondaryCTA | undefined => {\n const context = actionDrawer.context as DrilldownPayload | undefined\n const blockName = context?.block\n\n if (blockName === primary_cta?.block) {\n return primary_cta\n }\n return secondary_cta\n}\n\n/**\n * Resolves which CTA (primary/secondary/in-description) drives the currently open drawer's\n * title/variant, based on what triggered it. Falls back to `primary_cta` whenever resolution comes\n * up empty (e.g. a `secondaryCta` trigger with no configured secondary CTA), so callers never have\n * to null-check.\n */\nexport const getDynamicCtaBasedOnTriggers = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n in_description_cta?: InDescriptionCTA,\n): PrimaryCTA | SecondaryCTA | InDescriptionCTA | undefined => {\n // The description link names its own block and variant, like a CTA. Only its button fires this\n // trigger, so there is no other CTA to fall back to.\n if (actionDrawer.trigger === 'inDescriptionCta') {\n return in_description_cta\n }\n if (actionDrawer.trigger === 'secondaryCta') {\n return secondary_cta ?? primary_cta\n }\n if (actionDrawer.trigger === 'primaryCta') {\n return primary_cta\n }\n return getCtaForChartBarClick(actionDrawer, primary_cta, secondary_cta) ?? primary_cta\n}\n"],"mappings":"AAaA,IAAa,IAAA,CACX,GACA,GACA,MAEgB,EAAa,SACF,UAET,GAAa,QACtB,IAEF,GASI,IAAA,CACX,GACA,GACA,GACA,MAII,EAAa,YAAY,qBACpB,IAEL,EAAa,YAAY,iBACpB,KAAiB,IAEtB,EAAa,YAAY,eACpB,IAEF,EAAuB,GAAc,GAAa,CAAa,KAAK"}
|