@mx-cartographer/experiences 9.4.22 → 9.4.23

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +12 -2
  2. package/dist/core/stores/InsightsV2Store.d.ts +23 -4
  3. package/dist/core/stores/InsightsV2Store.es.js +16 -7
  4. package/dist/core/stores/InsightsV2Store.es.js.map +1 -1
  5. package/dist/core/types/Insights.d.ts +2 -0
  6. package/dist/core/types/localization/InsightsFeedCopy.d.ts +1 -0
  7. package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js +15 -14
  8. package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js.map +1 -1
  9. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.d.ts +1 -2
  10. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.es.js +8 -14
  11. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.es.js.map +1 -1
  12. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js +9 -8
  13. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js.map +1 -1
  14. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.d.ts +3 -0
  15. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js +8 -0
  16. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js.map +1 -0
  17. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.d.ts +2 -1
  18. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.es.js +37 -34
  19. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.es.js.map +1 -1
  20. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js +89 -73
  21. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js.map +1 -1
  22. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.d.ts +1 -1
  23. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js.map +1 -1
  24. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/utils.d.ts +1 -1
  25. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/utils.es.js.map +1 -1
  26. package/dist/insights-v2/actionBlocks/util.d.ts +13 -0
  27. package/dist/insights-v2/actionBlocks/util.es.js +7 -0
  28. package/dist/insights-v2/actionBlocks/util.es.js.map +1 -0
  29. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js +19 -15
  30. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js.map +1 -1
  31. package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js +15 -13
  32. package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js.map +1 -1
  33. package/dist/insights-v2/blocks/ChartBlocks/StepChartBlock/StepChartBlock.d.ts +1 -1
  34. package/dist/insights-v2/blocks/ChartBlocks/StepChartBlock/StepChartBlock.es.js.map +1 -1
  35. package/dist/insights-v2/mappings/actionBlocksKey.d.ts +6 -0
  36. package/dist/insights-v2/mappings/actionBlocksKey.es.js +11 -0
  37. package/dist/insights-v2/mappings/actionBlocksKey.es.js.map +1 -0
  38. package/dist/insights-v2/mappings/blocks.es.js +47 -46
  39. package/dist/insights-v2/mappings/blocks.es.js.map +1 -1
  40. package/package.json +1 -1
@@ -1,89 +1,105 @@
1
- import { useInsightsV2Store as E } from "../../../common/context/hooks.es.js";
2
- import { formatCurrency as M } from "../../../core/utils/NumberFormatting.es.js";
3
- import { BarChartV2 as N } from "../../components/chartblocks/BarchartV2.es.js";
4
- import { EmptyBarChart as P } from "../../components/chartblocks/EmptyBarChart.es.js";
5
- import { TransactionDrillDown as R } from "./TransactionDrillDown.es.js";
6
- import { useTransactionHistory as q } from "./useTransactionHistory.es.js";
7
- import { getDefaultSelection as z, getDrillDownConfig as J, getFlattenedDataSeries as O, toStoreFilter as Q } from "./utils.es.js";
8
- import { useLayoutEffect as U, useState as W } from "react";
9
- import { observer as X } from "mobx-react-lite";
10
- import { jsx as m } from "react/jsx-runtime";
11
- import { useTheme as Y } from "@mui/material/styles";
12
- var ct = X(({ beat: e }) => {
13
- const g = Y(), { instanceSlotData: a, beatTransactions: n, primaryTransaction: T, spendCategoryGuids: u, allAccountGuids: p, categoryName: C, displayedDateRange: l, transactionStore: v } = q(e), { actionDrawer: h } = E(), { insights_payload: y } = e, D = h.trigger === "secondaryCta" ? y?.secondary_cta?.variant : y?.primary_cta?.variant, { top: c, filterMode: i, header: S, colors: x, filterStrategy: L } = J(D ?? ""), { dataSeries: s, chartData: o, comparisonBars: B } = O({
14
- data: a?.data_series,
15
- ariaLabel: a?.ariaLabel ?? "",
16
- top: c,
17
- beatTransactions: n,
18
- payload: a
19
- }), { chartBarIndex: I, subTabIndex: _ } = z({
20
- chartTabCount: o.length,
21
- comparisonTabCount: B.length,
1
+ import { useGlobalCopyStore as q, useGlobalUiStore as z, useInsightsV2Store as J } from "../../../common/context/hooks.es.js";
2
+ import Q from "../../../common/components/drawer/Drawer.es.js";
3
+ import { formatCurrency as W } from "../../../core/utils/NumberFormatting.es.js";
4
+ import X from "../../../common/components/Loader.es.js";
5
+ import { BarChartV2 as Y } from "../../components/chartblocks/BarchartV2.es.js";
6
+ import { EmptyBarChart as Z } from "../../components/chartblocks/EmptyBarChart.es.js";
7
+ import { TransactionDrillDown as tt } from "./TransactionDrillDown.es.js";
8
+ import { useTransactionHistory as et } from "./useTransactionHistory.es.js";
9
+ import { getDefaultSelection as at, getDrillDownConfig as ot, getFlattenedDataSeries as rt, toStoreFilter as nt } from "./utils.es.js";
10
+ import { TransactionDetailsBlock as it } from "../TransactionDetailsBlock/TransactionDetailsBlock.es.js";
11
+ import { useLayoutEffect as st, useState as S } from "react";
12
+ import { observer as lt } from "mobx-react-lite";
13
+ import { Fragment as ct, jsx as o, jsxs as dt } from "react/jsx-runtime";
14
+ import { useTheme as mt } from "@mui/material/styles";
15
+ var xt = lt(({ beat: a }) => {
16
+ const g = mt(), { instanceSlotData: e, beatTransactions: i, primaryTransaction: _, spendCategoryGuids: p, allAccountGuids: u, categoryName: v, displayedDateRange: c, transactionStore: L } = et(a), { actionDrawer: h, setActionContext: y } = J(), { common: x, insights_feed: B } = q(), { isCopyLoaded: I } = z(), [F, f] = S(!1), { insights_payload: b } = a, G = h.trigger === "secondaryCta" ? b?.secondary_cta?.variant : b?.primary_cta?.variant, { top: d, filterMode: s, header: A, colors: j, filterStrategy: w } = ot(G ?? ""), { dataSeries: l, chartData: r, comparisonBars: k } = rt({
17
+ data: e?.data_series,
18
+ ariaLabel: e?.ariaLabel ?? "",
19
+ top: d,
20
+ beatTransactions: i,
21
+ payload: e
22
+ }), { chartBarIndex: H, subTabIndex: E } = at({
23
+ chartTabCount: r.length,
24
+ comparisonTabCount: k.length,
22
25
  actionDrawer: h,
23
- beatGuid: e.guid
24
- }), [r, b] = W(I), f = (t) => L({
25
- beat: e,
26
- beatTransactions: n,
27
- dataSeries: s,
26
+ beatGuid: a.guid
27
+ }), [n, C] = S(H), T = (t) => w({
28
+ beat: a,
29
+ beatTransactions: i,
30
+ dataSeries: l,
28
31
  selectedIndex: t,
29
- subIndex: _,
30
- isLastTab: t === s.length - 1,
31
- instanceSlotData: a,
32
- spendCategoryGuids: u,
33
- displayedDateRange: l
34
- }), G = n.map((t) => t.guid).join(","), A = u.join(","), F = p.join(",");
35
- U(() => {
36
- i !== "store" || !s.length || v.setFilter(Q(f(r), {
37
- allAccountGuids: p,
38
- displayedDateRange: l
32
+ subIndex: E,
33
+ isLastTab: t === l.length - 1,
34
+ instanceSlotData: e,
35
+ spendCategoryGuids: p,
36
+ displayedDateRange: c
37
+ }), K = i.map((t) => t.guid).join(","), O = p.join(","), V = u.join(","), D = () => {
38
+ s !== "store" || !l.length || L.setFilter(nt(T(n), {
39
+ allAccountGuids: u,
40
+ displayedDateRange: c
39
41
  }));
42
+ };
43
+ st(() => {
44
+ D();
40
45
  }, [
41
- e.guid,
42
- r,
43
- i,
44
- s.length,
45
- a,
46
- l,
47
- A,
48
- F,
49
- G
46
+ a.guid,
47
+ n,
48
+ s,
49
+ l.length,
50
+ e,
51
+ c,
52
+ O,
53
+ V,
54
+ K
50
55
  ]);
51
- const d = S?.({
52
- htmlTitle: e.html_title,
53
- primaryTransaction: T,
54
- categoryName: C,
55
- selectedDate: o[r]?.date ?? void 0
56
- }), j = x(g, a?.category_guid), [H, w] = (a?.legends ?? []).map((t) => t.label), K = i === "local" ? (t) => f(t).custom ?? (() => !0) : void 0, V = i === "local" ? n : void 0, k = c === "singleBar" || c === "upcomingBill" ? o.length ? /* @__PURE__ */ m(N, {
56
+ const m = A?.({
57
+ htmlTitle: a.html_title,
58
+ primaryTransaction: _,
59
+ categoryName: v,
60
+ selectedDate: r[n]?.date ?? void 0
61
+ }), R = j(g, e?.category_guid), [M, N] = (e?.legends ?? []).map((t) => t.label), P = s === "local" ? (t) => T(t).custom ?? (() => !0) : void 0, U = s === "local" ? i : void 0, $ = d === "singleBar" || d === "upcomingBill" ? r.length ? /* @__PURE__ */ o(Y, {
57
62
  amounts: {
58
- average: a?.average_amount,
59
- formattedAverage: M(a?.average_amount ?? 0, "0,0.00")
63
+ average: e?.average_amount,
64
+ formattedAverage: W(e?.average_amount ?? 0, "0,0.00")
60
65
  },
61
- color: j[0] ?? g.palette.primary.main,
62
- data: o,
66
+ color: R[0] ?? g.palette.primary.main,
67
+ data: r,
63
68
  legendPosition: "top",
64
- monthlyAmountLabel: H,
65
- onBarClick: b,
66
- selectedTabIndex: r,
67
- trendAmountLabel: w
68
- }) : /* @__PURE__ */ m(P, {}) : null;
69
- return /* @__PURE__ */ m(R, {
70
- ariaLabel: a?.ariaLabel,
71
- baseTransactions: V,
72
- heading: d?.heading,
73
- icon: d?.icon,
74
- onSelectionChange: b,
75
- selectedIndex: r,
76
- subHeadingText: d?.subHeadingText,
77
- tabs: o.map((t) => ({
69
+ monthlyAmountLabel: M,
70
+ onBarClick: C,
71
+ selectedTabIndex: n,
72
+ trendAmountLabel: N
73
+ }) : /* @__PURE__ */ o(Z, {}) : null;
74
+ return I ? /* @__PURE__ */ dt(ct, { children: [/* @__PURE__ */ o(tt, {
75
+ ariaLabel: e?.ariaLabel,
76
+ baseTransactions: U,
77
+ heading: m?.heading,
78
+ icon: m?.icon,
79
+ onSelectionChange: C,
80
+ selectedIndex: n,
81
+ subHeadingText: m?.subHeadingText,
82
+ tabs: r.map((t) => ({
78
83
  ariaLabel: t.ariaLabel,
79
84
  label: t.label
80
85
  })),
81
- top: k,
82
- transactionFilter: K
83
- });
86
+ top: $,
87
+ transactionFilter: P,
88
+ onEachRowClick: (t) => {
89
+ y({ transaction_guid: t }), f(!0);
90
+ }
91
+ }), /* @__PURE__ */ o(Q, {
92
+ ariaLabelClose: x.close_aria,
93
+ isOpen: F,
94
+ onClose: () => {
95
+ f(!1), y({ transaction_guid: void 0 }), D();
96
+ },
97
+ title: B.general.transaction_details_title,
98
+ children: /* @__PURE__ */ o(it, { beat: a })
99
+ })] }) : /* @__PURE__ */ o(X, {});
84
100
  });
85
101
  export {
86
- ct as TransactionHistoryBlock
102
+ xt as TransactionHistoryBlock
87
103
  };
88
104
 
89
105
  //# sourceMappingURL=TransactionHistoryBlock.es.js.map
@@ -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 { useInsightsV2Store } from '../../../common'\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 primaryTransaction,\n spendCategoryGuids,\n allAccountGuids,\n categoryName,\n displayedDateRange,\n transactionStore,\n } = useTransactionHistory(beat)\n\n const { actionDrawer } = useInsightsV2Store()\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 } = 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 // 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 if (filterMode !== 'store' || !dataSeries.length) return\n transactionStore.setFilter(\n toStoreFilter(resolveFilter(selectedIndex), { allAccountGuids, displayedDateRange }),\n )\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 htmlTitle: beat.html_title,\n primaryTransaction,\n categoryName,\n selectedDate: chartData[selectedIndex]?.date ?? undefined,\n })\n\n const barColors = colors(theme, instanceSlotData?.category_guid)\n const [monthlyAmountLabel, trendAmountLabel] = (instanceSlotData?.legends ?? []).map(\n (legend) => legend.label,\n )\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 monthlyAmountLabel={monthlyAmountLabel}\n onBarClick={setSelectedIndex}\n selectedTabIndex={selectedIndex}\n trendAmountLabel={trendAmountLabel}\n />\n ) : (\n <EmptyBarChart />\n )\n\n return (\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 transactionFilter={transactionFilter}\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 { Drawer, useInsightsV2Store, useGlobalCopyStore, useGlobalUiStore, Loader } 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 primaryTransaction,\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 { 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 } = 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 htmlTitle: beat.html_title,\n primaryTransaction,\n categoryName,\n selectedDate: chartData[selectedIndex]?.date ?? undefined,\n })\n\n const barColors = colors(theme, instanceSlotData?.category_guid)\n const [monthlyAmountLabel, trendAmountLabel] = (instanceSlotData?.legends ?? []).map(\n (legend) => legend.label,\n )\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 monthlyAmountLabel={monthlyAmountLabel}\n onBarClick={setSelectedIndex}\n selectedTabIndex={selectedIndex}\n trendAmountLabel={trendAmountLabel}\n />\n ) : (\n <EmptyBarChart />\n )\n if (!isCopyLoaded) return <Loader />\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 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})\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { Theme } from '@mui/material/styles';
3
3
  import { Beat, Transaction } from '../../../core';
4
4
  import { TransactionFilter } from '../../../core/stores/TransactionStore';
5
5
  import { InsightsInstanceSlotData } from '../../../core/types/InsightsInstanceSlotData';
6
- import { ChartDataSeriesItem } from '../../blocks';
6
+ import { ChartDataSeriesItem } from '../../blocks/ChartBlocks/BarchartBlock/utils';
7
7
  export interface DrillDownHeader {
8
8
  heading?: string;
9
9
  subHeadingText?: string;
@@ -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 type { Beat, Transaction } 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 { ChartDataSeriesItem } from '../../blocks'\n\nexport interface DrillDownHeader {\n heading?: string\n subHeadingText?: string\n icon?: ReactNode\n}\n\nexport interface DrillDownHeaderContext {\n htmlTitle?: string\n primaryTransaction?: Transaction\n categoryName: string\n selectedDate?: string | Date\n}\n\nexport const DRILLDOWN_VARIANTS = {\n TRANSACTION: 'bill_amount_not_standard',\n CATEGORY_SPEND: 'category_spend',\n MONTHLY_SPEND: 'monthly_spend_comparison',\n ACCOUNT_BALANCE: 'savings_account_balances_summary',\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 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 return {\n heading: ctx.htmlTitle,\n subHeadingText: ctx.primaryTransaction?.description || undefined,\n icon: (\n <MerchantLogo\n alt={ctx.primaryTransaction?.description}\n categoryGuid={ctx.primaryTransaction?.category_guid || ''}\n merchantGuid={ctx.primaryTransaction?.merchant_guid || ''}\n size={16}\n />\n ),\n }\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 type { Beat, Transaction } 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'\n\nexport interface DrillDownHeader {\n heading?: string\n subHeadingText?: string\n icon?: ReactNode\n}\n\nexport interface DrillDownHeaderContext {\n htmlTitle?: string\n primaryTransaction?: Transaction\n categoryName: string\n selectedDate?: string | Date\n}\n\nexport const DRILLDOWN_VARIANTS = {\n TRANSACTION: 'bill_amount_not_standard',\n CATEGORY_SPEND: 'category_spend',\n MONTHLY_SPEND: 'monthly_spend_comparison',\n ACCOUNT_BALANCE: 'savings_account_balances_summary',\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 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 return {\n heading: ctx.htmlTitle,\n subHeadingText: ctx.primaryTransaction?.description || undefined,\n icon: (\n <MerchantLogo\n alt={ctx.primaryTransaction?.description}\n categoryGuid={ctx.primaryTransaction?.category_guid || ''}\n merchantGuid={ctx.primaryTransaction?.merchant_guid || ''}\n size={16}\n />\n ),\n }\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,7 +1,7 @@
1
1
  import { ActionDrawerState, DataSeries, GlobalCopy, Transaction } from '../../../core';
2
2
  import { DataSet } from '../../../core/types/InsightsInstanceSlotData';
3
3
  import { TransactionFilter } from '../../../core/stores/TransactionStore';
4
- import { buildChartData, ChartDataSeriesItem } from '../../blocks';
4
+ import { buildChartData, ChartDataSeriesItem } from '../../blocks/ChartBlocks/BarchartBlock/utils';
5
5
  import { DrillDownVariantConfig } from './layout';
6
6
  interface DefaultSelectionProp {
7
7
  chartTabCount: number;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/utils.ts"],"sourcesContent":["import { format, fromUnixTime } from 'date-fns'\n\nimport type {\n ActionDrawerState,\n DataSeries,\n DrilldownPayload,\n GlobalCopy,\n Transaction,\n} from '../../../core'\nimport { DATE_FORMATS_INTL } from '../../../core/constants'\nimport type { DataSet } from '../../../core/types/InsightsInstanceSlotData'\nimport type { TransactionFilter } from '../../../core/stores/TransactionStore'\nimport { buildChartData, buildDataSeries, ChartDataSeriesItem } from '../../blocks'\nimport {\n layout,\n FALLBACK,\n DRILLDOWN_VARIANTS,\n DrillDownVariant,\n DrillDownVariantConfig,\n} from './layout'\nimport { TransactionHistoryBlock } from '../../../core/types/localization/InsightsFeedCopy'\n\ninterface DefaultSelectionProp {\n chartTabCount: number\n comparisonTabCount: number\n actionDrawer: ActionDrawerState\n beatGuid: string\n}\nexport const getDrillDownConfig = (variant?: string): DrillDownVariantConfig =>\n layout[variant as DrillDownVariant] ?? FALLBACK\n\n// The shaped chart inputs a drill-down needs, derived once from the beat's data_series. `dataSeries`\n// is the flat per-bar source (indexes the filterStrategy); `chartData` feeds the single-bar chart;\n// `comparisonBars` is reserved for the double-bar MR (empty until then).\nexport interface FlattenedDataSeries {\n dataSeries: ChartDataSeriesItem[]\n chartData: ReturnType<typeof buildChartData>\n comparisonBars: DataSet[]\n}\n\n/**\n * Shapes the beat's raw data_series into the chart inputs for the variant's top kind. This MR handles\n * the single-bar family (singleBar / upcomingBill); the double-bar and tabsOnly branches are stubbed\n * for the next MR so the call site is already wired.\n */\ninterface FlattenedDataSeriesInput {\n data: DataSeries | undefined\n ariaLabel: string\n top: DrillDownVariantConfig['top']\n // UpcomingBill has no data_series; it builds its bars from these instead.\n beatTransactions: Transaction[]\n payload: { date?: string; amount?: number } | undefined\n}\n\nexport const getFlattenedDataSeries = ({\n data,\n ariaLabel,\n top,\n beatTransactions,\n payload,\n}: FlattenedDataSeriesInput): FlattenedDataSeries => {\n // UpcomingBill has no backend data_series: synthesize the bars from the beat's recurring-bill\n // transactions + the projected bill, and label each bar by day (MONTH_DAY) since a bar is one bill.\n if (top === 'upcomingBill') {\n const dataSeries = buildUpcomingBillSeries(beatTransactions, payload)\n return {\n dataSeries,\n chartData: buildChartData(dataSeries, ariaLabel, DATE_FORMATS_INTL.MONTH_DAY),\n comparisonBars: [],\n }\n }\n\n // Single-bar family (THIS MR): the backend sends data_series newest-first, so normalize it\n // date-ascending here. chartData/tabs and the filter's dataSeries[selectedIndex] indexing both read\n // this one array, so they stay aligned and the last tab is the most recent month.\n const dataSeries = [...buildDataSeries(data)].sort((a, b) => {\n if (!a.date || !b.date) return 0\n\n return new Date(a.date).getTime() - new Date(b.date).getTime()\n })\n\n // NEXT MR — double bar: comparison beats build paired bars instead of chartData.\n // if (top === \"doubleBar\") {\n // return { dataSeries, chartData: [], comparisonBars: buildComparisonSeries(data, ariaLabel) };\n // }\n //\n // NEXT MR — tabsOnly: donut-drawer beats render no top chart.\n // if (top === \"tabsOnly\") {\n // return { dataSeries, chartData: [], comparisonBars: [] };\n // }\n\n return { dataSeries, chartData: buildChartData(dataSeries, ariaLabel), comparisonBars: [] }\n}\n\n// Sentinel guid for the synthesized projected bill. It intentionally matches no real store\n// transaction, so the projected tab's guid filter yields an empty list (projected-bar-only scope).\nexport const PROJECTED_BILL_GUID = 'TRN-projected-bill'\n\n// One bar in the UpcomingBill chart. `date` is 'yyyy-MM-dd' so buildChartData/parseISO can read both\n// historical unix timestamps and the ISO payload date after normalization here.\nexport interface UpcomingBillBar {\n date: string\n amount: number\n guid: string\n category_guid?: string\n}\n\nconst toUpcomingBillBar = (transaction: Transaction): UpcomingBillBar => ({\n date: format(fromUnixTime(transaction.date), 'yyyy-MM-dd'),\n amount: transaction.amount,\n guid: transaction.guid,\n category_guid: transaction.top_level_category_guid ?? transaction.category_guid,\n})\n\n/**\n * UpcomingBill has no data_series: build the bar series straight from the beat's recurring-bill\n * transactions plus the synthesized projected bill from payload (mirrors pulse's magicTransactions).\n * Historical bills are de-duped by date and each keeps its real transaction guid so the guid filter\n * finds it in the store; the projected bar (cloned category from the latest bill) carries the\n * PROJECTED_BILL_GUID sentinel. The result is sorted date-ascending so the projected bill lands last.\n */\nexport const buildUpcomingBillSeries = (\n transactions: Transaction[] = [],\n payload: { date?: string; amount?: number } | undefined,\n): UpcomingBillBar[] => {\n if (!transactions.length || payload?.date == null || payload?.amount == null) {\n return []\n }\n\n const sorted = [...transactions].sort((a, b) => a.date - b.date)\n\n const seenDates = new Set<number>()\n const history: UpcomingBillBar[] = []\n for (const transaction of sorted) {\n if (seenDates.has(transaction.date)) continue\n seenDates.add(transaction.date)\n history.push(toUpcomingBillBar(transaction))\n }\n\n const latestBill = sorted[sorted.length - 1]\n const projected: UpcomingBillBar = {\n date: payload.date,\n amount: payload.amount,\n guid: PROJECTED_BILL_GUID,\n category_guid: latestBill.top_level_category_guid ?? latestBill.category_guid,\n }\n\n return [...history, projected]\n}\n\nexport const getDrawerHeaderTitle = (\n variant: string | null | undefined,\n copy: GlobalCopy,\n): string => {\n const transactionHistoryTitle = copy.insights_feed?.general?.transaction_history_title ?? ''\n const drawerTitleCopy = copy.insights_feed?.transaction_history_block as TransactionHistoryBlock\n\n if (variant === DRILLDOWN_VARIANTS.TRANSACTION) return transactionHistoryTitle\n\n // Safely access the drawer title from transaction_history_block\n const key = `${variant}_drawer_title` as keyof TransactionHistoryBlock\n return (drawerTitleCopy?.[key] as string) ?? transactionHistoryTitle\n}\n\nexport const toStoreFilter = (\n filter: TransactionFilter,\n defaults: { allAccountGuids: string[]; displayedDateRange: { start: Date; end: Date } },\n): TransactionFilter => ({\n accounts: filter.accounts ?? defaults.allAccountGuids,\n dateRange: filter.dateRange ?? defaults.displayedDateRange,\n custom: filter.custom ?? (() => true),\n showSplits: filter.showSplits ?? false,\n})\n\nexport const getDefaultSelection = ({\n chartTabCount,\n actionDrawer,\n beatGuid,\n}: DefaultSelectionProp): { chartBarIndex: number; subTabIndex: number } => {\n const openedViaChartBar = actionDrawer.guid === beatGuid && actionDrawer.trigger === 'chartBar'\n\n // actionDrawer.context is an opaque `unknown` bag; narrow it to the shape the chart blocks write.\n const context = actionDrawer.context as DrilldownPayload | undefined\n const subTabIndex = openedViaChartBar ? (context?.tabIndex ?? 0) : 0\n\n if (openedViaChartBar) {\n const clamped = Math.min(\n Math.max(context?.chartBarIndex ?? 0, 0),\n Math.max(0, chartTabCount - 1),\n )\n return { chartBarIndex: clamped, subTabIndex }\n }\n\n return { chartBarIndex: Math.max(0, chartTabCount - 1), subTabIndex }\n}\n"],"mappings":";;;;AA4BA,IAAa,IAAA,CAAsB,MACjC,EAAO,CAAA,KAAgC,GAyB5B,IAAA,CAA0B,EACrC,MAAA,GACA,WAAA,GACA,KAAA,GACA,kBAAA,GACA,SAAA,EAAA,MACmD;AAGnD,MAAI,MAAQ,gBAAgB;AAC1B,UAAM,IAAa,EAAwB,GAAkB,CAAO;AACpE,WAAO;AAAA,MACL,YAAA;AAAA,MACA,WAAW,EAAe,GAAY,GAAW,EAAkB,SAAS;AAAA,MAC5E,gBAAgB,CAAC;AAAA,IACnB;AAAA,EACF;AAKA,QAAM,IAAa,CAAC,GAAG,EAAgB,CAAI,CAAC,EAAE,KAAA,CAAM,GAAG,MACjD,CAAC,EAAE,QAAQ,CAAC,EAAE,OAAa,IAExB,IAAI,KAAK,EAAE,IAAI,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,IAAI,EAAE,QAAQ,CAC9D;AAYD,SAAO;AAAA,IAAE,YAAA;AAAA,IAAY,WAAW,EAAe,GAAY,CAAS;AAAA,IAAG,gBAAgB,CAAC;AAAA,EAAE;AAC5F,GAIa,IAAsB,sBAW7B,IAAA,CAAqB,OAA+C;AAAA,EACxE,MAAM,EAAO,EAAa,EAAY,IAAI,GAAG,YAAY;AAAA,EACzD,QAAQ,EAAY;AAAA,EACpB,MAAM,EAAY;AAAA,EAClB,eAAe,EAAY,2BAA2B,EAAY;AACpE,IASa,IAAA,CACX,IAA8B,CAAC,GAC/B,MACsB;AACtB,MAAI,CAAC,EAAa,UAAU,GAAS,QAAQ,QAAQ,GAAS,UAAU,KACtE,QAAO,CAAC;AAGV,QAAM,IAAS,CAAC,GAAG,CAAY,EAAE,KAAA,CAAM,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,GAEzD,IAAY,oBAAI,IAAY,GAC5B,IAA6B,CAAC;AACpC,aAAW,KAAe;AACxB,IAAI,EAAU,IAAI,EAAY,IAAI,MAClC,EAAU,IAAI,EAAY,IAAI,GAC9B,EAAQ,KAAK,EAAkB,CAAW,CAAC;AAG7C,QAAM,IAAa,EAAO,EAAO,SAAS,CAAA,GACpC,IAA6B;AAAA,IACjC,MAAM,EAAQ;AAAA,IACd,QAAQ,EAAQ;AAAA,IAChB,MAAM;AAAA,IACN,eAAe,EAAW,2BAA2B,EAAW;AAAA,EAClE;AAEA,SAAO,CAAC,GAAG,GAAS,CAAS;AAC/B,GAEa,IAAA,CACX,GACA,MACW;AACX,QAAM,IAA0B,EAAK,eAAe,SAAS,6BAA6B,IACpF,IAAkB,EAAK,eAAe;AAE5C,MAAI,MAAY,EAAmB,YAAa,QAAO;AAGvD,QAAM,IAAM,GAAG,CAAA;AACf,SAAQ,IAAkB,CAAA,KAAmB;AAC/C,GAEa,IAAA,CACX,GACA,OACuB;AAAA,EACvB,UAAU,EAAO,YAAY,EAAS;AAAA,EACtC,WAAW,EAAO,aAAa,EAAS;AAAA,EACxC,QAAQ,EAAO,WAAA,MAAiB;AAAA,EAChC,YAAY,EAAO,cAAc;AACnC,IAEa,IAAA,CAAuB,EAClC,eAAA,GACA,cAAA,GACA,UAAA,EAAA,MAC0E;AAC1E,QAAM,IAAoB,EAAa,SAAS,KAAY,EAAa,YAAY,YAG/E,IAAU,EAAa,SACvB,IAAc,IAAqB,GAAS,YAAY,IAAK;AAEnE,SAAI,IAKK;AAAA,IAAE,eAJO,KAAK,IACnB,KAAK,IAAI,GAAS,iBAAiB,GAAG,CAAC,GACvC,KAAK,IAAI,GAAG,IAAgB,CAAC,CAEP;AAAA,IAAS,aAAA;AAAA,EAAY,IAGxC;AAAA,IAAE,eAAe,KAAK,IAAI,GAAG,IAAgB,CAAC;AAAA,IAAG,aAAA;AAAA,EAAY;AACtE"}
1
+ {"version":3,"file":"utils.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/utils.ts"],"sourcesContent":["import { format, fromUnixTime } from 'date-fns'\n\nimport type {\n ActionDrawerState,\n DataSeries,\n DrilldownPayload,\n GlobalCopy,\n Transaction,\n} from '../../../core'\nimport { DATE_FORMATS_INTL } from '../../../core/constants'\nimport type { DataSet } from '../../../core/types/InsightsInstanceSlotData'\nimport type { TransactionFilter } from '../../../core/stores/TransactionStore'\nimport {\n buildChartData,\n buildDataSeries,\n type ChartDataSeriesItem,\n} from '../../blocks/ChartBlocks/BarchartBlock/utils'\nimport {\n layout,\n FALLBACK,\n DRILLDOWN_VARIANTS,\n DrillDownVariant,\n DrillDownVariantConfig,\n} from './layout'\nimport { TransactionHistoryBlock } from '../../../core/types/localization/InsightsFeedCopy'\n\ninterface DefaultSelectionProp {\n chartTabCount: number\n comparisonTabCount: number\n actionDrawer: ActionDrawerState\n beatGuid: string\n}\nexport const getDrillDownConfig = (variant?: string): DrillDownVariantConfig =>\n layout[variant as DrillDownVariant] ?? FALLBACK\n\n// The shaped chart inputs a drill-down needs, derived once from the beat's data_series. `dataSeries`\n// is the flat per-bar source (indexes the filterStrategy); `chartData` feeds the single-bar chart;\n// `comparisonBars` is reserved for the double-bar MR (empty until then).\nexport interface FlattenedDataSeries {\n dataSeries: ChartDataSeriesItem[]\n chartData: ReturnType<typeof buildChartData>\n comparisonBars: DataSet[]\n}\n\n/**\n * Shapes the beat's raw data_series into the chart inputs for the variant's top kind. This MR handles\n * the single-bar family (singleBar / upcomingBill); the double-bar and tabsOnly branches are stubbed\n * for the next MR so the call site is already wired.\n */\ninterface FlattenedDataSeriesInput {\n data: DataSeries | undefined\n ariaLabel: string\n top: DrillDownVariantConfig['top']\n // UpcomingBill has no data_series; it builds its bars from these instead.\n beatTransactions: Transaction[]\n payload: { date?: string; amount?: number } | undefined\n}\n\nexport const getFlattenedDataSeries = ({\n data,\n ariaLabel,\n top,\n beatTransactions,\n payload,\n}: FlattenedDataSeriesInput): FlattenedDataSeries => {\n // UpcomingBill has no backend data_series: synthesize the bars from the beat's recurring-bill\n // transactions + the projected bill, and label each bar by day (MONTH_DAY) since a bar is one bill.\n if (top === 'upcomingBill') {\n const dataSeries = buildUpcomingBillSeries(beatTransactions, payload)\n return {\n dataSeries,\n chartData: buildChartData(dataSeries, ariaLabel, DATE_FORMATS_INTL.MONTH_DAY),\n comparisonBars: [],\n }\n }\n\n // Single-bar family (THIS MR): the backend sends data_series newest-first, so normalize it\n // date-ascending here. chartData/tabs and the filter's dataSeries[selectedIndex] indexing both read\n // this one array, so they stay aligned and the last tab is the most recent month.\n const dataSeries = [...buildDataSeries(data)].sort((a, b) => {\n if (!a.date || !b.date) return 0\n\n return new Date(a.date).getTime() - new Date(b.date).getTime()\n })\n\n // NEXT MR — double bar: comparison beats build paired bars instead of chartData.\n // if (top === \"doubleBar\") {\n // return { dataSeries, chartData: [], comparisonBars: buildComparisonSeries(data, ariaLabel) };\n // }\n //\n // NEXT MR — tabsOnly: donut-drawer beats render no top chart.\n // if (top === \"tabsOnly\") {\n // return { dataSeries, chartData: [], comparisonBars: [] };\n // }\n\n return { dataSeries, chartData: buildChartData(dataSeries, ariaLabel), comparisonBars: [] }\n}\n\n// Sentinel guid for the synthesized projected bill. It intentionally matches no real store\n// transaction, so the projected tab's guid filter yields an empty list (projected-bar-only scope).\nexport const PROJECTED_BILL_GUID = 'TRN-projected-bill'\n\n// One bar in the UpcomingBill chart. `date` is 'yyyy-MM-dd' so buildChartData/parseISO can read both\n// historical unix timestamps and the ISO payload date after normalization here.\nexport interface UpcomingBillBar {\n date: string\n amount: number\n guid: string\n category_guid?: string\n}\n\nconst toUpcomingBillBar = (transaction: Transaction): UpcomingBillBar => ({\n date: format(fromUnixTime(transaction.date), 'yyyy-MM-dd'),\n amount: transaction.amount,\n guid: transaction.guid,\n category_guid: transaction.top_level_category_guid ?? transaction.category_guid,\n})\n\n/**\n * UpcomingBill has no data_series: build the bar series straight from the beat's recurring-bill\n * transactions plus the synthesized projected bill from payload (mirrors pulse's magicTransactions).\n * Historical bills are de-duped by date and each keeps its real transaction guid so the guid filter\n * finds it in the store; the projected bar (cloned category from the latest bill) carries the\n * PROJECTED_BILL_GUID sentinel. The result is sorted date-ascending so the projected bill lands last.\n */\nexport const buildUpcomingBillSeries = (\n transactions: Transaction[] = [],\n payload: { date?: string; amount?: number } | undefined,\n): UpcomingBillBar[] => {\n if (!transactions.length || payload?.date == null || payload?.amount == null) {\n return []\n }\n\n const sorted = [...transactions].sort((a, b) => a.date - b.date)\n\n const seenDates = new Set<number>()\n const history: UpcomingBillBar[] = []\n for (const transaction of sorted) {\n if (seenDates.has(transaction.date)) continue\n seenDates.add(transaction.date)\n history.push(toUpcomingBillBar(transaction))\n }\n\n const latestBill = sorted[sorted.length - 1]\n const projected: UpcomingBillBar = {\n date: payload.date,\n amount: payload.amount,\n guid: PROJECTED_BILL_GUID,\n category_guid: latestBill.top_level_category_guid ?? latestBill.category_guid,\n }\n\n return [...history, projected]\n}\n\nexport const getDrawerHeaderTitle = (\n variant: string | null | undefined,\n copy: GlobalCopy,\n): string => {\n const transactionHistoryTitle = copy.insights_feed?.general?.transaction_history_title ?? ''\n const drawerTitleCopy = copy.insights_feed?.transaction_history_block as TransactionHistoryBlock\n\n if (variant === DRILLDOWN_VARIANTS.TRANSACTION) return transactionHistoryTitle\n\n // Safely access the drawer title from transaction_history_block\n const key = `${variant}_drawer_title` as keyof TransactionHistoryBlock\n return (drawerTitleCopy?.[key] as string) ?? transactionHistoryTitle\n}\n\nexport const toStoreFilter = (\n filter: TransactionFilter,\n defaults: { allAccountGuids: string[]; displayedDateRange: { start: Date; end: Date } },\n): TransactionFilter => ({\n accounts: filter.accounts ?? defaults.allAccountGuids,\n dateRange: filter.dateRange ?? defaults.displayedDateRange,\n custom: filter.custom ?? (() => true),\n showSplits: filter.showSplits ?? false,\n})\n\nexport const getDefaultSelection = ({\n chartTabCount,\n actionDrawer,\n beatGuid,\n}: DefaultSelectionProp): { chartBarIndex: number; subTabIndex: number } => {\n const openedViaChartBar = actionDrawer.guid === beatGuid && actionDrawer.trigger === 'chartBar'\n\n // actionDrawer.context is an opaque `unknown` bag; narrow it to the shape the chart blocks write.\n const context = actionDrawer.context as DrilldownPayload | undefined\n const subTabIndex = openedViaChartBar ? (context?.tabIndex ?? 0) : 0\n\n if (openedViaChartBar) {\n const clamped = Math.min(\n Math.max(context?.chartBarIndex ?? 0, 0),\n Math.max(0, chartTabCount - 1),\n )\n return { chartBarIndex: clamped, subTabIndex }\n }\n\n return { chartBarIndex: Math.max(0, chartTabCount - 1), subTabIndex }\n}\n"],"mappings":";;;;AAgCA,IAAa,IAAA,CAAsB,MACjC,EAAO,CAAA,KAAgC,GAyB5B,IAAA,CAA0B,EACrC,MAAA,GACA,WAAA,GACA,KAAA,GACA,kBAAA,GACA,SAAA,EAAA,MACmD;AAGnD,MAAI,MAAQ,gBAAgB;AAC1B,UAAM,IAAa,EAAwB,GAAkB,CAAO;AACpE,WAAO;AAAA,MACL,YAAA;AAAA,MACA,WAAW,EAAe,GAAY,GAAW,EAAkB,SAAS;AAAA,MAC5E,gBAAgB,CAAC;AAAA,IACnB;AAAA,EACF;AAKA,QAAM,IAAa,CAAC,GAAG,EAAgB,CAAI,CAAC,EAAE,KAAA,CAAM,GAAG,MACjD,CAAC,EAAE,QAAQ,CAAC,EAAE,OAAa,IAExB,IAAI,KAAK,EAAE,IAAI,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,IAAI,EAAE,QAAQ,CAC9D;AAYD,SAAO;AAAA,IAAE,YAAA;AAAA,IAAY,WAAW,EAAe,GAAY,CAAS;AAAA,IAAG,gBAAgB,CAAC;AAAA,EAAE;AAC5F,GAIa,IAAsB,sBAW7B,IAAA,CAAqB,OAA+C;AAAA,EACxE,MAAM,EAAO,EAAa,EAAY,IAAI,GAAG,YAAY;AAAA,EACzD,QAAQ,EAAY;AAAA,EACpB,MAAM,EAAY;AAAA,EAClB,eAAe,EAAY,2BAA2B,EAAY;AACpE,IASa,IAAA,CACX,IAA8B,CAAC,GAC/B,MACsB;AACtB,MAAI,CAAC,EAAa,UAAU,GAAS,QAAQ,QAAQ,GAAS,UAAU,KACtE,QAAO,CAAC;AAGV,QAAM,IAAS,CAAC,GAAG,CAAY,EAAE,KAAA,CAAM,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,GAEzD,IAAY,oBAAI,IAAY,GAC5B,IAA6B,CAAC;AACpC,aAAW,KAAe;AACxB,IAAI,EAAU,IAAI,EAAY,IAAI,MAClC,EAAU,IAAI,EAAY,IAAI,GAC9B,EAAQ,KAAK,EAAkB,CAAW,CAAC;AAG7C,QAAM,IAAa,EAAO,EAAO,SAAS,CAAA,GACpC,IAA6B;AAAA,IACjC,MAAM,EAAQ;AAAA,IACd,QAAQ,EAAQ;AAAA,IAChB,MAAM;AAAA,IACN,eAAe,EAAW,2BAA2B,EAAW;AAAA,EAClE;AAEA,SAAO,CAAC,GAAG,GAAS,CAAS;AAC/B,GAEa,IAAA,CACX,GACA,MACW;AACX,QAAM,IAA0B,EAAK,eAAe,SAAS,6BAA6B,IACpF,IAAkB,EAAK,eAAe;AAE5C,MAAI,MAAY,EAAmB,YAAa,QAAO;AAGvD,QAAM,IAAM,GAAG,CAAA;AACf,SAAQ,IAAkB,CAAA,KAAmB;AAC/C,GAEa,IAAA,CACX,GACA,OACuB;AAAA,EACvB,UAAU,EAAO,YAAY,EAAS;AAAA,EACtC,WAAW,EAAO,aAAa,EAAS;AAAA,EACxC,QAAQ,EAAO,WAAA,MAAiB;AAAA,EAChC,YAAY,EAAO,cAAc;AACnC,IAEa,IAAA,CAAuB,EAClC,eAAA,GACA,cAAA,GACA,UAAA,EAAA,MAC0E;AAC1E,QAAM,IAAoB,EAAa,SAAS,KAAY,EAAa,YAAY,YAG/E,IAAU,EAAa,SACvB,IAAc,IAAqB,GAAS,YAAY,IAAK;AAEnE,SAAI,IAKK;AAAA,IAAE,eAJO,KAAK,IACnB,KAAK,IAAI,GAAS,iBAAiB,GAAG,CAAC,GACvC,KAAK,IAAI,GAAG,IAAgB,CAAC,CAEP;AAAA,IAAS,aAAA;AAAA,EAAY,IAGxC;AAAA,IAAE,eAAe,KAAK,IAAI,GAAG,IAAgB,CAAC;AAAA,IAAG,aAAA;AAAA,EAAY;AACtE"}
@@ -0,0 +1,13 @@
1
+ import { ActionDrawerState, PrimaryCTA, SecondaryCTA } from '../../core';
2
+ /**
3
+ * A chart-bar drilldown's context carries which block it targets (see BarchartBlock /
4
+ * DoubleBarChartBlock), since either CTA could in principle open the same drawer. Match that
5
+ * against `primary_cta.block`; anything else is assumed to be the secondary CTA's block.
6
+ */
7
+ export declare const getCtaForChartBarClick: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined) => PrimaryCTA | SecondaryCTA | undefined;
8
+ /**
9
+ * Resolves which CTA (primary/secondary) drives the currently open drawer's title/variant, based
10
+ * on what triggered it. Falls back to `primary_cta` whenever resolution comes up empty (e.g. a
11
+ * `secondaryCta` trigger with no configured secondary CTA), so callers never have to null-check.
12
+ */
13
+ export declare const getDynamicCtaBasedOnTriggers: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined) => PrimaryCTA | SecondaryCTA | undefined;
@@ -0,0 +1,7 @@
1
+ var g = (e, r, t) => e.context?.block === r?.block ? r : t, n = (e, r, t) => e.trigger === "secondaryCta" ? t ?? r : e.trigger === "primaryCta" ? r : g(e, r, t) ?? r;
2
+ export {
3
+ g as getCtaForChartBarClick,
4
+ n as getDynamicCtaBasedOnTriggers
5
+ };
6
+
7
+ //# sourceMappingURL=util.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.es.js","names":[],"sources":["../../../src/insights-v2/actionBlocks/util.ts"],"sourcesContent":["import type { ActionDrawerState, DrilldownPayload, PrimaryCTA, SecondaryCTA } 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) drives the currently open drawer's title/variant, based\n * on what triggered it. Falls back to `primary_cta` whenever resolution comes up empty (e.g. a\n * `secondaryCta` trigger with no configured secondary CTA), so callers never have to null-check.\n */\nexport const getDynamicCtaBasedOnTriggers = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n): PrimaryCTA | SecondaryCTA | undefined => {\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":"AAOA,IAAa,IAAA,CACX,GACA,GACA,MAEgB,EAAa,SACF,UAET,GAAa,QACtB,IAEF,GAQI,IAAA,CACX,GACA,GACA,MAEI,EAAa,YAAY,iBACpB,KAAiB,IAEtB,EAAa,YAAY,eACpB,IAEF,EAAuB,GAAc,GAAa,CAAa,KAAK"}
@@ -1,32 +1,36 @@
1
1
  import { useInsightsV2Store as b } from "../../../../common/context/hooks.es.js";
2
2
  import { formatCurrency as B } from "../../../../core/utils/NumberFormatting.es.js";
3
3
  import { BarChartV2 as C } from "../../../components/chartblocks/BarchartV2.es.js";
4
- import { EmptyBarChart as x } from "../../../components/chartblocks/EmptyBarChart.es.js";
5
- import { barChartVariant as _, buildChartData as v, buildDataSeries as A } from "./utils.es.js";
6
- import D from "react";
7
- import { jsx as o } from "react/jsx-runtime";
8
- import { useTheme as y } from "@mui/material/styles";
9
- var E = ({ payload: n, beatGuid: m = "" }) => {
10
- const s = y(), { openActionDrawer: c } = b(), { instance_slot: i, instance_slot_data: a } = n, { data_series: l, ariaLabel: h = "", average_amount: e = 0, legends: d = [] } = a, t = v(A(l), h), [p] = D.useState(t.length - 1), { color: u } = _(i, a, s), [f, g] = d.map((r) => r.label);
11
- return t.length ? /* @__PURE__ */ o(C, {
4
+ import { EmptyBarChart as _ } from "../../../components/chartblocks/EmptyBarChart.es.js";
5
+ import { barChartVariant as A, buildChartData as I, buildDataSeries as T } from "./utils.es.js";
6
+ import { actionBlocksKey as x } from "../../../mappings/actionBlocksKey.es.js";
7
+ import S from "react";
8
+ import { jsx as e } from "react/jsx-runtime";
9
+ import { useTheme as k } from "@mui/material/styles";
10
+ var j = ({ payload: n, beatGuid: m = "" }) => {
11
+ const c = k(), { openActionDrawer: s } = b(), { instance_slot: i, instance_slot_data: a } = n, { data_series: l, ariaLabel: h = "", average_amount: o = 0, legends: p = [] } = a, t = I(T(l), h), [d] = S.useState(t.length - 1), { color: u } = A(i, a, c), [f, g] = p.map((r) => r.label);
12
+ return t.length ? /* @__PURE__ */ e(C, {
12
13
  amounts: {
13
- average: e,
14
- formattedAverage: B(e, "0,0")
14
+ average: o,
15
+ formattedAverage: B(o, "0,0")
15
16
  },
16
17
  color: u,
17
18
  data: t,
18
19
  monthlyAmountLabel: f,
19
- onBarClick: (r) => c({
20
+ onBarClick: (r) => s({
20
21
  guid: m,
21
22
  trigger: "chartBar",
22
- context: { chartBarIndex: r }
23
+ context: {
24
+ chartBarIndex: r,
25
+ block: x.TRANSCATION_HISTORY_ACTION_BLOCK
26
+ }
23
27
  }),
24
- selectedTabIndex: p,
28
+ selectedTabIndex: d,
25
29
  trendAmountLabel: g
26
- }) : /* @__PURE__ */ o(x, {});
30
+ }) : /* @__PURE__ */ e(_, {});
27
31
  };
28
32
  export {
29
- E as BarchartBlock
33
+ j as BarchartBlock
30
34
  };
31
35
 
32
36
  //# sourceMappingURL=BarchartBlock.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BarchartBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.tsx"],"sourcesContent":["import React from 'react'\nimport { useTheme } from '@mui/material/styles'\n\nimport { formatCurrency, useInsightsV2Store } from '../../../../common'\nimport type { DataSeries, DrilldownPayload } from '../../../../core'\nimport type { BarChartBlockData } from '../../../../core/types/InsightsInstanceSlotData'\n\nimport { BarChartV2 } from '../../../components/chartblocks/BarchartV2'\nimport { EmptyBarChart } from '../../../components/chartblocks/EmptyBarChart'\n\nimport type { BlockProps } from '../../types'\n\nimport { barChartVariant, buildChartData, buildDataSeries } from './utils'\n\nexport const BarchartBlock = ({ payload, beatGuid = '' }: BlockProps<BarChartBlockData>) => {\n const theme = useTheme()\n const { openActionDrawer } = useInsightsV2Store()\n const { instance_slot, instance_slot_data } = payload\n const { data_series, ariaLabel = '', average_amount = 0, legends = [] } = instance_slot_data\n const chartData = buildChartData(buildDataSeries(data_series as DataSeries), ariaLabel)\n const [selectedTabIndex] = React.useState(chartData.length - 1)\n const { color } = barChartVariant(instance_slot, instance_slot_data, theme)\n\n const [monthlyAmountLabel, trendAmountLabel] = legends.map((legend) => legend.label)\n\n return chartData.length ? (\n <BarChartV2\n amounts={{\n average: average_amount,\n formattedAverage: formatCurrency(average_amount, '0,0'),\n }}\n color={color}\n data={chartData}\n monthlyAmountLabel={monthlyAmountLabel}\n onBarClick={(index) =>\n openActionDrawer({\n guid: beatGuid,\n trigger: 'chartBar',\n context: { chartBarIndex: index } satisfies DrilldownPayload,\n })\n }\n selectedTabIndex={selectedTabIndex}\n trendAmountLabel={trendAmountLabel}\n />\n ) : (\n <EmptyBarChart />\n )\n}\n"],"mappings":";;;;;;;;AAcA,IAAa,IAAA,CAAiB,EAAE,SAAA,GAAS,UAAA,IAAW,GAAA,MAAwC;AAC1F,QAAM,IAAQ,EAAS,GACjB,EAAE,kBAAA,EAAA,IAAqB,EAAmB,GAC1C,EAAE,eAAA,GAAe,oBAAA,EAAA,IAAuB,GACxC,EAAE,aAAA,GAAa,WAAA,IAAY,IAAI,gBAAA,IAAiB,GAAG,SAAA,IAAU,CAAC,EAAA,IAAM,GACpE,IAAY,EAAe,EAAgB,CAAyB,GAAG,CAAS,GAChF,CAAC,CAAA,IAAoB,EAAM,SAAS,EAAU,SAAS,CAAC,GACxD,EAAE,OAAA,EAAA,IAAU,EAAgB,GAAe,GAAoB,CAAK,GAEpE,CAAC,GAAoB,CAAA,IAAoB,EAAQ,IAAA,CAAK,MAAW,EAAO,KAAK;AAEnF,SAAO,EAAU,SACf,gBAAA,EAAC,GAAD;AAAA,IACE,SAAS;AAAA,MACP,SAAS;AAAA,MACT,kBAAkB,EAAe,GAAgB,KAAK;AAAA,IACxD;AAAA,IACO,OAAA;AAAA,IACP,MAAM;AAAA,IACc,oBAAA;AAAA,IACpB,YAAA,CAAa,MACX,EAAiB;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS,EAAE,eAAe,EAAM;AAAA,IAClC,CAAC;AAAA,IAEe,kBAAA;AAAA,IACA,kBAAA;AAAA,EACnB,CAAA,IAED,gBAAA,EAAC,GAAD,CAAgB,CAAA;AAEpB"}
1
+ {"version":3,"file":"BarchartBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.tsx"],"sourcesContent":["import React from 'react'\nimport { useTheme } from '@mui/material/styles'\n\nimport { formatCurrency, useInsightsV2Store } from '../../../../common'\nimport type { DataSeries, DrilldownPayload } from '../../../../core'\nimport type { BarChartBlockData } from '../../../../core/types/InsightsInstanceSlotData'\n\nimport { BarChartV2 } from '../../../components/chartblocks/BarchartV2'\nimport { EmptyBarChart } from '../../../components/chartblocks/EmptyBarChart'\n\nimport type { BlockProps } from '../../types'\n\nimport { barChartVariant, buildChartData, buildDataSeries } from './utils'\nimport { actionBlocksKey } from '../../../mappings/actionBlocksKey'\n\nexport const BarchartBlock = ({ payload, beatGuid = '' }: BlockProps<BarChartBlockData>) => {\n const theme = useTheme()\n const { openActionDrawer } = useInsightsV2Store()\n const { instance_slot, instance_slot_data } = payload\n const { data_series, ariaLabel = '', average_amount = 0, legends = [] } = instance_slot_data\n const chartData = buildChartData(buildDataSeries(data_series as DataSeries), ariaLabel)\n const [selectedTabIndex] = React.useState(chartData.length - 1)\n const { color } = barChartVariant(instance_slot, instance_slot_data, theme)\n\n const [monthlyAmountLabel, trendAmountLabel] = legends.map((legend) => legend.label)\n\n return chartData.length ? (\n <BarChartV2\n amounts={{\n average: average_amount,\n formattedAverage: formatCurrency(average_amount, '0,0'),\n }}\n color={color}\n data={chartData}\n monthlyAmountLabel={monthlyAmountLabel}\n onBarClick={(index) =>\n openActionDrawer({\n guid: beatGuid,\n trigger: 'chartBar',\n context: {\n chartBarIndex: index,\n block: actionBlocksKey.TRANSCATION_HISTORY_ACTION_BLOCK,\n } satisfies DrilldownPayload,\n })\n }\n selectedTabIndex={selectedTabIndex}\n trendAmountLabel={trendAmountLabel}\n />\n ) : (\n <EmptyBarChart />\n )\n}\n"],"mappings":";;;;;;;;;AAeA,IAAa,IAAA,CAAiB,EAAE,SAAA,GAAS,UAAA,IAAW,GAAA,MAAwC;AAC1F,QAAM,IAAQ,EAAS,GACjB,EAAE,kBAAA,EAAA,IAAqB,EAAmB,GAC1C,EAAE,eAAA,GAAe,oBAAA,EAAA,IAAuB,GACxC,EAAE,aAAA,GAAa,WAAA,IAAY,IAAI,gBAAA,IAAiB,GAAG,SAAA,IAAU,CAAC,EAAA,IAAM,GACpE,IAAY,EAAe,EAAgB,CAAyB,GAAG,CAAS,GAChF,CAAC,CAAA,IAAoB,EAAM,SAAS,EAAU,SAAS,CAAC,GACxD,EAAE,OAAA,EAAA,IAAU,EAAgB,GAAe,GAAoB,CAAK,GAEpE,CAAC,GAAoB,CAAA,IAAoB,EAAQ,IAAA,CAAK,MAAW,EAAO,KAAK;AAEnF,SAAO,EAAU,SACf,gBAAA,EAAC,GAAD;AAAA,IACE,SAAS;AAAA,MACP,SAAS;AAAA,MACT,kBAAkB,EAAe,GAAgB,KAAK;AAAA,IACxD;AAAA,IACO,OAAA;AAAA,IACP,MAAM;AAAA,IACc,oBAAA;AAAA,IACpB,YAAA,CAAa,MACX,EAAiB;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,eAAe;AAAA,QACf,OAAO,EAAgB;AAAA,MACzB;AAAA,IACF,CAAC;AAAA,IAEe,kBAAA;AAAA,IACA,kBAAA;AAAA,EACnB,CAAA,IAED,gBAAA,EAAC,GAAD,CAAgB,CAAA;AAEpB"}
@@ -1,28 +1,30 @@
1
- import { useInsightsV2Store as f } from "../../../../common/context/hooks.es.js";
2
- import { DoubleBarChart as g } from "../../../components/chartblocks/DoubleBarChart.es.js";
3
- import { buildComparisonSeries as h } from "./comparisonUtils.es.js";
4
- import { getLayoutConfig as b } from "./layout.es.js";
5
- import { jsx as B } from "react/jsx-runtime";
6
- import { useTheme as x } from "@mui/material/styles";
7
- var L = ({ payload: { instance_slot: r, instance_slot_data: o, widget_type: t }, beatGuid: e = "" }) => {
8
- const a = x(), { openActionDrawer: i } = f(), { variant: n } = r, { ariaLabel: s = "", data_series: m, legends: c } = o, l = h(m, s), p = b(a, n)?.color ?? [];
9
- return /* @__PURE__ */ B(g, {
1
+ import { useInsightsV2Store as B } from "../../../../common/context/hooks.es.js";
2
+ import { actionBlocksKey as C } from "../../../mappings/actionBlocksKey.es.js";
3
+ import { DoubleBarChart as b } from "../../../components/chartblocks/DoubleBarChart.es.js";
4
+ import { buildComparisonSeries as d } from "./comparisonUtils.es.js";
5
+ import { getLayoutConfig as g } from "./layout.es.js";
6
+ import { jsx as h } from "react/jsx-runtime";
7
+ import { useTheme as I } from "@mui/material/styles";
8
+ var y = ({ payload: { instance_slot: o, instance_slot_data: r, widget_type: t }, beatGuid: e = "" }) => {
9
+ const a = I(), { openActionDrawer: i } = B(), { variant: n } = o, { ariaLabel: s = "", data_series: m, legends: c } = r, l = d(m, s), p = g(a, n)?.color ?? [];
10
+ return /* @__PURE__ */ h(b, {
10
11
  bars: l,
11
12
  colors: p,
12
13
  isMini: t === "mini",
13
14
  legends: c,
14
- onBarClick: (u, d) => i({
15
+ onBarClick: (f, u) => i({
15
16
  guid: e,
16
17
  trigger: "chartBar",
17
18
  context: {
18
- chartBarIndex: u,
19
- tabIndex: d
19
+ chartBarIndex: f,
20
+ tabIndex: u,
21
+ block: C.TRANSCATION_HISTORY_ACTION_BLOCK
20
22
  }
21
23
  })
22
24
  });
23
25
  };
24
26
  export {
25
- L as DoubleBarChartBlock
27
+ y as DoubleBarChartBlock
26
28
  };
27
29
 
28
30
  //# sourceMappingURL=DoubleBarChartBlock.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DoubleBarChartBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.tsx"],"sourcesContent":["import { useTheme } from '@mui/material/styles'\n\nimport { useInsightsV2Store } from '../../../../common'\nimport type { DataSeries, DrilldownPayload } from '../../../../core'\nimport { DoubleBarChart } from '../../../components/chartblocks/DoubleBarChart'\n\nimport type { BlockProps } from '../../types'\n\nimport { buildComparisonSeries } from './comparisonUtils'\nimport { getLayoutConfig } from './layout'\n\n/**\n * Card block for the double-bar chart. Mirrors BarchartBlock: it builds the shaped series\n * (buildComparisonSeries) and resolves the card palette (getLayoutConfig), then renders the reusable\n * DoubleBarChart and injects the card click behavior \\u2014 open the shared drawer scoped to this beat\n * (chartBarIndex = clicked column, tabIndex = clicked sub-series).\n */\nexport const DoubleBarChartBlock = ({\n payload: { instance_slot, instance_slot_data, widget_type },\n beatGuid = '',\n}: BlockProps) => {\n const theme = useTheme()\n const { openActionDrawer } = useInsightsV2Store()\n const { variant } = instance_slot\n const { ariaLabel = '', data_series, legends } = instance_slot_data\n const bars = buildComparisonSeries(data_series as DataSeries, ariaLabel)\n // getLayoutConfig returns undefined for an unknown/unsupported variant; fall back to an empty\n // palette so an unregistered beat can't throw on mount.\n const colors = getLayoutConfig(theme, variant)?.color ?? []\n\n return (\n <DoubleBarChart\n bars={bars}\n colors={colors}\n isMini={widget_type === 'mini'}\n legends={legends}\n onBarClick={(columnIndex, subIndex) =>\n openActionDrawer({\n guid: beatGuid,\n trigger: 'chartBar',\n context: { chartBarIndex: columnIndex, tabIndex: subIndex } satisfies DrilldownPayload,\n })\n }\n />\n )\n}\n"],"mappings":";;;;;;AAiBA,IAAa,IAAA,CAAuB,EAClC,SAAS,EAAE,eAAA,GAAe,oBAAA,GAAoB,aAAA,EAAA,GAC9C,UAAA,IAAW,GAAA,MACK;AAChB,QAAM,IAAQ,EAAS,GACjB,EAAE,kBAAA,EAAA,IAAqB,EAAmB,GAC1C,EAAE,SAAA,EAAA,IAAY,GACd,EAAE,WAAA,IAAY,IAAI,aAAA,GAAa,SAAA,EAAA,IAAY,GAC3C,IAAO,EAAsB,GAA2B,CAAS,GAGjE,IAAS,EAAgB,GAAO,CAAO,GAAG,SAAS,CAAC;AAE1D,SACE,gBAAA,EAAC,GAAD;AAAA,IACQ,MAAA;AAAA,IACE,QAAA;AAAA,IACR,QAAQ,MAAgB;AAAA,IACf,SAAA;AAAA,IACT,YAAA,CAAa,GAAa,MACxB,EAAiB;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QAAE,eAAe;AAAA,QAAa,UAAU;AAAA,MAAS;AAAA,IAC5D,CAAC;AAAA,EAEJ,CAAA;AAEL"}
1
+ {"version":3,"file":"DoubleBarChartBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.tsx"],"sourcesContent":["import { useTheme } from '@mui/material/styles'\n\nimport { useInsightsV2Store } from '../../../../common'\nimport type { DataSeries, DrilldownPayload } from '../../../../core'\nimport { DoubleBarChart } from '../../../components/chartblocks/DoubleBarChart'\n\nimport type { BlockProps } from '../../types'\n\nimport { buildComparisonSeries } from './comparisonUtils'\nimport { getLayoutConfig } from './layout'\nimport { actionBlocksKey } from '../../../mappings/actionBlocksKey'\n\n/**\n * Card block for the double-bar chart. Mirrors BarchartBlock: it builds the shaped series\n * (buildComparisonSeries) and resolves the card palette (getLayoutConfig), then renders the reusable\n * DoubleBarChart and injects the card click behavior \\u2014 open the shared drawer scoped to this beat\n * (chartBarIndex = clicked column, tabIndex = clicked sub-series).\n */\nexport const DoubleBarChartBlock = ({\n payload: { instance_slot, instance_slot_data, widget_type },\n beatGuid = '',\n}: BlockProps) => {\n const theme = useTheme()\n const { openActionDrawer } = useInsightsV2Store()\n const { variant } = instance_slot\n const { ariaLabel = '', data_series, legends } = instance_slot_data\n const bars = buildComparisonSeries(data_series as DataSeries, ariaLabel)\n // getLayoutConfig returns undefined for an unknown/unsupported variant; fall back to an empty\n // palette so an unregistered beat can't throw on mount.\n const colors = getLayoutConfig(theme, variant)?.color ?? []\n\n return (\n <DoubleBarChart\n bars={bars}\n colors={colors}\n isMini={widget_type === 'mini'}\n legends={legends}\n onBarClick={(columnIndex, subIndex) =>\n openActionDrawer({\n guid: beatGuid,\n trigger: 'chartBar',\n context: {\n chartBarIndex: columnIndex,\n tabIndex: subIndex,\n block: actionBlocksKey.TRANSCATION_HISTORY_ACTION_BLOCK,\n } satisfies DrilldownPayload,\n })\n }\n />\n )\n}\n"],"mappings":";;;;;;;AAkBA,IAAa,IAAA,CAAuB,EAClC,SAAS,EAAE,eAAA,GAAe,oBAAA,GAAoB,aAAA,EAAA,GAC9C,UAAA,IAAW,GAAA,MACK;AAChB,QAAM,IAAQ,EAAS,GACjB,EAAE,kBAAA,EAAA,IAAqB,EAAmB,GAC1C,EAAE,SAAA,EAAA,IAAY,GACd,EAAE,WAAA,IAAY,IAAI,aAAA,GAAa,SAAA,EAAA,IAAY,GAC3C,IAAO,EAAsB,GAA2B,CAAS,GAGjE,IAAS,EAAgB,GAAO,CAAO,GAAG,SAAS,CAAC;AAE1D,SACE,gBAAA,EAAC,GAAD;AAAA,IACQ,MAAA;AAAA,IACE,QAAA;AAAA,IACR,QAAQ,MAAgB;AAAA,IACf,SAAA;AAAA,IACT,YAAA,CAAa,GAAa,MACxB,EAAiB;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,eAAe;AAAA,QACf,UAAU;AAAA,QACV,OAAO,EAAgB;AAAA,MACzB;AAAA,IACF,CAAC;AAAA,EAEJ,CAAA;AAEL"}
@@ -1,4 +1,4 @@
1
1
  import { StepChartBlockData } from '../../../../core/types/InsightsInstanceSlotData';
2
- import { BlockProps } from '../..';
2
+ import { BlockProps } from '../../types';
3
3
  declare const StepChartBlock: ({ payload }: BlockProps<StepChartBlockData>) => import("react/jsx-runtime").JSX.Element;
4
4
  export default StepChartBlock;
@@ -1 +1 @@
1
- {"version":3,"file":"StepChartBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/StepChartBlock/StepChartBlock.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport type { StepChartBlockData } from '../../../../core/types/InsightsInstanceSlotData'\n\nimport type { BlockProps } from '../..'\n\nimport { variants } from '.'\n\nconst StepChartBlock = ({ payload }: BlockProps<StepChartBlockData>) => {\n const {\n instance_slot: { variant },\n instance_slot_data,\n } = payload\n\n const Variant = variants[variant as keyof typeof variants]\n\n return (\n <Stack sx={{ p: 16 }}>\n <Variant slotData={instance_slot_data} />\n </Stack>\n )\n}\n\nexport default StepChartBlock\n"],"mappings":";;;AAQA,IAAM,IAAA,CAAkB,EAAE,SAAA,EAAA,MAA8C;AACtE,QAAM,EACJ,eAAe,EAAE,SAAA,EAAA,GACjB,oBAAA,EAAA,IACE,GAEE,IAAU,EAAS,CAAA;AAEzB,SACE,gBAAA,EAAC,GAAD;AAAA,IAAO,IAAI,EAAE,GAAG,GAAG;AAAA,IACjB,UAAA,gBAAA,EAAC,GAAD,EAAS,UAAU,EAAqB,CAAA;AAAA,EACnC,CAAA;AAEX"}
1
+ {"version":3,"file":"StepChartBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/StepChartBlock/StepChartBlock.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport type { StepChartBlockData } from '../../../../core/types/InsightsInstanceSlotData'\n\nimport type { BlockProps } from '../../types'\n\nimport { variants } from '.'\n\nconst StepChartBlock = ({ payload }: BlockProps<StepChartBlockData>) => {\n const {\n instance_slot: { variant },\n instance_slot_data,\n } = payload\n\n const Variant = variants[variant as keyof typeof variants]\n\n return (\n <Stack sx={{ p: 16 }}>\n <Variant slotData={instance_slot_data} />\n </Stack>\n )\n}\n\nexport default StepChartBlock\n"],"mappings":";;;AAQA,IAAM,IAAA,CAAkB,EAAE,SAAA,EAAA,MAA8C;AACtE,QAAM,EACJ,eAAe,EAAE,SAAA,EAAA,GACjB,oBAAA,EAAA,IACE,GAEE,IAAU,EAAS,CAAA;AAEzB,SACE,gBAAA,EAAC,GAAD;AAAA,IAAO,IAAI,EAAE,GAAG,GAAG;AAAA,IACjB,UAAA,gBAAA,EAAC,GAAD,EAAS,UAAU,EAAqB,CAAA;AAAA,EACnC,CAAA;AAEX"}
@@ -0,0 +1,6 @@
1
+ export declare const actionBlocksKey: {
2
+ PLACEHOLDER_ACTION_BLOCK: string;
3
+ MAKE_TRANSFER_ACTION_BLOCK: string;
4
+ TRANSCATION_HISTORY_ACTION_BLOCK: string;
5
+ TRANSACTION_DETAILS_ACTION_BLOCK: string;
6
+ };
@@ -0,0 +1,11 @@
1
+ var _ = {
2
+ PLACEHOLDER_ACTION_BLOCK: "PlaceholderActionBlock",
3
+ MAKE_TRANSFER_ACTION_BLOCK: "make_transfer",
4
+ TRANSCATION_HISTORY_ACTION_BLOCK: "transaction_history_block",
5
+ TRANSACTION_DETAILS_ACTION_BLOCK: "TransactionDetailsBlock"
6
+ };
7
+ export {
8
+ _ as actionBlocksKey
9
+ };
10
+
11
+ //# sourceMappingURL=actionBlocksKey.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionBlocksKey.es.js","names":[],"sources":["../../../src/insights-v2/mappings/actionBlocksKey.ts"],"sourcesContent":["// Keys for the drawer drilldown registry in `blocks.ts`, extracted into their own module.\n//\n// Why: chart blocks (e.g. BarchartBlock, DoubleBarChartBlock) need\n// `TRANSCATION_HISTORY_ACTION_BLOCK` to tag a chart bar's drilldown context, but they are\n// themselves re-exported through `../blocks` -> `mappings/blocks.ts` imports from that same\n// barrel to build its `blocks` registry. Importing the key straight from `mappings/blocks.ts`\n// closed that loop into a circular import: evaluating `mappings/blocks.ts` pulled in the\n// `blocks` barrel, which (before it got to `ComponentBlocks`/`AccountBlock`) loaded\n// `BarchartBlock`, which imported back into the still-initializing `mappings/blocks.ts` —\n// tripping a \"Cannot access 'AccountBlock' before initialization\" TDZ error in Storybook/Vite.\n//\n// Keeping the keys here (no dependency on `mappings/blocks.ts`) lets chart blocks reference\n// them without re-entering that module.\nexport const actionBlocksKey = {\n PLACEHOLDER_ACTION_BLOCK: 'PlaceholderActionBlock',\n MAKE_TRANSFER_ACTION_BLOCK: 'make_transfer',\n TRANSCATION_HISTORY_ACTION_BLOCK: 'transaction_history_block',\n TRANSACTION_DETAILS_ACTION_BLOCK: 'TransactionDetailsBlock',\n}\n"],"mappings":"AAaA,IAAa,IAAkB;AAAA,EAC7B,0BAA0B;AAAA,EAC1B,4BAA4B;AAAA,EAC5B,kCAAkC;AAAA,EAClC,kCAAkC;AACpC"}