@mx-cartographer/experiences 9.4.24 → 9.4.25
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 +10 -0
- package/dist/core/types/Insights.d.ts +2 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.d.ts +3 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.es.js +39 -37
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js +80 -71
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.d.ts +5 -3
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js +61 -53
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js.map +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.d.ts +3 -1
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js +28 -24
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js.map +1 -1
- package/dist/insights-v2/components/BaseLayout.es.js +39 -39
- package/dist/insights-v2/components/BaseLayout.es.js.map +1 -1
- package/dist/insights-v2/components/SubHeader.es.js +4 -4
- package/dist/insights-v2/components/SubHeader.es.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## [9.4.25] - 09-16-2026
|
|
2
|
+
|
|
3
|
+
- **ADDED** - Dismissible tip section in the `TransactionHistoryBlock` drawer's `bill_amount_not_standard` (`TRANSACTION`) drilldown variant: a shared `TipSection` component nudging the user to reach out to the merchant, dismissible via a new `onDismiss` handler and `tip_section_message`/`tip_section_title` copy keys (`insights_feed.general`) (WEC-1804)
|
|
4
|
+
- **ADDED** - `InsightsPayload.title` (`string`), per backend confirmation that the beat's display title is sent on the payload rather than read off the beat itself (WEC-1804)
|
|
5
|
+
- **CHANGED** - Renamed `InsightsPayload.subtitle` to `InsightsPayload.sub_title` to match what the backend actually sends, updating `BaseLayout`, `TransactionHistoryBlock`, and all related test/story/mock fixtures (WEC-1804)
|
|
6
|
+
- **CHANGED** - `BaseLayout` and `TransactionHistoryBlock`'s `bill_amount_not_standard` (`TRANSACTION`) drilldown header now read the beat's title/subtitle from `insights_payload.title`/`insights_payload.sub_title` instead of `beat.title`/`beat.html_title`; `DrillDownHeaderContext` (`TransactionHistoryBlock/layout.tsx`) updated from `{ htmlTitle, primaryTransaction }` to `{ title, subHeader }` to match (WEC-1804)
|
|
7
|
+
- **CHANGED** - `SubHeader`'s logo resolution now checks `merchant_guid` before `institution_guid` (previously institution took priority over merchant), with a TODO to have the backend send only the one relevant guid per beat instead of relying on check order (WEC-1804)
|
|
8
|
+
- **FIXED** - `TransactionHistoryBlock` and `BarchartBlock` now fall back to the generic "Monthly Amount"/"Trend" copy for the bar chart's legend labels when the backend doesn't send `legends` on `instance_slot_data`. `TransactionHistoryBlock`'s first attempt at this fallback was dead code (`array.map() ?? fallback` — `.map()` never returns `null`/`undefined`, so the `??` could never trigger); fixed to check `legends?.length` before mapping, and added regression tests for the empty-legends case in both blocks (WEC-1804)
|
|
9
|
+
- **FIXED** - `BarchartBlock` now waits on `GlobalUiStore.isCopyLoaded` (rendering `Loader` until then) before reading copy for its legend fallback, matching `TransactionHistoryBlock`'s pattern — `BaseLayout` renders block components without waiting for copy to load, so `BarchartBlock` could previously mount and crash (`Cannot read properties of undefined (reading 'general')`) before `GlobalCopyStore` finished loading (WEC-1804)
|
|
10
|
+
|
|
1
11
|
## [9.4.24] - 09-16-2026
|
|
2
12
|
|
|
3
13
|
- **ADDED** - insights-v2 beat CTA post message (ported from Pulse): when a beat CTA has no drilldown drawer `block`, clicking it now notifies the host via a `beat/cta` post message (payload `action`, `beat_guid`, `beat_template`, `action_string?`, `user_guid`) or, on a native mobile webview, navigates to a `scheme://pulse/<event>?metadata=...` URL. New helpers in `common/utils/PostMessage.ts` (`getBaseCtaPostMessage`, `sendBeatPostMessage`, `setWebviewURL`, `dispatchBeatCta`, `BEAT_CTA_EVENT`, `BEAT_OPERATION_1/2/3`); `BaseLayout` CTA buttons route through a `handleCtaClick` helper that opens the drawer for CTAs with a real block and otherwise dispatches the post message. Scoped to the Save an extra $100 beat's "Make a Transfer" CTA (WEC-1805)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
import { TipSectionProps } from '../../../insights/components/shared/ChartDrawerTemplate/TipSection';
|
|
2
3
|
import { Transaction } from '../../../core';
|
|
3
4
|
interface TabItem {
|
|
4
5
|
label: string;
|
|
@@ -12,12 +13,13 @@ interface TransactionDrillDownProps {
|
|
|
12
13
|
tabs?: TabItem[];
|
|
13
14
|
selectedIndex: number;
|
|
14
15
|
top: React.ReactNode;
|
|
16
|
+
tipSection?: TipSectionProps | false;
|
|
15
17
|
onSelectionChange?: (selectedIndex: number) => void;
|
|
16
18
|
onEachRowClick?: (guid: string) => void;
|
|
17
19
|
transactionFilter?: (selectedIndex: number) => (transaction: Transaction) => boolean;
|
|
18
20
|
baseTransactions?: Transaction[];
|
|
19
21
|
}
|
|
20
|
-
export declare const TransactionDrillDown: (({ ariaLabel, heading, subHeadingText, icon, tabs, selectedIndex, top, onSelectionChange, transactionFilter, onEachRowClick, baseTransactions, }: TransactionDrillDownProps) => import("react/jsx-runtime").JSX.Element) & {
|
|
22
|
+
export declare const TransactionDrillDown: (({ ariaLabel, heading, subHeadingText, icon, tabs, selectedIndex, top, onSelectionChange, transactionFilter, tipSection, onEachRowClick, baseTransactions, }: TransactionDrillDownProps) => import("react/jsx-runtime").JSX.Element) & {
|
|
21
23
|
displayName: string;
|
|
22
24
|
};
|
|
23
25
|
export default TransactionDrillDown;
|
|
@@ -1,37 +1,38 @@
|
|
|
1
|
-
import { useGlobalCopyStore as
|
|
2
|
-
import { exportTransactionsToCSV as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import { useGlobalCopyStore as $, useGlobalUiStore as j, useTransactionStore as G } from "../../../common/context/hooks.es.js";
|
|
2
|
+
import { exportTransactionsToCSV as P } from "../../../core/utils/TransactionUtils.es.js";
|
|
3
|
+
import A from "../../../common/components/Loader.es.js";
|
|
4
|
+
import E from "../../../transactions/components/shared/TransactionList.es.js";
|
|
5
|
+
import { TipSection as N } from "../../../insights/components/shared/ChartDrawerTemplate/TipSection.es.js";
|
|
5
6
|
import "react";
|
|
6
|
-
import { observer as
|
|
7
|
+
import { observer as R } from "mobx-react-lite";
|
|
7
8
|
import c from "@mui/material/Stack";
|
|
8
|
-
import { H3 as
|
|
9
|
-
import
|
|
10
|
-
import { Icon as
|
|
9
|
+
import { H3 as U, Text as m } from "@mxenabled/mxui";
|
|
10
|
+
import V from "@mui/material/Button";
|
|
11
|
+
import { Icon as q } from "@mxenabled/mx-icons";
|
|
11
12
|
import { jsx as o, jsxs as r } from "react/jsx-runtime";
|
|
12
13
|
import p from "@mui/material/Box";
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
var
|
|
16
|
-
const { transactions: l } =
|
|
17
|
-
if (!
|
|
18
|
-
const s = !!b?.length,
|
|
19
|
-
|
|
20
|
-
},
|
|
14
|
+
import z from "@mui/material/Tab";
|
|
15
|
+
import J from "@mui/material/Tabs";
|
|
16
|
+
var v = "transaction-drill-down-panel", T = (d) => `transaction-details-tab-${d}`, lo = R(function({ ariaLabel: y, heading: i, subHeadingText: n, icon: C, tabs: b, selectedIndex: e, top: g, onSelectionChange: _, transactionFilter: f, tipSection: h, onEachRowClick: w, baseTransactions: D }) {
|
|
17
|
+
const { transactions: l } = $(), { isCopyLoaded: S } = j(), { sortedTransactionsWithSplits: L, tags: B, detailedTransactions: I } = G();
|
|
18
|
+
if (!S) return /* @__PURE__ */ o(A, {});
|
|
19
|
+
const s = !!b?.length, k = y ?? l.transactions_title, W = (t, a) => {
|
|
20
|
+
_?.(a);
|
|
21
|
+
}, x = f ? (D ?? I).filter(f(e)) : void 0, u = x ?? L;
|
|
21
22
|
return /* @__PURE__ */ r(p, {
|
|
22
23
|
sx: {
|
|
23
24
|
bgcolor: "background.paper",
|
|
24
25
|
width: "100%"
|
|
25
26
|
},
|
|
26
|
-
children: [s && /* @__PURE__ */ o(
|
|
27
|
-
"aria-label":
|
|
28
|
-
onChange:
|
|
27
|
+
children: [s && /* @__PURE__ */ o(J, {
|
|
28
|
+
"aria-label": k,
|
|
29
|
+
onChange: W,
|
|
29
30
|
value: e,
|
|
30
31
|
variant: "fullWidth",
|
|
31
|
-
children: b.map((t, a) => /* @__PURE__ */ o(
|
|
32
|
-
"aria-controls":
|
|
32
|
+
children: b.map((t, a) => /* @__PURE__ */ o(z, {
|
|
33
|
+
"aria-controls": v,
|
|
33
34
|
"aria-label": t.ariaLabel,
|
|
34
|
-
id:
|
|
35
|
+
id: T(a),
|
|
35
36
|
label: t.label,
|
|
36
37
|
sx: {
|
|
37
38
|
minWidth: "auto",
|
|
@@ -39,8 +40,8 @@ var u = "transaction-drill-down-panel", v = (m) => `transaction-details-tab-${m}
|
|
|
39
40
|
}
|
|
40
41
|
}, `${t.label}-${a}`))
|
|
41
42
|
}), /* @__PURE__ */ r(p, {
|
|
42
|
-
"aria-labelledby": s ?
|
|
43
|
-
id:
|
|
43
|
+
"aria-labelledby": s ? T(e) : void 0,
|
|
44
|
+
id: v,
|
|
44
45
|
role: s ? "tabpanel" : void 0,
|
|
45
46
|
children: [
|
|
46
47
|
(i || n) && /* @__PURE__ */ r(c, {
|
|
@@ -49,13 +50,13 @@ var u = "transaction-drill-down-panel", v = (m) => `transaction-details-tab-${m}
|
|
|
49
50
|
pt: 16,
|
|
50
51
|
px: 24
|
|
51
52
|
},
|
|
52
|
-
children: [i && /* @__PURE__ */ o(
|
|
53
|
+
children: [i && /* @__PURE__ */ o(U, { children: i }), n && /* @__PURE__ */ r(c, {
|
|
53
54
|
sx: {
|
|
54
55
|
alignItems: "center",
|
|
55
56
|
flexDirection: "row",
|
|
56
57
|
gap: 8
|
|
57
58
|
},
|
|
58
|
-
children: [
|
|
59
|
+
children: [C, /* @__PURE__ */ o(m, {
|
|
59
60
|
textTransform: "uppercase",
|
|
60
61
|
variant: "body2",
|
|
61
62
|
children: n
|
|
@@ -64,8 +65,9 @@ var u = "transaction-drill-down-panel", v = (m) => `transaction-details-tab-${m}
|
|
|
64
65
|
}),
|
|
65
66
|
/* @__PURE__ */ o(p, {
|
|
66
67
|
sx: { pt: 16 },
|
|
67
|
-
children:
|
|
68
|
+
children: g
|
|
68
69
|
}),
|
|
70
|
+
h && /* @__PURE__ */ o(N, { ...h }),
|
|
69
71
|
/* @__PURE__ */ r(c, {
|
|
70
72
|
sx: {
|
|
71
73
|
alignItems: "center",
|
|
@@ -78,34 +80,34 @@ var u = "transaction-drill-down-panel", v = (m) => `transaction-details-tab-${m}
|
|
|
78
80
|
pt: 16,
|
|
79
81
|
px: 24
|
|
80
82
|
},
|
|
81
|
-
children: [/* @__PURE__ */ o(
|
|
83
|
+
children: [/* @__PURE__ */ o(m, {
|
|
82
84
|
bold: !0,
|
|
83
85
|
variant: "body1",
|
|
84
86
|
children: l.transactions_title
|
|
85
|
-
}),
|
|
87
|
+
}), u.length > 0 && /* @__PURE__ */ o(V, {
|
|
86
88
|
onClick: () => {
|
|
87
|
-
|
|
89
|
+
P(u, B);
|
|
88
90
|
},
|
|
89
|
-
startIcon: /* @__PURE__ */ o(
|
|
91
|
+
startIcon: /* @__PURE__ */ o(q, { name: "ios_share" }),
|
|
90
92
|
sx: { height: 28 },
|
|
91
|
-
children: /* @__PURE__ */ o(
|
|
93
|
+
children: /* @__PURE__ */ o(m, {
|
|
92
94
|
bold: !0,
|
|
93
95
|
variant: "body2",
|
|
94
96
|
children: l.export_csv_btn
|
|
95
97
|
})
|
|
96
98
|
})]
|
|
97
99
|
}),
|
|
98
|
-
/* @__PURE__ */ o(
|
|
99
|
-
transaction:
|
|
100
|
-
onClick:
|
|
100
|
+
/* @__PURE__ */ o(E, {
|
|
101
|
+
transaction: x,
|
|
102
|
+
onClick: w
|
|
101
103
|
})
|
|
102
104
|
]
|
|
103
105
|
})]
|
|
104
106
|
});
|
|
105
107
|
});
|
|
106
108
|
export {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
lo as TransactionDrillDown,
|
|
110
|
+
lo as default
|
|
109
111
|
};
|
|
110
112
|
|
|
111
113
|
//# sourceMappingURL=TransactionDrillDown.es.js.map
|
package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionDrillDown.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.tsx"],"sourcesContent":["import React from 'react'\n\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport Tab from '@mui/material/Tab'\nimport Tabs from '@mui/material/Tabs'\nimport { observer } from 'mobx-react-lite'\n\nimport { Icon } from '@mxenabled/mx-icons'\nimport { H3, Text } from '@mxenabled/mxui'\n\nimport { Loader, useGlobalCopyStore, useGlobalUiStore, useTransactionStore } from '../../../common'\nimport type { Transaction } from '../../../core'\nimport { exportTransactionsToCSV } from '../../../core/utils/TransactionUtils'\nimport { TransactionList } from '../../../transactions'\n\ninterface TabItem {\n label: string\n ariaLabel?: string\n}\n\nconst PANEL_ID = 'transaction-drill-down-panel'\nconst tabId = (index: number) => `transaction-details-tab-${index}`\n\ninterface TransactionDrillDownProps {\n ariaLabel?: string\n heading?: string\n subHeadingText?: string\n icon?: React.ReactNode\n tabs?: TabItem[]\n selectedIndex: number\n top: React.ReactNode\n onSelectionChange?: (selectedIndex: number) => void\n onEachRowClick?: (guid: string) => void\n transactionFilter?: (selectedIndex: number) => (transaction: Transaction) => boolean\n baseTransactions?: Transaction[]\n}\n\nexport const TransactionDrillDown = observer(function TransactionDrillDown({\n ariaLabel,\n heading,\n subHeadingText,\n icon,\n tabs,\n selectedIndex,\n top,\n onSelectionChange,\n transactionFilter,\n onEachRowClick,\n baseTransactions,\n}: TransactionDrillDownProps) {\n const { transactions: transactionsCopy } = useGlobalCopyStore()\n const { isCopyLoaded } = useGlobalUiStore()\n const { sortedTransactionsWithSplits, tags, detailedTransactions } = useTransactionStore()\n\n if (!isCopyLoaded) return <Loader />\n\n const hasTabs = !!tabs?.length\n const tablistLabel = ariaLabel ?? transactionsCopy.transactions_title\n\n const handlePrimaryChange = (_event: React.SyntheticEvent, newValue: number) => {\n onSelectionChange?.(newValue)\n }\n\n const filteredTransactions = transactionFilter\n ? (baseTransactions ?? detailedTransactions).filter(transactionFilter(selectedIndex))\n : undefined\n\n const exportTransactions = filteredTransactions ?? sortedTransactionsWithSplits\n\n return (\n <Box sx={{ bgcolor: 'background.paper', width: '100%' }}>\n {hasTabs && (\n <Tabs\n aria-label={tablistLabel}\n onChange={handlePrimaryChange}\n value={selectedIndex}\n variant=\"fullWidth\"\n >\n {tabs!.map((tab, index) => (\n <Tab\n aria-controls={PANEL_ID}\n aria-label={tab.ariaLabel}\n id={tabId(index)}\n key={`${tab.label}-${index}`}\n label={tab.label}\n sx={{ minWidth: 'auto', px: 0 }}\n />\n ))}\n </Tabs>\n )}\n\n <Box\n aria-labelledby={hasTabs ? tabId(selectedIndex) : undefined}\n id={PANEL_ID}\n role={hasTabs ? 'tabpanel' : undefined}\n >\n {(heading || subHeadingText) && (\n <Stack sx={{ gap: 4, pt: 16, px: 24 }}>\n {heading && <H3>{heading}</H3>}\n {subHeadingText && (\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', gap: 8 }}>\n {icon}\n <Text textTransform=\"uppercase\" variant=\"body2\">\n {subHeadingText}\n </Text>\n </Stack>\n )}\n </Stack>\n )}\n\n <Box sx={{ pt: 16 }}>{top}</Box>\n\n <Stack\n sx={{\n alignItems: 'center',\n borderBottomColor: 'divider',\n borderBottomStyle: 'solid',\n borderBottomWidth: 1,\n flexDirection: 'row',\n justifyContent: 'space-between',\n pb: 4,\n pt: 16,\n px: 24,\n }}\n >\n <Text bold={true} variant=\"body1\">\n {transactionsCopy.transactions_title}\n </Text>\n {exportTransactions.length > 0 && (\n <Button\n onClick={() => {\n exportTransactionsToCSV(exportTransactions, tags)\n }}\n startIcon={<Icon name=\"ios_share\" />}\n sx={{ height: 28 }}\n >\n <Text bold={true} variant=\"body2\">\n {transactionsCopy.export_csv_btn}\n </Text>\n </Button>\n )}\n </Stack>\n\n <TransactionList transaction={filteredTransactions} onClick={onEachRowClick} />\n </Box>\n </Box>\n )\n})\n\nexport default TransactionDrillDown\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"TransactionDrillDown.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.tsx"],"sourcesContent":["import React from 'react'\n\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport Tab from '@mui/material/Tab'\nimport Tabs from '@mui/material/Tabs'\nimport { observer } from 'mobx-react-lite'\n\nimport { Icon } from '@mxenabled/mx-icons'\nimport { H3, Text } from '@mxenabled/mxui'\n\nimport {\n TipSection,\n type TipSectionProps,\n} from '../../../insights/components/shared/ChartDrawerTemplate/TipSection'\nimport { Loader, useGlobalCopyStore, useGlobalUiStore, useTransactionStore } from '../../../common'\nimport type { Transaction } from '../../../core'\nimport { exportTransactionsToCSV } from '../../../core/utils/TransactionUtils'\nimport { TransactionList } from '../../../transactions'\n\ninterface TabItem {\n label: string\n ariaLabel?: string\n}\n\nconst PANEL_ID = 'transaction-drill-down-panel'\nconst tabId = (index: number) => `transaction-details-tab-${index}`\n\ninterface TransactionDrillDownProps {\n ariaLabel?: string\n heading?: string\n subHeadingText?: string\n icon?: React.ReactNode\n tabs?: TabItem[]\n selectedIndex: number\n top: React.ReactNode\n tipSection?: TipSectionProps | false\n onSelectionChange?: (selectedIndex: number) => void\n onEachRowClick?: (guid: string) => void\n transactionFilter?: (selectedIndex: number) => (transaction: Transaction) => boolean\n baseTransactions?: Transaction[]\n}\n\nexport const TransactionDrillDown = observer(function TransactionDrillDown({\n ariaLabel,\n heading,\n subHeadingText,\n icon,\n tabs,\n selectedIndex,\n top,\n onSelectionChange,\n transactionFilter,\n tipSection,\n onEachRowClick,\n baseTransactions,\n}: TransactionDrillDownProps) {\n const { transactions: transactionsCopy } = useGlobalCopyStore()\n const { isCopyLoaded } = useGlobalUiStore()\n const { sortedTransactionsWithSplits, tags, detailedTransactions } = useTransactionStore()\n\n if (!isCopyLoaded) return <Loader />\n\n const hasTabs = !!tabs?.length\n const tablistLabel = ariaLabel ?? transactionsCopy.transactions_title\n\n const handlePrimaryChange = (_event: React.SyntheticEvent, newValue: number) => {\n onSelectionChange?.(newValue)\n }\n\n const filteredTransactions = transactionFilter\n ? (baseTransactions ?? detailedTransactions).filter(transactionFilter(selectedIndex))\n : undefined\n\n const exportTransactions = filteredTransactions ?? sortedTransactionsWithSplits\n\n return (\n <Box sx={{ bgcolor: 'background.paper', width: '100%' }}>\n {hasTabs && (\n <Tabs\n aria-label={tablistLabel}\n onChange={handlePrimaryChange}\n value={selectedIndex}\n variant=\"fullWidth\"\n >\n {tabs!.map((tab, index) => (\n <Tab\n aria-controls={PANEL_ID}\n aria-label={tab.ariaLabel}\n id={tabId(index)}\n key={`${tab.label}-${index}`}\n label={tab.label}\n sx={{ minWidth: 'auto', px: 0 }}\n />\n ))}\n </Tabs>\n )}\n\n <Box\n aria-labelledby={hasTabs ? tabId(selectedIndex) : undefined}\n id={PANEL_ID}\n role={hasTabs ? 'tabpanel' : undefined}\n >\n {(heading || subHeadingText) && (\n <Stack sx={{ gap: 4, pt: 16, px: 24 }}>\n {heading && <H3>{heading}</H3>}\n {subHeadingText && (\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', gap: 8 }}>\n {icon}\n <Text textTransform=\"uppercase\" variant=\"body2\">\n {subHeadingText}\n </Text>\n </Stack>\n )}\n </Stack>\n )}\n\n <Box sx={{ pt: 16 }}>{top}</Box>\n\n {/* TODO: need to use a nseperate compnent from insight-v2, for now using insights-shared component which will be shifted under insights-v2 in future */}\n {tipSection && <TipSection {...tipSection} />}\n\n <Stack\n sx={{\n alignItems: 'center',\n borderBottomColor: 'divider',\n borderBottomStyle: 'solid',\n borderBottomWidth: 1,\n flexDirection: 'row',\n justifyContent: 'space-between',\n pb: 4,\n pt: 16,\n px: 24,\n }}\n >\n <Text bold={true} variant=\"body1\">\n {transactionsCopy.transactions_title}\n </Text>\n {exportTransactions.length > 0 && (\n <Button\n onClick={() => {\n exportTransactionsToCSV(exportTransactions, tags)\n }}\n startIcon={<Icon name=\"ios_share\" />}\n sx={{ height: 28 }}\n >\n <Text bold={true} variant=\"body2\">\n {transactionsCopy.export_csv_btn}\n </Text>\n </Button>\n )}\n </Stack>\n\n <TransactionList transaction={filteredTransactions} onClick={onEachRowClick} />\n </Box>\n </Box>\n )\n})\n\nexport default TransactionDrillDown\n"],"mappings":"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"}
|
|
@@ -1,105 +1,114 @@
|
|
|
1
|
-
import { useGlobalCopyStore as
|
|
2
|
-
import
|
|
3
|
-
import { formatCurrency as
|
|
4
|
-
import
|
|
5
|
-
import { BarChartV2 as
|
|
6
|
-
import { EmptyBarChart as
|
|
7
|
-
import { TransactionDrillDown as
|
|
8
|
-
import { useTransactionHistory as
|
|
9
|
-
import { getDefaultSelection as
|
|
10
|
-
import { TransactionDetailsBlock as
|
|
11
|
-
import { useLayoutEffect as
|
|
12
|
-
import { observer as
|
|
13
|
-
import { Fragment as
|
|
14
|
-
import { useTheme as
|
|
15
|
-
var
|
|
16
|
-
const
|
|
1
|
+
import { useGlobalCopyStore as Q, useGlobalUiStore as W, useInsightsV2Store as X } from "../../../common/context/hooks.es.js";
|
|
2
|
+
import Y from "../../../common/components/drawer/Drawer.es.js";
|
|
3
|
+
import { formatCurrency as Z } from "../../../core/utils/NumberFormatting.es.js";
|
|
4
|
+
import tt from "../../../common/components/Loader.es.js";
|
|
5
|
+
import { BarChartV2 as et } from "../../components/chartblocks/BarchartV2.es.js";
|
|
6
|
+
import { EmptyBarChart as at } from "../../components/chartblocks/EmptyBarChart.es.js";
|
|
7
|
+
import { TransactionDrillDown as ot } from "./TransactionDrillDown.es.js";
|
|
8
|
+
import { useTransactionHistory as nt } from "./useTransactionHistory.es.js";
|
|
9
|
+
import { getDefaultSelection as rt, getDrillDownConfig as it, getFlattenedDataSeries as st, toStoreFilter as lt } from "./utils.es.js";
|
|
10
|
+
import { TransactionDetailsBlock as ct } from "../TransactionDetailsBlock/TransactionDetailsBlock.es.js";
|
|
11
|
+
import { useLayoutEffect as dt, useState as u } from "react";
|
|
12
|
+
import { observer as mt } from "mobx-react-lite";
|
|
13
|
+
import { Fragment as gt, jsx as o, jsxs as pt } from "react/jsx-runtime";
|
|
14
|
+
import { useTheme as ut } from "@mui/material/styles";
|
|
15
|
+
var It = mt(({ beat: a }) => {
|
|
16
|
+
const b = ut(), { instanceSlotData: e, beatTransactions: s, spendCategoryGuids: h, allAccountGuids: f, categoryName: v, displayedDateRange: m, transactionStore: x } = nt(a), { actionDrawer: y, setActionContext: C } = X(), { common: B, insights_feed: l } = Q(), { isCopyLoaded: F } = W(), [I, T] = u(!1), [G, A] = u(!1), { insights_payload: n } = a, j = y.trigger === "secondaryCta" ? n?.secondary_cta?.variant : n?.primary_cta?.variant, { top: g, filterMode: c, header: k, colors: w, filterStrategy: H, tipSection: S } = it(j ?? ""), { dataSeries: d, chartData: r, comparisonBars: E } = st({
|
|
17
17
|
data: e?.data_series,
|
|
18
18
|
ariaLabel: e?.ariaLabel ?? "",
|
|
19
|
-
top:
|
|
20
|
-
beatTransactions:
|
|
19
|
+
top: g,
|
|
20
|
+
beatTransactions: s,
|
|
21
21
|
payload: e
|
|
22
|
-
}), { chartBarIndex:
|
|
22
|
+
}), { chartBarIndex: K, subTabIndex: O } = rt({
|
|
23
23
|
chartTabCount: r.length,
|
|
24
|
-
comparisonTabCount:
|
|
25
|
-
actionDrawer:
|
|
24
|
+
comparisonTabCount: E.length,
|
|
25
|
+
actionDrawer: y,
|
|
26
26
|
beatGuid: a.guid
|
|
27
|
-
}), [
|
|
27
|
+
}), [i, _] = u(K), D = (t) => H({
|
|
28
28
|
beat: a,
|
|
29
|
-
beatTransactions:
|
|
30
|
-
dataSeries:
|
|
29
|
+
beatTransactions: s,
|
|
30
|
+
dataSeries: d,
|
|
31
31
|
selectedIndex: t,
|
|
32
|
-
subIndex:
|
|
33
|
-
isLastTab: t ===
|
|
32
|
+
subIndex: O,
|
|
33
|
+
isLastTab: t === d.length - 1,
|
|
34
34
|
instanceSlotData: e,
|
|
35
|
-
spendCategoryGuids:
|
|
36
|
-
displayedDateRange:
|
|
37
|
-
}),
|
|
38
|
-
|
|
39
|
-
allAccountGuids:
|
|
40
|
-
displayedDateRange:
|
|
35
|
+
spendCategoryGuids: h,
|
|
36
|
+
displayedDateRange: m
|
|
37
|
+
}), V = s.map((t) => t.guid).join(","), R = h.join(","), M = f.join(","), L = () => {
|
|
38
|
+
c !== "store" || !d.length || x.setFilter(lt(D(i), {
|
|
39
|
+
allAccountGuids: f,
|
|
40
|
+
displayedDateRange: m
|
|
41
41
|
}));
|
|
42
42
|
};
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
dt(() => {
|
|
44
|
+
L();
|
|
45
45
|
}, [
|
|
46
46
|
a.guid,
|
|
47
|
-
|
|
48
|
-
s,
|
|
49
|
-
l.length,
|
|
50
|
-
e,
|
|
47
|
+
i,
|
|
51
48
|
c,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
d.length,
|
|
50
|
+
e,
|
|
51
|
+
m,
|
|
52
|
+
R,
|
|
53
|
+
M,
|
|
54
|
+
V
|
|
55
55
|
]);
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
const p = k?.({
|
|
57
|
+
title: n?.title,
|
|
58
|
+
subHeader: n?.sub_title,
|
|
59
59
|
categoryName: v,
|
|
60
|
-
selectedDate: r[
|
|
61
|
-
}),
|
|
60
|
+
selectedDate: r[i]?.date ?? void 0
|
|
61
|
+
}), N = w(b, e?.category_guid);
|
|
62
|
+
if (!F) return /* @__PURE__ */ o(tt, {});
|
|
63
|
+
const P = [l.general.monthly_amount, l.general.trend], [U, $] = e?.legends?.length ? e.legends.map((t) => t.label) : P, q = c === "local" ? (t) => D(t).custom ?? (() => !0) : void 0, z = c === "local" ? s : void 0, J = g === "singleBar" || g === "upcomingBill" ? r.length ? /* @__PURE__ */ o(et, {
|
|
62
64
|
amounts: {
|
|
63
65
|
average: e?.average_amount,
|
|
64
|
-
formattedAverage:
|
|
66
|
+
formattedAverage: Z(e?.average_amount ?? 0, "0,0.00")
|
|
65
67
|
},
|
|
66
|
-
color:
|
|
68
|
+
color: N[0] ?? b.palette.primary.main,
|
|
67
69
|
data: r,
|
|
68
70
|
legendPosition: "top",
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
margin: {
|
|
72
|
+
bottom: 30,
|
|
73
|
+
top: 20,
|
|
74
|
+
left: 24,
|
|
75
|
+
right: 24
|
|
76
|
+
},
|
|
77
|
+
monthlyAmountLabel: U,
|
|
78
|
+
onBarClick: _,
|
|
79
|
+
selectedTabIndex: i,
|
|
80
|
+
trendAmountLabel: $
|
|
81
|
+
}) : /* @__PURE__ */ o(at, {}) : null;
|
|
82
|
+
return /* @__PURE__ */ pt(gt, { children: [/* @__PURE__ */ o(ot, {
|
|
75
83
|
ariaLabel: e?.ariaLabel,
|
|
76
|
-
baseTransactions:
|
|
77
|
-
heading:
|
|
78
|
-
icon:
|
|
79
|
-
onSelectionChange:
|
|
80
|
-
selectedIndex:
|
|
81
|
-
subHeadingText:
|
|
84
|
+
baseTransactions: z,
|
|
85
|
+
heading: p?.heading,
|
|
86
|
+
icon: p?.icon,
|
|
87
|
+
onSelectionChange: _,
|
|
88
|
+
selectedIndex: i,
|
|
89
|
+
subHeadingText: p?.subHeadingText,
|
|
82
90
|
tabs: r.map((t) => ({
|
|
83
91
|
ariaLabel: t.ariaLabel,
|
|
84
92
|
label: t.label
|
|
85
93
|
})),
|
|
86
|
-
top:
|
|
87
|
-
|
|
94
|
+
top: J,
|
|
95
|
+
...S && { tipSection: !G && S(A, l, n?.sub_title?.text) },
|
|
96
|
+
transactionFilter: q,
|
|
88
97
|
onEachRowClick: (t) => {
|
|
89
|
-
|
|
98
|
+
C({ transaction_guid: t }), T(!0);
|
|
90
99
|
}
|
|
91
|
-
}), /* @__PURE__ */ o(
|
|
92
|
-
ariaLabelClose:
|
|
93
|
-
isOpen:
|
|
100
|
+
}), /* @__PURE__ */ o(Y, {
|
|
101
|
+
ariaLabelClose: B.close_aria,
|
|
102
|
+
isOpen: I,
|
|
94
103
|
onClose: () => {
|
|
95
|
-
|
|
104
|
+
T(!1), C({ transaction_guid: void 0 }), L();
|
|
96
105
|
},
|
|
97
|
-
title:
|
|
98
|
-
children: /* @__PURE__ */ o(
|
|
99
|
-
})] })
|
|
106
|
+
title: l.general.transaction_details_title,
|
|
107
|
+
children: /* @__PURE__ */ o(ct, { beat: a })
|
|
108
|
+
})] });
|
|
100
109
|
});
|
|
101
110
|
export {
|
|
102
|
-
|
|
111
|
+
It as TransactionHistoryBlock
|
|
103
112
|
};
|
|
104
113
|
|
|
105
114
|
//# 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 { 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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"}
|
|
1
|
+
{"version":3,"file":"TransactionHistoryBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.tsx"],"sourcesContent":["import { useLayoutEffect, useState } from 'react'\n\nimport { useTheme } from '@mui/material/styles'\nimport { observer } from 'mobx-react-lite'\n\nimport type { Beat, DataSeries, Transaction } from '../../../core'\nimport { formatCurrency } from '../../../core/utils/NumberFormatting'\nimport { BarChartV2 } from '../../components/chartblocks/BarchartV2'\nimport { EmptyBarChart } from '../../components/chartblocks/EmptyBarChart'\n\nimport { TransactionDrillDown } from './TransactionDrillDown'\nimport { useTransactionHistory } from './useTransactionHistory'\nimport {\n getDefaultSelection,\n getDrillDownConfig,\n getFlattenedDataSeries,\n toStoreFilter,\n} from './utils'\nimport {\n Drawer,\n useInsightsV2Store,\n useGlobalCopyStore,\n useGlobalUiStore,\n Loader,\n} from '../../../common'\nimport { TransactionDetailsBlock } from '../TransactionDetailsBlock'\n\ninterface TransactionHistoryProp {\n beat: Beat\n}\n\nexport const TransactionHistoryBlock = observer(({ beat }: TransactionHistoryProp) => {\n const theme = useTheme()\n const {\n instanceSlotData,\n beatTransactions,\n spendCategoryGuids,\n allAccountGuids,\n categoryName,\n displayedDateRange,\n transactionStore,\n } = useTransactionHistory(beat)\n\n const { actionDrawer, setActionContext } = useInsightsV2Store()\n\n const { common: commonCopy, insights_feed: insightsCopy } = useGlobalCopyStore()\n\n const { isCopyLoaded } = useGlobalUiStore()\n\n const [isTransactionDetailsOpen, setIsTransactionDetailsOpen] = useState(false)\n\n const [closeTipSection, setCloseTipSection] = useState(false)\n\n const { insights_payload } = beat\n\n const dynamicCtaVariant =\n actionDrawer.trigger === 'secondaryCta'\n ? insights_payload?.secondary_cta?.variant\n : insights_payload?.primary_cta?.variant\n\n const { top, filterMode, header, colors, filterStrategy, tipSection } = getDrillDownConfig(\n dynamicCtaVariant ?? '',\n )\n\n const { dataSeries, chartData, comparisonBars } = getFlattenedDataSeries({\n data: instanceSlotData?.data_series as DataSeries,\n ariaLabel: instanceSlotData?.ariaLabel ?? '',\n top,\n beatTransactions,\n payload: instanceSlotData,\n })\n\n const { chartBarIndex, subTabIndex } = getDefaultSelection({\n chartTabCount: chartData.length,\n comparisonTabCount: comparisonBars.length,\n actionDrawer,\n beatGuid: beat.guid,\n })\n\n const [selectedIndex, setSelectedIndex] = useState(chartBarIndex)\n\n const resolveFilter = (index: number) =>\n filterStrategy({\n beat,\n beatTransactions,\n dataSeries,\n selectedIndex: index,\n subIndex: subTabIndex,\n isLastTab: index === dataSeries.length - 1,\n instanceSlotData,\n spendCategoryGuids,\n displayedDateRange,\n })\n\n // Apply the current selection's filter. Store variants route through the store filter; local\n // (upcomingBill) variants filter beatTransactions directly and only backfill the cache when the\n // Stable primitive keys for the collections below: beatTransactions/spendCategoryGuids/\n // allAccountGuids are recomputed (new array identity) every render, so depending on them directly\n // re-fires the effect each render (REVIEW.md MEW-3732). Key on content instead.\n const beatTransactionGuidsKey = beatTransactions.map((transaction) => transaction.guid).join(',')\n const spendCategoryGuidsKey = spendCategoryGuids.join(',')\n const allAccountGuidsKey = allAccountGuids.join(',')\n\n // Re-applies the current selection's filter to the shared transactionStore. Called both by the\n // effect below (on selection change) and when the nested TransactionDetailsBlock drawer closes:\n // AddMerchantBudgetAction (opened from within that drawer) overwrites transactionStore.filter\n // with a merchant_guid-only filter while its own drawer is open, and never restores it — leaving\n // the row list stuck showing only that one merchant's transactions after backing all the way out.\n // Re-running this on close re-derives the filter fresh instead of relying on whatever the nested\n // drawers left behind.\n const applyCurrentSelectionFilter = () => {\n if (filterMode !== 'store' || !dataSeries.length) return\n transactionStore.setFilter(\n toStoreFilter(resolveFilter(selectedIndex), { allAccountGuids, displayedDateRange }),\n )\n }\n\n // store variants route the selection through the shared store filter; local (upcomingBill) variants\n // filter beatTransactions directly, so there's nothing to push to the store for them.\n useLayoutEffect(() => {\n applyCurrentSelectionFilter()\n }, [\n beat.guid,\n selectedIndex,\n filterMode,\n dataSeries.length,\n instanceSlotData,\n displayedDateRange,\n spendCategoryGuidsKey,\n allAccountGuidsKey,\n beatTransactionGuidsKey,\n ])\n\n const headerContent = header?.({\n title: insights_payload?.title,\n subHeader: insights_payload?.sub_title,\n categoryName,\n selectedDate: chartData[selectedIndex]?.date ?? undefined,\n })\n\n const barColors = colors(theme, instanceSlotData?.category_guid)\n\n if (!isCopyLoaded) return <Loader />\n\n // TODO: Temporary fallback while the backend doesn't always send `legends` on every beat/variant.\n // Remove this once the backend guarantees `legends` on the payload.\n const legendFallbackLabels = [insightsCopy.general.monthly_amount, insightsCopy.general.trend]\n\n const [monthlyAmountLabel, trendAmountLabel] = instanceSlotData?.legends?.length\n ? instanceSlotData.legends.map((legend) => legend.label)\n : legendFallbackLabels\n\n const transactionFilter =\n filterMode === 'local'\n ? (index: number) => resolveFilter(index).custom ?? (() => true)\n : undefined\n\n const baseTransactions: Transaction[] | undefined =\n filterMode === 'local' ? beatTransactions : undefined\n\n const isBarTop = top === 'singleBar' || top === 'upcomingBill'\n const chartTop = !isBarTop ? null : chartData.length ? (\n <BarChartV2\n amounts={{\n average: instanceSlotData?.average_amount,\n formattedAverage: formatCurrency(instanceSlotData?.average_amount ?? 0, '0,0.00'),\n }}\n color={barColors[0] ?? theme.palette.primary.main}\n data={chartData}\n legendPosition=\"top\"\n margin={{\n bottom: 30,\n top: 20,\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,17 +1,18 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { Theme } from '@mui/material/styles';
|
|
3
|
-
import { Beat, Transaction } from '../../../core';
|
|
3
|
+
import { Beat, InsightsFeedCopy, Subtitle, Transaction } from '../../../core';
|
|
4
4
|
import { TransactionFilter } from '../../../core/stores/TransactionStore';
|
|
5
5
|
import { InsightsInstanceSlotData } from '../../../core/types/InsightsInstanceSlotData';
|
|
6
6
|
import { ChartDataSeriesItem } from '../../blocks/ChartBlocks/BarchartBlock/utils';
|
|
7
|
+
import { TipSectionProps } from '../../../insights/components/shared/ChartDrawerTemplate/TipSection';
|
|
7
8
|
export interface DrillDownHeader {
|
|
8
9
|
heading?: string;
|
|
9
10
|
subHeadingText?: string;
|
|
10
11
|
icon?: ReactNode;
|
|
11
12
|
}
|
|
12
13
|
export interface DrillDownHeaderContext {
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
title?: string;
|
|
15
|
+
subHeader?: Subtitle;
|
|
15
16
|
categoryName: string;
|
|
16
17
|
selectedDate?: string | Date;
|
|
17
18
|
}
|
|
@@ -61,6 +62,7 @@ export interface DrillDownVariantConfig {
|
|
|
61
62
|
filterStrategy: FilterStrategy;
|
|
62
63
|
colors: ColorKind;
|
|
63
64
|
header?: HeaderKind;
|
|
65
|
+
tipSection?: (setCloseTipSection: (flag: boolean) => void, copy: InsightsFeedCopy, merchantName?: string) => TipSectionProps;
|
|
64
66
|
scope: 'store' | 'beat';
|
|
65
67
|
filterMode: 'store' | 'local';
|
|
66
68
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { buildDynamicCopy as u } from "../../../core/utils/Localization.es.js";
|
|
2
|
+
import { DATE_FORMATS_INTL as p, formatDate as y } from "../../../core/constants/DateFormats.es.js";
|
|
3
|
+
import { getCategoryColor as N } from "../../../core/utils/CategoryUtil.es.js";
|
|
4
|
+
import { MerchantLogo as S } from "@mxenabled/mxui";
|
|
5
|
+
import { Icon as O } from "@mxenabled/mx-icons";
|
|
6
|
+
import { jsx as c } from "react/jsx-runtime";
|
|
7
|
+
import { endOfMonth as T, startOfMonth as f } from "date-fns";
|
|
7
8
|
var i = {
|
|
8
9
|
TRANSACTION: "bill_amount_not_standard",
|
|
9
10
|
CATEGORY_SPEND: "category_spend",
|
|
@@ -16,66 +17,73 @@ var i = {
|
|
|
16
17
|
COST_OF_LIVING: "cost_living_to_income",
|
|
17
18
|
NON_ESSENTIAL_CATEGORY: "non_essential_category_summary",
|
|
18
19
|
DEPOSIT_SUMMARY: "monthly_deposit_summary"
|
|
19
|
-
},
|
|
20
|
-
start:
|
|
21
|
-
end:
|
|
22
|
-
}), d = (e) => e?.length ? { accounts: e } : {},
|
|
23
|
-
const
|
|
20
|
+
}, _ = (e, t) => t && N(t, e) || e.palette.primary.main, l = (e) => ({
|
|
21
|
+
start: f(new Date(e ?? NaN)),
|
|
22
|
+
end: T(new Date(e ?? NaN))
|
|
23
|
+
}), d = (e) => e?.length ? { accounts: e } : {}, g = ({ beatTransactions: e, dataSeries: t, selectedIndex: o }) => {
|
|
24
|
+
const r = t[o], a = r?.guid, s = e.find((n) => n.guid === a)?.has_been_split;
|
|
24
25
|
return {
|
|
25
|
-
custom: (
|
|
26
|
-
dateRange:
|
|
27
|
-
showSplits: !
|
|
26
|
+
custom: (n) => n.guid === a,
|
|
27
|
+
dateRange: l(r?.date),
|
|
28
|
+
showSplits: !s
|
|
28
29
|
};
|
|
29
|
-
},
|
|
30
|
-
const
|
|
30
|
+
}, C = ({ dataSeries: e, selectedIndex: t, instanceSlotData: o }) => {
|
|
31
|
+
const r = e[t], a = o.category_guid ?? r?.guid;
|
|
31
32
|
return {
|
|
32
|
-
custom: (
|
|
33
|
-
dateRange:
|
|
33
|
+
custom: (s) => s.category_guid === a || s.top_level_category_guid === a,
|
|
34
|
+
dateRange: l(r?.date)
|
|
34
35
|
};
|
|
35
|
-
},
|
|
36
|
-
const
|
|
36
|
+
}, I = ({ dataSeries: e, selectedIndex: t, spendCategoryGuids: o, instanceSlotData: r }) => {
|
|
37
|
+
const a = e[t];
|
|
37
38
|
return {
|
|
38
|
-
custom: (
|
|
39
|
-
dateRange:
|
|
40
|
-
...d(
|
|
39
|
+
custom: (s) => !!s.top_level_category_guid && o.includes(s.top_level_category_guid),
|
|
40
|
+
dateRange: l(a?.date),
|
|
41
|
+
...d(r.account_guids)
|
|
41
42
|
};
|
|
42
|
-
},
|
|
43
|
-
const
|
|
43
|
+
}, h = ({ beat: e, dataSeries: t, selectedIndex: o, isLastTab: r, instanceSlotData: a }) => {
|
|
44
|
+
const s = t[o], { start: n, end: m } = l(s?.date);
|
|
44
45
|
return {
|
|
45
46
|
dateRange: {
|
|
46
|
-
start:
|
|
47
|
-
end:
|
|
47
|
+
start: n,
|
|
48
|
+
end: r && e.created_at ? new Date(e.created_at) : m
|
|
48
49
|
},
|
|
49
|
-
...d(
|
|
50
|
+
...d(a.account_guids)
|
|
50
51
|
};
|
|
51
|
-
},
|
|
52
|
+
}, B = {
|
|
52
53
|
[i.TRANSACTION]: {
|
|
53
54
|
top: "singleBar",
|
|
54
55
|
scope: "store",
|
|
55
56
|
filterMode: "store",
|
|
56
|
-
filterStrategy:
|
|
57
|
-
colors: (e, t) => [
|
|
58
|
-
header: (e) =>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
filterStrategy: g,
|
|
58
|
+
colors: (e, t) => [_(e, t)],
|
|
59
|
+
header: (e) => {
|
|
60
|
+
const { title: t, subHeader: o } = e;
|
|
61
|
+
return {
|
|
62
|
+
heading: t,
|
|
63
|
+
subHeadingText: o?.text || void 0,
|
|
64
|
+
icon: /* @__PURE__ */ c(S, {
|
|
65
|
+
alt: o?.text,
|
|
66
|
+
categoryGuid: o?.logo?.category_guid || "",
|
|
67
|
+
merchantGuid: o?.logo?.merchant_guid || "",
|
|
68
|
+
size: 16
|
|
69
|
+
})
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
tipSection: (e, t, o = "") => ({
|
|
73
|
+
message: u(t.general.tip_section_message, /* @__PURE__ */ c("strong", { children: t.general.tip_section_title }), /* @__PURE__ */ c("strong", { children: o })),
|
|
74
|
+
onDismiss: () => e(!0)
|
|
67
75
|
})
|
|
68
76
|
},
|
|
69
77
|
[i.CATEGORY_SPEND]: {
|
|
70
78
|
top: "singleBar",
|
|
71
|
-
filterStrategy:
|
|
79
|
+
filterStrategy: C,
|
|
72
80
|
scope: "store",
|
|
73
81
|
filterMode: "store",
|
|
74
|
-
colors: (e, t) => [
|
|
82
|
+
colors: (e, t) => [_(e, t)],
|
|
75
83
|
header: (e) => ({
|
|
76
84
|
heading: e.categoryName,
|
|
77
|
-
subHeadingText: e.selectedDate &&
|
|
78
|
-
icon: /* @__PURE__ */
|
|
85
|
+
subHeadingText: e.selectedDate && y(e.selectedDate, p.MONTH_LONG) || "",
|
|
86
|
+
icon: /* @__PURE__ */ c(O, {
|
|
79
87
|
name: "calendar_month",
|
|
80
88
|
size: 16
|
|
81
89
|
})
|
|
@@ -83,36 +91,36 @@ var i = {
|
|
|
83
91
|
},
|
|
84
92
|
[i.MONTHLY_SPEND]: {
|
|
85
93
|
top: "singleBar",
|
|
86
|
-
filterStrategy:
|
|
94
|
+
filterStrategy: I,
|
|
87
95
|
scope: "store",
|
|
88
96
|
filterMode: "store",
|
|
89
97
|
colors: (e) => [e.palette.chart.chart2 ?? e.palette.primary.main]
|
|
90
98
|
},
|
|
91
99
|
[i.ACCOUNT_BALANCE]: {
|
|
92
100
|
top: "singleBar",
|
|
93
|
-
filterStrategy:
|
|
101
|
+
filterStrategy: h,
|
|
94
102
|
scope: "store",
|
|
95
103
|
filterMode: "store",
|
|
96
104
|
colors: (e) => [e.palette.success.main]
|
|
97
105
|
},
|
|
98
106
|
[i.UPCOMING_BILL]: {
|
|
99
107
|
top: "upcomingBill",
|
|
100
|
-
filterStrategy:
|
|
108
|
+
filterStrategy: g,
|
|
101
109
|
scope: "beat",
|
|
102
110
|
filterMode: "local",
|
|
103
|
-
colors: (e, t) => [
|
|
111
|
+
colors: (e, t) => [_(e, t)]
|
|
104
112
|
}
|
|
105
|
-
},
|
|
113
|
+
}, G = {
|
|
106
114
|
top: "singleBar",
|
|
107
|
-
filterStrategy:
|
|
115
|
+
filterStrategy: g,
|
|
108
116
|
scope: "store",
|
|
109
117
|
filterMode: "store",
|
|
110
|
-
colors: (e, t) => [
|
|
118
|
+
colors: (e, t) => [_(e, t)]
|
|
111
119
|
};
|
|
112
120
|
export {
|
|
113
121
|
i as DRILLDOWN_VARIANTS,
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
G as FALLBACK,
|
|
123
|
+
B as layout
|
|
116
124
|
};
|
|
117
125
|
|
|
118
126
|
//# sourceMappingURL=layout.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/layout.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport type { Theme } from '@mui/material/styles'\nimport { endOfMonth, startOfMonth } from 'date-fns'\nimport { getCategoryColor } from '../../../core/utils/CategoryUtil'\nimport 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
|
+
{"version":3,"file":"layout.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/layout.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport type { Theme } from '@mui/material/styles'\nimport { endOfMonth, startOfMonth } from 'date-fns'\nimport { getCategoryColor } from '../../../core/utils/CategoryUtil'\nimport {\n type Beat,\n type InsightsFeedCopy,\n type Subtitle,\n type Transaction,\n buildDynamicCopy,\n} from '../../../core'\nimport type { TransactionFilter } from '../../../core/stores/TransactionStore'\nimport type { InsightsInstanceSlotData } from '../../../core/types/InsightsInstanceSlotData'\nimport { MerchantLogo } from '@mxenabled/mxui'\nimport { DATE_FORMATS_INTL, formatDate } from '../../../core/constants'\nimport { Icon } from '@mxenabled/mx-icons'\nimport type { ChartDataSeriesItem } from '../../blocks/ChartBlocks/BarchartBlock/utils'\nimport type { TipSectionProps } from '../../../insights/components/shared/ChartDrawerTemplate/TipSection'\n\nexport interface DrillDownHeader {\n heading?: string\n subHeadingText?: string\n icon?: ReactNode\n}\n\nexport interface DrillDownHeaderContext {\n title?: string\n subHeader?: Subtitle\n categoryName: string\n selectedDate?: string | Date\n}\n\nexport const DRILLDOWN_VARIANTS = {\n TRANSACTION: '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 tipSection?: (\n setCloseTipSection: (flag: boolean) => void,\n copy: InsightsFeedCopy,\n merchantName?: string,\n ) => TipSectionProps\n scope: 'store' | 'beat'\n filterMode: 'store' | 'local'\n}\nconst categoryColor = (theme: Theme, categoryGuid?: string): string =>\n (categoryGuid && getCategoryColor(categoryGuid, theme)) || theme.palette.primary.main\n\nconst monthRange = (date: string | number | Date | undefined) => ({\n start: startOfMonth(new Date(date ?? NaN)),\n end: endOfMonth(new Date(date ?? NaN)),\n})\n\n// Scopes a filter to the beat's accounts when the beat carries account_guids; otherwise leaves\n// accounts unset so the store default (all accounts) applies.\nconst accountScope = (accountGuids?: string[]): Pick<TransactionFilter, 'accounts'> =>\n accountGuids?.length ? { accounts: accountGuids } : {}\n\n// ── Single-bar filter strategies (this MR) ────────────────────────────────────────────────────\n\n// BillAmountNotStandard / UpcomingBill — the series carries a transaction (TRN) guid; match a single\n// transaction by guid within its month.\nconst transactionGuidStrategy: FilterStrategy = ({\n beatTransactions,\n dataSeries,\n selectedIndex,\n}) => {\n const seriesItem = dataSeries[selectedIndex]\n const seriesGuid = seriesItem?.guid\n const hasBeenSplit = beatTransactions.find((trn) => trn.guid === seriesGuid)?.has_been_split\n\n return {\n custom: (trn) => trn.guid === seriesGuid,\n dateRange: monthRange(seriesItem?.date),\n showSplits: !hasBeenSplit,\n }\n}\n\n// CategorySpendingV2 — match transactions in the beat's category (or whose top-level category is that\n// guid) within the month.\nconst categoryStrategy: FilterStrategy = ({ dataSeries, selectedIndex, instanceSlotData }) => {\n const seriesItem = dataSeries[selectedIndex]\n const categoryGuid = instanceSlotData.category_guid ?? seriesItem?.guid\n\n return {\n custom: (trn) =>\n trn.category_guid === categoryGuid || trn.top_level_category_guid === categoryGuid,\n dateRange: monthRange(seriesItem?.date),\n }\n}\n\n// MonthlySpendComparisonV2 — no per-bar guid; show all spending-category transactions\n// (income/transfers/investments excluded via spendCategoryGuids) within the month.\nconst spendCategoriesStrategy: FilterStrategy = ({\n dataSeries,\n selectedIndex,\n spendCategoryGuids,\n instanceSlotData,\n}) => {\n const seriesItem = dataSeries[selectedIndex]\n\n return {\n custom: (trn) =>\n !!trn.top_level_category_guid && spendCategoryGuids.includes(trn.top_level_category_guid),\n dateRange: monthRange(seriesItem?.date),\n ...accountScope(instanceSlotData.account_guids),\n }\n}\n\n// SavingsAccountBalancesSummary — balances, not categorized spend. Filter by month only; the most\n// recent month is capped at the beat's creation time to match the snapshot the balance was computed\n// from.\nconst accountDateStrategy: FilterStrategy = ({\n beat,\n dataSeries,\n selectedIndex,\n isLastTab,\n instanceSlotData,\n}) => {\n const seriesItem = dataSeries[selectedIndex]\n const { start, end } = monthRange(seriesItem?.date)\n\n return {\n dateRange: {\n start,\n end: isLastTab && beat.created_at ? new Date(beat.created_at) : end,\n },\n ...accountScope(instanceSlotData.account_guids),\n }\n}\n\n// ── Double-bar + tabsOnly strategies (NEXT MR) ───────────────────────────────────────────────────\n// TODO(next MR — double bar): comparisonAggregatedGuidsStrategy — month × sub-tab membership over the\n// comparison bars' precomputed subGuids. Needs comparisonBars in FilterContext.\n// TODO(next MR — tabsOnly): aggregatedGuids / depositSummary strategies for the donut-drawer beats.\n\nexport const layout: Partial<Record<DrillDownVariant, DrillDownVariantConfig>> = {\n [DRILLDOWN_VARIANTS.TRANSACTION]: {\n top: 'singleBar',\n scope: 'store',\n filterMode: 'store',\n filterStrategy: transactionGuidStrategy,\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n header: (ctx: DrillDownHeaderContext) => {\n const { title, subHeader } = ctx\n return {\n heading: title,\n subHeadingText: subHeader?.text || undefined,\n icon: (\n <MerchantLogo\n alt={subHeader?.text}\n categoryGuid={subHeader?.logo?.category_guid || ''}\n merchantGuid={subHeader?.logo?.merchant_guid || ''}\n size={16}\n />\n ),\n }\n },\n tipSection: (setCloseTipSection, copy, merchantName = '') => {\n return {\n message: buildDynamicCopy(\n copy.general.tip_section_message,\n <strong>{copy.general.tip_section_title}</strong>,\n <strong>{merchantName}</strong>,\n ),\n onDismiss: () => setCloseTipSection(true),\n } as TipSectionProps\n },\n },\n [DRILLDOWN_VARIANTS.CATEGORY_SPEND]: {\n top: 'singleBar',\n filterStrategy: categoryStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n header: (ctx: DrillDownHeaderContext) => {\n return {\n heading: ctx.categoryName,\n subHeadingText: ctx.selectedDate\n ? formatDate(ctx.selectedDate, DATE_FORMATS_INTL.MONTH_LONG) || ''\n : '',\n icon: <Icon name=\"calendar_month\" size={16} />,\n }\n },\n },\n [DRILLDOWN_VARIANTS.MONTHLY_SPEND]: {\n top: 'singleBar',\n filterStrategy: spendCategoriesStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme) => [theme.palette.chart.chart2 ?? theme.palette.primary.main],\n },\n [DRILLDOWN_VARIANTS.ACCOUNT_BALANCE]: {\n top: 'singleBar',\n filterStrategy: accountDateStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme) => [theme.palette.success.main],\n },\n [DRILLDOWN_VARIANTS.UPCOMING_BILL]: {\n top: 'upcomingBill',\n filterStrategy: transactionGuidStrategy,\n scope: 'beat',\n filterMode: 'local',\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n },\n\n // ── NEXT MR: double-bar comparison beats (month tabs + spend/income sub-tabs) ────────────────\n // [DRILLDOWN_VARIANTS.SPEND_TO_INCOME]: comparison('spendVsIncome'),\n // [DRILLDOWN_VARIANTS.SAVINGS_TO_INCOME]: comparison('savingsVsIncome'),\n // [DRILLDOWN_VARIANTS.DEBT_TO_INCOME]: comparison('debtVsIncome'),\n // [DRILLDOWN_VARIANTS.COST_OF_LIVING]: comparison('costOfLiving'),\n //\n // ── NEXT MR: tabsOnly donut-drawer beats (no top chart) ───────────────────────────────────\n // [DRILLDOWN_VARIANTS.NON_ESSENTIAL_CATEGORY]: { top: 'tabsOnly', ... },\n // [DRILLDOWN_VARIANTS.DEPOSIT_SUMMARY]: { top: 'tabsOnly', ... },\n}\n\n// Fallback for a missing/typo'd backend variant: a single-bar, store-scoped drawer filtered by the\n// beat's transaction guid and colored by category, so the drawer still renders instead of crashing.\nexport const FALLBACK: DrillDownVariantConfig = {\n top: 'singleBar',\n filterStrategy: transactionGuidStrategy,\n scope: 'store',\n filterMode: 'store',\n colors: (theme: Theme, categoryGuid?: string) => [categoryColor(theme, categoryGuid)],\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { BarChartBlockData } from '../../../../core/types/InsightsInstanceSlotData';
|
|
2
2
|
import { BlockProps } from '../../types';
|
|
3
|
-
export declare const BarchartBlock: ({ payload, beatGuid }: BlockProps<BarChartBlockData>) => import("react/jsx-runtime").JSX.Element
|
|
3
|
+
export declare const BarchartBlock: (({ payload, beatGuid }: BlockProps<BarChartBlockData>) => import("react/jsx-runtime").JSX.Element) & {
|
|
4
|
+
displayName: string;
|
|
5
|
+
};
|
|
@@ -1,36 +1,40 @@
|
|
|
1
|
-
import { useInsightsV2Store as
|
|
2
|
-
import { formatCurrency as
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { useGlobalCopyStore as B, useGlobalUiStore as y, useInsightsV2Store as A } from "../../../../common/context/hooks.es.js";
|
|
2
|
+
import { formatCurrency as L } from "../../../../core/utils/NumberFormatting.es.js";
|
|
3
|
+
import S from "../../../../common/components/Loader.es.js";
|
|
4
|
+
import { BarChartV2 as I } from "../../../components/chartblocks/BarchartV2.es.js";
|
|
5
|
+
import { EmptyBarChart as T } from "../../../components/chartblocks/EmptyBarChart.es.js";
|
|
6
|
+
import { barChartVariant as k, buildChartData as v, buildDataSeries as x } from "./utils.es.js";
|
|
7
|
+
import { actionBlocksKey as D } from "../../../mappings/actionBlocksKey.es.js";
|
|
8
|
+
import O from "react";
|
|
9
|
+
import { observer as N } from "mobx-react-lite";
|
|
10
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
11
|
+
import { useTheme as R } from "@mui/material/styles";
|
|
12
|
+
var z = N(({ payload: m, beatGuid: i = "" }) => {
|
|
13
|
+
const l = R(), { openActionDrawer: c } = A(), { insights_feed: e } = B(), { isCopyLoaded: d } = y(), { instance_slot: h, instance_slot_data: a } = m, { data_series: p, ariaLabel: f = "", average_amount: n = 0, legends: s = [] } = a, t = v(x(p), f), [u] = O.useState(t.length - 1), { color: g } = k(h, a, l);
|
|
14
|
+
if (!d) return /* @__PURE__ */ o(S, {});
|
|
15
|
+
const b = [e.general.monthly_amount, e.general.trend], [C, _] = s.length ? s.map((r) => r.label) : b;
|
|
16
|
+
return t.length ? /* @__PURE__ */ o(I, {
|
|
13
17
|
amounts: {
|
|
14
|
-
average:
|
|
15
|
-
formattedAverage:
|
|
18
|
+
average: n,
|
|
19
|
+
formattedAverage: L(n, "0,0")
|
|
16
20
|
},
|
|
17
|
-
color:
|
|
21
|
+
color: g,
|
|
18
22
|
data: t,
|
|
19
|
-
monthlyAmountLabel:
|
|
20
|
-
onBarClick: (r) =>
|
|
21
|
-
guid:
|
|
23
|
+
monthlyAmountLabel: C,
|
|
24
|
+
onBarClick: (r) => c({
|
|
25
|
+
guid: i,
|
|
22
26
|
trigger: "chartBar",
|
|
23
27
|
context: {
|
|
24
28
|
chartBarIndex: r,
|
|
25
|
-
block:
|
|
29
|
+
block: D.TRANSCATION_HISTORY_ACTION_BLOCK
|
|
26
30
|
}
|
|
27
31
|
}),
|
|
28
|
-
selectedTabIndex:
|
|
29
|
-
trendAmountLabel:
|
|
30
|
-
}) : /* @__PURE__ */
|
|
31
|
-
};
|
|
32
|
+
selectedTabIndex: u,
|
|
33
|
+
trendAmountLabel: _
|
|
34
|
+
}) : /* @__PURE__ */ o(T, {});
|
|
35
|
+
});
|
|
32
36
|
export {
|
|
33
|
-
|
|
37
|
+
z as BarchartBlock
|
|
34
38
|
};
|
|
35
39
|
|
|
36
40
|
//# 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 {
|
|
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 } = 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 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)\n"],"mappings":";;;;;;;;;;;AAsBA,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,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;AAE1E,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,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,CACF"}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { useAppConfig as
|
|
2
|
-
import { sendBeatCta as
|
|
3
|
-
import { blocks as
|
|
4
|
-
import
|
|
5
|
-
import { BeatActionsProvider as
|
|
6
|
-
import
|
|
7
|
-
import { FeedbackBar as
|
|
8
|
-
import
|
|
9
|
-
import { DismissInsightDialog as
|
|
10
|
-
import { HiddenConfirmationCard as
|
|
11
|
-
import { ObsolesceBanner as
|
|
12
|
-
import { ActionBlockLayer as
|
|
13
|
-
import { useBeatFeedbackFlow as
|
|
14
|
-
import { observer as
|
|
1
|
+
import { useAppConfig as D, useGlobalCopyStore as L, useInsightsV2Store as O } from "../../common/context/hooks.es.js";
|
|
2
|
+
import { sendBeatCta as T } from "../../common/utils/PostMessage.es.js";
|
|
3
|
+
import { blocks as F, hasDrawerBlock as A } from "../mappings/blocks.es.js";
|
|
4
|
+
import I from "./Footer.es.js";
|
|
5
|
+
import { BeatActionsProvider as E } from "../beatActions.es.js";
|
|
6
|
+
import H from "./Header.es.js";
|
|
7
|
+
import { FeedbackBar as M } from "./FeedbackBar.es.js";
|
|
8
|
+
import G from "./FeedbackDialog.es.js";
|
|
9
|
+
import { DismissInsightDialog as R } from "./DismissInsightDialog.es.js";
|
|
10
|
+
import { HiddenConfirmationCard as j } from "./HiddenConfirmationCard.es.js";
|
|
11
|
+
import { ObsolesceBanner as z } from "./ObsolesceBanner.es.js";
|
|
12
|
+
import { ActionBlockLayer as N } from "../actionBlocks/ActionBlockLayer.es.js";
|
|
13
|
+
import { useBeatFeedbackFlow as U } from "../hooks/useBeatFeedbackFlow.es.js";
|
|
14
|
+
import { observer as V } from "mobx-react-lite";
|
|
15
15
|
import m from "@mui/material/Stack";
|
|
16
16
|
import d from "@mui/material/Button";
|
|
17
|
-
import { ChevronRight as
|
|
18
|
-
import { Fragment as
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
var
|
|
17
|
+
import { ChevronRight as P } from "@mxenabled/mx-icons";
|
|
18
|
+
import { Fragment as W, jsx as o, jsxs as t } from "react/jsx-runtime";
|
|
19
|
+
import X from "@mui/material/Box";
|
|
20
|
+
import Y from "@mui/material/Card";
|
|
21
|
+
var q = {}, J = {
|
|
22
22
|
position: "absolute",
|
|
23
23
|
top: 0,
|
|
24
24
|
left: 0,
|
|
@@ -27,29 +27,29 @@ var Y = {}, q = {
|
|
|
27
27
|
backgroundColor: "background.default",
|
|
28
28
|
opacity: 0.7,
|
|
29
29
|
zIndex: 1
|
|
30
|
-
},
|
|
31
|
-
const { openCtaDrawer: h } =
|
|
30
|
+
}, he = V(({ beat: i, beatActions: b = q, obsolete: s }) => {
|
|
31
|
+
const { openCtaDrawer: h } = O(), y = L(), { is_mobile_webview: g, clientConfig: k } = D(), e = U(i, b), r = i.insights_payload;
|
|
32
32
|
if (!r || e.cardState === "dismissed") return null;
|
|
33
|
-
const { instance_slot: v, primary_cta: n, secondary_cta: a,
|
|
34
|
-
|
|
33
|
+
const { instance_slot: v, primary_cta: n, secondary_cta: a, sub_title: _, title: C, widget_type: x } = r, { block: S } = v, p = (w, B) => {
|
|
34
|
+
A(w) ? h(i.guid, B) : T(i, {
|
|
35
35
|
isMobileWebview: g,
|
|
36
36
|
webviewScheme: k?.master?.ui_message_webview_url_scheme,
|
|
37
37
|
userGuid: i.user_guid
|
|
38
38
|
});
|
|
39
|
-
}, u =
|
|
40
|
-
return /* @__PURE__ */ o(
|
|
39
|
+
}, u = F[S], f = x === "mini", l = y.insights_feed?.general, c = s?.state === "not_refreshable" && !i.dismissed_at && !!l;
|
|
40
|
+
return /* @__PURE__ */ o(E, {
|
|
41
41
|
value: e.wrappedActions,
|
|
42
42
|
children: /* @__PURE__ */ t(m, {
|
|
43
43
|
sx: { mb: 16 },
|
|
44
44
|
children: [
|
|
45
|
-
e.cardState === "confirming" ? /* @__PURE__ */ o(
|
|
45
|
+
e.cardState === "confirming" ? /* @__PURE__ */ o(j, {
|
|
46
46
|
onClose: e.collapseConfirmation,
|
|
47
47
|
onLeaveFeedback: e.openHideSurvey,
|
|
48
48
|
onUndo: e.undoDismiss
|
|
49
|
-
}) : /* @__PURE__ */ t(
|
|
49
|
+
}) : /* @__PURE__ */ t(W, { children: [s && l && /* @__PURE__ */ o(z, {
|
|
50
50
|
...s,
|
|
51
51
|
copy: l
|
|
52
|
-
}), /* @__PURE__ */ t(
|
|
52
|
+
}), /* @__PURE__ */ t(Y, {
|
|
53
53
|
inert: c,
|
|
54
54
|
sx: { ...c && {
|
|
55
55
|
position: "relative",
|
|
@@ -57,11 +57,11 @@ var Y = {}, q = {
|
|
|
57
57
|
pointerEvents: "none"
|
|
58
58
|
} },
|
|
59
59
|
children: [
|
|
60
|
-
c && /* @__PURE__ */ o(
|
|
61
|
-
/* @__PURE__ */ o(
|
|
60
|
+
c && /* @__PURE__ */ o(X, { sx: J }),
|
|
61
|
+
/* @__PURE__ */ o(H, {
|
|
62
62
|
isMini: f,
|
|
63
|
-
subtitle:
|
|
64
|
-
title:
|
|
63
|
+
subtitle: _,
|
|
64
|
+
title: C ?? ""
|
|
65
65
|
}),
|
|
66
66
|
u && /* @__PURE__ */ o(u, {
|
|
67
67
|
beatGuid: i.guid,
|
|
@@ -79,7 +79,7 @@ var Y = {}, q = {
|
|
|
79
79
|
dangerouslySetInnerHTML: { __html: i.html_description },
|
|
80
80
|
style: { paddingLeft: 4 }
|
|
81
81
|
}), i?.in_description_cta && /* @__PURE__ */ o(d, {
|
|
82
|
-
endIcon: /* @__PURE__ */ o(
|
|
82
|
+
endIcon: /* @__PURE__ */ o(P, {}),
|
|
83
83
|
onClick: () => {
|
|
84
84
|
},
|
|
85
85
|
sx: {
|
|
@@ -106,19 +106,19 @@ var Y = {}, q = {
|
|
|
106
106
|
children: a.label
|
|
107
107
|
})]
|
|
108
108
|
}),
|
|
109
|
-
/* @__PURE__ */ o(
|
|
109
|
+
/* @__PURE__ */ o(M, {
|
|
110
110
|
onTellUsMore: e.openRatingSurvey,
|
|
111
111
|
show: e.isFeedbackBarShown
|
|
112
112
|
})
|
|
113
113
|
]
|
|
114
114
|
})] }),
|
|
115
|
-
/* @__PURE__ */ o(
|
|
116
|
-
/* @__PURE__ */ o(
|
|
115
|
+
/* @__PURE__ */ o(N, { beat: i }),
|
|
116
|
+
/* @__PURE__ */ o(R, {
|
|
117
117
|
isOpen: e.isDismissOpen,
|
|
118
118
|
onClose: e.closeDismissDialog,
|
|
119
119
|
onDismiss: e.confirmDismiss
|
|
120
120
|
}),
|
|
121
|
-
e.isSurveyOpen && /* @__PURE__ */ o(
|
|
121
|
+
e.isSurveyOpen && /* @__PURE__ */ o(G, {
|
|
122
122
|
characterLimitLabel: e.survey.characterLimitLabel,
|
|
123
123
|
closeAriaLabel: e.survey.closeAriaLabel,
|
|
124
124
|
isOpen: !0,
|
|
@@ -131,13 +131,13 @@ var Y = {}, q = {
|
|
|
131
131
|
secondaryText: e.survey.backText,
|
|
132
132
|
title: e.survey.title
|
|
133
133
|
}),
|
|
134
|
-
e.cardState === "visible" && r.footer && /* @__PURE__ */ o(
|
|
134
|
+
e.cardState === "visible" && r.footer && /* @__PURE__ */ o(I, { footer: r.footer })
|
|
135
135
|
]
|
|
136
136
|
})
|
|
137
137
|
});
|
|
138
138
|
});
|
|
139
139
|
export {
|
|
140
|
-
|
|
140
|
+
he as default
|
|
141
141
|
};
|
|
142
142
|
|
|
143
143
|
//# sourceMappingURL=BaseLayout.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseLayout.es.js","names":[],"sources":["../../../src/insights-v2/components/BaseLayout.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\n\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport Stack from '@mui/material/Stack'\n\nimport { ChevronRight } from '@mxenabled/mx-icons'\n\nimport { blocks, hasDrawerBlock } from '../mappings/blocks'\n\nimport Footer from './Footer'\nimport Header from './Header'\nimport FeedbackBar from './FeedbackBar'\nimport FeedbackDialog from './FeedbackDialog'\nimport DismissInsightDialog from './DismissInsightDialog'\nimport HiddenConfirmationCard from './HiddenConfirmationCard'\nimport { ObsolesceBanner, type ObsolesceBannerState } from './ObsolesceBanner'\nimport { useAppConfig, useGlobalCopyStore, useInsightsV2Store } from '../../common'\nimport { sendBeatCta } from '../../common/utils/PostMessage'\nimport type { Beat } from '../../core'\nimport { BeatActionsProvider, type BeatActions } from '../beatActions'\nimport { ActionBlockLayer } from '../actionBlocks/ActionBlockLayer'\nimport { useBeatFeedbackFlow } from '../hooks/useBeatFeedbackFlow'\n\nexport interface ObsoleteState {\n state: ObsolesceBannerState\n onRefresh: () => void\n onDismiss: () => void\n}\n\ninterface BaseLayoutProps {\n beat: Beat\n beatActions?: BeatActions\n obsolete?: ObsoleteState\n}\n\nconst NO_BEAT_ACTIONS: BeatActions = {}\n\nconst OBSOLETE_OVERLAY_SX = {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n backgroundColor: 'background.default',\n opacity: 0.7,\n zIndex: 1,\n} as const\n\nconst BaseLayout = observer(\n ({ beat, beatActions = NO_BEAT_ACTIONS, obsolete }: BaseLayoutProps) => {\n const { openCtaDrawer } = useInsightsV2Store()\n const copy = useGlobalCopyStore()\n const { is_mobile_webview, clientConfig } = useAppConfig()\n const flow = useBeatFeedbackFlow(beat, beatActions)\n\n const insights_payload = beat.insights_payload\n\n if (!insights_payload) return null\n if (flow.cardState === 'dismissed') return null\n\n const { instance_slot, primary_cta, secondary_cta, subtitle, widget_type } = insights_payload\n const { block } = instance_slot\n\n // A CTA with a real drilldown `block` opens a drawer; otherwise it notifies\n // the host app via a beat/cta post message (the \"Make a Transfer\" CTA on the\n // Save an extra $100 beat). Mirrors Pulse's SaveAnExtra100Dollars beat.\n const handleCtaClick = (\n ctaBlock: string | null | undefined,\n source: 'primaryCta' | 'secondaryCta',\n ) => {\n if (hasDrawerBlock(ctaBlock)) {\n openCtaDrawer(beat.guid, source)\n } else {\n sendBeatCta(beat, {\n isMobileWebview: is_mobile_webview,\n webviewScheme: clientConfig?.master?.ui_message_webview_url_scheme,\n userGuid: beat.user_guid,\n })\n }\n }\n\n const Block = blocks[block as keyof typeof blocks]\n\n const isMini = widget_type === 'mini'\n const obsoleteCopy = copy.insights_feed?.general\n const isObsoleteDimmed =\n obsolete?.state === 'not_refreshable' && !beat.dismissed_at && !!obsoleteCopy\n\n return (\n <BeatActionsProvider value={flow.wrappedActions}>\n <Stack sx={{ mb: 16 }}>\n {flow.cardState === 'confirming' ? (\n <HiddenConfirmationCard\n onClose={flow.collapseConfirmation}\n onLeaveFeedback={flow.openHideSurvey}\n onUndo={flow.undoDismiss}\n />\n ) : (\n <>\n {obsolete && obsoleteCopy && <ObsolesceBanner {...obsolete} copy={obsoleteCopy} />}\n <Card\n inert={isObsoleteDimmed}\n sx={{\n ...(isObsoleteDimmed && {\n position: 'relative',\n zIndex: 2,\n pointerEvents: 'none',\n }),\n }}\n >\n {isObsoleteDimmed && <Box sx={OBSOLETE_OVERLAY_SX} />}\n <Header isMini={isMini} subtitle={subtitle} title={beat.title} />\n {Block && <Block beatGuid={beat.guid} payload={insights_payload} />}\n\n <Stack sx={{ gap: 6, pb: 16, pl: 12, pr: 16, pt: 12 }}>\n <div\n dangerouslySetInnerHTML={{\n __html: beat.html_description as string,\n }}\n style={{ paddingLeft: 4 }}\n />\n {beat?.in_description_cta && (\n <Button\n endIcon={<ChevronRight />}\n onClick={() => {}}\n sx={{ height: 24, p: 4, width: 'max-content' }}\n >\n {beat.in_description_cta}\n </Button>\n )}\n </Stack>\n\n {!isMini && primary_cta?.label && (\n <Stack sx={{ gap: 8, pb: 16, px: 16 }}>\n <Button\n onClick={() => handleCtaClick(primary_cta.block, 'primaryCta')}\n variant=\"outlined\"\n >\n {primary_cta.label}\n </Button>\n {secondary_cta?.label && (\n <Button\n color=\"secondary\"\n onClick={() => handleCtaClick(secondary_cta.block, 'secondaryCta')}\n >\n {secondary_cta.label}\n </Button>\n )}\n </Stack>\n )}\n\n <FeedbackBar onTellUsMore={flow.openRatingSurvey} show={flow.isFeedbackBarShown} />\n </Card>\n </>\n )}\n\n <ActionBlockLayer beat={beat} />\n\n <DismissInsightDialog\n isOpen={flow.isDismissOpen}\n onClose={flow.closeDismissDialog}\n onDismiss={flow.confirmDismiss}\n />\n\n {flow.isSurveyOpen && (\n <FeedbackDialog\n characterLimitLabel={flow.survey.characterLimitLabel}\n closeAriaLabel={flow.survey.closeAriaLabel}\n isOpen={true}\n onBackClick={flow.feedbackDialogCallbacks.onBackClick}\n onClose={flow.closeSurvey}\n onSubmit={flow.submitSurvey}\n onTextInputFocus={flow.feedbackDialogCallbacks.onTextInputFocus}\n options={flow.survey.options}\n primaryText={flow.survey.submitText}\n secondaryText={flow.survey.backText}\n title={flow.survey.title}\n />\n )}\n\n {flow.cardState === 'visible' && insights_payload.footer && (\n <Footer footer={insights_payload.footer} />\n )}\n </Stack>\n </BeatActionsProvider>\n )\n },\n)\n\nexport default BaseLayout\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BaseLayout.es.js","names":[],"sources":["../../../src/insights-v2/components/BaseLayout.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\n\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport Stack from '@mui/material/Stack'\n\nimport { ChevronRight } from '@mxenabled/mx-icons'\n\nimport { blocks, hasDrawerBlock } from '../mappings/blocks'\n\nimport Footer from './Footer'\nimport Header from './Header'\nimport FeedbackBar from './FeedbackBar'\nimport FeedbackDialog from './FeedbackDialog'\nimport DismissInsightDialog from './DismissInsightDialog'\nimport HiddenConfirmationCard from './HiddenConfirmationCard'\nimport { ObsolesceBanner, type ObsolesceBannerState } from './ObsolesceBanner'\nimport { useAppConfig, useGlobalCopyStore, useInsightsV2Store } from '../../common'\nimport { sendBeatCta } from '../../common/utils/PostMessage'\nimport type { Beat } from '../../core'\nimport { BeatActionsProvider, type BeatActions } from '../beatActions'\nimport { ActionBlockLayer } from '../actionBlocks/ActionBlockLayer'\nimport { useBeatFeedbackFlow } from '../hooks/useBeatFeedbackFlow'\n\nexport interface ObsoleteState {\n state: ObsolesceBannerState\n onRefresh: () => void\n onDismiss: () => void\n}\n\ninterface BaseLayoutProps {\n beat: Beat\n beatActions?: BeatActions\n obsolete?: ObsoleteState\n}\n\nconst NO_BEAT_ACTIONS: BeatActions = {}\n\nconst OBSOLETE_OVERLAY_SX = {\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n backgroundColor: 'background.default',\n opacity: 0.7,\n zIndex: 1,\n} as const\n\nconst BaseLayout = observer(\n ({ beat, beatActions = NO_BEAT_ACTIONS, obsolete }: BaseLayoutProps) => {\n const { openCtaDrawer } = useInsightsV2Store()\n const copy = useGlobalCopyStore()\n const { is_mobile_webview, clientConfig } = useAppConfig()\n const flow = useBeatFeedbackFlow(beat, beatActions)\n\n const insights_payload = beat.insights_payload\n\n if (!insights_payload) return null\n if (flow.cardState === 'dismissed') return null\n\n const { instance_slot, primary_cta, secondary_cta, sub_title, title, widget_type } =\n insights_payload\n const { block } = instance_slot\n\n // A CTA with a real drilldown `block` opens a drawer; otherwise it notifies\n // the host app via a beat/cta post message (the \"Make a Transfer\" CTA on the\n // Save an extra $100 beat). Mirrors Pulse's SaveAnExtra100Dollars beat.\n const handleCtaClick = (\n ctaBlock: string | null | undefined,\n source: 'primaryCta' | 'secondaryCta',\n ) => {\n if (hasDrawerBlock(ctaBlock)) {\n openCtaDrawer(beat.guid, source)\n } else {\n sendBeatCta(beat, {\n isMobileWebview: is_mobile_webview,\n webviewScheme: clientConfig?.master?.ui_message_webview_url_scheme,\n userGuid: beat.user_guid,\n })\n }\n }\n\n const Block = blocks[block as keyof typeof blocks]\n\n const isMini = widget_type === 'mini'\n const obsoleteCopy = copy.insights_feed?.general\n const isObsoleteDimmed =\n obsolete?.state === 'not_refreshable' && !beat.dismissed_at && !!obsoleteCopy\n\n return (\n <BeatActionsProvider value={flow.wrappedActions}>\n <Stack sx={{ mb: 16 }}>\n {flow.cardState === 'confirming' ? (\n <HiddenConfirmationCard\n onClose={flow.collapseConfirmation}\n onLeaveFeedback={flow.openHideSurvey}\n onUndo={flow.undoDismiss}\n />\n ) : (\n <>\n {obsolete && obsoleteCopy && <ObsolesceBanner {...obsolete} copy={obsoleteCopy} />}\n <Card\n inert={isObsoleteDimmed}\n sx={{\n ...(isObsoleteDimmed && {\n position: 'relative',\n zIndex: 2,\n pointerEvents: 'none',\n }),\n }}\n >\n {isObsoleteDimmed && <Box sx={OBSOLETE_OVERLAY_SX} />}\n <Header isMini={isMini} subtitle={sub_title} title={title ?? ''} />\n {Block && <Block beatGuid={beat.guid} payload={insights_payload} />}\n\n <Stack sx={{ gap: 6, pb: 16, pl: 12, pr: 16, pt: 12 }}>\n <div\n dangerouslySetInnerHTML={{\n __html: beat.html_description as string,\n }}\n style={{ paddingLeft: 4 }}\n />\n {beat?.in_description_cta && (\n <Button\n endIcon={<ChevronRight />}\n onClick={() => {}}\n sx={{ height: 24, p: 4, width: 'max-content' }}\n >\n {beat.in_description_cta}\n </Button>\n )}\n </Stack>\n\n {!isMini && primary_cta?.label && (\n <Stack sx={{ gap: 8, pb: 16, px: 16 }}>\n <Button\n onClick={() => handleCtaClick(primary_cta.block, 'primaryCta')}\n variant=\"outlined\"\n >\n {primary_cta.label}\n </Button>\n {secondary_cta?.label && (\n <Button\n color=\"secondary\"\n onClick={() => handleCtaClick(secondary_cta.block, 'secondaryCta')}\n >\n {secondary_cta.label}\n </Button>\n )}\n </Stack>\n )}\n\n <FeedbackBar onTellUsMore={flow.openRatingSurvey} show={flow.isFeedbackBarShown} />\n </Card>\n </>\n )}\n\n <ActionBlockLayer beat={beat} />\n\n <DismissInsightDialog\n isOpen={flow.isDismissOpen}\n onClose={flow.closeDismissDialog}\n onDismiss={flow.confirmDismiss}\n />\n\n {flow.isSurveyOpen && (\n <FeedbackDialog\n characterLimitLabel={flow.survey.characterLimitLabel}\n closeAriaLabel={flow.survey.closeAriaLabel}\n isOpen={true}\n onBackClick={flow.feedbackDialogCallbacks.onBackClick}\n onClose={flow.closeSurvey}\n onSubmit={flow.submitSurvey}\n onTextInputFocus={flow.feedbackDialogCallbacks.onTextInputFocus}\n options={flow.survey.options}\n primaryText={flow.survey.submitText}\n secondaryText={flow.survey.backText}\n title={flow.survey.title}\n />\n )}\n\n {flow.cardState === 'visible' && insights_payload.footer && (\n <Footer footer={insights_payload.footer} />\n )}\n </Stack>\n </BeatActionsProvider>\n )\n },\n)\n\nexport default BaseLayout\n"],"mappings":"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"}
|
|
@@ -6,15 +6,15 @@ var m = (t) => t ? t.logo_name ? /* @__PURE__ */ r(s, {
|
|
|
6
6
|
name: t.logo_name,
|
|
7
7
|
size: 16,
|
|
8
8
|
sx: { color: t.logo_color }
|
|
9
|
-
}) : t.institution_guid ? /* @__PURE__ */ r(u, {
|
|
10
|
-
alt: t.institution_name,
|
|
11
|
-
institutionGuid: t.institution_guid,
|
|
12
|
-
size: 16
|
|
13
9
|
}) : t.merchant_guid ? /* @__PURE__ */ r(o, {
|
|
14
10
|
alt: t.merchant_name,
|
|
15
11
|
categoryGuid: t.category_guid,
|
|
16
12
|
merchantGuid: t.merchant_guid,
|
|
17
13
|
size: 16
|
|
14
|
+
}) : t.institution_guid ? /* @__PURE__ */ r(u, {
|
|
15
|
+
alt: t.institution_name,
|
|
16
|
+
institutionGuid: t.institution_guid,
|
|
17
|
+
size: 16
|
|
18
18
|
}) : t.category_guid ? /* @__PURE__ */ r(a, {
|
|
19
19
|
categoryGuid: t.category_guid,
|
|
20
20
|
size: 16
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubHeader.es.js","names":[],"sources":["../../../src/insights-v2/components/SubHeader.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport { CategoryIcon, InstitutionLogo, MerchantLogo, Text } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\nimport type { Logo, Subtitle } from '../../core'\n\ninterface SubHeaderProps {\n subtitle: Subtitle\n}\n\nconst renderLogo = (logo: Logo | undefined) => {\n if (!logo) return null\n\n if (logo.logo_name) {\n return <Icon name={logo.logo_name} size={16} sx={{ color: logo.logo_color }} />\n }\n\n if (logo.
|
|
1
|
+
{"version":3,"file":"SubHeader.es.js","names":[],"sources":["../../../src/insights-v2/components/SubHeader.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport { CategoryIcon, InstitutionLogo, MerchantLogo, Text } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\nimport type { Logo, Subtitle } from '../../core'\n\ninterface SubHeaderProps {\n subtitle: Subtitle\n}\n\n// TODO: Ask backend to send the correct guid (institution_guid, merchant_guid, or category_guid)\n// per beat's logo, matching what that beat's subtitle is actually about.\nconst renderLogo = (logo: Logo | undefined) => {\n if (!logo) return null\n\n if (logo.logo_name) {\n return <Icon name={logo.logo_name} size={16} sx={{ color: logo.logo_color }} />\n }\n\n if (logo.merchant_guid) {\n return (\n <MerchantLogo\n alt={logo.merchant_name as string}\n categoryGuid={logo.category_guid as string}\n merchantGuid={logo.merchant_guid}\n size={16}\n />\n )\n }\n\n if (logo.institution_guid) {\n return (\n <InstitutionLogo\n alt={logo.institution_name as string}\n institutionGuid={logo.institution_guid}\n size={16}\n />\n )\n }\n\n if (logo.category_guid) {\n return <CategoryIcon categoryGuid={logo.category_guid} size={16} />\n }\n\n return null\n}\n\nconst SubHeader = ({ subtitle }: SubHeaderProps) => {\n const { logo, text } = subtitle\n\n return (\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', gap: 8 }}>\n {renderLogo(logo)}\n <Text color=\"text.secondary\" variant=\"body2\">\n {text}\n </Text>\n </Stack>\n )\n}\n\nexport default SubHeader\n"],"mappings":";;;;AAYA,IAAM,IAAA,CAAc,MACb,IAED,EAAK,YACA,gBAAA,EAAC,GAAD;AAAA,EAAM,MAAM,EAAK;AAAA,EAAW,MAAM;AAAA,EAAI,IAAI,EAAE,OAAO,EAAK,WAAW;AAAI,CAAA,IAG5E,EAAK,gBAEL,gBAAA,EAAC,GAAD;AAAA,EACE,KAAK,EAAK;AAAA,EACV,cAAc,EAAK;AAAA,EACnB,cAAc,EAAK;AAAA,EACnB,MAAM;AACP,CAAA,IAID,EAAK,mBAEL,gBAAA,EAAC,GAAD;AAAA,EACE,KAAK,EAAK;AAAA,EACV,iBAAiB,EAAK;AAAA,EACtB,MAAM;AACP,CAAA,IAID,EAAK,gBACA,gBAAA,EAAC,GAAD;AAAA,EAAc,cAAc,EAAK;AAAA,EAAe,MAAM;AAAK,CAAA,IAG7D,OA/BW,MAkCd,IAAA,CAAa,EAAE,UAAA,EAAA,MAA+B;AAClD,QAAM,EAAE,MAAA,GAAM,MAAA,EAAA,IAAS;AAEvB,SACE,gBAAA,EAAC,GAAD;AAAA,IAAO,IAAI;AAAA,MAAE,YAAY;AAAA,MAAU,eAAe;AAAA,MAAO,KAAK;AAAA,IAAE;AAAA,IAAhE,UAAA,CACG,EAAW,CAAI,GAChB,gBAAA,EAAC,GAAD;AAAA,MAAM,OAAM;AAAA,MAAiB,SAAQ;AAAA,MAClC,UAAA;AAAA,IACG,CAAA,CACD;AAAA;AAEX"}
|