@mx-cartographer/experiences 9.6.12 → 9.6.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/common/components/CurrencyDialog.d.ts +6 -1
  3. package/dist/common/components/CurrencyDialog.es.js +24 -23
  4. package/dist/common/components/CurrencyDialog.es.js.map +1 -1
  5. package/dist/core/types/Insights.d.ts +7 -1
  6. package/dist/core/types/Insights.es.js.map +1 -1
  7. package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js +3 -3
  8. package/dist/insights-v2/actionBlocks/AmountInputModalBlock/AmountInputModalBlock.es.js +66 -61
  9. package/dist/insights-v2/actionBlocks/AmountInputModalBlock/AmountInputModalBlock.es.js.map +1 -1
  10. package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.es.js +17 -11
  11. package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.es.js.map +1 -1
  12. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/layout.d.ts +27 -0
  13. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/layout.es.js +14 -0
  14. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/layout.es.js.map +1 -0
  15. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js +5 -5
  16. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js.map +1 -1
  17. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.d.ts +6 -2
  18. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js +7 -4
  19. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js.map +1 -1
  20. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js +63 -57
  21. package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js.map +1 -1
  22. package/dist/insights-v2/actionBlocks/util.d.ts +4 -3
  23. package/dist/insights-v2/actionBlocks/util.es.js.map +1 -1
  24. package/dist/insights-v2/analytics/analyticsEventsConfig.d.ts +67 -0
  25. package/dist/insights-v2/analytics/analyticsEventsConfig.es.js +59 -0
  26. package/dist/insights-v2/analytics/analyticsEventsConfig.es.js.map +1 -0
  27. package/dist/insights-v2/analytics/index.d.ts +3 -0
  28. package/dist/insights-v2/analytics/resolveAnalyticsEvent.d.ts +5 -0
  29. package/dist/insights-v2/analytics/resolveAnalyticsEvent.es.js +19 -0
  30. package/dist/insights-v2/analytics/resolveAnalyticsEvent.es.js.map +1 -0
  31. package/dist/insights-v2/analytics/useAnalyticsEvent.d.ts +3 -0
  32. package/dist/insights-v2/analytics/useAnalyticsEvent.es.js +20 -0
  33. package/dist/insights-v2/analytics/useAnalyticsEvent.es.js.map +1 -0
  34. package/dist/insights-v2/beatActions.d.ts +18 -13
  35. package/dist/insights-v2/beatActions.es.js.map +1 -1
  36. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js +24 -22
  37. package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js.map +1 -1
  38. package/dist/insights-v2/components/BaseLayout.es.js +89 -79
  39. package/dist/insights-v2/components/BaseLayout.es.js.map +1 -1
  40. package/dist/insights-v2/components/CompactInsightCard.es.js +34 -24
  41. package/dist/insights-v2/components/CompactInsightCard.es.js.map +1 -1
  42. package/dist/insights-v2/components/LogoFromGuid.d.ts +2 -2
  43. package/dist/insights-v2/components/LogoFromGuid.es.js +44 -32
  44. package/dist/insights-v2/components/LogoFromGuid.es.js.map +1 -1
  45. package/dist/insights-v2/components/SubHeader.es.js +3 -2
  46. package/dist/insights-v2/components/SubHeader.es.js.map +1 -1
  47. package/dist/insights-v2/components/chartblocks/EmptyBarChart.es.js +4 -4
  48. package/dist/insights-v2/components/shared/EntityLogo.es.js +31 -21
  49. package/dist/insights-v2/components/shared/EntityLogo.es.js.map +1 -1
  50. package/dist/insights-v2/components/shared/images/FeeDetected.es.js +243 -0
  51. package/dist/insights-v2/components/shared/images/FeeDetected.es.js.map +1 -0
  52. package/dist/insights-v2/ctaActions/ctaHandlers.d.ts +1 -6
  53. package/dist/insights-v2/ctaActions/ctaHandlers.es.js.map +1 -1
  54. package/dist/insights-v2/ctaActions/index.d.ts +1 -1
  55. package/dist/insights-v2/ctaActions/runCtaAction.d.ts +20 -5
  56. package/dist/insights-v2/ctaActions/runCtaAction.es.js +63 -41
  57. package/dist/insights-v2/ctaActions/runCtaAction.es.js.map +1 -1
  58. package/dist/insights-v2/ctaActions/types.d.ts +6 -5
  59. package/dist/insights-v2/index.es.js +84 -84
  60. package/dist/insights-v2/mappings/blocks.es.js +2 -2
  61. package/package.json +1 -1
@@ -1,16 +1,22 @@
1
- import { useAccountStore as c, useInsightsV2Store as i } from "../../common/context/hooks.es.js";
2
- import s from "../../common/components/ConnectWidgetPanel.es.js";
3
- import { useEffect as u, useRef as f } from "react";
4
- import { observer as m } from "mobx-react-lite";
5
- import { jsx as p } from "react/jsx-runtime";
6
- var v = m(function({ beat: o }) {
7
- const { actionDrawer: e } = i(), { refreshAccounts: n } = c(), t = e.isDrawerOpen && e.guid === o.guid, r = f(t);
8
- return u(() => {
9
- r.current && !t && n(), r.current = t;
10
- }, [t]), /* @__PURE__ */ p(s, { isActive: t });
1
+ import { useAccountStore as u, useInsightsV2Store as m } from "../../common/context/hooks.es.js";
2
+ import a from "../../common/components/ConnectWidgetPanel.es.js";
3
+ import { ANALYTICS_EVENTS_CONFIG as p } from "../analytics/analyticsEventsConfig.es.js";
4
+ import { useAnalyticsEvent as A } from "../analytics/useAnalyticsEvent.es.js";
5
+ import { useEffect as c, useRef as i } from "react";
6
+ import { observer as E } from "mobx-react-lite";
7
+ import { jsx as C } from "react/jsx-runtime";
8
+ var S = E(function({ beat: s }) {
9
+ const { actionDrawer: e } = m(), { refreshAccounts: f } = u(), r = A(), t = e.isDrawerOpen && e.guid === s.guid, n = i(t);
10
+ c(() => {
11
+ n.current && !t && f(), n.current = t;
12
+ }, [t]);
13
+ const o = i(!1);
14
+ return c(() => {
15
+ t && !o.current && r(p.OPENED_CONNECT_DRAWER), o.current = t;
16
+ }, [t, r]), /* @__PURE__ */ C(a, { isActive: t });
11
17
  });
12
18
  export {
13
- v as ConnectWidgetActionBlock
19
+ S as ConnectWidgetActionBlock
14
20
  };
15
21
 
16
22
  //# sourceMappingURL=ConnectWidgetActionBlock.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectWidgetActionBlock.es.js","names":[],"sources":["../../../src/insights-v2/actionBlocks/ConnectWidgetActionBlock.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport { ConnectWidgetPanel, useAccountStore, useInsightsV2Store } from '../../common'\nimport type { ActionBlockProps } from '../mappings/blocks'\n\n/**\n * `connect_widget_block` — opens MX's Connect widget itself via the shared\n * `ConnectWidgetPanel` (src/common): SSO url via ConnectStore and the\n * iframe-based `@mxenabled/web-widget-sdk` ConnectWidget, with loading/error\n * statuses.\n *\n * Renders the panel directly (not `ConnectDrawer`, which wraps it in its own\n * `Drawer`) — `ActionBlockLayer` already supplies the action drawer's chrome\n * (title from the CTA label, close button), so a second nested `Drawer` here\n * would produce two stacked drawers with two headers and two close buttons.\n *\n * `ActionBlockLayer` does not unmount a drawer-presentation block when the\n * drawer closes — it only toggles the `Drawer`'s `isOpen` — so the account\n * refresh (parity with `ConnectDrawer`'s own `onClose`) is driven by watching\n * this beat's `actionDrawer.isDrawerOpen` transition from true to false,\n * rather than an unmount effect, which would never fire.\n */\nexport const ConnectWidgetActionBlock = observer(function ConnectWidgetActionBlock({\n beat,\n}: ActionBlockProps) {\n const { actionDrawer } = useInsightsV2Store()\n const { refreshAccounts } = useAccountStore()\n\n const isCurrentBeatOpen = actionDrawer.isDrawerOpen && actionDrawer.guid === beat.guid\n const wasOpen = useRef(isCurrentBeatOpen)\n\n useEffect(() => {\n if (wasOpen.current && !isCurrentBeatOpen) {\n void refreshAccounts()\n }\n wasOpen.current = isCurrentBeatOpen\n }, [isCurrentBeatOpen])\n\n return <ConnectWidgetPanel isActive={isCurrentBeatOpen} />\n})\n"],"mappings":";;;;;AAuBA,IAAa,IAA2B,EAAS,SAAkC,EACjF,MAAA,EAAA,GACmB;AACnB,QAAM,EAAE,cAAA,EAAA,IAAiB,EAAmB,GACtC,EAAE,iBAAA,EAAA,IAAoB,EAAgB,GAEtC,IAAoB,EAAa,gBAAgB,EAAa,SAAS,EAAK,MAC5E,IAAU,EAAO,CAAiB;AAExC,SAAA,EAAA,MAAgB;AACd,IAAI,EAAQ,WAAW,CAAC,KACtB,EAAqB,GAEvB,EAAQ,UAAU;AAAA,EACpB,GAAG,CAAC,CAAiB,CAAC,GAEf,gBAAA,EAAC,GAAD,EAAoB,UAAU,EAAoB,CAAA;AAC3D,CAAC"}
1
+ {"version":3,"file":"ConnectWidgetActionBlock.es.js","names":[],"sources":["../../../src/insights-v2/actionBlocks/ConnectWidgetActionBlock.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport { ConnectWidgetPanel, useAccountStore, useInsightsV2Store } from '../../common'\nimport { ANALYTICS_EVENTS_CONFIG, useAnalyticsEvent } from '../analytics'\nimport type { ActionBlockProps } from '../mappings/blocks'\n\n/**\n * `connect_widget_block` — opens MX's Connect widget itself via the shared\n * `ConnectWidgetPanel` (src/common): SSO url via ConnectStore and the\n * iframe-based `@mxenabled/web-widget-sdk` ConnectWidget, with loading/error\n * statuses.\n *\n * Renders the panel directly (not `ConnectDrawer`, which wraps it in its own\n * `Drawer`) — `ActionBlockLayer` already supplies the action drawer's chrome\n * (title from the CTA label, close button), so a second nested `Drawer` here\n * would produce two stacked drawers with two headers and two close buttons.\n *\n * `ActionBlockLayer` does not unmount a drawer-presentation block when the\n * drawer closes — it only toggles the `Drawer`'s `isOpen` — so the account\n * refresh (parity with `ConnectDrawer`'s own `onClose`) is driven by watching\n * this beat's `actionDrawer.isDrawerOpen` transition from true to false,\n * rather than an unmount effect, which would never fire.\n */\nexport const ConnectWidgetActionBlock = observer(function ConnectWidgetActionBlock({\n beat,\n}: ActionBlockProps) {\n const { actionDrawer } = useInsightsV2Store()\n const { refreshAccounts } = useAccountStore()\n const fireAnalyticsEvent = useAnalyticsEvent()\n\n const isCurrentBeatOpen = actionDrawer.isDrawerOpen && actionDrawer.guid === beat.guid\n const wasOpen = useRef(isCurrentBeatOpen)\n\n useEffect(() => {\n if (wasOpen.current && !isCurrentBeatOpen) {\n void refreshAccounts()\n }\n wasOpen.current = isCurrentBeatOpen\n }, [isCurrentBeatOpen])\n\n // OPENED_CONNECT_DRAWER: the drawer actually opened (any path — CTA or otherwise). Own ref +\n // effect, separate from the refresh logic above: this one is rising-edge, so its ref starts\n // `false` — the block's first render typically happens with the drawer already open (children\n // render on open), and that first open must fire too. Fires once per open, re-arms on close.\n // Pulse parity: ConnectDiscoveredAccounts/Beat.js onPrimaryCtaClick's `opened_connect_drawer`.\n const hasFiredOpen = useRef(false)\n\n useEffect(() => {\n if (isCurrentBeatOpen && !hasFiredOpen.current) {\n fireAnalyticsEvent(ANALYTICS_EVENTS_CONFIG.OPENED_CONNECT_DRAWER)\n }\n hasFiredOpen.current = isCurrentBeatOpen\n }, [isCurrentBeatOpen, fireAnalyticsEvent])\n\n return <ConnectWidgetPanel isActive={isCurrentBeatOpen} />\n})\n"],"mappings":";;;;;;;AAwBA,IAAa,IAA2B,EAAS,SAAkC,EACjF,MAAA,EAAA,GACmB;AACnB,QAAM,EAAE,cAAA,EAAA,IAAiB,EAAmB,GACtC,EAAE,iBAAA,EAAA,IAAoB,EAAgB,GACtC,IAAqB,EAAkB,GAEvC,IAAoB,EAAa,gBAAgB,EAAa,SAAS,EAAK,MAC5E,IAAU,EAAO,CAAiB;AAExC,EAAA,EAAA,MAAgB;AACd,IAAI,EAAQ,WAAW,CAAC,KACtB,EAAqB,GAEvB,EAAQ,UAAU;AAAA,EACpB,GAAG,CAAC,CAAiB,CAAC;AAOtB,QAAM,IAAe,EAAO,EAAK;AAEjC,SAAA,EAAA,MAAgB;AACd,IAAI,KAAqB,CAAC,EAAa,WACrC,EAAmB,EAAwB,qBAAqB,GAElE,EAAa,UAAU;AAAA,EACzB,GAAG,CAAC,GAAmB,CAAkB,CAAC,GAEnC,gBAAA,EAAC,GAAD,EAAoB,UAAU,EAAoB,CAAA;AAC3D,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { BottomActions } from '../../../transactions/constants/Actions';
2
+ export interface TransactionDetailsLayoutConfig {
3
+ /** Bottom action rows rendered in the drawer. */
4
+ bottomActions: BottomActions[];
5
+ }
6
+ /**
7
+ * Drilldown variations of the Transaction Details drawer, keyed by the CTA's `variant`
8
+ * (`primary_cta.variant` — the CTA's `block` picks which action block opens, `variant` tunes what it
9
+ * does). Names describe the behavior, not the originating beat, so any beat whose CTA wants the same
10
+ * drilldown reuses the value. Extend `TransactionDetailsLayoutConfig` (styles, top actions, …) as
11
+ * variants need to differ, rather than branching on the variant string across the block.
12
+ *
13
+ * - `MerchantBudget` — shows the "Add a Merchant Budget" row.
14
+ * - `NoMerchantBudget` — drops the "Add a Merchant Budget" row.
15
+ */
16
+ export declare const transactionDetailsVariant: {
17
+ readonly MerchantBudget: "merchant_budget";
18
+ readonly NoMerchantBudget: "no_merchant_budget";
19
+ };
20
+ export type TransactionDetailsVariant = (typeof transactionDetailsVariant)[keyof typeof transactionDetailsVariant];
21
+ /**
22
+ * Resolve a CTA variant's drawer config. Any variant without its own entry — including `null` and
23
+ * unknown values — falls back to the full action set (merchant budget included). That default is the
24
+ * common case, not a misconfiguration, so this does not warn. `Object.hasOwn` avoids inherited keys
25
+ * (e.g. `constructor`) resolving to a non-config.
26
+ */
27
+ export declare const resolveLayoutConfig: (variant: string | null | undefined) => TransactionDetailsLayoutConfig;
@@ -0,0 +1,14 @@
1
+ import { BottomActions as n, DEFAULT_BOTTOM_ACTIONS as r } from "../../../transactions/constants/Actions.es.js";
2
+ var a = { bottomActions: [n.MerchantBudget, ...r] }, c = { bottomActions: r }, e = {
3
+ MerchantBudget: "merchant_budget",
4
+ NoMerchantBudget: "no_merchant_budget"
5
+ }, o = {
6
+ [e.MerchantBudget]: a,
7
+ [e.NoMerchantBudget]: c
8
+ }, _ = (t) => t != null && Object.hasOwn(o, t) ? o[t] : a;
9
+ export {
10
+ _ as resolveLayoutConfig,
11
+ e as transactionDetailsVariant
12
+ };
13
+
14
+ //# sourceMappingURL=layout.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/layout.ts"],"sourcesContent":["import { BottomActions, DEFAULT_BOTTOM_ACTIONS } from '../../../transactions/constants/Actions'\n\nexport interface TransactionDetailsLayoutConfig {\n /** Bottom action rows rendered in the drawer. */\n bottomActions: BottomActions[]\n}\n\n// Reusable configs named by intent, not by any one beat, so any CTA variant can point at them.\nconst WITH_MERCHANT_BUDGET: TransactionDetailsLayoutConfig = {\n bottomActions: [BottomActions.MerchantBudget, ...DEFAULT_BOTTOM_ACTIONS],\n}\nconst WITHOUT_MERCHANT_BUDGET: TransactionDetailsLayoutConfig = {\n bottomActions: DEFAULT_BOTTOM_ACTIONS,\n}\n\n/**\n * Drilldown variations of the Transaction Details drawer, keyed by the CTA's `variant`\n * (`primary_cta.variant` — the CTA's `block` picks which action block opens, `variant` tunes what it\n * does). Names describe the behavior, not the originating beat, so any beat whose CTA wants the same\n * drilldown reuses the value. Extend `TransactionDetailsLayoutConfig` (styles, top actions, …) as\n * variants need to differ, rather than branching on the variant string across the block.\n *\n * - `MerchantBudget` — shows the \"Add a Merchant Budget\" row.\n * - `NoMerchantBudget` — drops the \"Add a Merchant Budget\" row.\n */\nexport const transactionDetailsVariant = {\n MerchantBudget: 'merchant_budget',\n NoMerchantBudget: 'no_merchant_budget',\n} as const\n\nexport type TransactionDetailsVariant =\n (typeof transactionDetailsVariant)[keyof typeof transactionDetailsVariant]\n\nconst VARIANT_CONFIG: Record<string, TransactionDetailsLayoutConfig> = {\n [transactionDetailsVariant.MerchantBudget]: WITH_MERCHANT_BUDGET,\n [transactionDetailsVariant.NoMerchantBudget]: WITHOUT_MERCHANT_BUDGET,\n}\n\n/**\n * Resolve a CTA variant's drawer config. Any variant without its own entry — including `null` and\n * unknown values — falls back to the full action set (merchant budget included). That default is the\n * common case, not a misconfiguration, so this does not warn. `Object.hasOwn` avoids inherited keys\n * (e.g. `constructor`) resolving to a non-config.\n */\nexport const resolveLayoutConfig = (\n variant: string | null | undefined,\n): TransactionDetailsLayoutConfig =>\n variant != null && Object.hasOwn(VARIANT_CONFIG, variant)\n ? VARIANT_CONFIG[variant]\n : WITH_MERCHANT_BUDGET\n"],"mappings":";AAQA,IAAM,IAAuD,EAC3D,eAAe,CAAC,EAAc,gBAAgB,GAAG,CAAsB,EACzE,GACM,IAA0D,EAC9D,eAAe,EACjB,GAYa,IAA4B;AAAA,EACvC,gBAAgB;AAAA,EAChB,kBAAkB;AACpB,GAKM,IAAiE;AAAA,EACpE,CAAA,EAA0B,cAAA,GAAiB;AAAA,EAC3C,CAAA,EAA0B,gBAAA,GAAmB;AAChD,GAQa,IAAA,CACX,MAEA,KAAW,QAAQ,OAAO,OAAO,GAAgB,CAAO,IACpD,EAAe,CAAA,IACf"}
@@ -1,11 +1,11 @@
1
- import { useActionContext as d, useInsightsV2Store as m, useTransactionStore as p } from "../../../common/context/hooks.es.js";
1
+ import { useActionContext as d, useInsightsV2Store as p, useTransactionStore as m } from "../../../common/context/hooks.es.js";
2
2
  import { getBottomActionsByVariant as u } from "./util.es.js";
3
3
  import { resolveTopActions as g } from "./transactionDetailsActions.es.js";
4
- var A = (a) => {
5
- const { detailedTransactions: n, isTransactionDataLoaded: i } = p(), { actionDrawer: s } = m(), { transaction_guid: r } = d() ?? {}, t = a.insights_payload, o = r ?? t?.primary_transaction_guid, c = o ? n.find((e) => e.guid === o) : void 0;
4
+ var A = (i) => {
5
+ const { detailedTransactions: n, isTransactionDataLoaded: a } = m(), { actionDrawer: s } = p(), { transaction_guid: r } = d() ?? {}, t = i.insights_payload, o = r ?? t?.primary_transaction_guid, c = o ? n.find((e) => e.guid === o) : void 0;
6
6
  return {
7
- bottomActions: u(s, t?.primary_cta, t?.secondary_cta),
8
- isLoading: !i,
7
+ bottomActions: u(s, t?.primary_cta, t?.secondary_cta, t?.in_description_cta),
8
+ isLoading: !a,
9
9
  topActions: g(),
10
10
  transaction: c
11
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useTransactionDetailsBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.ts"],"sourcesContent":["import { useActionContext, useInsightsV2Store, useTransactionStore } from '../../../common'\nimport type { Beat, Transaction, DrilldownPayload } from '../../../core'\nimport type { BottomActions, TopActions } from '../../../transactions/constants/Actions'\nimport { getBottomActionsByVariant } from './util'\nimport { resolveTopActions } from './transactionDetailsActions'\n\ninterface TransactionDetailsBlockState {\n bottomActions: BottomActions[]\n /** True while the store is still loading; the block shows a loader instead of an empty state. */\n isLoading: boolean\n topActions: TopActions[]\n /** `undefined` once loading finishes means the transaction could not be resolved. */\n transaction?: Transaction\n}\n\n/**\n * Resolves which transaction this drawer is about, and which inline actions it offers.\n *\n * The subject comes from one of two places:\n * 1. `actionContext.transaction_guid` — set by a parent drawer (e.g. a row tapped in\n * `TransactionHistoryBlock`) when this drawer is opened nested.\n * 2. `insights_payload.primary_transaction_guid` — the ditto contract for every beat whose\n * `primary_cta_block` is `transaction_details_block`.\n *\n * The guid is then looked up in `transactionStore.detailedTransactions` rather than used directly,\n * because `TransactionDetails` needs the *detailed* shape (account + category + taggings joined in)\n * and edits must write through to the same store object the rest of the app renders. `buildDetailed\n * Transactions` inside the store is this repo's equivalent of pulse's `buildTransactionDetails`.\n * A guid the store does not have resolves to `undefined` (the block's error state) rather than to\n * any beat-level snapshot, so inline edits can never be made against a stale copy.\n *\n * Actions are not beat-configurable on the v2 contract: `instance_slot_data` is not part of it (the\n * LargeTransactionV2 payload omits the key entirely), so top actions are always the defaults and\n * bottom actions are derived from the triggering CTA's variant.\n */\nexport const useTransactionDetailsBlock = (beat: Beat): TransactionDetailsBlockState => {\n const { detailedTransactions, isTransactionDataLoaded } = useTransactionStore()\n\n const { actionDrawer } = useInsightsV2Store()\n\n const { transaction_guid } = useActionContext<DrilldownPayload>() ?? {}\n const payload = beat.insights_payload\n\n const guid = transaction_guid ?? payload?.primary_transaction_guid\n\n const transaction = guid\n ? detailedTransactions.find((transaction) => transaction.guid === guid)\n : undefined\n\n const bottomActions = getBottomActionsByVariant(\n actionDrawer,\n payload?.primary_cta,\n payload?.secondary_cta,\n )\n return {\n bottomActions,\n isLoading: !isTransactionDataLoaded,\n topActions: resolveTopActions(),\n transaction,\n }\n}\n"],"mappings":";;;AAmCA,IAAa,IAAA,CAA8B,MAA6C;AACtF,QAAM,EAAE,sBAAA,GAAsB,yBAAA,EAAA,IAA4B,EAAoB,GAExE,EAAE,cAAA,EAAA,IAAiB,EAAmB,GAEtC,EAAE,kBAAA,EAAA,IAAqB,EAAmC,KAAK,CAAC,GAChE,IAAU,EAAK,kBAEf,IAAO,KAAoB,GAAS,0BAEpC,IAAc,IAChB,EAAqB,KAAA,CAAM,MAAgB,EAAY,SAAS,CAAI,IACpE;AAOJ,SAAO;AAAA,IACL,eANoB,EACpB,GACA,GAAS,aACT,GAAS,aAGT;AAAA,IACA,WAAW,CAAC;AAAA,IACZ,YAAY,EAAkB;AAAA,IAC9B,aAAA;AAAA,EACF;AACF"}
1
+ {"version":3,"file":"useTransactionDetailsBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.ts"],"sourcesContent":["import { useActionContext, useInsightsV2Store, useTransactionStore } from '../../../common'\nimport type { Beat, Transaction, DrilldownPayload } from '../../../core'\nimport type { BottomActions, TopActions } from '../../../transactions/constants/Actions'\nimport { getBottomActionsByVariant } from './util'\nimport { resolveTopActions } from './transactionDetailsActions'\n\ninterface TransactionDetailsBlockState {\n bottomActions: BottomActions[]\n /** True while the store is still loading; the block shows a loader instead of an empty state. */\n isLoading: boolean\n topActions: TopActions[]\n /** `undefined` once loading finishes means the transaction could not be resolved. */\n transaction?: Transaction\n}\n\n/**\n * Resolves which transaction this drawer is about, and which inline actions it offers.\n *\n * The subject comes from one of two places:\n * 1. `actionContext.transaction_guid` — set by a parent drawer (e.g. a row tapped in\n * `TransactionHistoryBlock`) when this drawer is opened nested.\n * 2. `insights_payload.primary_transaction_guid` — the ditto contract for every beat whose\n * `primary_cta_block` is `transaction_details_block`.\n *\n * The guid is then looked up in `transactionStore.detailedTransactions` rather than used directly,\n * because `TransactionDetails` needs the *detailed* shape (account + category + taggings joined in)\n * and edits must write through to the same store object the rest of the app renders. `buildDetailed\n * Transactions` inside the store is this repo's equivalent of pulse's `buildTransactionDetails`.\n * A guid the store does not have resolves to `undefined` (the block's error state) rather than to\n * any beat-level snapshot, so inline edits can never be made against a stale copy.\n *\n * Actions are not beat-configurable on the v2 contract: `instance_slot_data` is not part of it (the\n * LargeTransactionV2 payload omits the key entirely), so top actions are always the defaults and\n * bottom actions are derived from the triggering CTA's variant.\n */\nexport const useTransactionDetailsBlock = (beat: Beat): TransactionDetailsBlockState => {\n const { detailedTransactions, isTransactionDataLoaded } = useTransactionStore()\n\n const { actionDrawer } = useInsightsV2Store()\n\n const { transaction_guid } = useActionContext<DrilldownPayload>() ?? {}\n const payload = beat.insights_payload\n\n const guid = transaction_guid ?? payload?.primary_transaction_guid\n\n const transaction = guid\n ? detailedTransactions.find((transaction) => transaction.guid === guid)\n : undefined\n\n const bottomActions = getBottomActionsByVariant(\n actionDrawer,\n payload?.primary_cta,\n payload?.secondary_cta,\n payload?.in_description_cta,\n )\n return {\n bottomActions,\n isLoading: !isTransactionDataLoaded,\n topActions: resolveTopActions(),\n transaction,\n }\n}\n"],"mappings":";;;AAmCA,IAAa,IAAA,CAA8B,MAA6C;AACtF,QAAM,EAAE,sBAAA,GAAsB,yBAAA,EAAA,IAA4B,EAAoB,GAExE,EAAE,cAAA,EAAA,IAAiB,EAAmB,GAEtC,EAAE,kBAAA,EAAA,IAAqB,EAAmC,KAAK,CAAC,GAChE,IAAU,EAAK,kBAEf,IAAO,KAAoB,GAAS,0BAEpC,IAAc,IAChB,EAAqB,KAAA,CAAM,MAAgB,EAAY,SAAS,CAAI,IACpE;AAQJ,SAAO;AAAA,IACL,eAPoB,EACpB,GACA,GAAS,aACT,GAAS,eACT,GAAS,kBAGT;AAAA,IACA,WAAW,CAAC;AAAA,IACZ,YAAY,EAAkB;AAAA,IAC9B,aAAA;AAAA,EACF;AACF"}
@@ -1,3 +1,7 @@
1
- import { ActionDrawerState, PrimaryCTA, SecondaryCTA } from '../../../core';
1
+ import { ActionDrawerState, InDescriptionCTA, PrimaryCTA, SecondaryCTA } from '../../../core';
2
2
  import { BottomActions } from '../../../transactions/constants/Actions';
3
- export declare const getBottomActionsByVariant: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined) => BottomActions[];
3
+ /**
4
+ * Bottom actions for the drawer, driven by the triggering CTA's `variant` via the per-variant
5
+ * config table in `./layout.ts`. Add variant-specific behavior (or styles) there, not here.
6
+ */
7
+ export declare const getBottomActionsByVariant: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined, in_description_cta?: InDescriptionCTA) => BottomActions[];
@@ -1,8 +1,11 @@
1
- import { BottomActions as o, DEFAULT_BOTTOM_ACTIONS as t } from "../../../transactions/constants/Actions.es.js";
2
- import { getDynamicCtaBasedOnTriggers as i } from "../util.es.js";
3
- var m = (e, r, a) => i(e, r, a)?.variant === "fee_detected" ? t : [o.MerchantBudget, ...t];
1
+ import { getDynamicCtaBasedOnTriggers as n } from "../util.es.js";
2
+ import { resolveLayoutConfig as e } from "./layout.es.js";
3
+ var c = (t, o, r, a) => {
4
+ const i = n(t, o, r, a);
5
+ return e(i?.variant).bottomActions;
6
+ };
4
7
  export {
5
- m as getBottomActionsByVariant
8
+ c as getBottomActionsByVariant
6
9
  };
7
10
 
8
11
  //# sourceMappingURL=util.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/util.ts"],"sourcesContent":["import type { ActionDrawerState, PrimaryCTA, SecondaryCTA } from '../../../core'\nimport { BottomActions, DEFAULT_BOTTOM_ACTIONS } from '../../../transactions/constants/Actions'\nimport { getDynamicCtaBasedOnTriggers } from '../util'\n\nexport const getBottomActionsByVariant = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n): BottomActions[] => {\n const cta = getDynamicCtaBasedOnTriggers(actionDrawer, primary_cta, secondary_cta)\n\n switch (cta?.variant) {\n case 'fee_detected':\n return DEFAULT_BOTTOM_ACTIONS\n default:\n return [BottomActions.MerchantBudget, ...DEFAULT_BOTTOM_ACTIONS]\n }\n}\n"],"mappings":";;AAIA,IAAa,IAAA,CACX,GACA,GACA,MAEY,EAA6B,GAAc,GAAa,CAE5D,GAAK,YACN,iBACI,IAEA,CAAC,EAAc,gBAAgB,GAAG,CAAsB"}
1
+ {"version":3,"file":"util.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/util.ts"],"sourcesContent":["import type { ActionDrawerState, InDescriptionCTA, PrimaryCTA, SecondaryCTA } from '../../../core'\nimport type { BottomActions } from '../../../transactions/constants/Actions'\nimport { getDynamicCtaBasedOnTriggers } from '../util'\nimport { resolveLayoutConfig } from './layout'\n\n/**\n * Bottom actions for the drawer, driven by the triggering CTA's `variant` via the per-variant\n * config table in `./layout.ts`. Add variant-specific behavior (or styles) there, not here.\n */\nexport const getBottomActionsByVariant = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n in_description_cta?: InDescriptionCTA,\n): BottomActions[] => {\n const cta = getDynamicCtaBasedOnTriggers(\n actionDrawer,\n primary_cta,\n secondary_cta,\n in_description_cta,\n )\n\n return resolveLayoutConfig(cta?.variant).bottomActions\n}\n"],"mappings":";;AASA,IAAa,IAAA,CACX,GACA,GACA,GACA,MACoB;AACpB,QAAM,IAAM,EACV,GACA,GACA,GACA,CACF;AAEA,SAAO,EAAoB,GAAK,OAAO,EAAE;AAC3C"}
@@ -1,73 +1,75 @@
1
- import { useGlobalCopyStore as W, useGlobalUiStore as X, useInsightsV2Store as Y } from "../../../common/context/hooks.es.js";
2
- import { formatCurrency as Z } from "../../../core/utils/NumberFormatting.es.js";
3
- import tt from "../../../common/components/drawer/Drawer.es.js";
4
- import et from "../../../common/components/Loader.es.js";
5
- import { BarChartV2 as at } from "../../components/chartblocks/BarchartV2.es.js";
6
- import { EmptyBarChart as ot } from "../../components/chartblocks/EmptyBarChart.es.js";
7
- import { TransactionDrillDown as nt } from "./TransactionDrillDown.es.js";
8
- import { useTransactionHistory as rt } from "./useTransactionHistory.es.js";
9
- import { getDefaultSelection as it, getDrillDownConfig as st, getFlattenedDataSeries as lt, toStoreFilter as ct } from "./utils.es.js";
10
- import { getDynamicCtaBasedOnTriggers as dt } from "../util.es.js";
11
- import { TransactionDetailsBlock as mt } from "../TransactionDetailsBlock/TransactionDetailsBlock.es.js";
12
- import { useLayoutEffect as gt, useState as u } from "react";
13
- import { observer as pt } from "mobx-react-lite";
14
- import { Fragment as ut, jsx as n, jsxs as ht } from "react/jsx-runtime";
15
- import { useTheme as bt } from "@mui/material/styles";
16
- var jt = pt(({ beat: a }) => {
17
- const h = bt(), { instanceSlotData: e, beatTransactions: l, spendCategoryGuids: b, allAccountGuids: f, categoryName: v, displayedDateRange: g, transactionStore: x } = rt(a), { actionDrawer: y, setActionContext: C } = Y(), { common: B, insights_feed: c } = W(), { isCopyLoaded: F } = X(), [I, T] = u(!1), [G, A] = u(!1), { insights_payload: o } = a, j = dt(y, o?.primary_cta, o?.secondary_cta, o?.in_description_cta)?.variant, { top: r, filterMode: d, header: k, colors: w, filterStrategy: H, tipSection: S } = st(j ?? ""), { dataSeries: m, chartData: i, comparisonBars: O } = lt({
1
+ import { useGlobalCopyStore as X, useGlobalUiStore as Z, useInsightsV2Store as tt } from "../../../common/context/hooks.es.js";
2
+ import { formatCurrency as et } from "../../../core/utils/NumberFormatting.es.js";
3
+ import at from "../../../common/components/drawer/Drawer.es.js";
4
+ import ot from "../../../common/components/Loader.es.js";
5
+ import { BarChartV2 as nt } from "../../components/chartblocks/BarchartV2.es.js";
6
+ import { EmptyBarChart as rt } from "../../components/chartblocks/EmptyBarChart.es.js";
7
+ import { ANALYTICS_EVENTS_CONFIG as A } from "../../analytics/analyticsEventsConfig.es.js";
8
+ import { useAnalyticsEvent as it } from "../../analytics/useAnalyticsEvent.es.js";
9
+ import { TransactionDrillDown as st } from "./TransactionDrillDown.es.js";
10
+ import { useTransactionHistory as lt } from "./useTransactionHistory.es.js";
11
+ import { getDefaultSelection as ct, getDrillDownConfig as mt, getFlattenedDataSeries as dt, toStoreFilter as pt } from "./utils.es.js";
12
+ import { getDynamicCtaBasedOnTriggers as gt } from "../util.es.js";
13
+ import { TransactionDetailsBlock as ut } from "../TransactionDetailsBlock/TransactionDetailsBlock.es.js";
14
+ import { useLayoutEffect as ft, useState as u } from "react";
15
+ import { observer as ht } from "mobx-react-lite";
16
+ import { Fragment as yt, jsx as n, jsxs as bt } from "react/jsx-runtime";
17
+ import { useTheme as Ct } from "@mui/material/styles";
18
+ var kt = ht(({ beat: a }) => {
19
+ const f = Ct(), { instanceSlotData: e, beatTransactions: l, spendCategoryGuids: h, allAccountGuids: y, categoryName: x, displayedDateRange: p, transactionStore: B } = lt(a), { actionDrawer: b, setActionContext: C } = tt(), { common: E, insights_feed: c } = X(), { isCopyLoaded: I } = Z(), [F, T] = u(!1), [G, H] = u(!1), _ = it(), { insights_payload: o } = a, O = gt(b, o?.primary_cta, o?.secondary_cta, o?.in_description_cta)?.variant, { top: r, filterMode: m, header: R, colors: j, filterStrategy: k, tipSection: S } = mt(O ?? ""), { dataSeries: d, chartData: i, comparisonBars: w } = dt({
18
20
  data: e?.data_series,
19
21
  ariaLabel: e?.ariaLabel ?? "",
20
22
  top: r,
21
23
  beatTransactions: l,
22
24
  payload: e
23
- }), { chartBarIndex: E, subTabIndex: K } = it({
25
+ }), { chartBarIndex: K, subTabIndex: N } = ct({
24
26
  chartTabCount: i.length,
25
- comparisonTabCount: O.length,
26
- actionDrawer: y,
27
+ comparisonTabCount: w.length,
28
+ actionDrawer: b,
27
29
  beatGuid: a.guid
28
- }), [s, _] = u(E), D = (t) => H({
30
+ }), [s, D] = u(K), L = (t) => k({
29
31
  beat: a,
30
32
  beatTransactions: l,
31
- dataSeries: m,
33
+ dataSeries: d,
32
34
  selectedIndex: t,
33
- subIndex: K,
34
- isLastTab: t === m.length - 1,
35
+ subIndex: N,
36
+ isLastTab: t === d.length - 1,
35
37
  instanceSlotData: e,
36
- spendCategoryGuids: b,
37
- displayedDateRange: g
38
- }), V = l.map((t) => t.guid).join(","), R = b.join(","), M = f.join(","), N = r === "list" || m.length > 0, L = () => {
39
- d !== "store" || !N || x.setFilter(ct(D(s), {
40
- allAccountGuids: f,
41
- displayedDateRange: g
38
+ spendCategoryGuids: h,
39
+ displayedDateRange: p
40
+ }), V = l.map((t) => t.guid).join(","), M = h.join(","), P = y.join(","), U = r === "list" || d.length > 0, v = () => {
41
+ m !== "store" || !U || B.setFilter(pt(L(s), {
42
+ allAccountGuids: y,
43
+ displayedDateRange: p
42
44
  }));
43
45
  };
44
- gt(() => {
45
- L();
46
+ ft(() => {
47
+ v();
46
48
  }, [
47
49
  a.guid,
48
50
  s,
49
- d,
50
- m.length,
51
+ m,
52
+ d.length,
51
53
  e,
52
- g,
53
- R,
54
+ p,
54
55
  M,
56
+ P,
55
57
  V,
56
58
  r
57
59
  ]);
58
- const p = k?.({
60
+ const g = R?.({
59
61
  title: o?.title,
60
62
  subHeader: o?.sub_title,
61
- categoryName: v,
63
+ categoryName: x,
62
64
  selectedDate: i[s]?.date ?? void 0
63
- }), P = w(h, e?.category_guid);
64
- if (!F) return /* @__PURE__ */ n(et, {});
65
- const U = [c.general.monthly_amount, c.general.trend], [$, q] = e?.legends?.length ? e.legends.map((t) => t.label) : U, z = d === "local" ? (t) => D(t).custom ?? (() => !0) : void 0, J = d === "local" ? l : void 0, Q = r === "singleBar" || r === "upcomingBill" ? i.length ? /* @__PURE__ */ n(at, {
65
+ }), W = j(f, e?.category_guid);
66
+ if (!I) return /* @__PURE__ */ n(ot, {});
67
+ const Y = [c.general.monthly_amount, c.general.trend], [$, q] = e?.legends?.length ? e.legends.map((t) => t.label) : Y, z = m === "local" ? (t) => L(t).custom ?? (() => !0) : void 0, J = m === "local" ? l : void 0, Q = r === "singleBar" || r === "upcomingBill" ? i.length ? /* @__PURE__ */ n(nt, {
66
68
  amounts: {
67
69
  average: e?.average_amount,
68
- formattedAverage: Z(e?.average_amount ?? 0, "0,0.00")
70
+ formattedAverage: et(e?.average_amount ?? 0, "0,0.00")
69
71
  },
70
- color: P[0] ?? h.palette.primary.main,
72
+ color: W[0] ?? f.palette.primary.main,
71
73
  data: i,
72
74
  legendPosition: "top",
73
75
  heightOverride: 142,
@@ -78,40 +80,44 @@ var jt = pt(({ beat: a }) => {
78
80
  right: 24
79
81
  },
80
82
  monthlyAmountLabel: $,
81
- onBarClick: _,
83
+ onBarClick: (t) => {
84
+ _(A.DRAWER_CHART_BAR_CLICKED), D(t);
85
+ },
82
86
  selectedTabIndex: s,
83
87
  trendAmountLabel: q
84
- }) : /* @__PURE__ */ n(ot, {}) : null;
85
- return /* @__PURE__ */ ht(ut, { children: [/* @__PURE__ */ n(nt, {
88
+ }) : /* @__PURE__ */ n(rt, {}) : null;
89
+ return /* @__PURE__ */ bt(yt, { children: [/* @__PURE__ */ n(st, {
86
90
  ariaLabel: e?.ariaLabel,
87
91
  baseTransactions: J,
88
- heading: p?.heading,
89
- icon: p?.icon,
90
- onSelectionChange: _,
92
+ heading: g?.heading,
93
+ icon: g?.icon,
94
+ onSelectionChange: (t) => {
95
+ _(A.TAB_SELECTED), D(t);
96
+ },
91
97
  selectedIndex: s,
92
- subHeadingText: p?.subHeadingText,
98
+ subHeadingText: g?.subHeadingText,
93
99
  tabs: i.map((t) => ({
94
100
  ariaLabel: t.ariaLabel,
95
101
  label: t.label
96
102
  })),
97
103
  top: Q,
98
- ...S && { tipSection: !G && S(A, c, o?.sub_title?.text) },
104
+ ...S && { tipSection: !G && S(H, c, o?.sub_title?.text) },
99
105
  transactionFilter: z,
100
106
  onEachRowClick: (t) => {
101
107
  C({ transaction_guid: t }), T(!0);
102
108
  }
103
- }), /* @__PURE__ */ n(tt, {
104
- ariaLabelClose: B.close_aria,
105
- isOpen: I,
109
+ }), /* @__PURE__ */ n(at, {
110
+ ariaLabelClose: E.close_aria,
111
+ isOpen: F,
106
112
  onClose: () => {
107
- T(!1), C({ transaction_guid: void 0 }), L();
113
+ T(!1), C({ transaction_guid: void 0 }), v();
108
114
  },
109
115
  title: c.general.transaction_details_title,
110
- children: /* @__PURE__ */ n(mt, { beat: a })
116
+ children: /* @__PURE__ */ n(ut, { beat: a })
111
117
  })] });
112
118
  });
113
119
  export {
114
- jt as TransactionHistoryBlock
120
+ kt as TransactionHistoryBlock
115
121
  };
116
122
 
117
123
  //# sourceMappingURL=TransactionHistoryBlock.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TransactionHistoryBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.tsx"],"sourcesContent":["import { useLayoutEffect, useState } from 'react'\n\nimport { useTheme } from '@mui/material/styles'\nimport { observer } from 'mobx-react-lite'\n\nimport type { Beat, DataSeries, Transaction } from '../../../core'\nimport { formatCurrency } from '../../../core/utils/NumberFormatting'\nimport { BarChartV2 } from '../../components/chartblocks/BarchartV2'\nimport { EmptyBarChart } from '../../components/chartblocks/EmptyBarChart'\n\nimport { TransactionDrillDown } from './TransactionDrillDown'\nimport { useTransactionHistory } from './useTransactionHistory'\nimport {\n getDefaultSelection,\n getDrillDownConfig,\n getFlattenedDataSeries,\n toStoreFilter,\n} from './utils'\nimport {\n Drawer,\n useInsightsV2Store,\n useGlobalCopyStore,\n useGlobalUiStore,\n Loader,\n} from '../../../common'\nimport { TransactionDetailsBlock } from '../TransactionDetailsBlock'\nimport { getDynamicCtaBasedOnTriggers } from '../util'\n\ninterface TransactionHistoryProp {\n beat: Beat\n}\n\nexport const TransactionHistoryBlock = observer(({ beat }: TransactionHistoryProp) => {\n const theme = useTheme()\n const {\n instanceSlotData,\n beatTransactions,\n spendCategoryGuids,\n allAccountGuids,\n categoryName,\n displayedDateRange,\n transactionStore,\n } = useTransactionHistory(beat)\n\n const { actionDrawer, setActionContext } = useInsightsV2Store()\n\n const { common: commonCopy, insights_feed: insightsCopy } = useGlobalCopyStore()\n\n const { isCopyLoaded } = useGlobalUiStore()\n\n const [isTransactionDetailsOpen, setIsTransactionDetailsOpen] = useState(false)\n\n const [closeTipSection, setCloseTipSection] = useState(false)\n\n const { insights_payload } = beat\n\n const dynamicCtaVariant = getDynamicCtaBasedOnTriggers(\n actionDrawer,\n insights_payload?.primary_cta,\n insights_payload?.secondary_cta,\n insights_payload?.in_description_cta,\n )?.variant\n\n const { top, filterMode, header, colors, filterStrategy, tipSection } = getDrillDownConfig(\n dynamicCtaVariant ?? '',\n )\n\n const { dataSeries, chartData, comparisonBars } = getFlattenedDataSeries({\n data: instanceSlotData?.data_series as DataSeries,\n ariaLabel: instanceSlotData?.ariaLabel ?? '',\n top,\n beatTransactions,\n payload: instanceSlotData,\n })\n\n const { chartBarIndex, subTabIndex } = getDefaultSelection({\n chartTabCount: chartData.length,\n comparisonTabCount: comparisonBars.length,\n actionDrawer,\n beatGuid: beat.guid,\n })\n\n const [selectedIndex, setSelectedIndex] = useState(chartBarIndex)\n\n const resolveFilter = (index: number) =>\n filterStrategy({\n beat,\n beatTransactions,\n dataSeries,\n selectedIndex: index,\n subIndex: subTabIndex,\n isLastTab: index === dataSeries.length - 1,\n instanceSlotData,\n spendCategoryGuids,\n displayedDateRange,\n })\n\n // Apply the current selection's filter. Store variants route through the store filter; local\n // (upcomingBill) variants filter beatTransactions directly and only backfill the cache when the\n // Stable primitive keys for the collections below: beatTransactions/spendCategoryGuids/\n // allAccountGuids are recomputed (new array identity) every render, so depending on them directly\n // re-fires the effect each render (REVIEW.md MEW-3732). Key on content instead.\n const beatTransactionGuidsKey = beatTransactions.map((transaction) => transaction.guid).join(',')\n const spendCategoryGuidsKey = spendCategoryGuids.join(',')\n const allAccountGuidsKey = allAccountGuids.join(',')\n\n // Re-applies the current selection's filter to the shared transactionStore. Called both by the\n // effect below (on selection change) and when the nested TransactionDetailsBlock drawer closes:\n // AddMerchantBudgetAction (opened from within that drawer) overwrites transactionStore.filter\n // with a merchant_guid-only filter while its own drawer is open, and never restores it — leaving\n // the row list stuck showing only that one merchant's transactions after backing all the way out.\n // Re-running this on close re-derives the filter fresh instead of relying on whatever the nested\n // drawers left behind.\n // A `list` drawer has no bars: it filters once from the beat alone.\n const canApplyFilter = top === 'list' || dataSeries.length > 0\n const applyCurrentSelectionFilter = () => {\n if (filterMode !== 'store' || !canApplyFilter) return\n transactionStore.setFilter(\n toStoreFilter(resolveFilter(selectedIndex), { allAccountGuids, displayedDateRange }),\n )\n }\n\n // store variants route the selection through the shared store filter; local (upcomingBill) variants\n // filter beatTransactions directly, so there's nothing to push to the store for them.\n useLayoutEffect(() => {\n applyCurrentSelectionFilter()\n }, [\n beat.guid,\n selectedIndex,\n filterMode,\n dataSeries.length,\n instanceSlotData,\n displayedDateRange,\n spendCategoryGuidsKey,\n allAccountGuidsKey,\n beatTransactionGuidsKey,\n top,\n ])\n\n const headerContent = header?.({\n title: insights_payload?.title,\n subHeader: insights_payload?.sub_title,\n categoryName,\n selectedDate: chartData[selectedIndex]?.date ?? undefined,\n })\n\n const barColors = colors(theme, instanceSlotData?.category_guid)\n\n if (!isCopyLoaded) return <Loader />\n\n // TODO: Temporary fallback while the backend doesn't always send `legends` on every beat/variant.\n // Remove this once the backend guarantees `legends` on the payload.\n const legendFallbackLabels = [insightsCopy.general.monthly_amount, insightsCopy.general.trend]\n\n const [monthlyAmountLabel, trendAmountLabel] = instanceSlotData?.legends?.length\n ? instanceSlotData.legends.map((legend) => legend.label)\n : legendFallbackLabels\n\n const transactionFilter =\n filterMode === 'local'\n ? (index: number) => resolveFilter(index).custom ?? (() => true)\n : undefined\n\n const baseTransactions: Transaction[] | undefined =\n filterMode === 'local' ? beatTransactions : undefined\n\n const isBarTop = top === 'singleBar' || top === 'upcomingBill'\n const chartTop = !isBarTop ? null : chartData.length ? (\n <BarChartV2\n amounts={{\n average: instanceSlotData?.average_amount,\n formattedAverage: formatCurrency(instanceSlotData?.average_amount ?? 0, '0,0.00'),\n }}\n color={barColors[0] ?? theme.palette.primary.main}\n data={chartData}\n legendPosition=\"top\"\n heightOverride={142}\n margin={{\n bottom: 8,\n top: 24,\n left: 24,\n right: 24,\n }}\n monthlyAmountLabel={monthlyAmountLabel}\n onBarClick={setSelectedIndex}\n selectedTabIndex={selectedIndex}\n trendAmountLabel={trendAmountLabel}\n />\n ) : (\n <EmptyBarChart />\n )\n\n return (\n <>\n <TransactionDrillDown\n ariaLabel={instanceSlotData?.ariaLabel}\n baseTransactions={baseTransactions}\n heading={headerContent?.heading}\n icon={headerContent?.icon}\n onSelectionChange={setSelectedIndex}\n selectedIndex={selectedIndex}\n subHeadingText={headerContent?.subHeadingText}\n tabs={chartData.map((bar) => ({\n ariaLabel: bar.ariaLabel,\n label: bar.label,\n }))}\n top={chartTop}\n {...(tipSection && {\n tipSection:\n !closeTipSection &&\n tipSection(setCloseTipSection, insightsCopy, insights_payload?.sub_title?.text),\n })}\n transactionFilter={transactionFilter}\n onEachRowClick={(guid) => {\n setActionContext({ transaction_guid: guid })\n setIsTransactionDetailsOpen(true)\n }}\n />\n <Drawer\n ariaLabelClose={commonCopy.close_aria}\n isOpen={isTransactionDetailsOpen}\n onClose={() => {\n setIsTransactionDetailsOpen(false)\n // Clear only the key this nested drawer owns — setActionContext merges, so an\n // explicit `{}` would be a no-op and leave transaction_guid stuck in the shared\n // context, and the outer drawer's own context (e.g. chartBarIndex) must survive.\n setActionContext({ transaction_guid: undefined })\n // Re-apply this block's own filter: a further-nested AddMerchantBudgetAction drawer may\n // have overwritten transactionStore.filter (merchant_guid-only) without restoring it.\n applyCurrentSelectionFilter()\n }}\n title={insightsCopy.general.transaction_details_title}\n >\n <TransactionDetailsBlock beat={beat} />\n </Drawer>\n </>\n )\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"TransactionHistoryBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.tsx"],"sourcesContent":["import { useLayoutEffect, useState } from 'react'\n\nimport { useTheme } from '@mui/material/styles'\nimport { observer } from 'mobx-react-lite'\n\nimport type { Beat, DataSeries, Transaction } from '../../../core'\nimport { formatCurrency } from '../../../core/utils/NumberFormatting'\nimport { ANALYTICS_EVENTS_CONFIG, useAnalyticsEvent } from '../../analytics'\nimport { BarChartV2 } from '../../components/chartblocks/BarchartV2'\nimport { EmptyBarChart } from '../../components/chartblocks/EmptyBarChart'\n\nimport { TransactionDrillDown } from './TransactionDrillDown'\nimport { useTransactionHistory } from './useTransactionHistory'\nimport {\n getDefaultSelection,\n getDrillDownConfig,\n getFlattenedDataSeries,\n toStoreFilter,\n} from './utils'\nimport {\n Drawer,\n useInsightsV2Store,\n useGlobalCopyStore,\n useGlobalUiStore,\n Loader,\n} from '../../../common'\nimport { TransactionDetailsBlock } from '../TransactionDetailsBlock'\nimport { getDynamicCtaBasedOnTriggers } from '../util'\n\ninterface TransactionHistoryProp {\n beat: Beat\n}\n\nexport const TransactionHistoryBlock = observer(({ beat }: TransactionHistoryProp) => {\n const theme = useTheme()\n const {\n instanceSlotData,\n beatTransactions,\n spendCategoryGuids,\n allAccountGuids,\n categoryName,\n displayedDateRange,\n transactionStore,\n } = useTransactionHistory(beat)\n\n const { actionDrawer, setActionContext } = useInsightsV2Store()\n\n const { common: commonCopy, insights_feed: insightsCopy } = useGlobalCopyStore()\n\n const { isCopyLoaded } = useGlobalUiStore()\n\n const [isTransactionDetailsOpen, setIsTransactionDetailsOpen] = useState(false)\n\n const [closeTipSection, setCloseTipSection] = useState(false)\n\n const fireAnalyticsEvent = useAnalyticsEvent()\n\n const { insights_payload } = beat\n\n const dynamicCtaVariant = getDynamicCtaBasedOnTriggers(\n actionDrawer,\n insights_payload?.primary_cta,\n insights_payload?.secondary_cta,\n insights_payload?.in_description_cta,\n )?.variant\n\n const { top, filterMode, header, colors, filterStrategy, tipSection } = getDrillDownConfig(\n dynamicCtaVariant ?? '',\n )\n\n const { dataSeries, chartData, comparisonBars } = getFlattenedDataSeries({\n data: instanceSlotData?.data_series as DataSeries,\n ariaLabel: instanceSlotData?.ariaLabel ?? '',\n top,\n beatTransactions,\n payload: instanceSlotData,\n })\n\n const { chartBarIndex, subTabIndex } = getDefaultSelection({\n chartTabCount: chartData.length,\n comparisonTabCount: comparisonBars.length,\n actionDrawer,\n beatGuid: beat.guid,\n })\n\n const [selectedIndex, setSelectedIndex] = useState(chartBarIndex)\n\n const resolveFilter = (index: number) =>\n filterStrategy({\n beat,\n beatTransactions,\n dataSeries,\n selectedIndex: index,\n subIndex: subTabIndex,\n isLastTab: index === dataSeries.length - 1,\n instanceSlotData,\n spendCategoryGuids,\n displayedDateRange,\n })\n\n // Apply the current selection's filter. Store variants route through the store filter; local\n // (upcomingBill) variants filter beatTransactions directly and only backfill the cache when the\n // Stable primitive keys for the collections below: beatTransactions/spendCategoryGuids/\n // allAccountGuids are recomputed (new array identity) every render, so depending on them directly\n // re-fires the effect each render (REVIEW.md MEW-3732). Key on content instead.\n const beatTransactionGuidsKey = beatTransactions.map((transaction) => transaction.guid).join(',')\n const spendCategoryGuidsKey = spendCategoryGuids.join(',')\n const allAccountGuidsKey = allAccountGuids.join(',')\n\n // Re-applies the current selection's filter to the shared transactionStore. Called both by the\n // effect below (on selection change) and when the nested TransactionDetailsBlock drawer closes:\n // AddMerchantBudgetAction (opened from within that drawer) overwrites transactionStore.filter\n // with a merchant_guid-only filter while its own drawer is open, and never restores it — leaving\n // the row list stuck showing only that one merchant's transactions after backing all the way out.\n // Re-running this on close re-derives the filter fresh instead of relying on whatever the nested\n // drawers left behind.\n // A `list` drawer has no bars: it filters once from the beat alone.\n const canApplyFilter = top === 'list' || dataSeries.length > 0\n const applyCurrentSelectionFilter = () => {\n if (filterMode !== 'store' || !canApplyFilter) return\n transactionStore.setFilter(\n toStoreFilter(resolveFilter(selectedIndex), { allAccountGuids, displayedDateRange }),\n )\n }\n\n // store variants route the selection through the shared store filter; local (upcomingBill) variants\n // filter beatTransactions directly, so there's nothing to push to the store for them.\n useLayoutEffect(() => {\n applyCurrentSelectionFilter()\n }, [\n beat.guid,\n selectedIndex,\n filterMode,\n dataSeries.length,\n instanceSlotData,\n displayedDateRange,\n spendCategoryGuidsKey,\n allAccountGuidsKey,\n beatTransactionGuidsKey,\n top,\n ])\n\n const headerContent = header?.({\n title: insights_payload?.title,\n subHeader: insights_payload?.sub_title,\n categoryName,\n selectedDate: chartData[selectedIndex]?.date ?? undefined,\n })\n\n const barColors = colors(theme, instanceSlotData?.category_guid)\n\n if (!isCopyLoaded) return <Loader />\n\n // TODO: Temporary fallback while the backend doesn't always send `legends` on every beat/variant.\n // Remove this once the backend guarantees `legends` on the payload.\n const legendFallbackLabels = [insightsCopy.general.monthly_amount, insightsCopy.general.trend]\n\n const [monthlyAmountLabel, trendAmountLabel] = instanceSlotData?.legends?.length\n ? instanceSlotData.legends.map((legend) => legend.label)\n : legendFallbackLabels\n\n const transactionFilter =\n filterMode === 'local'\n ? (index: number) => resolveFilter(index).custom ?? (() => true)\n : undefined\n\n const baseTransactions: Transaction[] | undefined =\n filterMode === 'local' ? beatTransactions : undefined\n\n const isBarTop = top === 'singleBar' || top === 'upcomingBill'\n const chartTop = !isBarTop ? null : chartData.length ? (\n <BarChartV2\n amounts={{\n average: instanceSlotData?.average_amount,\n formattedAverage: formatCurrency(instanceSlotData?.average_amount ?? 0, '0,0.00'),\n }}\n color={barColors[0] ?? theme.palette.primary.main}\n data={chartData}\n legendPosition=\"top\"\n heightOverride={142}\n margin={{\n bottom: 8,\n top: 24,\n left: 24,\n right: 24,\n }}\n monthlyAmountLabel={monthlyAmountLabel}\n onBarClick={(index) => {\n fireAnalyticsEvent(ANALYTICS_EVENTS_CONFIG.DRAWER_CHART_BAR_CLICKED)\n setSelectedIndex(index)\n }}\n selectedTabIndex={selectedIndex}\n trendAmountLabel={trendAmountLabel}\n />\n ) : (\n <EmptyBarChart />\n )\n\n return (\n <>\n <TransactionDrillDown\n ariaLabel={instanceSlotData?.ariaLabel}\n baseTransactions={baseTransactions}\n heading={headerContent?.heading}\n icon={headerContent?.icon}\n onSelectionChange={(index) => {\n // MUI Tabs only fires onChange on real user selection, not on mount.\n fireAnalyticsEvent(ANALYTICS_EVENTS_CONFIG.TAB_SELECTED)\n setSelectedIndex(index)\n }}\n selectedIndex={selectedIndex}\n subHeadingText={headerContent?.subHeadingText}\n tabs={chartData.map((bar) => ({\n ariaLabel: bar.ariaLabel,\n label: bar.label,\n }))}\n top={chartTop}\n {...(tipSection && {\n tipSection:\n !closeTipSection &&\n tipSection(setCloseTipSection, insightsCopy, insights_payload?.sub_title?.text),\n })}\n transactionFilter={transactionFilter}\n onEachRowClick={(guid) => {\n setActionContext({ transaction_guid: guid })\n setIsTransactionDetailsOpen(true)\n }}\n />\n <Drawer\n ariaLabelClose={commonCopy.close_aria}\n isOpen={isTransactionDetailsOpen}\n onClose={() => {\n setIsTransactionDetailsOpen(false)\n // Clear only the key this nested drawer owns — setActionContext merges, so an\n // explicit `{}` would be a no-op and leave transaction_guid stuck in the shared\n // context, and the outer drawer's own context (e.g. chartBarIndex) must survive.\n setActionContext({ transaction_guid: undefined })\n // Re-apply this block's own filter: a further-nested AddMerchantBudgetAction drawer may\n // have overwritten transactionStore.filter (merchant_guid-only) without restoring it.\n applyCurrentSelectionFilter()\n }}\n title={insightsCopy.general.transaction_details_title}\n >\n <TransactionDetailsBlock beat={beat} />\n </Drawer>\n </>\n )\n})\n"],"mappings":"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"}
@@ -6,8 +6,9 @@ import { ActionDrawerState, InDescriptionCTA, PrimaryCTA, SecondaryCTA } from '.
6
6
  */
7
7
  export declare const getCtaForChartBarClick: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined) => PrimaryCTA | SecondaryCTA | undefined;
8
8
  /**
9
- * Resolves which CTA (primary/secondary) drives the currently open drawer's title/variant, based
10
- * on what triggered it. Falls back to `primary_cta` whenever resolution comes up empty (e.g. a
11
- * `secondaryCta` trigger with no configured secondary CTA), so callers never have to null-check.
9
+ * Resolves which CTA (primary/secondary/in-description) drives the currently open drawer's
10
+ * title/variant, based on what triggered it. Falls back to `primary_cta` whenever resolution comes
11
+ * up empty (e.g. a `secondaryCta` trigger with no configured secondary CTA), so callers never have
12
+ * to null-check.
12
13
  */
13
14
  export declare const getDynamicCtaBasedOnTriggers: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined, in_description_cta?: InDescriptionCTA) => PrimaryCTA | SecondaryCTA | InDescriptionCTA | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"util.es.js","names":[],"sources":["../../../src/insights-v2/actionBlocks/util.ts"],"sourcesContent":["import type {\n ActionDrawerState,\n DrilldownPayload,\n InDescriptionCTA,\n PrimaryCTA,\n SecondaryCTA,\n} from '../../core'\n\n/**\n * A chart-bar drilldown's context carries which block it targets (see BarchartBlock /\n * DoubleBarChartBlock), since either CTA could in principle open the same drawer. Match that\n * against `primary_cta.block`; anything else is assumed to be the secondary CTA's block.\n */\nexport const getCtaForChartBarClick = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n): PrimaryCTA | SecondaryCTA | undefined => {\n const context = actionDrawer.context as DrilldownPayload | undefined\n const blockName = context?.block\n\n if (blockName === primary_cta?.block) {\n return primary_cta\n }\n return secondary_cta\n}\n\n/**\n * Resolves which CTA (primary/secondary) drives the currently open drawer's title/variant, based\n * on what triggered it. Falls back to `primary_cta` whenever resolution comes up empty (e.g. a\n * `secondaryCta` trigger with no configured secondary CTA), so callers never have to null-check.\n */\nexport const getDynamicCtaBasedOnTriggers = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n in_description_cta?: InDescriptionCTA,\n): PrimaryCTA | SecondaryCTA | InDescriptionCTA | undefined => {\n // The description link names its own block and variant, like a CTA. Only its button fires this\n // trigger, so there is no other CTA to fall back to.\n if (actionDrawer.trigger === 'inDescriptionCta') {\n return in_description_cta\n }\n if (actionDrawer.trigger === 'secondaryCta') {\n return secondary_cta ?? primary_cta\n }\n if (actionDrawer.trigger === 'primaryCta') {\n return primary_cta\n }\n return getCtaForChartBarClick(actionDrawer, primary_cta, secondary_cta) ?? primary_cta\n}\n"],"mappings":"AAaA,IAAa,IAAA,CACX,GACA,GACA,MAEgB,EAAa,SACF,UAET,GAAa,QACtB,IAEF,GAQI,IAAA,CACX,GACA,GACA,GACA,MAII,EAAa,YAAY,qBACpB,IAEL,EAAa,YAAY,iBACpB,KAAiB,IAEtB,EAAa,YAAY,eACpB,IAEF,EAAuB,GAAc,GAAa,CAAa,KAAK"}
1
+ {"version":3,"file":"util.es.js","names":[],"sources":["../../../src/insights-v2/actionBlocks/util.ts"],"sourcesContent":["import type {\n ActionDrawerState,\n DrilldownPayload,\n InDescriptionCTA,\n PrimaryCTA,\n SecondaryCTA,\n} from '../../core'\n\n/**\n * A chart-bar drilldown's context carries which block it targets (see BarchartBlock /\n * DoubleBarChartBlock), since either CTA could in principle open the same drawer. Match that\n * against `primary_cta.block`; anything else is assumed to be the secondary CTA's block.\n */\nexport const getCtaForChartBarClick = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n): PrimaryCTA | SecondaryCTA | undefined => {\n const context = actionDrawer.context as DrilldownPayload | undefined\n const blockName = context?.block\n\n if (blockName === primary_cta?.block) {\n return primary_cta\n }\n return secondary_cta\n}\n\n/**\n * Resolves which CTA (primary/secondary/in-description) drives the currently open drawer's\n * title/variant, based on what triggered it. Falls back to `primary_cta` whenever resolution comes\n * up empty (e.g. a `secondaryCta` trigger with no configured secondary CTA), so callers never have\n * to null-check.\n */\nexport const getDynamicCtaBasedOnTriggers = (\n actionDrawer: ActionDrawerState,\n primary_cta: PrimaryCTA | undefined,\n secondary_cta: SecondaryCTA | undefined,\n in_description_cta?: InDescriptionCTA,\n): PrimaryCTA | SecondaryCTA | InDescriptionCTA | undefined => {\n // The description link names its own block and variant, like a CTA. Only its button fires this\n // trigger, so there is no other CTA to fall back to.\n if (actionDrawer.trigger === 'inDescriptionCta') {\n return in_description_cta\n }\n if (actionDrawer.trigger === 'secondaryCta') {\n return secondary_cta ?? primary_cta\n }\n if (actionDrawer.trigger === 'primaryCta') {\n return primary_cta\n }\n return getCtaForChartBarClick(actionDrawer, primary_cta, secondary_cta) ?? primary_cta\n}\n"],"mappings":"AAaA,IAAa,IAAA,CACX,GACA,GACA,MAEgB,EAAa,SACF,UAET,GAAa,QACtB,IAEF,GASI,IAAA,CACX,GACA,GACA,GACA,MAII,EAAa,YAAY,qBACpB,IAEL,EAAa,YAAY,iBACpB,KAAiB,IAEtB,EAAa,YAAY,eACpB,IAEF,EAAuB,GAAc,GAAa,CAAa,KAAK"}
@@ -0,0 +1,67 @@
1
+ import { Beat } from '../../core';
2
+ export declare const sentenceCaseTemplate: (template?: string | null) => string;
3
+ type Resolvable = string | ((beat: Beat) => string);
4
+ export interface AnalyticsEventConfigEntry {
5
+ category?: Resolvable;
6
+ action?: Resolvable;
7
+ postHog?: {
8
+ eventName: string;
9
+ properties?: (beat: Beat) => Record<string, unknown>;
10
+ };
11
+ }
12
+ export declare const ANALYTICS_EVENTS_CONFIG: {
13
+ readonly PRIMARY_ACTION_SELECTED: {
14
+ readonly category: "Beat Interaction";
15
+ readonly action: "Primary Action Selected";
16
+ };
17
+ readonly SECONDARY_ACTION_SELECTED: {
18
+ readonly category: "Beat Interaction";
19
+ readonly action: "Secondary Action Selected";
20
+ };
21
+ readonly FIRST_TIME_PRIMARY_ACTION_SELECTED: {
22
+ readonly category: "Beat Interaction";
23
+ readonly action: "First Time Primary Action Selected";
24
+ };
25
+ readonly CHART_BAR_CLICKED: {
26
+ readonly category: "Beat Chart";
27
+ readonly action: (beat: Beat) => string;
28
+ };
29
+ readonly DRAWER_CHART_BAR_CLICKED: {
30
+ readonly category: "Drawer Chart";
31
+ readonly action: (beat: Beat) => string;
32
+ };
33
+ readonly TAB_SELECTED: {
34
+ readonly category: "Drawer Chart";
35
+ readonly action: (beat: Beat) => string;
36
+ };
37
+ readonly EDIT_INSIGHT_THRESHOLD_SAVE: {
38
+ readonly category: "User Configurable Settings";
39
+ readonly action: "Edit Insight Threshold Save";
40
+ };
41
+ readonly EDIT_INSIGHT_THRESHOLD_CANCELED: {
42
+ readonly category: "User Configurable Settings";
43
+ readonly action: "Edit Insight Threshold Canceled";
44
+ };
45
+ readonly EDIT_INSIGHT_THRESHOLD_INPUT_SELECTED: {
46
+ readonly category: "User Configurable Settings";
47
+ readonly action: "Edit Insight Threshold Input Selected";
48
+ };
49
+ readonly EDIT_SAFETY_NET_SAVE: {
50
+ readonly category: "Safety Net";
51
+ readonly action: "Edit Safety Net";
52
+ };
53
+ readonly EDIT_SAFETY_NET_CANCEL: {
54
+ readonly category: "Safety Net";
55
+ readonly action: (beat: Beat) => string;
56
+ };
57
+ readonly OPENED_CONNECT_DRAWER: {
58
+ readonly postHog: {
59
+ readonly eventName: "opened_connect_drawer";
60
+ readonly properties: (beat: Beat) => {
61
+ beat_guid: string;
62
+ template: string;
63
+ };
64
+ };
65
+ };
66
+ };
67
+ export {};
@@ -0,0 +1,59 @@
1
+ var t = (e) => e?.replace(/([A-Z]+)/g, " $1")?.replace(/^ /, "") ?? "", a = {
2
+ PRIMARY_ACTION_SELECTED: {
3
+ category: "Beat Interaction",
4
+ action: "Primary Action Selected"
5
+ },
6
+ SECONDARY_ACTION_SELECTED: {
7
+ category: "Beat Interaction",
8
+ action: "Secondary Action Selected"
9
+ },
10
+ FIRST_TIME_PRIMARY_ACTION_SELECTED: {
11
+ category: "Beat Interaction",
12
+ action: "First Time Primary Action Selected"
13
+ },
14
+ CHART_BAR_CLICKED: {
15
+ category: "Beat Chart",
16
+ action: (e) => `${t(e.template)} - Bar Clicked`
17
+ },
18
+ DRAWER_CHART_BAR_CLICKED: {
19
+ category: "Drawer Chart",
20
+ action: (e) => `${t(e.template)} - Bar Clicked`
21
+ },
22
+ TAB_SELECTED: {
23
+ category: "Drawer Chart",
24
+ action: (e) => `${t(e.template)} - Month Tab Selected`
25
+ },
26
+ EDIT_INSIGHT_THRESHOLD_SAVE: {
27
+ category: "User Configurable Settings",
28
+ action: "Edit Insight Threshold Save"
29
+ },
30
+ EDIT_INSIGHT_THRESHOLD_CANCELED: {
31
+ category: "User Configurable Settings",
32
+ action: "Edit Insight Threshold Canceled"
33
+ },
34
+ EDIT_INSIGHT_THRESHOLD_INPUT_SELECTED: {
35
+ category: "User Configurable Settings",
36
+ action: "Edit Insight Threshold Input Selected"
37
+ },
38
+ EDIT_SAFETY_NET_SAVE: {
39
+ category: "Safety Net",
40
+ action: "Edit Safety Net"
41
+ },
42
+ EDIT_SAFETY_NET_CANCEL: {
43
+ category: "Safety Net",
44
+ action: (e) => `${t(e.template)} = Edit Safety Net - Cancel`
45
+ },
46
+ OPENED_CONNECT_DRAWER: { postHog: {
47
+ eventName: "opened_connect_drawer",
48
+ properties: (e) => ({
49
+ beat_guid: e.guid,
50
+ template: e.template
51
+ })
52
+ } }
53
+ };
54
+ export {
55
+ a as ANALYTICS_EVENTS_CONFIG,
56
+ t as sentenceCaseTemplate
57
+ };
58
+
59
+ //# sourceMappingURL=analyticsEventsConfig.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyticsEventsConfig.es.js","names":[],"sources":["../../../src/insights-v2/analytics/analyticsEventsConfig.ts"],"sourcesContent":["import type { Beat } from '../../core'\n\n// PascalCase template to label, ported from Pulse.\nexport const sentenceCaseTemplate = (template?: string | null): string =>\n template?.replace(/([A-Z]+)/g, ' $1')?.replace(/^ /, '') ?? ''\n\n// Fixed or beat-computed value.\ntype Resolvable = string | ((beat: Beat) => string)\n\n// Source of truth for insights-v2 analytics events. Mirrors Pulse's strings.\n// Entry has a Firefly half (action/category) and/or a postHog half.\nexport interface AnalyticsEventConfigEntry {\n category?: Resolvable\n action?: Resolvable\n postHog?: {\n eventName: string\n properties?: (beat: Beat) => Record<string, unknown>\n }\n}\n\nexport const ANALYTICS_EVENTS_CONFIG = {\n // Primary/secondary CTA click, fired via sendCtaAnalytics.\n PRIMARY_ACTION_SELECTED: {\n category: 'Beat Interaction',\n action: 'Primary Action Selected',\n },\n SECONDARY_ACTION_SELECTED: {\n category: 'Beat Interaction',\n action: 'Secondary Action Selected',\n },\n // Fires once, gated on !beat.cta_clicked_at.\n FIRST_TIME_PRIMARY_ACTION_SELECTED: {\n category: 'Beat Interaction',\n action: 'First Time Primary Action Selected',\n },\n\n // Bar click on the card's inline chart.\n CHART_BAR_CLICKED: {\n category: 'Beat Chart',\n action: (beat) => `${sentenceCaseTemplate(beat.template)} - Bar Clicked`,\n },\n // Bar click inside the drill-down drawer.\n DRAWER_CHART_BAR_CLICKED: {\n category: 'Drawer Chart',\n action: (beat) => `${sentenceCaseTemplate(beat.template)} - Bar Clicked`,\n },\n // Month/tab change inside the drill-down drawer.\n TAB_SELECTED: {\n category: 'Drawer Chart',\n action: (beat) => `${sentenceCaseTemplate(beat.template)} - Month Tab Selected`,\n },\n\n // LowAccountBalance threshold dialog.\n EDIT_INSIGHT_THRESHOLD_SAVE: {\n category: 'User Configurable Settings',\n action: 'Edit Insight Threshold Save',\n },\n EDIT_INSIGHT_THRESHOLD_CANCELED: {\n category: 'User Configurable Settings',\n action: 'Edit Insight Threshold Canceled',\n },\n EDIT_INSIGHT_THRESHOLD_INPUT_SELECTED: {\n category: 'User Configurable Settings',\n action: 'Edit Insight Threshold Input Selected',\n },\n\n // SavingsOpportunityV2 safety-net dialog.\n EDIT_SAFETY_NET_SAVE: {\n category: 'Safety Net',\n action: 'Edit Safety Net',\n },\n // Ported verbatim from Pulse (uses '=' not '-').\n EDIT_SAFETY_NET_CANCEL: {\n category: 'Safety Net',\n action: (beat) => `${sentenceCaseTemplate(beat.template)} = Edit Safety Net - Cancel`,\n },\n\n // Connect drawer opened. PostHog-only.\n OPENED_CONNECT_DRAWER: {\n postHog: {\n eventName: 'opened_connect_drawer',\n properties: (beat) => ({ beat_guid: beat.guid, template: beat.template }),\n },\n },\n} as const satisfies Record<string, AnalyticsEventConfigEntry>\n"],"mappings":"AAGA,IAAa,IAAA,CAAwB,MACnC,GAAU,QAAQ,aAAa,KAAK,GAAG,QAAQ,MAAM,EAAE,KAAK,IAgBjD,IAA0B;AAAA,EAErC,yBAAyB;AAAA,IACvB,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EACA,2BAA2B;AAAA,IACzB,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EAEA,oCAAoC;AAAA,IAClC,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EAGA,mBAAmB;AAAA,IACjB,UAAU;AAAA,IACV,QAAA,CAAS,MAAS,GAAG,EAAqB,EAAK,QAAQ,CAAA;AAAA,EACzD;AAAA,EAEA,0BAA0B;AAAA,IACxB,UAAU;AAAA,IACV,QAAA,CAAS,MAAS,GAAG,EAAqB,EAAK,QAAQ,CAAA;AAAA,EACzD;AAAA,EAEA,cAAc;AAAA,IACZ,UAAU;AAAA,IACV,QAAA,CAAS,MAAS,GAAG,EAAqB,EAAK,QAAQ,CAAA;AAAA,EACzD;AAAA,EAGA,6BAA6B;AAAA,IAC3B,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EACA,iCAAiC;AAAA,IAC/B,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EACA,uCAAuC;AAAA,IACrC,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EAGA,sBAAsB;AAAA,IACpB,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAAA,EAEA,wBAAwB;AAAA,IACtB,UAAU;AAAA,IACV,QAAA,CAAS,MAAS,GAAG,EAAqB,EAAK,QAAQ,CAAA;AAAA,EACzD;AAAA,EAGA,uBAAuB,EACrB,SAAS;AAAA,IACP,WAAW;AAAA,IACX,YAAA,CAAa,OAAU;AAAA,MAAE,WAAW,EAAK;AAAA,MAAM,UAAU,EAAK;AAAA,IAAS;AAAA,EACzE,EACF;AACF"}
@@ -0,0 +1,3 @@
1
+ export { ANALYTICS_EVENTS_CONFIG, sentenceCaseTemplate, type AnalyticsEventConfigEntry, } from './analyticsEventsConfig';
2
+ export { resolveAnalyticsEvent } from './resolveAnalyticsEvent';
3
+ export { useAnalyticsEvent, type FireAnalyticsEvent } from './useAnalyticsEvent';
@@ -0,0 +1,5 @@
1
+ import { AnalyticsEventPayload } from '../beatActions';
2
+ import { Beat } from '../../core';
3
+ import { sentenceCaseTemplate, AnalyticsEventConfigEntry } from './analyticsEventsConfig';
4
+ export { sentenceCaseTemplate };
5
+ export declare const resolveAnalyticsEvent: (config: AnalyticsEventConfigEntry, beat: Beat) => AnalyticsEventPayload;