@mx-cartographer/experiences 9.4.22 → 9.4.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -2
- package/dist/core/stores/InsightsV2Store.d.ts +23 -4
- package/dist/core/stores/InsightsV2Store.es.js +16 -7
- package/dist/core/stores/InsightsV2Store.es.js.map +1 -1
- package/dist/core/types/Insights.d.ts +2 -0
- package/dist/core/types/localization/InsightsFeedCopy.d.ts +1 -0
- package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js +15 -14
- package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.d.ts +1 -2
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.es.js +8 -14
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js +9 -8
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.d.ts +3 -0
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js +8 -0
- package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js.map +1 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.d.ts +2 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.es.js +37 -34
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js +89 -73
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.d.ts +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/utils.d.ts +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/utils.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/util.d.ts +13 -0
- package/dist/insights-v2/actionBlocks/util.es.js +7 -0
- package/dist/insights-v2/actionBlocks/util.es.js.map +1 -0
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js +19 -15
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js.map +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js +15 -13
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js.map +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/StepChartBlock/StepChartBlock.d.ts +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/StepChartBlock/StepChartBlock.es.js.map +1 -1
- package/dist/insights-v2/mappings/actionBlocksKey.d.ts +6 -0
- package/dist/insights-v2/mappings/actionBlocksKey.es.js +11 -0
- package/dist/insights-v2/mappings/actionBlocksKey.es.js.map +1 -0
- package/dist/insights-v2/mappings/blocks.es.js +47 -46
- package/dist/insights-v2/mappings/blocks.es.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## [9.4.23] - 09-16-2026
|
|
2
|
+
|
|
3
|
+
- **ADDED** - Nested-drawer support for the insights-v2 `TransactionHistoryBlock`: clicking a transaction row in the history drawer opens a second, stacked `TransactionDetailsBlock` drawer scoped to that transaction, via `InsightsV2Store.setActionContext({ transaction_guid })` and `useActionContext<DrilldownPayload>()`. `TransactionDrillDown`'s row click is forwarded through a new `onEachRowClick` prop (WEC-1699)
|
|
4
|
+
- **ADDED** - `InsightsV2/ActionBlock/NestedDrawers` Storybook story demonstrating the full history → details drilldown through the real action-block registry (WEC-1699)
|
|
5
|
+
- **ADDED** - `transaction_details_title` copy key (`insights_feed.general`) for the nested `TransactionDetailsBlock` drawer's title (WEC-1699)
|
|
6
|
+
- **ADDED** - Shared CTA-resolution helpers (`getDynamicCtaBasedOnTriggers`, `getCtaForChartBarClick` in `insights-v2/actionBlocks/util.ts`) resolving which CTA (primary/secondary) drives a drawer based on its trigger, with a fallback to the primary CTA whenever resolution comes up empty; `actionBlocksKey` constants extracted for the action-block registry keys in `mappings/blocks.ts` (WEC-1699)
|
|
7
|
+
- **CHANGED** - `TransactionDetailsBlock`'s bottom actions are now resolved from the triggering CTA's `variant` via `getBottomActionsByVariant` instead of `instance_slot_data.bottom_actions`: the `fee_detected` variant gets `DEFAULT_BOTTOM_ACTIONS` (Split/Hide/Merchant-Logo), everything else gets `[BottomActions.MerchantBudget, ...DEFAULT_BOTTOM_ACTIONS]` — so the nested `TransactionDetailsBlock` drawer shows "Add Merchant Budget" by default when the transaction has a `merchant_guid`. Clicking it opens the existing `MerchantBudgetDetailsDrawer` as a third, further-stacked drawer; no changes were made to that budgets code itself. `DEFAULT_BOTTOM_ACTIONS` itself (`transactions/constants/Actions.ts`) is unchanged — every other `TransactionDetails` caller still omits `MerchantBudget` by default unless it opts in via an explicit `bottomActions` prop (WEC-1699)
|
|
8
|
+
- **CHANGED** - `BarchartBlock`/`DoubleBarChartBlock`'s chart-bar drilldown context now carries an explicit target `block` (`DrilldownPayload.block`), used by the new CTA-resolution helpers to pick the correct CTA for a chart-bar click (WEC-1699)
|
|
9
|
+
- **FIXED** - `InsightsV2Store.setActionContext` now merges new keys into the current drawer session's context bag instead of destructively replacing it, so an outer drawer's context (e.g. `chartBarIndex`) survives while a nested drawer layers its own key (e.g. `transaction_guid`) on top (WEC-1699)
|
|
10
|
+
|
|
1
11
|
## [9.4.22] - 09-12-2026
|
|
2
12
|
|
|
3
13
|
- **FIXED** - The category-change confirmation dialog (and all `common` `Dialog` modals) read their title twice on screen readers: the title was both the dialog's accessible name and a separate visible heading node. The dialog now labels itself via `aria-labelledby` pointing at the heading, and passes `ariaHidden` so the heading is removed from the a11y tree, so the title is announced once
|
|
@@ -12,7 +22,7 @@
|
|
|
12
22
|
|
|
13
23
|
- **ADDED** - DataDog RUM for Pulse and MDB
|
|
14
24
|
|
|
15
|
-
## [9.4.19] - 09-
|
|
25
|
+
## [9.4.19] - 09-14-2026
|
|
16
26
|
|
|
17
27
|
- **ADDED** - insights-v2 `ObsolesceBanner` component: presentational banner displaying beat obsolescence states (refresh_available, refreshing, updated, not_refreshable, hidden) with smooth Collapse animation, proper ARIA labels, and state-appropriate icons (Sync/CheckCircle/Cancel) and actions (Update/Dismiss buttons). Exported from insights-v2 with full TypeScript types (`ObsolesceBannerProps`, `ObsolesceBannerState`, `ObsolesceBannerCopy`). Component accepts state + callbacks + copy as props; host owns data logic (WEC-1766)
|
|
18
28
|
- **CHANGED** - `ObsolesceBanner` reuses existing `insights_feed.general` copy keys (`dismiss`, `insight_no_longer_applicable`, `insight_updated`, `new_information_available`, `update`, `updating`) rather than introducing a dedicated copy section — matches the copy already consumed by the legacy `ObsoleteManager` and defined in mrs_content, avoiding duplicate keys and translations. `GeneralInsightsFeedCopy` extended with these keys; `BaseLayout` passes `copy.insights_feed.general` straight through (WEC-1766)
|
|
@@ -20,7 +30,7 @@
|
|
|
20
30
|
- **ADDED** - Comprehensive test coverage: 20 `ObsolesceBanner` tests (all 5 states, button interactions, copy variations, state transitions, callback isolation) plus `BaseLayout` obsolete tests (banner render, dimming overlay, click blocking, callbacks) (WEC-1766)
|
|
21
31
|
- **ADDED** - Storybook stories for `ObsolesceBanner`: 5 static state stories plus 1 interactive state-machine story with debug panel and automatic transitions (WEC-1766)
|
|
22
32
|
|
|
23
|
-
## [9.4.18] - 09-
|
|
33
|
+
## [9.4.18] - 09-14-2026
|
|
24
34
|
|
|
25
35
|
- **CHANGED** - insights-v2 feedback UI cleanup: removed verbose comments and section dividers from `BaseLayout`, `FeedbackDialog`, `FeedbackBar`, `HiddenConfirmationCard`, `DismissInsightDialog`, `InsightOptionsMenu`, and `useBeatFeedbackFlow`; code is now self-documenting with brief one-line descriptions only where complexity warrants explanation. Minimal comment philosophy applied throughout (WEC-1766)
|
|
26
36
|
- **CHANGED** - insights-v2 dismiss flow simplified: replaced controlled `dismissState` prop with direct `beat.is_dismissed` observation paired with local `hasClosedConfirmation` state in `useBeatFeedbackFlow`; `cardState` now derived via `useMemo` from these two sources. Eliminates need for parent-managed dismiss state while maintaining clean separation: Pulse owns persistence (`is_dismissed` property), experiences owns transient UI state (confirmation visibility). Survives navigation and handles API failures gracefully (WEC-1766)
|
|
@@ -5,10 +5,18 @@ export interface ActionDrawerState {
|
|
|
5
5
|
trigger: ActionDrawerTrigger;
|
|
6
6
|
guid: string;
|
|
7
7
|
/**
|
|
8
|
-
* Block-specific drilldown data
|
|
9
|
-
* and reads its own shape (via
|
|
10
|
-
*
|
|
11
|
-
* CTAs carry none.
|
|
8
|
+
* Block-specific drilldown data for the current drawer SESSION, opaque to the
|
|
9
|
+
* store. Each action block defines and reads its own shape (via
|
|
10
|
+
* useActionContext<T>()). Chart drilldowns put `{ chartBarIndex, tabIndex }`
|
|
11
|
+
* here; CTAs carry none.
|
|
12
|
+
*
|
|
13
|
+
* This is an accumulating bag, not a single owner's value: a nested drawer
|
|
14
|
+
* (e.g. TransactionDetailsBlock opened from a row inside TransactionHistory
|
|
15
|
+
* Block) adds its own key via `setActionContext` ON TOP of whatever the outer
|
|
16
|
+
* drawer already put here, so the outer block's own context survives while the
|
|
17
|
+
* nested block is open. It resets to a clean slate only when a NEW drawer
|
|
18
|
+
* session starts (`openActionDrawer`/`openCtaDrawer`, which fully replace the
|
|
19
|
+
* envelope) — not on every `setActionContext` call.
|
|
12
20
|
*/
|
|
13
21
|
context: unknown;
|
|
14
22
|
}
|
|
@@ -28,6 +36,17 @@ export declare class InsightsV2Store {
|
|
|
28
36
|
globalStore: GlobalStore;
|
|
29
37
|
actionDrawer: ActionDrawerState;
|
|
30
38
|
constructor(globalStore: GlobalStore);
|
|
39
|
+
/**
|
|
40
|
+
* Merges keys into the current drawer session's context bag — it does NOT
|
|
41
|
+
* replace it. A nested drawer (e.g. a row click inside TransactionHistoryBlock
|
|
42
|
+
* opening TransactionDetailsBlock) calls this to layer its own key (e.g.
|
|
43
|
+
* `transaction_guid`) on top of whatever context the outer drawer already set
|
|
44
|
+
* (e.g. `chartBarIndex`), so the outer block keeps reading its own keys via
|
|
45
|
+
* useActionContext while the nested block is open. The bag only returns to a
|
|
46
|
+
* clean slate when a new drawer session starts via `openActionDrawer`/
|
|
47
|
+
* `openCtaDrawer`, which fully replace the envelope.
|
|
48
|
+
*/
|
|
49
|
+
setActionContext: (context: Record<string, unknown>) => void;
|
|
31
50
|
/**
|
|
32
51
|
* Generic drawer opener — the only opener a new action block needs. Pass the
|
|
33
52
|
* beat guid, the CTA/source that triggered it, and (optionally) a block-specific
|
|
@@ -4,24 +4,33 @@ var o = {
|
|
|
4
4
|
trigger: "primaryCta",
|
|
5
5
|
guid: "",
|
|
6
6
|
context: void 0
|
|
7
|
-
},
|
|
7
|
+
}, n = class {
|
|
8
8
|
globalStore;
|
|
9
9
|
actionDrawer = o;
|
|
10
10
|
constructor(r) {
|
|
11
11
|
this.globalStore = r, a(this);
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
setActionContext = (r) => {
|
|
14
|
+
this.actionDrawer = {
|
|
15
|
+
...this.actionDrawer,
|
|
16
|
+
context: {
|
|
17
|
+
...this.actionDrawer.context,
|
|
18
|
+
...r
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
openActionDrawer = ({ guid: r, trigger: t, context: e }) => {
|
|
14
23
|
this.actionDrawer = {
|
|
15
24
|
isDrawerOpen: !0,
|
|
16
|
-
trigger:
|
|
25
|
+
trigger: t,
|
|
17
26
|
guid: r,
|
|
18
|
-
context:
|
|
27
|
+
context: e
|
|
19
28
|
};
|
|
20
29
|
};
|
|
21
|
-
openCtaDrawer = (r,
|
|
30
|
+
openCtaDrawer = (r, t) => {
|
|
22
31
|
this.openActionDrawer({
|
|
23
32
|
guid: r,
|
|
24
|
-
trigger:
|
|
33
|
+
trigger: t
|
|
25
34
|
});
|
|
26
35
|
};
|
|
27
36
|
closeActionDrawer = () => {
|
|
@@ -34,7 +43,7 @@ var o = {
|
|
|
34
43
|
};
|
|
35
44
|
export {
|
|
36
45
|
o as CLOSED_ACTION_DRAWER,
|
|
37
|
-
|
|
46
|
+
n as InsightsV2Store
|
|
38
47
|
};
|
|
39
48
|
|
|
40
49
|
//# sourceMappingURL=InsightsV2Store.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InsightsV2Store.es.js","names":[],"sources":["../../../src/core/stores/InsightsV2Store.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\n\nimport type { GlobalStore } from './GlobalStore'\n\nexport type ActionDrawerTrigger = 'primaryCta' | 'secondaryCta' | 'chartBar'\n\nexport interface ActionDrawerState {\n isDrawerOpen: boolean\n trigger: ActionDrawerTrigger\n guid: string\n /**\n * Block-specific drilldown data, opaque to the store. Each action block defines
|
|
1
|
+
{"version":3,"file":"InsightsV2Store.es.js","names":[],"sources":["../../../src/core/stores/InsightsV2Store.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\n\nimport type { GlobalStore } from './GlobalStore'\n\nexport type ActionDrawerTrigger = 'primaryCta' | 'secondaryCta' | 'chartBar'\n\nexport interface ActionDrawerState {\n isDrawerOpen: boolean\n trigger: ActionDrawerTrigger\n guid: string\n /**\n * Block-specific drilldown data for the current drawer SESSION, opaque to the\n * store. Each action block defines and reads its own shape (via\n * useActionContext<T>()). Chart drilldowns put `{ chartBarIndex, tabIndex }`\n * here; CTAs carry none.\n *\n * This is an accumulating bag, not a single owner's value: a nested drawer\n * (e.g. TransactionDetailsBlock opened from a row inside TransactionHistory\n * Block) adds its own key via `setActionContext` ON TOP of whatever the outer\n * drawer already put here, so the outer block's own context survives while the\n * nested block is open. It resets to a clean slate only when a NEW drawer\n * session starts (`openActionDrawer`/`openCtaDrawer`, which fully replace the\n * envelope) — not on every `setActionContext` call.\n */\n context: unknown\n}\n\nexport const CLOSED_ACTION_DRAWER: ActionDrawerState = {\n isDrawerOpen: false,\n trigger: 'primaryCta',\n guid: '',\n context: undefined,\n}\n\ninterface OpenActionDrawerArgs {\n guid: string\n trigger: ActionDrawerTrigger\n context?: unknown\n}\n\n/**\n * UI state shared across the insights-v2 widget tree. Owns the action drawer so\n * cards, charts, and action blocks coordinate through the store instead of prop\n * drilling. The drawer state is a fixed envelope (isDrawerOpen/guid/trigger) plus\n * an opaque `context` bag, so per-block drilldown data never leaks into this shape.\n */\nexport class InsightsV2Store {\n globalStore: GlobalStore\n\n actionDrawer: ActionDrawerState = CLOSED_ACTION_DRAWER\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n\n makeAutoObservable(this)\n }\n\n /**\n * Merges keys into the current drawer session's context bag — it does NOT\n * replace it. A nested drawer (e.g. a row click inside TransactionHistoryBlock\n * opening TransactionDetailsBlock) calls this to layer its own key (e.g.\n * `transaction_guid`) on top of whatever context the outer drawer already set\n * (e.g. `chartBarIndex`), so the outer block keeps reading its own keys via\n * useActionContext while the nested block is open. The bag only returns to a\n * clean slate when a new drawer session starts via `openActionDrawer`/\n * `openCtaDrawer`, which fully replace the envelope.\n */\n setActionContext = (context: Record<string, unknown>) => {\n this.actionDrawer = {\n ...this.actionDrawer,\n context: { ...(this.actionDrawer.context as Record<string, unknown> | undefined), ...context },\n }\n }\n\n /**\n * Generic drawer opener — the only opener a new action block needs. Pass the\n * beat guid, the CTA/source that triggered it, and (optionally) a block-specific\n * context object the block reads back via useActionContext.\n */\n openActionDrawer = ({ guid, trigger, context }: OpenActionDrawerArgs) => {\n this.actionDrawer = { isDrawerOpen: true, trigger, guid, context }\n }\n\n /** Convenience opener for CTA drawers (no drilldown context). */\n openCtaDrawer = (guid: string, trigger: 'primaryCta' | 'secondaryCta') => {\n this.openActionDrawer({ guid, trigger })\n }\n\n closeActionDrawer = () => {\n // Preserve `trigger` + `context` so the drawer keeps its variant-specific\n // title/content through the slide-out animation (ActionBlockLayer stays\n // mounted while closing). Only flip isDrawerOpen off and clear the beat guid.\n this.actionDrawer = { ...this.actionDrawer, isDrawerOpen: false, guid: '' }\n }\n}\n"],"mappings":";AA2BA,IAAa,IAA0C;AAAA,EACrD,cAAc;AAAA,EACd,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AACX,GAca,IAAb,MAA6B;AAAA,EAC3B;AAAA,EAEA,eAAkC;AAAA,EAElC,YAAY,GAA0B;AACpC,SAAK,cAAc,GAEnB,EAAmB,IAAI;AAAA,EACzB;AAAA,EAYA,mBAAA,CAAoB,MAAqC;AACvD,SAAK,eAAe;AAAA,MAClB,GAAG,KAAK;AAAA,MACR,SAAS;AAAA,QAAE,GAAI,KAAK,aAAa;AAAA,QAAiD,GAAG;AAAA,MAAQ;AAAA,IAC/F;AAAA,EACF;AAAA,EAOA,mBAAA,CAAoB,EAAE,MAAA,GAAM,SAAA,GAAS,SAAA,EAAA,MAAoC;AACvE,SAAK,eAAe;AAAA,MAAE,cAAc;AAAA,MAAM,SAAA;AAAA,MAAS,MAAA;AAAA,MAAM,SAAA;AAAA,IAAQ;AAAA,EACnE;AAAA,EAGA,gBAAA,CAAiB,GAAc,MAA2C;AACxE,SAAK,iBAAiB;AAAA,MAAE,MAAA;AAAA,MAAM,SAAA;AAAA,IAAQ,CAAC;AAAA,EACzC;AAAA,EAEA,oBAAA,MAA0B;AAIxB,SAAK,eAAe;AAAA,MAAE,GAAG,KAAK;AAAA,MAAc,cAAc;AAAA,MAAO,MAAM;AAAA,IAAG;AAAA,EAC5E;AACF"}
|
|
@@ -12,6 +12,8 @@ export interface ThemedSVGImageProps {
|
|
|
12
12
|
export interface DrilldownPayload {
|
|
13
13
|
chartBarIndex: number;
|
|
14
14
|
tabIndex?: number;
|
|
15
|
+
transaction_guid?: string;
|
|
16
|
+
block?: string;
|
|
15
17
|
}
|
|
16
18
|
export interface InsightsPayload {
|
|
17
19
|
widget_type: 'full' | 'mini' | 'micro';
|
|
@@ -1,35 +1,36 @@
|
|
|
1
|
-
import { useGlobalCopyStore as y, useGlobalUiStore as
|
|
1
|
+
import { useGlobalCopyStore as y, useGlobalUiStore as g, useInsightsV2Store as k } from "../../common/context/hooks.es.js";
|
|
2
2
|
import C from "../../common/components/drawer/Drawer.es.js";
|
|
3
3
|
import h from "../../common/components/Loader.es.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import w from "
|
|
4
|
+
import { getDynamicCtaBasedOnTriggers as B } from "./util.es.js";
|
|
5
|
+
import { actionBlocks as _, hasDrawerBlock as b } from "../mappings/blocks.es.js";
|
|
6
|
+
import { observer as w } from "mobx-react-lite";
|
|
7
|
+
import D from "@mui/material/Stack";
|
|
7
8
|
import { Text as v } from "@mxenabled/mxui";
|
|
8
9
|
import { jsx as e } from "react/jsx-runtime";
|
|
9
|
-
var
|
|
10
|
-
const { Component: n, usePrepare: t } =
|
|
10
|
+
var L = ({ actionBlock: s, ...o }) => {
|
|
11
|
+
const { Component: n, usePrepare: t } = s;
|
|
11
12
|
return t(o), /* @__PURE__ */ e(n, { ...o });
|
|
12
|
-
},
|
|
13
|
-
const n = y(), t = n.common, { isCopyLoaded: m } =
|
|
14
|
-
if (!m) return
|
|
13
|
+
}, R = w(function({ beat: o }) {
|
|
14
|
+
const n = y(), t = n.common, { isCopyLoaded: m } = g(), { actionDrawer: a, closeActionDrawer: p } = k(), l = a.isDrawerOpen && a.guid === o.guid;
|
|
15
|
+
if (!m) return l ? /* @__PURE__ */ e(h, {}) : null;
|
|
15
16
|
if (!o.insights_payload) return null;
|
|
16
|
-
const { primary_cta: u, secondary_cta: d } = o.insights_payload, r =
|
|
17
|
+
const { primary_cta: u, secondary_cta: d } = o.insights_payload, r = B(a, u, d), c = b(r?.block), i = c ? _[r?.block] : void 0, f = i ? i.title?.(r?.variant, n) ?? r?.label ?? "" : c ? t.error_heading : r?.label ?? "";
|
|
17
18
|
return /* @__PURE__ */ e(C, {
|
|
18
19
|
ariaLabelClose: t.close_aria,
|
|
19
|
-
isOpen:
|
|
20
|
+
isOpen: l,
|
|
20
21
|
onClose: p,
|
|
21
22
|
title: f,
|
|
22
|
-
children: i ? /* @__PURE__ */ e(
|
|
23
|
+
children: i ? /* @__PURE__ */ e(L, {
|
|
23
24
|
actionBlock: i,
|
|
24
25
|
beat: o
|
|
25
|
-
}, r?.block) :
|
|
26
|
+
}, r?.block) : c ? /* @__PURE__ */ e(D, {
|
|
26
27
|
sx: { p: 24 },
|
|
27
28
|
children: /* @__PURE__ */ e(v, { children: t.error_message })
|
|
28
29
|
}) : null
|
|
29
30
|
});
|
|
30
31
|
});
|
|
31
32
|
export {
|
|
32
|
-
|
|
33
|
+
R as ActionBlockLayer
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
//# sourceMappingURL=ActionBlockLayer.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionBlockLayer.es.js","names":[],"sources":["../../../src/insights-v2/actionBlocks/ActionBlockLayer.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport { Text } from '@mxenabled/mxui'\nimport { observer } from 'mobx-react-lite'\n\nimport {\n Drawer,\n Loader,\n useGlobalCopyStore,\n useGlobalUiStore,\n useInsightsV2Store,\n} from '../../common'\nimport { type Beat } from '../../core'\nimport {\n actionBlocks,\n hasDrawerBlock,\n type ActionBlockEntry,\n type ActionBlockProps,\n} from '../mappings/blocks'\n\ninterface ActionBlockLayerProps {\n beat: Beat\n}\n\n/**\n * Renders a registered action block. Callers MUST key this per block name — a\n * block with `usePrepare` and one without run a different number of hooks, so\n * reusing the same fiber across a block switch violates the rules of hooks.\n */\nconst ActionBlockRunner = ({\n actionBlock,\n ...blockProps\n}: ActionBlockProps & { actionBlock: ActionBlockEntry }) => {\n const { Component, usePrepare } = actionBlock\n\n usePrepare(blockProps)\n\n return <Component {...blockProps} />\n}\n\n// `observer` is required: this reads `isCopyLoaded` off GlobalUiStore and the\n// action drawer off InsightsV2Store. Without it the component never re-renders\n// and stays stuck on <Loader /> forever.\nexport const ActionBlockLayer = observer(function ActionBlockLayer({\n beat,\n}: ActionBlockLayerProps) {\n const copy = useGlobalCopyStore()\n const commonCopy = copy.common\n const { isCopyLoaded } = useGlobalUiStore()\n const { actionDrawer, closeActionDrawer } = useInsightsV2Store()\n\n // Every card in the feed renders its own layer against the shared store, so\n // this card's drawer only opens when its beat is the one that triggered it.\n const isCurrentBeatOpen = actionDrawer.isDrawerOpen && actionDrawer.guid === beat.guid\n\n if (!isCopyLoaded) return isCurrentBeatOpen ? <Loader /> : null\n\n // Mirrors BaseLayout's guard — the layer is exported, so callers are not\n // guaranteed to have narrowed this already.\n if (!beat.insights_payload) return null\n\n const { primary_cta, secondary_cta } = beat.insights_payload\n\n const currentCta = actionDrawer
|
|
1
|
+
{"version":3,"file":"ActionBlockLayer.es.js","names":[],"sources":["../../../src/insights-v2/actionBlocks/ActionBlockLayer.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport { Text } from '@mxenabled/mxui'\nimport { observer } from 'mobx-react-lite'\n\nimport {\n Drawer,\n Loader,\n useGlobalCopyStore,\n useGlobalUiStore,\n useInsightsV2Store,\n} from '../../common'\nimport { type Beat } from '../../core'\nimport {\n actionBlocks,\n hasDrawerBlock,\n type ActionBlockEntry,\n type ActionBlockProps,\n} from '../mappings/blocks'\nimport { getDynamicCtaBasedOnTriggers } from './util'\n\ninterface ActionBlockLayerProps {\n beat: Beat\n}\n\n/**\n * Renders a registered action block. Callers MUST key this per block name — a\n * block with `usePrepare` and one without run a different number of hooks, so\n * reusing the same fiber across a block switch violates the rules of hooks.\n */\nconst ActionBlockRunner = ({\n actionBlock,\n ...blockProps\n}: ActionBlockProps & { actionBlock: ActionBlockEntry }) => {\n const { Component, usePrepare } = actionBlock\n\n usePrepare(blockProps)\n\n return <Component {...blockProps} />\n}\n\n// `observer` is required: this reads `isCopyLoaded` off GlobalUiStore and the\n// action drawer off InsightsV2Store. Without it the component never re-renders\n// and stays stuck on <Loader /> forever.\nexport const ActionBlockLayer = observer(function ActionBlockLayer({\n beat,\n}: ActionBlockLayerProps) {\n const copy = useGlobalCopyStore()\n const commonCopy = copy.common\n const { isCopyLoaded } = useGlobalUiStore()\n const { actionDrawer, closeActionDrawer } = useInsightsV2Store()\n\n // Every card in the feed renders its own layer against the shared store, so\n // this card's drawer only opens when its beat is the one that triggered it.\n const isCurrentBeatOpen = actionDrawer.isDrawerOpen && actionDrawer.guid === beat.guid\n\n if (!isCopyLoaded) return isCurrentBeatOpen ? <Loader /> : null\n\n // Mirrors BaseLayout's guard — the layer is exported, so callers are not\n // guaranteed to have narrowed this already.\n if (!beat.insights_payload) return null\n\n const { primary_cta, secondary_cta } = beat.insights_payload\n\n const currentCta = getDynamicCtaBasedOnTriggers(actionDrawer, primary_cta, secondary_cta)\n\n // A CTA without a real block never opens a drawer (BaseLayout won't trigger it);\n // a real-but-unknown block shows the error (\"oops\") content.\n const blockValid = hasDrawerBlock(currentCta?.block)\n const actionBlock = blockValid\n ? actionBlocks[currentCta?.block as keyof typeof actionBlocks]\n : undefined\n\n const drawerTitle = actionBlock\n ? (actionBlock.title?.(currentCta?.variant, copy) ?? currentCta?.label ?? '')\n : blockValid\n ? commonCopy.error_heading\n : (currentCta?.label ?? '')\n\n return (\n <Drawer\n ariaLabelClose={commonCopy.close_aria}\n isOpen={isCurrentBeatOpen}\n onClose={closeActionDrawer}\n title={drawerTitle}\n >\n {actionBlock ? (\n <ActionBlockRunner actionBlock={actionBlock} beat={beat} key={currentCta?.block}/>\n ) : blockValid ? (\n <Stack sx={{ p: 24 }}>\n <Text>{commonCopy.error_message}</Text>\n </Stack>\n ) : null}\n </Drawer>\n )\n})\n"],"mappings":";;;;;;;;;AA8BA,IAAM,IAAA,CAAqB,EACzB,aAAA,GACA,GAAG,EAAA,MACuD;AAC1D,QAAM,EAAE,WAAA,GAAW,YAAA,EAAA,IAAe;AAElC,SAAA,EAAW,CAAU,GAEd,gBAAA,EAAC,GAAD,EAAW,GAAI,EAAa,CAAA;AACrC,GAKa,IAAmB,EAAS,SAA0B,EACjE,MAAA,EAAA,GACwB;AACxB,QAAM,IAAO,EAAmB,GAC1B,IAAa,EAAK,QAClB,EAAE,cAAA,EAAA,IAAiB,EAAiB,GACpC,EAAE,cAAA,GAAc,mBAAA,EAAA,IAAsB,EAAmB,GAIzD,IAAoB,EAAa,gBAAgB,EAAa,SAAS,EAAK;AAElF,MAAI,CAAC,EAAc,QAAO,IAAoB,gBAAA,EAAC,GAAD,CAAS,CAAA,IAAI;AAI3D,MAAI,CAAC,EAAK,iBAAkB,QAAO;AAEnC,QAAM,EAAE,aAAA,GAAa,eAAA,EAAA,IAAkB,EAAK,kBAEtC,IAAa,EAA6B,GAAc,GAAa,CAAa,GAIlF,IAAa,EAAe,GAAY,KAAK,GAC7C,IAAc,IAChB,EAAa,GAAY,KAAA,IACzB,QAEE,IAAc,IACf,EAAY,QAAQ,GAAY,SAAS,CAAI,KAAK,GAAY,SAAS,KACxE,IACE,EAAW,gBACV,GAAY,SAAS;AAE5B,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,gBAAgB,EAAW;AAAA,IAC3B,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IAEN,UAAA,IACC,gBAAA,EAAC,GAAD;AAAA,MAAgC,aAAA;AAAA,MAAmB,MAAA;AAAA,IAA8B,GAAnB,GAAY,KAAO,IAC/E,IACF,gBAAA,EAAC,GAAD;AAAA,MAAO,IAAI,EAAE,GAAG,GAAG;AAAA,MACjB,UAAA,gBAAA,EAAC,GAAD,EAAA,UAAO,EAAW,cAAoB,CAAA;AAAA,IACjC,CAAA,IACL;AAAA,EACE,CAAA;AAEZ,CAAC"}
|
package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TopActions } from '../../../transactions/constants/Actions';
|
|
2
2
|
export declare const resolveTopActions: (names?: string[]) => TopActions[];
|
|
3
|
-
export declare const resolveBottomActions: (names?: string[]) => BottomActions[];
|
package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.es.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
var
|
|
3
|
-
Category:
|
|
4
|
-
Date:
|
|
5
|
-
Memo:
|
|
6
|
-
Tags:
|
|
7
|
-
},
|
|
8
|
-
MerchantBudget: t.MerchantBudget,
|
|
9
|
-
SplitTransaction: t.SplitTransaction,
|
|
10
|
-
HideTransaction: t.HideTransaction,
|
|
11
|
-
MerchantLogo: t.MerchantLogo
|
|
12
|
-
}, e = (o, T, n) => o ? o.map((a) => T[a]).filter((a) => a !== void 0) : n, O = (o) => e(o, s, c), _ = (o) => e(o, A, i);
|
|
1
|
+
import { DEFAULT_TOP_ACTIONS as T, TopActions as o } from "../../../transactions/constants/Actions.es.js";
|
|
2
|
+
var i = {
|
|
3
|
+
Category: o.Category,
|
|
4
|
+
Date: o.Date,
|
|
5
|
+
Memo: o.Memo,
|
|
6
|
+
Tags: o.Tags
|
|
7
|
+
}, v = (r, t, a) => r ? r.map((e) => t[e]).filter((e) => e !== void 0) : a, p = (r) => v(r, i, T);
|
|
13
8
|
export {
|
|
14
|
-
|
|
15
|
-
O as resolveTopActions
|
|
9
|
+
p as resolveTopActions
|
|
16
10
|
};
|
|
17
11
|
|
|
18
12
|
//# sourceMappingURL=transactionDetailsActions.es.js.map
|
package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transactionDetailsActions.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"transactionDetailsActions.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/transactionDetailsActions.ts"],"sourcesContent":["import { DEFAULT_TOP_ACTIONS, TopActions } from '../../../transactions/constants/Actions'\n\n/**\n * The backend sends action names as strings on `instance_slot_data`; `TransactionDetails` takes the\n * numeric enums. Keep the lookup keyed by the enum's own member names so adding a member to\n * `Actions.ts` is picked up here without a second edit.\n *\n * Unknown names are dropped rather than throwing: a beat configured against a newer ditto config\n * than the bundle should render with the actions it *does* understand, not blow up the drawer.\n */\nconst TOP_ACTION_BY_NAME: Record<string, TopActions> = {\n Category: TopActions.Category,\n Date: TopActions.Date,\n Memo: TopActions.Memo,\n Tags: TopActions.Tags,\n}\n\nconst resolve = <T>(names: string[] | undefined, lookup: Record<string, T>, fallback: T[]): T[] => {\n // `undefined` means \"not configured\" -> defaults. An explicit empty array means \"no actions\",\n // which is a legitimate per-beat choice (a read-only details view) and must not fall back.\n if (!names) return fallback\n\n return names.map((name) => lookup[name]).filter((action): action is T => action !== undefined)\n}\n\nexport const resolveTopActions = (names?: string[]): TopActions[] =>\n resolve(names, TOP_ACTION_BY_NAME, DEFAULT_TOP_ACTIONS)\n"],"mappings":";AAUA,IAAM,IAAiD;AAAA,EACrD,UAAU,EAAW;AAAA,EACrB,MAAM,EAAW;AAAA,EACjB,MAAM,EAAW;AAAA,EACjB,MAAM,EAAW;AACnB,GAEM,IAAA,CAAc,GAA6B,GAA2B,MAGrE,IAEE,EAAM,IAAA,CAAK,MAAS,EAAO,CAAA,CAAK,EAAE,OAAA,CAAQ,MAAwB,MAAW,MAAS,IAF1E,GAKR,IAAA,CAAqB,MAChC,EAAQ,GAAO,GAAoB,CAAmB"}
|
package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { useTransactionStore as
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { useActionContext as _, useInsightsV2Store as g, useTransactionStore as m } from "../../../common/context/hooks.es.js";
|
|
2
|
+
import { getBottomActionsByVariant as u } from "./util.es.js";
|
|
3
|
+
import { resolveTopActions as l } from "./transactionDetailsActions.es.js";
|
|
4
|
+
var A = (t) => {
|
|
5
|
+
const { detailedTransactions: a, isTransactionDataLoaded: i } = m(), { actionDrawer: r } = g(), { transaction_guid: c } = _() ?? {}, s = t.insights_payload?.instance_slot_data ?? {}, o = c ?? s.transaction_guid ?? t.primary_transaction_guid ?? t.transaction_guids?.[0], d = o ? a.find((p) => p.guid === o) : void 0, n = t.primary_transaction, e = !o || n?.guid === o;
|
|
5
6
|
return {
|
|
6
|
-
bottomActions:
|
|
7
|
+
bottomActions: u(r, t.insights_payload?.primary_cta, t.insights_payload?.secondary_cta),
|
|
7
8
|
isLoading: !i,
|
|
8
|
-
topActions:
|
|
9
|
-
transaction:
|
|
9
|
+
topActions: l(s.top_actions),
|
|
10
|
+
transaction: d ?? (e ? n : void 0)
|
|
10
11
|
};
|
|
11
12
|
};
|
|
12
13
|
export {
|
|
13
|
-
|
|
14
|
+
A as useTransactionDetailsBlock
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
//# sourceMappingURL=useTransactionDetailsBlock.es.js.map
|
package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTransactionDetailsBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.ts"],"sourcesContent":["import { useTransactionStore } from '../../../common'\nimport type { Beat, Transaction } from '../../../core'\nimport type { TransactionDetailsBlockData } from '../../../core/types/InsightsInstanceSlotData'\nimport type { BottomActions, TopActions } from '../../../transactions/constants/Actions'\
|
|
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 { TransactionDetailsBlockData } from '../../../core/types/InsightsInstanceSlotData'\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 * Resolution order is deliberate:\n * 1. `instance_slot_data.transaction_guid` — the beat explicitly naming its subject.\n * 2. `beat.primary_transaction_guid` — the standard beat-level pointer.\n * 3. `beat.transaction_guids[0]` — last resort for beats that only carry the list.\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 *\n * `beat.primary_transaction` is the fallback of last resort: it is a payload snapshot, not a store\n * object, so inline edits against it would not propagate. Preferring it over a store hit would make\n * editing silently no-op, which is why it is only used when the store genuinely has nothing — and\n * only when it is a snapshot of the *same* transaction the guid resolved to (or when no guid\n * resolved at all). A snapshot of some other transaction is not an answer to this question.\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 slotData = (beat.insights_payload?.instance_slot_data ?? {}) as TransactionDetailsBlockData\n\n const guid = transaction_guid ??\n slotData.transaction_guid ?? beat.primary_transaction_guid ?? beat.transaction_guids?.[0]\n\n const fromStore = guid\n ? detailedTransactions.find((transaction) => transaction.guid === guid)\n : undefined\n\n // The snapshot is only a valid answer for the guid we actually resolved. When a beat names its\n // subject via instance_slot_data (or transaction_guids[0]) and that guid misses in the store,\n // falling back unconditionally would render a *different* transaction's details — and inline\n // edits would then be made against the wrong subject. Match on guid, or accept the snapshot only\n // when no guid resolved at all.\n const snapshot = beat.primary_transaction\n const snapshotMatches = !guid || snapshot?.guid === guid\n\n const bottomActions = getBottomActionsByVariant(actionDrawer, beat.insights_payload?.primary_cta, beat.insights_payload?.secondary_cta)\n return {\n bottomActions,\n isLoading: !isTransactionDataLoaded,\n topActions: resolveTopActions(slotData.top_actions),\n transaction: fromStore ?? (snapshotMatches ? snapshot : undefined),\n }\n}\n"],"mappings":";;;AAmCA,IAAa,IAAA,CAA8B,MAA6C;AACtF,QAAM,EAAE,sBAAA,GAAsB,yBAAA,EAAA,IAA4B,EAAoB,GAExE,EAAC,cAAA,EAAA,IAAgB,EAAmB,GAEpC,EAAE,kBAAA,EAAA,IAAqB,EAAmC,KAAK,CAAC,GAChE,IAAY,EAAK,kBAAkB,sBAAsB,CAAC,GAE1D,IAAO,KACX,EAAS,oBAAoB,EAAK,4BAA4B,EAAK,oBAAoB,CAAA,GAEnF,IAAY,IACd,EAAqB,KAAA,CAAM,MAAgB,EAAY,SAAS,CAAI,IACpE,QAOE,IAAW,EAAK,qBAChB,IAAkB,CAAC,KAAQ,GAAU,SAAS;AAGpD,SAAO;AAAA,IACL,eAFoB,EAA0B,GAAc,EAAK,kBAAkB,aAAa,EAAK,kBAAkB,aAEvH;AAAA,IACA,WAAW,CAAC;AAAA,IACZ,YAAY,EAAkB,EAAS,WAAW;AAAA,IAClD,aAAa,MAAc,IAAkB,IAAW;AAAA,EAC1D;AACF"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ActionDrawerState, PrimaryCTA, SecondaryCTA } from '../../../core';
|
|
2
|
+
import { BottomActions } from '../../../transactions/constants/Actions';
|
|
3
|
+
export declare const getBottomActionsByVariant: (actionDrawer: ActionDrawerState, primary_cta: PrimaryCTA | undefined, secondary_cta: SecondaryCTA | undefined) => BottomActions[];
|
|
@@ -0,0 +1,8 @@
|
|
|
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];
|
|
4
|
+
export {
|
|
5
|
+
m as getBottomActionsByVariant
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=util.es.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -13,10 +13,11 @@ interface TransactionDrillDownProps {
|
|
|
13
13
|
selectedIndex: number;
|
|
14
14
|
top: React.ReactNode;
|
|
15
15
|
onSelectionChange?: (selectedIndex: number) => void;
|
|
16
|
+
onEachRowClick?: (guid: string) => void;
|
|
16
17
|
transactionFilter?: (selectedIndex: number) => (transaction: Transaction) => boolean;
|
|
17
18
|
baseTransactions?: Transaction[];
|
|
18
19
|
}
|
|
19
|
-
export declare const TransactionDrillDown: (({ ariaLabel, heading, subHeadingText, icon, tabs, selectedIndex, top, onSelectionChange, transactionFilter, baseTransactions, }: TransactionDrillDownProps) => import("react/jsx-runtime").JSX.Element) & {
|
|
20
|
+
export declare const TransactionDrillDown: (({ ariaLabel, heading, subHeadingText, icon, tabs, selectedIndex, top, onSelectionChange, transactionFilter, onEachRowClick, baseTransactions, }: TransactionDrillDownProps) => import("react/jsx-runtime").JSX.Element) & {
|
|
20
21
|
displayName: string;
|
|
21
22
|
};
|
|
22
23
|
export default TransactionDrillDown;
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
import { useGlobalCopyStore as W, useGlobalUiStore as $, useTransactionStore as j } from "../../../common/context/hooks.es.js";
|
|
2
|
-
import { exportTransactionsToCSV as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import { exportTransactionsToCSV as G } from "../../../core/utils/TransactionUtils.es.js";
|
|
3
|
+
import P from "../../../common/components/Loader.es.js";
|
|
4
|
+
import A from "../../../transactions/components/shared/TransactionList.es.js";
|
|
5
5
|
import "react";
|
|
6
|
-
import { observer as
|
|
6
|
+
import { observer as E } from "mobx-react-lite";
|
|
7
7
|
import c from "@mui/material/Stack";
|
|
8
|
-
import { H3 as
|
|
9
|
-
import
|
|
10
|
-
import { Icon as
|
|
11
|
-
import { jsx as
|
|
8
|
+
import { H3 as N, Text as d } from "@mxenabled/mxui";
|
|
9
|
+
import R from "@mui/material/Button";
|
|
10
|
+
import { Icon as U } from "@mxenabled/mx-icons";
|
|
11
|
+
import { jsx as o, jsxs as r } from "react/jsx-runtime";
|
|
12
12
|
import p from "@mui/material/Box";
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
var u = "transaction-drill-down-panel", v = (m) => `transaction-details-tab-${m}`,
|
|
16
|
-
const { transactions: l } = W(), { isCopyLoaded:
|
|
17
|
-
if (!
|
|
18
|
-
const s = !!b?.length,
|
|
13
|
+
import V from "@mui/material/Tab";
|
|
14
|
+
import q from "@mui/material/Tabs";
|
|
15
|
+
var u = "transaction-drill-down-panel", v = (m) => `transaction-details-tab-${m}`, io = E(function({ ariaLabel: T, heading: i, subHeadingText: n, icon: y, tabs: b, selectedIndex: e, top: C, onSelectionChange: g, transactionFilter: f, onEachRowClick: _, baseTransactions: w }) {
|
|
16
|
+
const { transactions: l } = W(), { isCopyLoaded: D } = $(), { sortedTransactionsWithSplits: S, tags: L, detailedTransactions: B } = j();
|
|
17
|
+
if (!D) return /* @__PURE__ */ o(P, {});
|
|
18
|
+
const s = !!b?.length, I = T ?? l.transactions_title, k = (t, a) => {
|
|
19
19
|
g?.(a);
|
|
20
|
-
}, h = f ? (
|
|
21
|
-
return /* @__PURE__ */
|
|
20
|
+
}, h = f ? (w ?? B).filter(f(e)) : void 0, x = h ?? S;
|
|
21
|
+
return /* @__PURE__ */ r(p, {
|
|
22
22
|
sx: {
|
|
23
23
|
bgcolor: "background.paper",
|
|
24
24
|
width: "100%"
|
|
25
25
|
},
|
|
26
|
-
children: [s && /* @__PURE__ */
|
|
27
|
-
"aria-label":
|
|
28
|
-
onChange:
|
|
26
|
+
children: [s && /* @__PURE__ */ o(q, {
|
|
27
|
+
"aria-label": I,
|
|
28
|
+
onChange: k,
|
|
29
29
|
value: e,
|
|
30
30
|
variant: "fullWidth",
|
|
31
|
-
children: b.map((t, a) => /* @__PURE__ */
|
|
31
|
+
children: b.map((t, a) => /* @__PURE__ */ o(V, {
|
|
32
32
|
"aria-controls": u,
|
|
33
33
|
"aria-label": t.ariaLabel,
|
|
34
34
|
id: v(a),
|
|
@@ -38,35 +38,35 @@ var u = "transaction-drill-down-panel", v = (m) => `transaction-details-tab-${m}
|
|
|
38
38
|
px: 0
|
|
39
39
|
}
|
|
40
40
|
}, `${t.label}-${a}`))
|
|
41
|
-
}), /* @__PURE__ */
|
|
41
|
+
}), /* @__PURE__ */ r(p, {
|
|
42
42
|
"aria-labelledby": s ? v(e) : void 0,
|
|
43
43
|
id: u,
|
|
44
44
|
role: s ? "tabpanel" : void 0,
|
|
45
45
|
children: [
|
|
46
|
-
(i || n) && /* @__PURE__ */
|
|
46
|
+
(i || n) && /* @__PURE__ */ r(c, {
|
|
47
47
|
sx: {
|
|
48
48
|
gap: 4,
|
|
49
49
|
pt: 16,
|
|
50
50
|
px: 24
|
|
51
51
|
},
|
|
52
|
-
children: [i && /* @__PURE__ */
|
|
52
|
+
children: [i && /* @__PURE__ */ o(N, { children: i }), n && /* @__PURE__ */ r(c, {
|
|
53
53
|
sx: {
|
|
54
54
|
alignItems: "center",
|
|
55
55
|
flexDirection: "row",
|
|
56
56
|
gap: 8
|
|
57
57
|
},
|
|
58
|
-
children: [y, /* @__PURE__ */
|
|
58
|
+
children: [y, /* @__PURE__ */ o(d, {
|
|
59
59
|
textTransform: "uppercase",
|
|
60
60
|
variant: "body2",
|
|
61
61
|
children: n
|
|
62
62
|
})]
|
|
63
63
|
})]
|
|
64
64
|
}),
|
|
65
|
-
/* @__PURE__ */
|
|
65
|
+
/* @__PURE__ */ o(p, {
|
|
66
66
|
sx: { pt: 16 },
|
|
67
67
|
children: C
|
|
68
68
|
}),
|
|
69
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ r(c, {
|
|
70
70
|
sx: {
|
|
71
71
|
alignItems: "center",
|
|
72
72
|
borderBottomColor: "divider",
|
|
@@ -78,31 +78,34 @@ var u = "transaction-drill-down-panel", v = (m) => `transaction-details-tab-${m}
|
|
|
78
78
|
pt: 16,
|
|
79
79
|
px: 24
|
|
80
80
|
},
|
|
81
|
-
children: [/* @__PURE__ */
|
|
81
|
+
children: [/* @__PURE__ */ o(d, {
|
|
82
82
|
bold: !0,
|
|
83
83
|
variant: "body1",
|
|
84
84
|
children: l.transactions_title
|
|
85
|
-
}), x.length > 0 && /* @__PURE__ */
|
|
85
|
+
}), x.length > 0 && /* @__PURE__ */ o(R, {
|
|
86
86
|
onClick: () => {
|
|
87
|
-
|
|
87
|
+
G(x, L);
|
|
88
88
|
},
|
|
89
|
-
startIcon: /* @__PURE__ */
|
|
89
|
+
startIcon: /* @__PURE__ */ o(U, { name: "ios_share" }),
|
|
90
90
|
sx: { height: 28 },
|
|
91
|
-
children: /* @__PURE__ */
|
|
91
|
+
children: /* @__PURE__ */ o(d, {
|
|
92
92
|
bold: !0,
|
|
93
93
|
variant: "body2",
|
|
94
94
|
children: l.export_csv_btn
|
|
95
95
|
})
|
|
96
96
|
})]
|
|
97
97
|
}),
|
|
98
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ o(A, {
|
|
99
|
+
transaction: h,
|
|
100
|
+
onClick: _
|
|
101
|
+
})
|
|
99
102
|
]
|
|
100
103
|
})]
|
|
101
104
|
});
|
|
102
105
|
});
|
|
103
106
|
export {
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
io as TransactionDrillDown,
|
|
108
|
+
io as default
|
|
106
109
|
};
|
|
107
110
|
|
|
108
111
|
//# 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 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 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} />\n </Box>\n </Box>\n )\n})\n\nexport default TransactionDrillDown\n"],"mappings":";;;;;;;;;;;;;;AAsBA,IAAM,IAAW,gCACX,IAAA,CAAS,MAAkB,2BAA2B,CAAA,
|
|
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":"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"}
|