@mx-cartographer/experiences 9.6.13 → 9.6.15
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 +18 -0
- package/dist/common/components/CurrencyDialog.d.ts +6 -1
- package/dist/common/components/CurrencyDialog.es.js +24 -23
- package/dist/common/components/CurrencyDialog.es.js.map +1 -1
- package/dist/core/types/localization/InsightsFeedCopy.d.ts +2 -0
- package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js +3 -3
- package/dist/insights-v2/actionBlocks/AmountInputModalBlock/AmountInputModalBlock.es.js +64 -59
- package/dist/insights-v2/actionBlocks/AmountInputModalBlock/AmountInputModalBlock.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.es.js +17 -11
- package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js +63 -57
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js.map +1 -1
- package/dist/insights-v2/analytics/analyticsEventsConfig.d.ts +67 -0
- package/dist/insights-v2/analytics/analyticsEventsConfig.es.js +59 -0
- package/dist/insights-v2/analytics/analyticsEventsConfig.es.js.map +1 -0
- package/dist/insights-v2/analytics/index.d.ts +3 -0
- package/dist/insights-v2/analytics/resolveAnalyticsEvent.d.ts +5 -0
- package/dist/insights-v2/analytics/resolveAnalyticsEvent.es.js +19 -0
- package/dist/insights-v2/analytics/resolveAnalyticsEvent.es.js.map +1 -0
- package/dist/insights-v2/analytics/useAnalyticsEvent.d.ts +3 -0
- package/dist/insights-v2/analytics/useAnalyticsEvent.es.js +20 -0
- package/dist/insights-v2/analytics/useAnalyticsEvent.es.js.map +1 -0
- package/dist/insights-v2/beatActions.d.ts +18 -13
- package/dist/insights-v2/beatActions.es.js.map +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js +24 -22
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js.map +1 -1
- package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/DebtsBlock.d.ts +16 -12
- package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/DebtsBlock.es.js +67 -46
- package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/DebtsBlock.es.js.map +1 -1
- package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/layout.d.ts +17 -0
- package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/layout.es.js +24 -0
- package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/layout.es.js.map +1 -0
- package/dist/insights-v2/components/BaseLayout.es.js +89 -79
- package/dist/insights-v2/components/BaseLayout.es.js.map +1 -1
- package/dist/insights-v2/components/TransactionListCard.es.js +15 -14
- package/dist/insights-v2/components/TransactionListCard.es.js.map +1 -1
- package/dist/insights-v2/ctaActions/ctaHandlers.d.ts +1 -6
- package/dist/insights-v2/ctaActions/ctaHandlers.es.js.map +1 -1
- package/dist/insights-v2/ctaActions/index.d.ts +1 -1
- package/dist/insights-v2/ctaActions/runCtaAction.d.ts +20 -5
- package/dist/insights-v2/ctaActions/runCtaAction.es.js +63 -41
- package/dist/insights-v2/ctaActions/runCtaAction.es.js.map +1 -1
- package/dist/insights-v2/ctaActions/types.d.ts +6 -5
- package/dist/insights-v2/index.es.js +84 -84
- package/dist/insights-v2/mappings/blocks.es.js +2 -2
- package/package.json +1 -1
|
@@ -1,73 +1,75 @@
|
|
|
1
|
-
import { useGlobalCopyStore as
|
|
2
|
-
import { formatCurrency as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { BarChartV2 as
|
|
6
|
-
import { EmptyBarChart as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
import { useGlobalCopyStore as X, useGlobalUiStore as Z, useInsightsV2Store as tt } from "../../../common/context/hooks.es.js";
|
|
2
|
+
import { formatCurrency as et } from "../../../core/utils/NumberFormatting.es.js";
|
|
3
|
+
import at from "../../../common/components/drawer/Drawer.es.js";
|
|
4
|
+
import ot from "../../../common/components/Loader.es.js";
|
|
5
|
+
import { BarChartV2 as nt } from "../../components/chartblocks/BarchartV2.es.js";
|
|
6
|
+
import { EmptyBarChart as rt } from "../../components/chartblocks/EmptyBarChart.es.js";
|
|
7
|
+
import { ANALYTICS_EVENTS_CONFIG as A } from "../../analytics/analyticsEventsConfig.es.js";
|
|
8
|
+
import { useAnalyticsEvent as it } from "../../analytics/useAnalyticsEvent.es.js";
|
|
9
|
+
import { TransactionDrillDown as st } from "./TransactionDrillDown.es.js";
|
|
10
|
+
import { useTransactionHistory as lt } from "./useTransactionHistory.es.js";
|
|
11
|
+
import { getDefaultSelection as ct, getDrillDownConfig as mt, getFlattenedDataSeries as dt, toStoreFilter as pt } from "./utils.es.js";
|
|
12
|
+
import { getDynamicCtaBasedOnTriggers as gt } from "../util.es.js";
|
|
13
|
+
import { TransactionDetailsBlock as ut } from "../TransactionDetailsBlock/TransactionDetailsBlock.es.js";
|
|
14
|
+
import { useLayoutEffect as ft, useState as u } from "react";
|
|
15
|
+
import { observer as ht } from "mobx-react-lite";
|
|
16
|
+
import { Fragment as yt, jsx as n, jsxs as bt } from "react/jsx-runtime";
|
|
17
|
+
import { useTheme as Ct } from "@mui/material/styles";
|
|
18
|
+
var kt = ht(({ beat: a }) => {
|
|
19
|
+
const f = Ct(), { instanceSlotData: e, beatTransactions: l, spendCategoryGuids: h, allAccountGuids: y, categoryName: x, displayedDateRange: p, transactionStore: B } = lt(a), { actionDrawer: b, setActionContext: C } = tt(), { common: E, insights_feed: c } = X(), { isCopyLoaded: I } = Z(), [F, T] = u(!1), [G, H] = u(!1), _ = it(), { insights_payload: o } = a, O = gt(b, o?.primary_cta, o?.secondary_cta, o?.in_description_cta)?.variant, { top: r, filterMode: m, header: R, colors: j, filterStrategy: k, tipSection: S } = mt(O ?? ""), { dataSeries: d, chartData: i, comparisonBars: w } = dt({
|
|
18
20
|
data: e?.data_series,
|
|
19
21
|
ariaLabel: e?.ariaLabel ?? "",
|
|
20
22
|
top: r,
|
|
21
23
|
beatTransactions: l,
|
|
22
24
|
payload: e
|
|
23
|
-
}), { chartBarIndex:
|
|
25
|
+
}), { chartBarIndex: K, subTabIndex: N } = ct({
|
|
24
26
|
chartTabCount: i.length,
|
|
25
|
-
comparisonTabCount:
|
|
26
|
-
actionDrawer:
|
|
27
|
+
comparisonTabCount: w.length,
|
|
28
|
+
actionDrawer: b,
|
|
27
29
|
beatGuid: a.guid
|
|
28
|
-
}), [s,
|
|
30
|
+
}), [s, D] = u(K), L = (t) => k({
|
|
29
31
|
beat: a,
|
|
30
32
|
beatTransactions: l,
|
|
31
|
-
dataSeries:
|
|
33
|
+
dataSeries: d,
|
|
32
34
|
selectedIndex: t,
|
|
33
|
-
subIndex:
|
|
34
|
-
isLastTab: t ===
|
|
35
|
+
subIndex: N,
|
|
36
|
+
isLastTab: t === d.length - 1,
|
|
35
37
|
instanceSlotData: e,
|
|
36
|
-
spendCategoryGuids:
|
|
37
|
-
displayedDateRange:
|
|
38
|
-
}), V = l.map((t) => t.guid).join(","),
|
|
39
|
-
|
|
40
|
-
allAccountGuids:
|
|
41
|
-
displayedDateRange:
|
|
38
|
+
spendCategoryGuids: h,
|
|
39
|
+
displayedDateRange: p
|
|
40
|
+
}), V = l.map((t) => t.guid).join(","), M = h.join(","), P = y.join(","), U = r === "list" || d.length > 0, v = () => {
|
|
41
|
+
m !== "store" || !U || B.setFilter(pt(L(s), {
|
|
42
|
+
allAccountGuids: y,
|
|
43
|
+
displayedDateRange: p
|
|
42
44
|
}));
|
|
43
45
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
ft(() => {
|
|
47
|
+
v();
|
|
46
48
|
}, [
|
|
47
49
|
a.guid,
|
|
48
50
|
s,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
m,
|
|
52
|
+
d.length,
|
|
51
53
|
e,
|
|
52
|
-
|
|
53
|
-
R,
|
|
54
|
+
p,
|
|
54
55
|
M,
|
|
56
|
+
P,
|
|
55
57
|
V,
|
|
56
58
|
r
|
|
57
59
|
]);
|
|
58
|
-
const
|
|
60
|
+
const g = R?.({
|
|
59
61
|
title: o?.title,
|
|
60
62
|
subHeader: o?.sub_title,
|
|
61
|
-
categoryName:
|
|
63
|
+
categoryName: x,
|
|
62
64
|
selectedDate: i[s]?.date ?? void 0
|
|
63
|
-
}),
|
|
64
|
-
if (!
|
|
65
|
-
const
|
|
65
|
+
}), W = j(f, e?.category_guid);
|
|
66
|
+
if (!I) return /* @__PURE__ */ n(ot, {});
|
|
67
|
+
const Y = [c.general.monthly_amount, c.general.trend], [$, q] = e?.legends?.length ? e.legends.map((t) => t.label) : Y, z = m === "local" ? (t) => L(t).custom ?? (() => !0) : void 0, J = m === "local" ? l : void 0, Q = r === "singleBar" || r === "upcomingBill" ? i.length ? /* @__PURE__ */ n(nt, {
|
|
66
68
|
amounts: {
|
|
67
69
|
average: e?.average_amount,
|
|
68
|
-
formattedAverage:
|
|
70
|
+
formattedAverage: et(e?.average_amount ?? 0, "0,0.00")
|
|
69
71
|
},
|
|
70
|
-
color:
|
|
72
|
+
color: W[0] ?? f.palette.primary.main,
|
|
71
73
|
data: i,
|
|
72
74
|
legendPosition: "top",
|
|
73
75
|
heightOverride: 142,
|
|
@@ -78,40 +80,44 @@ var jt = pt(({ beat: a }) => {
|
|
|
78
80
|
right: 24
|
|
79
81
|
},
|
|
80
82
|
monthlyAmountLabel: $,
|
|
81
|
-
onBarClick:
|
|
83
|
+
onBarClick: (t) => {
|
|
84
|
+
_(A.DRAWER_CHART_BAR_CLICKED), D(t);
|
|
85
|
+
},
|
|
82
86
|
selectedTabIndex: s,
|
|
83
87
|
trendAmountLabel: q
|
|
84
|
-
}) : /* @__PURE__ */ n(
|
|
85
|
-
return /* @__PURE__ */
|
|
88
|
+
}) : /* @__PURE__ */ n(rt, {}) : null;
|
|
89
|
+
return /* @__PURE__ */ bt(yt, { children: [/* @__PURE__ */ n(st, {
|
|
86
90
|
ariaLabel: e?.ariaLabel,
|
|
87
91
|
baseTransactions: J,
|
|
88
|
-
heading:
|
|
89
|
-
icon:
|
|
90
|
-
onSelectionChange:
|
|
92
|
+
heading: g?.heading,
|
|
93
|
+
icon: g?.icon,
|
|
94
|
+
onSelectionChange: (t) => {
|
|
95
|
+
_(A.TAB_SELECTED), D(t);
|
|
96
|
+
},
|
|
91
97
|
selectedIndex: s,
|
|
92
|
-
subHeadingText:
|
|
98
|
+
subHeadingText: g?.subHeadingText,
|
|
93
99
|
tabs: i.map((t) => ({
|
|
94
100
|
ariaLabel: t.ariaLabel,
|
|
95
101
|
label: t.label
|
|
96
102
|
})),
|
|
97
103
|
top: Q,
|
|
98
|
-
...S && { tipSection: !G && S(
|
|
104
|
+
...S && { tipSection: !G && S(H, c, o?.sub_title?.text) },
|
|
99
105
|
transactionFilter: z,
|
|
100
106
|
onEachRowClick: (t) => {
|
|
101
107
|
C({ transaction_guid: t }), T(!0);
|
|
102
108
|
}
|
|
103
|
-
}), /* @__PURE__ */ n(
|
|
104
|
-
ariaLabelClose:
|
|
105
|
-
isOpen:
|
|
109
|
+
}), /* @__PURE__ */ n(at, {
|
|
110
|
+
ariaLabelClose: E.close_aria,
|
|
111
|
+
isOpen: F,
|
|
106
112
|
onClose: () => {
|
|
107
|
-
T(!1), C({ transaction_guid: void 0 }),
|
|
113
|
+
T(!1), C({ transaction_guid: void 0 }), v();
|
|
108
114
|
},
|
|
109
115
|
title: c.general.transaction_details_title,
|
|
110
|
-
children: /* @__PURE__ */ n(
|
|
116
|
+
children: /* @__PURE__ */ n(ut, { beat: a })
|
|
111
117
|
})] });
|
|
112
118
|
});
|
|
113
119
|
export {
|
|
114
|
-
|
|
120
|
+
kt as TransactionHistoryBlock
|
|
115
121
|
};
|
|
116
122
|
|
|
117
123
|
//# 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'\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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"}
|
|
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 { ANALYTICS_EVENTS_CONFIG, useAnalyticsEvent } from '../../analytics'\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 fireAnalyticsEvent = useAnalyticsEvent()\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={(index) => {\n fireAnalyticsEvent(ANALYTICS_EVENTS_CONFIG.DRAWER_CHART_BAR_CLICKED)\n setSelectedIndex(index)\n }}\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={(index) => {\n // MUI Tabs only fires onChange on real user selection, not on mount.\n fireAnalyticsEvent(ANALYTICS_EVENTS_CONFIG.TAB_SELECTED)\n setSelectedIndex(index)\n }}\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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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Beat } from '../../core';
|
|
2
|
+
export declare const sentenceCaseTemplate: (template?: string | null) => string;
|
|
3
|
+
type Resolvable = string | ((beat: Beat) => string);
|
|
4
|
+
export interface AnalyticsEventConfigEntry {
|
|
5
|
+
category?: Resolvable;
|
|
6
|
+
action?: Resolvable;
|
|
7
|
+
postHog?: {
|
|
8
|
+
eventName: string;
|
|
9
|
+
properties?: (beat: Beat) => Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export declare const ANALYTICS_EVENTS_CONFIG: {
|
|
13
|
+
readonly PRIMARY_ACTION_SELECTED: {
|
|
14
|
+
readonly category: "Beat Interaction";
|
|
15
|
+
readonly action: "Primary Action Selected";
|
|
16
|
+
};
|
|
17
|
+
readonly SECONDARY_ACTION_SELECTED: {
|
|
18
|
+
readonly category: "Beat Interaction";
|
|
19
|
+
readonly action: "Secondary Action Selected";
|
|
20
|
+
};
|
|
21
|
+
readonly FIRST_TIME_PRIMARY_ACTION_SELECTED: {
|
|
22
|
+
readonly category: "Beat Interaction";
|
|
23
|
+
readonly action: "First Time Primary Action Selected";
|
|
24
|
+
};
|
|
25
|
+
readonly CHART_BAR_CLICKED: {
|
|
26
|
+
readonly category: "Beat Chart";
|
|
27
|
+
readonly action: (beat: Beat) => string;
|
|
28
|
+
};
|
|
29
|
+
readonly DRAWER_CHART_BAR_CLICKED: {
|
|
30
|
+
readonly category: "Drawer Chart";
|
|
31
|
+
readonly action: (beat: Beat) => string;
|
|
32
|
+
};
|
|
33
|
+
readonly TAB_SELECTED: {
|
|
34
|
+
readonly category: "Drawer Chart";
|
|
35
|
+
readonly action: (beat: Beat) => string;
|
|
36
|
+
};
|
|
37
|
+
readonly EDIT_INSIGHT_THRESHOLD_SAVE: {
|
|
38
|
+
readonly category: "User Configurable Settings";
|
|
39
|
+
readonly action: "Edit Insight Threshold Save";
|
|
40
|
+
};
|
|
41
|
+
readonly EDIT_INSIGHT_THRESHOLD_CANCELED: {
|
|
42
|
+
readonly category: "User Configurable Settings";
|
|
43
|
+
readonly action: "Edit Insight Threshold Canceled";
|
|
44
|
+
};
|
|
45
|
+
readonly EDIT_INSIGHT_THRESHOLD_INPUT_SELECTED: {
|
|
46
|
+
readonly category: "User Configurable Settings";
|
|
47
|
+
readonly action: "Edit Insight Threshold Input Selected";
|
|
48
|
+
};
|
|
49
|
+
readonly EDIT_SAFETY_NET_SAVE: {
|
|
50
|
+
readonly category: "Safety Net";
|
|
51
|
+
readonly action: "Edit Safety Net";
|
|
52
|
+
};
|
|
53
|
+
readonly EDIT_SAFETY_NET_CANCEL: {
|
|
54
|
+
readonly category: "Safety Net";
|
|
55
|
+
readonly action: (beat: Beat) => string;
|
|
56
|
+
};
|
|
57
|
+
readonly OPENED_CONNECT_DRAWER: {
|
|
58
|
+
readonly postHog: {
|
|
59
|
+
readonly eventName: "opened_connect_drawer";
|
|
60
|
+
readonly properties: (beat: Beat) => {
|
|
61
|
+
beat_guid: string;
|
|
62
|
+
template: string;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
var t = (e) => e?.replace(/([A-Z]+)/g, " $1")?.replace(/^ /, "") ?? "", a = {
|
|
2
|
+
PRIMARY_ACTION_SELECTED: {
|
|
3
|
+
category: "Beat Interaction",
|
|
4
|
+
action: "Primary Action Selected"
|
|
5
|
+
},
|
|
6
|
+
SECONDARY_ACTION_SELECTED: {
|
|
7
|
+
category: "Beat Interaction",
|
|
8
|
+
action: "Secondary Action Selected"
|
|
9
|
+
},
|
|
10
|
+
FIRST_TIME_PRIMARY_ACTION_SELECTED: {
|
|
11
|
+
category: "Beat Interaction",
|
|
12
|
+
action: "First Time Primary Action Selected"
|
|
13
|
+
},
|
|
14
|
+
CHART_BAR_CLICKED: {
|
|
15
|
+
category: "Beat Chart",
|
|
16
|
+
action: (e) => `${t(e.template)} - Bar Clicked`
|
|
17
|
+
},
|
|
18
|
+
DRAWER_CHART_BAR_CLICKED: {
|
|
19
|
+
category: "Drawer Chart",
|
|
20
|
+
action: (e) => `${t(e.template)} - Bar Clicked`
|
|
21
|
+
},
|
|
22
|
+
TAB_SELECTED: {
|
|
23
|
+
category: "Drawer Chart",
|
|
24
|
+
action: (e) => `${t(e.template)} - Month Tab Selected`
|
|
25
|
+
},
|
|
26
|
+
EDIT_INSIGHT_THRESHOLD_SAVE: {
|
|
27
|
+
category: "User Configurable Settings",
|
|
28
|
+
action: "Edit Insight Threshold Save"
|
|
29
|
+
},
|
|
30
|
+
EDIT_INSIGHT_THRESHOLD_CANCELED: {
|
|
31
|
+
category: "User Configurable Settings",
|
|
32
|
+
action: "Edit Insight Threshold Canceled"
|
|
33
|
+
},
|
|
34
|
+
EDIT_INSIGHT_THRESHOLD_INPUT_SELECTED: {
|
|
35
|
+
category: "User Configurable Settings",
|
|
36
|
+
action: "Edit Insight Threshold Input Selected"
|
|
37
|
+
},
|
|
38
|
+
EDIT_SAFETY_NET_SAVE: {
|
|
39
|
+
category: "Safety Net",
|
|
40
|
+
action: "Edit Safety Net"
|
|
41
|
+
},
|
|
42
|
+
EDIT_SAFETY_NET_CANCEL: {
|
|
43
|
+
category: "Safety Net",
|
|
44
|
+
action: (e) => `${t(e.template)} = Edit Safety Net - Cancel`
|
|
45
|
+
},
|
|
46
|
+
OPENED_CONNECT_DRAWER: { postHog: {
|
|
47
|
+
eventName: "opened_connect_drawer",
|
|
48
|
+
properties: (e) => ({
|
|
49
|
+
beat_guid: e.guid,
|
|
50
|
+
template: e.template
|
|
51
|
+
})
|
|
52
|
+
} }
|
|
53
|
+
};
|
|
54
|
+
export {
|
|
55
|
+
a as ANALYTICS_EVENTS_CONFIG,
|
|
56
|
+
t as sentenceCaseTemplate
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=analyticsEventsConfig.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyticsEventsConfig.es.js","names":[],"sources":["../../../src/insights-v2/analytics/analyticsEventsConfig.ts"],"sourcesContent":["import type { Beat } from '../../core'\n\n// PascalCase template to label, ported from Pulse.\nexport const sentenceCaseTemplate = (template?: string | null): string =>\n template?.replace(/([A-Z]+)/g, ' $1')?.replace(/^ /, '') ?? ''\n\n// Fixed or beat-computed value.\ntype Resolvable = string | ((beat: Beat) => string)\n\n// Source of truth for insights-v2 analytics events. Mirrors Pulse's strings.\n// Entry has a Firefly half (action/category) and/or a postHog half.\nexport interface AnalyticsEventConfigEntry {\n category?: Resolvable\n action?: Resolvable\n postHog?: {\n eventName: string\n properties?: (beat: Beat) => Record<string, unknown>\n }\n}\n\nexport const ANALYTICS_EVENTS_CONFIG = {\n // Primary/secondary CTA click, fired via sendCtaAnalytics.\n PRIMARY_ACTION_SELECTED: {\n category: 'Beat Interaction',\n action: 'Primary Action Selected',\n },\n SECONDARY_ACTION_SELECTED: {\n category: 'Beat Interaction',\n action: 'Secondary Action Selected',\n },\n // Fires once, gated on !beat.cta_clicked_at.\n FIRST_TIME_PRIMARY_ACTION_SELECTED: {\n category: 'Beat Interaction',\n action: 'First Time Primary Action Selected',\n },\n\n // Bar click on the card's inline chart.\n CHART_BAR_CLICKED: {\n category: 'Beat Chart',\n action: (beat) => `${sentenceCaseTemplate(beat.template)} - Bar Clicked`,\n },\n // Bar click inside the drill-down drawer.\n DRAWER_CHART_BAR_CLICKED: {\n category: 'Drawer Chart',\n action: (beat) => `${sentenceCaseTemplate(beat.template)} - Bar Clicked`,\n },\n // Month/tab change inside the drill-down drawer.\n TAB_SELECTED: {\n category: 'Drawer Chart',\n action: (beat) => `${sentenceCaseTemplate(beat.template)} - Month Tab Selected`,\n },\n\n // LowAccountBalance threshold dialog.\n EDIT_INSIGHT_THRESHOLD_SAVE: {\n category: 'User Configurable Settings',\n action: 'Edit Insight Threshold Save',\n },\n EDIT_INSIGHT_THRESHOLD_CANCELED: {\n category: 'User Configurable Settings',\n action: 'Edit Insight Threshold Canceled',\n },\n EDIT_INSIGHT_THRESHOLD_INPUT_SELECTED: {\n category: 'User Configurable Settings',\n action: 'Edit Insight Threshold Input Selected',\n },\n\n // SavingsOpportunityV2 safety-net dialog.\n EDIT_SAFETY_NET_SAVE: {\n category: 'Safety Net',\n action: 'Edit Safety Net',\n },\n // Ported verbatim from Pulse (uses '=' not '-').\n EDIT_SAFETY_NET_CANCEL: {\n category: 'Safety Net',\n action: (beat) => `${sentenceCaseTemplate(beat.template)} = Edit Safety Net - Cancel`,\n },\n\n // Connect drawer opened. PostHog-only.\n OPENED_CONNECT_DRAWER: {\n postHog: {\n eventName: 'opened_connect_drawer',\n properties: (beat) => ({ beat_guid: beat.guid, template: beat.template }),\n },\n },\n} as const satisfies Record<string, AnalyticsEventConfigEntry>\n"],"mappings":"AAGA,IAAa,IAAA,CAAwB,MACnC,GAAU,QAAQ,aAAa,KAAK,GAAG,QAAQ,MAAM,EAAE,KAAK,IAgBjD,IAA0B;AAAA,EAErC,yBAAyB;AAAA,IACvB,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EACA,2BAA2B;AAAA,IACzB,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EAEA,oCAAoC;AAAA,IAClC,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EAGA,mBAAmB;AAAA,IACjB,UAAU;AAAA,IACV,QAAA,CAAS,MAAS,GAAG,EAAqB,EAAK,QAAQ,CAAA;AAAA,EACzD;AAAA,EAEA,0BAA0B;AAAA,IACxB,UAAU;AAAA,IACV,QAAA,CAAS,MAAS,GAAG,EAAqB,EAAK,QAAQ,CAAA;AAAA,EACzD;AAAA,EAEA,cAAc;AAAA,IACZ,UAAU;AAAA,IACV,QAAA,CAAS,MAAS,GAAG,EAAqB,EAAK,QAAQ,CAAA;AAAA,EACzD;AAAA,EAGA,6BAA6B;AAAA,IAC3B,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EACA,iCAAiC;AAAA,IAC/B,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EACA,uCAAuC;AAAA,IACrC,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EAGA,sBAAsB;AAAA,IACpB,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EAEA,wBAAwB;AAAA,IACtB,UAAU;AAAA,IACV,QAAA,CAAS,MAAS,GAAG,EAAqB,EAAK,QAAQ,CAAA;AAAA,EACzD;AAAA,EAGA,uBAAuB,EACrB,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAA,CAAa,OAAU;AAAA,MAAE,WAAW,EAAK;AAAA,MAAM,UAAU,EAAK;AAAA,IAAS;AAAA,EACzE,EACF;AACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AnalyticsEventPayload } from '../beatActions';
|
|
2
|
+
import { Beat } from '../../core';
|
|
3
|
+
import { sentenceCaseTemplate, AnalyticsEventConfigEntry } from './analyticsEventsConfig';
|
|
4
|
+
export { sentenceCaseTemplate };
|
|
5
|
+
export declare const resolveAnalyticsEvent: (config: AnalyticsEventConfigEntry, beat: Beat) => AnalyticsEventPayload;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { sentenceCaseTemplate as s } from "./analyticsEventsConfig.es.js";
|
|
2
|
+
var p = (e, t) => typeof e == "function" ? e(t) : e, a = (e, t) => {
|
|
3
|
+
const o = p(e.action, t), r = p(e.category, t);
|
|
4
|
+
return {
|
|
5
|
+
...o && { action: o },
|
|
6
|
+
...r && { category: r },
|
|
7
|
+
...(o || r) && { label: s(t.template) },
|
|
8
|
+
...e.postHog && { postHog: {
|
|
9
|
+
eventName: e.postHog.eventName,
|
|
10
|
+
properties: e.postHog.properties?.(t) ?? {}
|
|
11
|
+
} }
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
a as resolveAnalyticsEvent,
|
|
16
|
+
s as sentenceCaseTemplate
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=resolveAnalyticsEvent.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveAnalyticsEvent.es.js","names":[],"sources":["../../../src/insights-v2/analytics/resolveAnalyticsEvent.ts"],"sourcesContent":["import type { AnalyticsEventPayload } from '../beatActions'\nimport type { Beat } from '../../core'\nimport { sentenceCaseTemplate, type AnalyticsEventConfigEntry } from './analyticsEventsConfig'\n\nexport { sentenceCaseTemplate }\n\nconst resolve = (\n value: string | ((beat: Beat) => string) | undefined,\n beat: Beat,\n): string | undefined => (typeof value === 'function' ? value(beat) : value)\n\n// Resolves a catalogue entry (e.g. ANALYTICS_EVENTS_CONFIG.PRIMARY_ACTION_SELECTED) + beat into\n// a final analytics payload. Takes the entry directly, not a lookup key: the call site already\n// has the entry via property access, so there is nothing to look up and nothing to mistype.\nexport const resolveAnalyticsEvent = (\n config: AnalyticsEventConfigEntry,\n beat: Beat,\n): AnalyticsEventPayload => {\n const action = resolve(config.action, beat)\n const category = resolve(config.category, beat)\n\n return {\n ...(action && { action }),\n ...(category && { category }),\n ...((action || category) && { label: sentenceCaseTemplate(beat.template) }),\n ...(config.postHog && {\n postHog: {\n eventName: config.postHog.eventName,\n properties: config.postHog.properties?.(beat) ?? {},\n },\n }),\n }\n}\n"],"mappings":";AAMA,IAAM,IAAA,CACJ,GACA,MACwB,OAAO,KAAU,aAAa,EAAM,CAAI,IAAI,GAKzD,IAAA,CACX,GACA,MAC0B;AAC1B,QAAM,IAAS,EAAQ,EAAO,QAAQ,CAAI,GACpC,IAAW,EAAQ,EAAO,UAAU,CAAI;AAE9C,SAAO;AAAA,IACL,GAAI,KAAU,EAAE,QAAA,EAAO;AAAA,IACvB,GAAI,KAAY,EAAE,UAAA,EAAS;AAAA,IAC3B,IAAK,KAAU,MAAa,EAAE,OAAO,EAAqB,EAAK,QAAQ,EAAE;AAAA,IACzE,GAAI,EAAO,WAAW,EACpB,SAAS;AAAA,MACP,WAAW,EAAO,QAAQ;AAAA,MAC1B,YAAY,EAAO,QAAQ,aAAa,CAAI,KAAK,CAAC;AAAA,IACpD,EACF;AAAA,EACF;AACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useGlobalStore as e } from "../../common/context/hooks.es.js";
|
|
2
|
+
import { useBeatActions as a } from "../beatActions.es.js";
|
|
3
|
+
import { sendCtaAnalytics as i } from "../ctaActions/runCtaAction.es.js";
|
|
4
|
+
import { useCallback as c } from "react";
|
|
5
|
+
var p = () => {
|
|
6
|
+
const t = a(), o = e();
|
|
7
|
+
return c((n) => {
|
|
8
|
+
const { beat: s, ...r } = t;
|
|
9
|
+
!s || !r.onAnalyticsEvent || i({
|
|
10
|
+
beat: s,
|
|
11
|
+
stores: o,
|
|
12
|
+
hostActions: r
|
|
13
|
+
}, n);
|
|
14
|
+
}, [t, o]);
|
|
15
|
+
};
|
|
16
|
+
export {
|
|
17
|
+
p as useAnalyticsEvent
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=useAnalyticsEvent.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAnalyticsEvent.es.js","names":[],"sources":["../../../src/insights-v2/analytics/useAnalyticsEvent.ts"],"sourcesContent":["import { useCallback } from 'react'\n\nimport { useGlobalStore } from '../../common'\nimport { useBeatActions } from '../beatActions'\nimport { sendCtaAnalytics } from '../ctaActions'\nimport type { AnalyticsEventConfigEntry } from './analyticsEventsConfig'\n\n// Call-site API: fireAnalyticsEvent(ANALYTICS_EVENTS_CONFIG.SOME_KEY).\nexport type FireAnalyticsEvent = (event: AnalyticsEventConfigEntry) => void\n\n// sendCtaAnalytics for React components; reads ctx from context, no-ops if unset.\n// Stable across renders (given a stable context value from BaseLayout's memoized\n// BeatActionsProvider) so effects that list it as a dependency (e.g.\n// ConnectWidgetActionBlock's open-fire effect) don't re-run every render. Depend on the\n// context object itself here, not a `{ beat, ...hostActions }` rest-spread of it: the\n// spread allocates a new object every render regardless of the context value's own\n// identity, which would re-break the memoization one layer down.\nexport const useAnalyticsEvent = (): FireAnalyticsEvent => {\n const actions = useBeatActions()\n const stores = useGlobalStore()\n\n return useCallback(\n (event: AnalyticsEventConfigEntry) => {\n const { beat, ...hostActions } = actions\n\n if (!beat || !hostActions.onAnalyticsEvent) return\n\n sendCtaAnalytics({ beat, stores, hostActions }, event)\n },\n [actions, stores],\n )\n}\n"],"mappings":";;;;AAiBA,IAAa,IAAA,MAA8C;AACzD,QAAM,IAAU,EAAe,GACzB,IAAS,EAAe;AAE9B,SAAO,EAAA,CACJ,MAAqC;AACpC,UAAM,EAAE,MAAA,GAAM,GAAG,EAAA,IAAgB;AAEjC,IAAI,CAAC,KAAQ,CAAC,EAAY,oBAE1B,EAAiB;AAAA,MAAE,MAAA;AAAA,MAAM,QAAA;AAAA,MAAQ,aAAA;AAAA,IAAY,GAAG,CAAK;AAAA,EACvD,GACA,CAAC,GAAS,CAAM,CAClB;AACF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
+
import { Beat } from '../core';
|
|
2
3
|
import { DismissType } from './components/DismissInsightDialog';
|
|
3
4
|
import { FeedbackDialogCloseReason } from './components/FeedbackDialog';
|
|
4
5
|
export type InsightMenuAction = 'helpful' | 'not_helpful' | 'hide';
|
|
@@ -21,11 +22,16 @@ export interface DismissParams {
|
|
|
21
22
|
beatGuid: string;
|
|
22
23
|
type: DismissType;
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
export interface AnalyticsEventPayload {
|
|
26
|
+
action?: string;
|
|
27
|
+
category?: string;
|
|
28
|
+
label?: string;
|
|
29
|
+
postHog?: {
|
|
30
|
+
eventName: string;
|
|
31
|
+
properties?: Record<string, unknown>;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** A host-side CTA effect. See ctaActions/README.md. */
|
|
29
35
|
export interface CtaActionParams {
|
|
30
36
|
beatGuid: string;
|
|
31
37
|
name: string;
|
|
@@ -43,17 +49,16 @@ export interface BeatActions {
|
|
|
43
49
|
onFeedbackDialogClose?: (reason: FeedbackDialogCloseReason) => void;
|
|
44
50
|
onFeedbackDialogBack?: () => void;
|
|
45
51
|
onFeedbackTextFocus?: () => void;
|
|
46
|
-
|
|
47
|
-
* Opens the host's contact-support flow for a `contact_support_block` CTA. insights-v2 cannot
|
|
48
|
-
* import the help module (hosts that don't ship it stub the import), so the host supplies it:
|
|
49
|
-
* the experiences Help widget wires `RequestSupport`; pulse wires its own. When absent, the CTA
|
|
50
|
-
* renders disabled (see `isContactSupportCtaDisabled`).
|
|
51
|
-
*/
|
|
52
|
+
onAnalyticsEvent?: (payload: AnalyticsEventPayload) => void;
|
|
52
53
|
onContactSupport?: () => void;
|
|
53
54
|
onCtaAction?: (params: CtaActionParams) => Promise<void> | void;
|
|
54
55
|
}
|
|
56
|
+
interface BeatActionsContextValue extends BeatActions {
|
|
57
|
+
beat?: Beat;
|
|
58
|
+
}
|
|
55
59
|
export declare const BeatActionsProvider: ({ value, children, }: {
|
|
56
|
-
value:
|
|
60
|
+
value: BeatActionsContextValue;
|
|
57
61
|
children: ReactNode;
|
|
58
62
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
59
|
-
export declare const useBeatActions: () =>
|
|
63
|
+
export declare const useBeatActions: () => BeatActionsContextValue;
|
|
64
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"beatActions.es.js","names":[],"sources":["../../src/insights-v2/beatActions.tsx"],"sourcesContent":["import { createContext, useContext, type ReactNode } from 'react'\n\nimport type { DismissType } from './components/DismissInsightDialog'\nimport type { FeedbackDialogCloseReason } from './components/FeedbackDialog'\n\nexport type InsightMenuAction = 'helpful' | 'not_helpful' | 'hide'\nexport type InsightRating = 'helpful' | 'not_helpful'\n\nexport interface MenuActionHandlers {\n onAction: (action: InsightMenuAction) => void\n onOpen?: () => void\n disabled?: boolean\n}\n\nexport interface UpdateParams {\n beatGuid: string\n}\n\nexport interface FeedbackParams {\n beatGuid: string\n source: InsightRating | 'hide' | 'cta'\n option: string\n detail?: string\n}\n\nexport interface DismissParams {\n beatGuid: string\n type: DismissType\n}\n\n
|
|
1
|
+
{"version":3,"file":"beatActions.es.js","names":[],"sources":["../../src/insights-v2/beatActions.tsx"],"sourcesContent":["import { createContext, useContext, type ReactNode } from 'react'\n\nimport type { Beat } from '../core'\nimport type { DismissType } from './components/DismissInsightDialog'\nimport type { FeedbackDialogCloseReason } from './components/FeedbackDialog'\n\nexport type InsightMenuAction = 'helpful' | 'not_helpful' | 'hide'\nexport type InsightRating = 'helpful' | 'not_helpful'\n\nexport interface MenuActionHandlers {\n onAction: (action: InsightMenuAction) => void\n onOpen?: () => void\n disabled?: boolean\n}\n\nexport interface UpdateParams {\n beatGuid: string\n}\n\nexport interface FeedbackParams {\n beatGuid: string\n source: InsightRating | 'hide' | 'cta'\n option: string\n detail?: string\n}\n\nexport interface DismissParams {\n beatGuid: string\n type: DismissType\n}\n\n// Raw analytics payload for the host.\nexport interface AnalyticsEventPayload {\n action?: string\n category?: string\n label?: string\n postHog?: {\n eventName: string\n properties?: Record<string, unknown>\n }\n}\n/** A host-side CTA effect. See ctaActions/README.md. */\nexport interface CtaActionParams {\n beatGuid: string\n name: string\n params?: Record<string, unknown>\n}\n\n/** Host callbacks for a beat card. */\nexport interface BeatActions {\n onMenuAction?: MenuActionHandlers\n onUpdate?: (params: UpdateParams) => void\n onSubmitFeedback?: (params: FeedbackParams) => void | Promise<void>\n onDismissInsight?: (params: DismissParams) => void\n onUndoDismiss?: (params: { beatGuid: string }) => void\n onFeedbackDialogClose?: (reason: FeedbackDialogCloseReason) => void\n onFeedbackDialogBack?: () => void\n onFeedbackTextFocus?: () => void\n // Raw analytics callback; use useAnalyticsEvent() instead.\n onAnalyticsEvent?: (payload: AnalyticsEventPayload) => void\n // Host's contact-support flow for a contact_support_block CTA.\n onContactSupport?: () => void\n onCtaAction?: (params: CtaActionParams) => Promise<void> | void\n}\n\n// BeatActions plus beat, for useAnalyticsEvent().\ninterface BeatActionsContextValue extends BeatActions {\n beat?: Beat\n}\n\nconst BeatActionsContext = createContext<BeatActionsContextValue>({})\n\nexport const BeatActionsProvider = ({\n value,\n children,\n}: {\n value: BeatActionsContextValue\n children: ReactNode\n}) => <BeatActionsContext.Provider value={value}>{children}</BeatActionsContext.Provider>\n\nexport const useBeatActions = () => useContext(BeatActionsContext)\n"],"mappings":";;AAsEA,IAAM,IAAqB,EAAuC,CAAC,CAAC,GAEvD,IAAA,CAAuB,EAClC,OAAA,GACA,UAAA,EAAA,MAII,gBAAA,EAAC,EAAmB,UAApB;AAAA,EAAoC,OAAA;AAAA,EAAQ,UAAA;AAAsC,CAAA,GAE3E,IAAA,MAAuB,EAAW,CAAkB"}
|
|
@@ -1,26 +1,28 @@
|
|
|
1
|
-
import { useGlobalCopyStore as B, useGlobalUiStore as
|
|
1
|
+
import { useGlobalCopyStore as B, useGlobalUiStore as I, useInsightsV2Store as L } from "../../../../common/context/hooks.es.js";
|
|
2
2
|
import { formatCurrency as S } from "../../../../core/utils/NumberFormatting.es.js";
|
|
3
|
-
import
|
|
4
|
-
import { actionBlocksKey as
|
|
5
|
-
import { BarChartV2 as
|
|
6
|
-
import { EmptyBarChart as
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
3
|
+
import T from "../../../../common/components/Loader.es.js";
|
|
4
|
+
import { actionBlocksKey as v } from "../../../mappings/actionBlocksKey.es.js";
|
|
5
|
+
import { BarChartV2 as E } from "../../../components/chartblocks/BarchartV2.es.js";
|
|
6
|
+
import { EmptyBarChart as N } from "../../../components/chartblocks/EmptyBarChart.es.js";
|
|
7
|
+
import { ANALYTICS_EVENTS_CONFIG as k } from "../../../analytics/analyticsEventsConfig.es.js";
|
|
8
|
+
import { useAnalyticsEvent as x } from "../../../analytics/useAnalyticsEvent.es.js";
|
|
9
|
+
import { barChartVariant as D, buildChartData as O, buildDataSeries as R } from "./utils.es.js";
|
|
10
|
+
import V from "react";
|
|
11
|
+
import { observer as G } from "mobx-react-lite";
|
|
10
12
|
import { jsx as e } from "react/jsx-runtime";
|
|
11
|
-
import { useTheme as
|
|
12
|
-
var
|
|
13
|
-
const l =
|
|
14
|
-
if (!f) return /* @__PURE__ */ e(
|
|
15
|
-
const
|
|
16
|
-
return t.length ? /* @__PURE__ */ e(
|
|
13
|
+
import { useTheme as K } from "@mui/material/styles";
|
|
14
|
+
var X = G(({ payload: i, beatGuid: m = "" }) => {
|
|
15
|
+
const l = K(), { openActionDrawer: c } = L(), { insights_feed: o } = B(), { isCopyLoaded: f } = I(), { instance_slot: p, instance_slot_data: a, widget_type: d } = i, { data_series: h, ariaLabel: u = "", average_amount: n = 0, legends: s = [] } = a, t = O(R(h), u), [g] = V.useState(t.length - 1), { color: C } = D(p, a, l), b = x();
|
|
16
|
+
if (!f) return /* @__PURE__ */ e(T, {});
|
|
17
|
+
const _ = [o.general.monthly_amount, o.general.trend], [A, y] = s.length ? s.map((r) => r.label) : _;
|
|
18
|
+
return t.length ? /* @__PURE__ */ e(E, {
|
|
17
19
|
amounts: {
|
|
18
20
|
average: n,
|
|
19
21
|
formattedAverage: S(n, "0,0")
|
|
20
22
|
},
|
|
21
|
-
color:
|
|
23
|
+
color: C,
|
|
22
24
|
data: t,
|
|
23
|
-
monthlyAmountLabel:
|
|
25
|
+
monthlyAmountLabel: A,
|
|
24
26
|
margin: {
|
|
25
27
|
bottom: 8,
|
|
26
28
|
left: 16,
|
|
@@ -29,21 +31,21 @@ var J = R(({ payload: m, beatGuid: i = "" }) => {
|
|
|
29
31
|
},
|
|
30
32
|
onBarClick: (r) => {
|
|
31
33
|
if (d !== "full") return !1;
|
|
32
|
-
c({
|
|
33
|
-
guid:
|
|
34
|
+
b(k.CHART_BAR_CLICKED), c({
|
|
35
|
+
guid: m,
|
|
34
36
|
trigger: "chartBar",
|
|
35
37
|
context: {
|
|
36
38
|
chartBarIndex: r,
|
|
37
|
-
block:
|
|
39
|
+
block: v.TRANSCATION_HISTORY_ACTION_BLOCK
|
|
38
40
|
}
|
|
39
41
|
});
|
|
40
42
|
},
|
|
41
|
-
selectedTabIndex:
|
|
43
|
+
selectedTabIndex: g,
|
|
42
44
|
trendAmountLabel: y
|
|
43
|
-
}) : /* @__PURE__ */ e(
|
|
45
|
+
}) : /* @__PURE__ */ e(N, {});
|
|
44
46
|
});
|
|
45
47
|
export {
|
|
46
|
-
|
|
48
|
+
X as BarchartBlock
|
|
47
49
|
};
|
|
48
50
|
|
|
49
51
|
//# 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'\nimport { observer } from 'mobx-react-lite'\n\nimport {\n formatCurrency,\n Loader,\n useGlobalCopyStore,\n useGlobalUiStore,\n useInsightsV2Store,\n} 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 = observer(\n ({ payload, beatGuid = '' }: BlockProps<BarChartBlockData>) => {\n const theme = useTheme()\n const { openActionDrawer } = useInsightsV2Store()\n const { insights_feed: insightsFeedCopy } = useGlobalCopyStore()\n const { isCopyLoaded } = useGlobalUiStore()\n const { instance_slot, instance_slot_data, widget_type } = 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 if (!isCopyLoaded) {\n return <Loader />\n }\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 fallbackLabels = [insightsFeedCopy.general.monthly_amount, insightsFeedCopy.general.trend]\n\n const [monthlyAmountLabel, trendAmountLabel] = legends.length\n ? legends.map((legend) => legend.label)\n : fallbackLabels\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 margin={{\n bottom: 8,\n left: 16,\n right: 16,\n top: 16,\n }}\n onBarClick={(index) => {\n if (widget_type !== 'full') return false\n\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)\n"],"mappings":"
|
|
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'\nimport { observer } from 'mobx-react-lite'\n\nimport {\n formatCurrency,\n Loader,\n useGlobalCopyStore,\n useGlobalUiStore,\n useInsightsV2Store,\n} 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 { ANALYTICS_EVENTS_CONFIG, useAnalyticsEvent } from '../../../analytics'\nimport type { BlockProps } from '../../types'\n\nimport { barChartVariant, buildChartData, buildDataSeries } from './utils'\nimport { actionBlocksKey } from '../../../mappings/actionBlocksKey'\n\nexport const BarchartBlock = observer(\n ({ payload, beatGuid = '' }: BlockProps<BarChartBlockData>) => {\n const theme = useTheme()\n const { openActionDrawer } = useInsightsV2Store()\n const { insights_feed: insightsFeedCopy } = useGlobalCopyStore()\n const { isCopyLoaded } = useGlobalUiStore()\n const { instance_slot, instance_slot_data, widget_type } = 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 const fireAnalyticsEvent = useAnalyticsEvent()\n\n if (!isCopyLoaded) {\n return <Loader />\n }\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 fallbackLabels = [insightsFeedCopy.general.monthly_amount, insightsFeedCopy.general.trend]\n\n const [monthlyAmountLabel, trendAmountLabel] = legends.length\n ? legends.map((legend) => legend.label)\n : fallbackLabels\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 margin={{\n bottom: 8,\n left: 16,\n right: 16,\n top: 16,\n }}\n onBarClick={(index) => {\n if (widget_type !== 'full') return false\n\n fireAnalyticsEvent(ANALYTICS_EVENTS_CONFIG.CHART_BAR_CLICKED)\n\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)\n"],"mappings":";;;;;;;;;;;;;AAuBA,IAAa,IAAgB,EAAA,CAC1B,EAAE,SAAA,GAAS,UAAA,IAAW,GAAA,MAAwC;AAC7D,QAAM,IAAQ,EAAS,GACjB,EAAE,kBAAA,EAAA,IAAqB,EAAmB,GAC1C,EAAE,eAAe,EAAA,IAAqB,EAAmB,GACzD,EAAE,cAAA,EAAA,IAAiB,EAAiB,GACpC,EAAE,eAAA,GAAe,oBAAA,GAAoB,aAAA,EAAA,IAAgB,GACrD,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,GACpE,IAAqB,EAAkB;AAE7C,MAAI,CAAC,EACH,QAAO,gBAAA,EAAC,GAAD,CAAS,CAAA;AAKlB,QAAM,IAAiB,CAAC,EAAiB,QAAQ,gBAAgB,EAAiB,QAAQ,KAAK,GAEzF,CAAC,GAAoB,CAAA,IAAoB,EAAQ,SACnD,EAAQ,IAAA,CAAK,MAAW,EAAO,KAAK,IACpC;AAEJ,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,QAAQ;AAAA,MACN,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,KAAK;AAAA,IACP;AAAA,IACA,YAAA,CAAa,MAAU;AACrB,UAAI,MAAgB,OAAQ,QAAO;AAEnC,MAAA,EAAmB,EAAwB,iBAAiB,GAE5D,EAAiB;AAAA,QACf,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,UACP,eAAe;AAAA,UACf,OAAO,EAAgB;AAAA,QACzB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACkB,kBAAA;AAAA,IACA,kBAAA;AAAA,EACnB,CAAA,IAED,gBAAA,EAAC,GAAD,CAAgB,CAAA;AAEpB,CACF"}
|