@mx-cartographer/experiences 9.4.14 → 9.4.16
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 +20 -0
- package/dist/core/types/Insights.d.ts +14 -14
- package/dist/core/types/InsightsInstanceSlotData.d.ts +5 -1
- package/dist/core/types/InsightsInstanceSlotData.es.js.map +1 -1
- package/dist/core/types/localization/InsightsFeedCopy.d.ts +21 -0
- package/dist/core/types/localization/index.d.ts +1 -1
- package/dist/insights-v2/CommonUtils.d.ts +2 -0
- package/dist/insights-v2/CommonUtils.es.js +8 -3
- package/dist/insights-v2/CommonUtils.es.js.map +1 -1
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.d.ts +22 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.es.js +108 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionDrillDown.es.js.map +1 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.d.ts +8 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js +89 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js.map +1 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.d.ts +68 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js +118 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/layout.es.js.map +1 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/useTransactionHistory.d.ts +15 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/useTransactionHistory.es.js +20 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/useTransactionHistory.es.js.map +1 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/utils.d.ts +64 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/utils.es.js +67 -0
- package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/utils.es.js.map +1 -0
- package/dist/insights-v2/beatActions.d.ts +30 -0
- package/dist/insights-v2/beatActions.es.js +12 -0
- package/dist/insights-v2/beatActions.es.js.map +1 -0
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/layout.d.ts +2 -2
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/layout.es.js +2 -2
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/layout.es.js.map +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/utils.d.ts +14 -3
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/utils.es.js +26 -25
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/utils.es.js.map +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/DonutChartBlock/DonutChartBlock.es.js +3 -3
- package/dist/insights-v2/blocks/ChartBlocks/DonutChartBlock/DonutChartBlock.es.js.map +1 -1
- package/dist/insights-v2/components/BaseLayout.d.ts +5 -1
- package/dist/insights-v2/components/BaseLayout.es.js +68 -64
- package/dist/insights-v2/components/BaseLayout.es.js.map +1 -1
- package/dist/insights-v2/components/Header.es.js +23 -33
- package/dist/insights-v2/components/Header.es.js.map +1 -1
- package/dist/insights-v2/components/InsightOptionsMenu.d.ts +10 -0
- package/dist/insights-v2/components/InsightOptionsMenu.es.js +54 -0
- package/dist/insights-v2/components/InsightOptionsMenu.es.js.map +1 -0
- package/dist/insights-v2/components/OverflowMenu.d.ts +32 -0
- package/dist/insights-v2/components/OverflowMenu.es.js +73 -0
- package/dist/insights-v2/components/OverflowMenu.es.js.map +1 -0
- package/dist/insights-v2/index.d.ts +3 -0
- package/dist/insights-v2/index.es.js +51 -45
- package/dist/insights-v2/mappings/blocks.es.js +45 -38
- package/dist/insights-v2/mappings/blocks.es.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## [9.4.16] - 09-03-2026
|
|
2
|
+
|
|
3
|
+
- **ADDED** - insights-v2 overflow (“…”) menu on the insight card header: new presentational `OverflowMenu` (icon trigger + action list with full aria/keyboard support) and `InsightOptionsMenu`, which owns the item set — helpful / not helpful / hide — from `insights_feed.overflow_menu` copy. The host supplies the action handler via `beatActions.onMenuAction`, delivered through the new `BeatActionsProvider`/`useBeatActions` context; the menu renders only on the full (non-mini) layout when a handler is wired (WEC-1767)
|
|
4
|
+
- **ADDED** - `OverflowMenuCopy` (`insights_feed.overflow_menu`) localization type and copy keys (`aria_label`, `helpful`, `not_helpful`, `hide`) (WEC-1767)
|
|
5
|
+
|
|
6
|
+
## [9.4.15] - 09-03-2026
|
|
7
|
+
|
|
8
|
+
- **ADDED** - Transaction History action block (single-bar): `transaction_history_block` registered in `mappings/blocks.ts`, rendering a `BarChartV2` over the beat's monthly `data_series` above a reused transactions `TransactionList` drilldown. Variant behavior (chart top, bar colors, drawer header, and the per-variant `filterStrategy`) is driven by `drillDownConfig`, covering the Transaction, CategorySpend, MonthlySpend, AccountBalance, and UpcomingBill variants (WEC-1701)
|
|
9
|
+
- **ADDED** - Upcoming-bill drilldown synthesizes its chart bars from the beat's recurring-bill transactions plus a projected bill read off `instance_slot_data` (`buildUpcomingBillSeries`), de-duped by date and sorted oldest→newest with a `TRN-projected-bill` sentinel bar (WEC-1701)
|
|
10
|
+
- **CHANGED** - Migrated insights-v2 instance-slot block names and bar-chart variant names to snake_case to match the backend contract: `BlockType` values, the `mappings/blocks.ts` map keys, `BAR_CHART_VARIANTS`, `BarchartBlock` layout keys, and the corresponding mock payloads (e.g. `bar_chart_block`, `category_color`, `monthly_spend_comparison`, `savings_account_balances_summary`, `budget_block`, `category_transactions_block`) (WEC-1701)
|
|
11
|
+
- **CHANGED** - `buildChartData` accepts an optional date format (defaults to month-short; upcoming-bill passes month-day) and now carries each bar's `date` so chart tabs, filter indexing, and the drawer header stay aligned (WEC-1701)
|
|
12
|
+
- **CHANGED** - `Legends` type made consistent: `additional_value`, `additional_value_type`, and `value_type` are now optional, and `instance_slot_data.legends` is typed as `Legends[]` (WEC-1701)
|
|
13
|
+
- **CHANGED** - `drillDownConfig` type-hardened: `DataSeriesItem` replaces `any[]` for the data series shape; removed the unused `filterKind` field; `filterStrategy` is now a required discriminated union returning a typed `TransactionFilter` or `{ skip: true }` (WEC-1701)
|
|
14
|
+
- **CHANGED** - `ActionDrawerState.context` stays `unknown` at the store level; drilldown components narrow to their expected payload shape via the new `useActionContext<DrilldownPayload>()` hook (WEC-1701)
|
|
15
|
+
- **CHANGED** - `TransactionHistoryBlock` snapshots the shared transaction filter on mount and restores it on unmount via a `useLayoutEffect` cleanup function, keeping beat-specific filter state scoped to the block lifecycle instead of leaking into `InsightsV2Store` as a global concern (WEC-1701)
|
|
16
|
+
- **FIXED** - Transaction History block renders the shared `EmptyBarChart` empty state instead of crashing when a single-bar or upcoming-bill beat produces no chart data (WEC-1701)
|
|
17
|
+
- **FIXED** - Upcoming-bill drilldown rendered an empty chart because the recurring-bill scoping guids were read from the top-level `Beat`; they (plus `primary_transaction_guid` and `account_guids`) are now sourced from `instance_slot_data`, where the payload actually carries them, so the synthesized bars render again (WEC-1701)
|
|
18
|
+
- **FIXED** - `TransactionHistoryBlock` `useLayoutEffect` deps now use stable joined-string keys (`beatTransactionGuidsKey`, `recurringBillGuidsKey`) instead of unmemoized computed arrays, preventing infinite render/fetch loops (WEC-1701)
|
|
19
|
+
- **ADDED** - Unit tests for the Transaction History action block: `drillDownConfig` + filter strategies, `utils` (flattened series, upcoming-bill synthesis, drawer titles, default selection), the `useTransactionHistory` hook, `TransactionDrillDown`, the block render, `buildChartData` date-format behavior, and the block registry mapping (WEC-1701)
|
|
20
|
+
|
|
1
21
|
## [9.4.14] - 09-03-2026
|
|
2
22
|
|
|
3
23
|
- **ADDED** - insights-v2 `TransactionDetailsBlock` action block: shared drawer content any transaction beat opens via `primary_cta.block = 'TransactionDetailsBlock'`. Resolves its subject transaction from `instance_slot_data.transaction_guid`, then `beat.primary_transaction_guid`, then `transaction_guids[0]`, preferring the `transactionStore` object over the payload snapshot so inline edits write through; maps backend action-name strings to the `TopActions`/`BottomActions` enums (unknown names dropped, `undefined` means defaults, `[]` means none); `useTransactionDetailsPrepare` loads transaction data at drawer-open time. Registered in `mappings/blocks.ts`, with a Storybook story (WEC-1499)
|
|
@@ -26,9 +26,9 @@ export interface InsightsPayload {
|
|
|
26
26
|
export interface Legends {
|
|
27
27
|
label: string;
|
|
28
28
|
value: number;
|
|
29
|
-
additional_value
|
|
30
|
-
additional_value_type
|
|
31
|
-
value_type
|
|
29
|
+
additional_value?: number;
|
|
30
|
+
additional_value_type?: string;
|
|
31
|
+
value_type?: string;
|
|
32
32
|
}
|
|
33
33
|
export interface Logo {
|
|
34
34
|
category_guid?: string;
|
|
@@ -75,18 +75,18 @@ export interface Footer {
|
|
|
75
75
|
account: string;
|
|
76
76
|
}
|
|
77
77
|
export declare const BlockType: {
|
|
78
|
-
readonly AccountBlock: "
|
|
79
|
-
readonly BarChartBlock: "
|
|
80
|
-
readonly BudgetBlock: "
|
|
81
|
-
readonly CategoryTransactionsBlock: "
|
|
82
|
-
readonly ImageBlock: "
|
|
83
|
-
readonly DonutChartBlock: "
|
|
84
|
-
readonly DoubleBarChartBlock: "
|
|
85
|
-
readonly DoubleProgressBarBlock: "
|
|
86
|
-
readonly StepChartBlock: "
|
|
87
|
-
readonly SVGImageBlock: "
|
|
78
|
+
readonly AccountBlock: "account_block";
|
|
79
|
+
readonly BarChartBlock: "bar_chart_block";
|
|
80
|
+
readonly BudgetBlock: "budget_block";
|
|
81
|
+
readonly CategoryTransactionsBlock: "category_transactions_block";
|
|
82
|
+
readonly ImageBlock: "image_block";
|
|
83
|
+
readonly DonutChartBlock: "donut_chart_block";
|
|
84
|
+
readonly DoubleBarChartBlock: "double_bar_chart_block";
|
|
85
|
+
readonly DoubleProgressBarBlock: "double_progress_bar_block";
|
|
86
|
+
readonly StepChartBlock: "step_chart_block";
|
|
87
|
+
readonly SVGImageBlock: "svg_image_block";
|
|
88
88
|
};
|
|
89
|
-
export type BlockType = keyof typeof BlockType;
|
|
89
|
+
export type BlockType = (typeof BlockType)[keyof typeof BlockType];
|
|
90
90
|
export interface InstanceSlot {
|
|
91
91
|
block: BlockType;
|
|
92
92
|
variant: string | null;
|
|
@@ -4,9 +4,13 @@ export interface InsightsInstanceSlotData extends Partial<BarChartBlockData>, Pa
|
|
|
4
4
|
}
|
|
5
5
|
interface CommonProps {
|
|
6
6
|
amount?: number;
|
|
7
|
-
|
|
7
|
+
date?: string;
|
|
8
|
+
legends?: Legends[];
|
|
8
9
|
category_guid?: string;
|
|
9
10
|
data_series?: DataSeries | DataSet[];
|
|
11
|
+
transaction_guids?: string[];
|
|
12
|
+
account_guids?: string[];
|
|
13
|
+
primary_transaction_guid?: string;
|
|
10
14
|
}
|
|
11
15
|
export interface BarChartBlockData {
|
|
12
16
|
average_amount?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InsightsInstanceSlotData.es.js","names":[],"sources":["../../../src/core/types/InsightsInstanceSlotData.ts"],"sourcesContent":["import type { DataSeries, Legends } from '../../core'\nimport type { Transaction } from './Transaction'\n\nexport interface InsightsInstanceSlotData\n extends\n Partial<BarChartBlockData>,\n Partial<BudgetBlockData>,\n Partial<DonutChartBlockData>,\n Partial<DoubleProgressBarBlockData>,\n Partial<ImageBlockData>,\n Partial<AccountBlockData>,\n Partial<SaveExtraBlockData>,\n Partial<StepChartBlockData>,\n Partial<SVGImageBlockData>,\n Partial<CategoryTransactionsBlockData>,\n Partial<AccountSwitchBlockData>,\n Partial<TransactionDetailsBlockData>,\n Partial<CommonProps> {}\n\n//when any of the type is used more than one times, we can use the common props\ninterface CommonProps {\n amount?: number\n legends?:
|
|
1
|
+
{"version":3,"file":"InsightsInstanceSlotData.es.js","names":[],"sources":["../../../src/core/types/InsightsInstanceSlotData.ts"],"sourcesContent":["import type { DataSeries, Legends } from '../../core'\nimport type { Transaction } from './Transaction'\n\nexport interface InsightsInstanceSlotData\n extends\n Partial<BarChartBlockData>,\n Partial<BudgetBlockData>,\n Partial<DonutChartBlockData>,\n Partial<DoubleProgressBarBlockData>,\n Partial<ImageBlockData>,\n Partial<AccountBlockData>,\n Partial<SaveExtraBlockData>,\n Partial<StepChartBlockData>,\n Partial<SVGImageBlockData>,\n Partial<CategoryTransactionsBlockData>,\n Partial<AccountSwitchBlockData>,\n Partial<TransactionDetailsBlockData>,\n Partial<CommonProps> {}\n\n//when any of the type is used more than one times, we can use the common props\ninterface CommonProps {\n amount?: number\n date?: string\n legends?: Legends[]\n category_guid?: string\n data_series?: DataSeries | DataSet[]\n transaction_guids?: string[]\n account_guids?: string[]\n primary_transaction_guid?: string\n}\n\n//BarChart Block\nexport interface BarChartBlockData {\n average_amount?: number\n ariaLabel?: string\n}\n\n//DonutChart Block\ninterface Main {\n value: string\n value_type: string\n label: string\n}\nexport interface DonutChartBlockData {\n main: Main\n}\n\n//DoubleBarChart Block\n// TODO : This has to be revisited again to update the below types based on API response once we have the final shape of the data_series for double bar chart from BE\nexport interface LegendProps extends Legends {\n amount: number\n formattedAmount: string\n label: string\n color?: string\n}\n\nexport interface DataSet extends DataSeries {\n ariaLabelComparison: string\n ariaLabelMain: string\n comparison: number\n formattedComparison: string\n formattedMain: string\n label: string\n main: number\n}\n\n//DoubleProgressBar Block\n\ninterface DoubleProgressBarProps {\n label: string\n value: number\n}\nexport interface DoubleProgressBarBlockData {\n doubleProgressBar: {\n previous: DoubleProgressBarProps\n latest: DoubleProgressBarProps\n }\n}\n\n//Image Block\nexport interface ImageBlockData {\n image: string\n}\n\n//Account Block\nexport interface AccountBlockData {\n sub_text: string\n institution_guid?: string\n institution_name?: string\n icon_name?: string\n /** Header bar text (standard card), or the colored category strip label (deposit cards). */\n header_text?: string\n // Deposit variants (Unified Deposit, Unified Deposit Emergency Fund, Savings Account Deposit)\n /** Merchant guid — renders a real merchant logo in the deposit card when present. */\n merchant_guid?: string\n /** Merchant display name — logo alt text and the payer line under the amount. */\n merchant_name?: string\n /** Secondary label beside the amount, e.g. `On {date}, you saved` or `Balance as of MM/DD/YY`. */\n label?: string\n}\n\nexport interface SaveExtraBlockData {\n /** Styled segments `[lead-in, amount digits, trailing copy]`, e.g. `['Save an extra', '100', 'to help your funds grow']`. */\n primary_text?: string[]\n /** Styled segments `[projected balance, caption]`, e.g. `['$8,313.87', 'After payday & projected expenses']`. */\n secondary_text?: string[]\n /** MakeTransfer drilldown: available balance (both variants). */\n available_balance?: number\n /** SAVE_ENOUGH_TO_LIVE_ON: average monthly spend. */\n avg_monthly_spend?: number\n /** SAVE_ENOUGH_TO_LIVE_ON: how long the balance lasts, overlaid on the timeline SVG (e.g. \"2 months, 11 days\"). */\n time_period?: string\n /** SAVE_AN_EXTRA_100: upcoming expenses (the \"Expenses\" figure). */\n upcoming_expenses?: number\n /** SAVE_AN_EXTRA_100: total remaining after expenses. */\n total_remaining?: number\n /** SAVE_ENOUGH_TO_LIVE_ON: date for the \"Your available balances as of {date}\" line. */\n date?: string\n}\n\n//AccountSwitch Block\nexport interface AccountSwitchBlockData {\n discovered_institution_guid: string\n discovered_institution_name: string\n held_institution_guid: string\n held_institution_name: string\n is_connected: boolean\n}\n\n// StepChart Block\nexport interface StepChartBlockData {\n completed_steps: number\n label_1: string\n label_2?: string\n}\n\n//Budgets Blocks\nexport enum BudgetTierType {\n LOW_BUDGET_TIER = 'LOW',\n MEDIUM_BUDGET_TIER = 'MEDIUM',\n OFF_TRACK_BUDGET_TIER = 'OFF_TRACK',\n}\n\nexport type BudgetTierValue = `${BudgetTierType}`\n\nexport interface BudgetLocalizedPayload {\n primary_text?: string\n amount_left_label?: string\n spent_label?: string\n budgeted_label?: string\n}\n\nexport interface BudgetBlockData {\n budget_percent: number\n budget_tier: BudgetTierValue\n category_guid?: string\n merchant_guid?: string\n spent_amount: number\n budgeted_amount: number\n localized_payload: BudgetLocalizedPayload\n}\n\nexport interface SVGImageBlockData {\n isCIBC?: boolean\n}\n\nexport type InsightTransaction = Pick<Transaction, 'amount'> &\n Partial<Pick<Transaction, 'category_guid' | 'date' | 'description' | 'merchant_guid'>> & {\n merchant_name?: string\n }\n\nexport interface CategoryTransactionsBlockData {\n primary_transaction?: InsightTransaction\n}\n\n// TransactionDetails Action Block\nexport interface TransactionDetailsBlockData {\n /**\n * Explicit subject of the details drawer. Optional: the block falls back to\n * `beat.primary_transaction_guid`, then `beat.transaction_guids[0]`.\n */\n transaction_guid?: string\n /** `TopActions` member names, e.g. `['Category', 'Date', 'Memo']`. Omit for the defaults. */\n top_actions?: string[]\n /** `BottomActions` member names, e.g. `['MerchantBudget', 'HideTransaction']`. Omit for defaults. */\n bottom_actions?: string[]\n}\n"],"mappings":"AAyIA,IAAY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,kBAAA,OACA,EAAA,qBAAA,UACA,EAAA,wBAAA;AACF,GAAA,CAAA,CAAA"}
|
|
@@ -48,9 +48,30 @@ export interface MakeTransferCopy {
|
|
|
48
48
|
increment_aria_label: string;
|
|
49
49
|
decrement_aria_label: string;
|
|
50
50
|
}
|
|
51
|
+
export interface OverflowMenuCopy {
|
|
52
|
+
/** Accessible label for the "…" trigger button. */
|
|
53
|
+
aria_label: string;
|
|
54
|
+
helpful: string;
|
|
55
|
+
not_helpful: string;
|
|
56
|
+
hide: string;
|
|
57
|
+
}
|
|
58
|
+
export interface TransactionHistoryBlock {
|
|
59
|
+
category_spend_drawer_title: string;
|
|
60
|
+
monthly_spend_comparison_drawer_title: string;
|
|
61
|
+
savings_account_balances_summary_drawer_title: string;
|
|
62
|
+
upcoming_bill_drawer_title: string;
|
|
63
|
+
monthly_spend_to_income_drawer_title: string;
|
|
64
|
+
monthly_debt_to_income_drawer_title: string;
|
|
65
|
+
monthly_savings_to_income_drawer_title: string;
|
|
66
|
+
cost_living_to_income_drawer_title: string;
|
|
67
|
+
non_essential_category_summary_drawer_title: string;
|
|
68
|
+
monthly_deposit_summary_drawer_title: string;
|
|
69
|
+
}
|
|
51
70
|
export interface InsightsFeedCopy {
|
|
52
71
|
general: GeneralInsightsFeedCopy;
|
|
53
72
|
settings_menu: SettingsMenuCopy;
|
|
54
73
|
make_transfer: MakeTransferCopy;
|
|
74
|
+
overflow_menu: OverflowMenuCopy;
|
|
75
|
+
transaction_history_block: TransactionHistoryBlock;
|
|
55
76
|
}
|
|
56
77
|
export {};
|
|
@@ -13,7 +13,7 @@ export type { DebtsCopy } from './DebtsCopy';
|
|
|
13
13
|
export type { FinstrongCopy } from './FinstrongCopy';
|
|
14
14
|
export type { GoalsCopy } from './GoalsCopy';
|
|
15
15
|
export type { HelpCopy, HelpByCategoryList } from './HelpCopy';
|
|
16
|
-
export type { InsightsFeedCopy, MakeTransferCopy } from './InsightsFeedCopy';
|
|
16
|
+
export type { InsightsFeedCopy, MakeTransferCopy, OverflowMenuCopy } from './InsightsFeedCopy';
|
|
17
17
|
export type { InvestmentsCopy } from './InvestmentsCopy';
|
|
18
18
|
export type { MicroInsightsCopy } from './MicroInsightsCopy';
|
|
19
19
|
export type { NetWorthCopy } from './NetWorthCopy';
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { formatCurrency as
|
|
2
|
-
var
|
|
1
|
+
import { formatCurrency as i } from "../core/utils/NumberFormatting.es.js";
|
|
2
|
+
var u = (r, t, e) => t === "amount" ? i(r, e) : t === "percent" ? `${r}%` : String(r), a = (r, t) => {
|
|
3
|
+
if (!t?.length) return [];
|
|
4
|
+
const e = new Set(t);
|
|
5
|
+
return r.filter((n) => e.has(n.guid));
|
|
6
|
+
};
|
|
3
7
|
export {
|
|
4
|
-
|
|
8
|
+
u as formatValueByType,
|
|
9
|
+
a as selectTransactionsByGuids
|
|
5
10
|
};
|
|
6
11
|
|
|
7
12
|
//# sourceMappingURL=CommonUtils.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommonUtils.es.js","names":[],"sources":["../../src/insights-v2/CommonUtils.ts"],"sourcesContent":["import { formatCurrency } from '../core/utils/NumberFormatting'\n\nexport const formatValueByType = (value: number, type: string, format: string): string => {\n if (type === 'amount') return formatCurrency(value, format)\n if (type === 'percent') return `${value}%`\n return String(value)\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"file":"CommonUtils.es.js","names":[],"sources":["../../src/insights-v2/CommonUtils.ts"],"sourcesContent":["import type { Transaction } from '../core'\nimport { formatCurrency } from '../core/utils/NumberFormatting'\n\nexport const formatValueByType = (value: number, type: string, format: string): string => {\n if (type === 'amount') return formatCurrency(value, format)\n if (type === 'percent') return `${value}%`\n return String(value)\n}\n\nexport const selectTransactionsByGuids = (\n detailedTransactions: Transaction[],\n guids: string[] | undefined,\n): Transaction[] => {\n if (!guids?.length) return []\n const guidSet = new Set(guids)\n return detailedTransactions.filter((transaction) => guidSet.has(transaction.guid))\n}\n"],"mappings":";AAGA,IAAa,IAAA,CAAqB,GAAe,GAAc,MACzD,MAAS,WAAiB,EAAe,GAAO,CAAM,IACtD,MAAS,YAAkB,GAAG,CAAA,MAC3B,OAAO,CAAK,GAGR,IAAA,CACX,GACA,MACkB;AAClB,MAAI,CAAC,GAAO,OAAQ,QAAO,CAAC;AAC5B,QAAM,IAAU,IAAI,IAAI,CAAK;AAC7B,SAAO,EAAqB,OAAA,CAAQ,MAAgB,EAAQ,IAAI,EAAY,IAAI,CAAC;AACnF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { Transaction } from '../../../core';
|
|
3
|
+
interface TabItem {
|
|
4
|
+
label: string;
|
|
5
|
+
ariaLabel?: string;
|
|
6
|
+
}
|
|
7
|
+
interface TransactionDrillDownProps {
|
|
8
|
+
ariaLabel?: string;
|
|
9
|
+
heading?: string;
|
|
10
|
+
subHeadingText?: string;
|
|
11
|
+
icon?: React.ReactNode;
|
|
12
|
+
tabs?: TabItem[];
|
|
13
|
+
selectedIndex: number;
|
|
14
|
+
top: React.ReactNode;
|
|
15
|
+
onSelectionChange?: (selectedIndex: number) => void;
|
|
16
|
+
transactionFilter?: (selectedIndex: number) => (transaction: Transaction) => boolean;
|
|
17
|
+
baseTransactions?: Transaction[];
|
|
18
|
+
}
|
|
19
|
+
export declare const TransactionDrillDown: (({ ariaLabel, heading, subHeadingText, icon, tabs, selectedIndex, top, onSelectionChange, transactionFilter, baseTransactions, }: TransactionDrillDownProps) => import("react/jsx-runtime").JSX.Element) & {
|
|
20
|
+
displayName: string;
|
|
21
|
+
};
|
|
22
|
+
export default TransactionDrillDown;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { useGlobalCopyStore as W, useGlobalUiStore as $, useTransactionStore as j } from "../../../common/context/hooks.es.js";
|
|
2
|
+
import { exportTransactionsToCSV as k } from "../../../core/utils/TransactionUtils.es.js";
|
|
3
|
+
import G from "../../../common/components/Loader.es.js";
|
|
4
|
+
import P from "../../../transactions/components/shared/TransactionList.es.js";
|
|
5
|
+
import "react";
|
|
6
|
+
import { observer as A } from "mobx-react-lite";
|
|
7
|
+
import c from "@mui/material/Stack";
|
|
8
|
+
import { H3 as E, Text as d } from "@mxenabled/mxui";
|
|
9
|
+
import N from "@mui/material/Button";
|
|
10
|
+
import { Icon as R } from "@mxenabled/mx-icons";
|
|
11
|
+
import { jsx as r, jsxs as o } from "react/jsx-runtime";
|
|
12
|
+
import p from "@mui/material/Box";
|
|
13
|
+
import U from "@mui/material/Tab";
|
|
14
|
+
import V from "@mui/material/Tabs";
|
|
15
|
+
var u = "transaction-drill-down-panel", v = (m) => `transaction-details-tab-${m}`, ar = A(function({ ariaLabel: T, heading: i, subHeadingText: n, icon: y, tabs: b, selectedIndex: e, top: C, onSelectionChange: g, transactionFilter: f, baseTransactions: _ }) {
|
|
16
|
+
const { transactions: l } = W(), { isCopyLoaded: w } = $(), { sortedTransactionsWithSplits: D, tags: S, detailedTransactions: L } = j();
|
|
17
|
+
if (!w) return /* @__PURE__ */ r(G, {});
|
|
18
|
+
const s = !!b?.length, B = T ?? l.transactions_title, I = (t, a) => {
|
|
19
|
+
g?.(a);
|
|
20
|
+
}, h = f ? (_ ?? L).filter(f(e)) : void 0, x = h ?? D;
|
|
21
|
+
return /* @__PURE__ */ o(p, {
|
|
22
|
+
sx: {
|
|
23
|
+
bgcolor: "background.paper",
|
|
24
|
+
width: "100%"
|
|
25
|
+
},
|
|
26
|
+
children: [s && /* @__PURE__ */ r(V, {
|
|
27
|
+
"aria-label": B,
|
|
28
|
+
onChange: I,
|
|
29
|
+
value: e,
|
|
30
|
+
variant: "fullWidth",
|
|
31
|
+
children: b.map((t, a) => /* @__PURE__ */ r(U, {
|
|
32
|
+
"aria-controls": u,
|
|
33
|
+
"aria-label": t.ariaLabel,
|
|
34
|
+
id: v(a),
|
|
35
|
+
label: t.label,
|
|
36
|
+
sx: {
|
|
37
|
+
minWidth: "auto",
|
|
38
|
+
px: 0
|
|
39
|
+
}
|
|
40
|
+
}, `${t.label}-${a}`))
|
|
41
|
+
}), /* @__PURE__ */ o(p, {
|
|
42
|
+
"aria-labelledby": s ? v(e) : void 0,
|
|
43
|
+
id: u,
|
|
44
|
+
role: s ? "tabpanel" : void 0,
|
|
45
|
+
children: [
|
|
46
|
+
(i || n) && /* @__PURE__ */ o(c, {
|
|
47
|
+
sx: {
|
|
48
|
+
gap: 4,
|
|
49
|
+
pt: 16,
|
|
50
|
+
px: 24
|
|
51
|
+
},
|
|
52
|
+
children: [i && /* @__PURE__ */ r(E, { children: i }), n && /* @__PURE__ */ o(c, {
|
|
53
|
+
sx: {
|
|
54
|
+
alignItems: "center",
|
|
55
|
+
flexDirection: "row",
|
|
56
|
+
gap: 8
|
|
57
|
+
},
|
|
58
|
+
children: [y, /* @__PURE__ */ r(d, {
|
|
59
|
+
textTransform: "uppercase",
|
|
60
|
+
variant: "body2",
|
|
61
|
+
children: n
|
|
62
|
+
})]
|
|
63
|
+
})]
|
|
64
|
+
}),
|
|
65
|
+
/* @__PURE__ */ r(p, {
|
|
66
|
+
sx: { pt: 16 },
|
|
67
|
+
children: C
|
|
68
|
+
}),
|
|
69
|
+
/* @__PURE__ */ o(c, {
|
|
70
|
+
sx: {
|
|
71
|
+
alignItems: "center",
|
|
72
|
+
borderBottomColor: "divider",
|
|
73
|
+
borderBottomStyle: "solid",
|
|
74
|
+
borderBottomWidth: 1,
|
|
75
|
+
flexDirection: "row",
|
|
76
|
+
justifyContent: "space-between",
|
|
77
|
+
pb: 4,
|
|
78
|
+
pt: 16,
|
|
79
|
+
px: 24
|
|
80
|
+
},
|
|
81
|
+
children: [/* @__PURE__ */ r(d, {
|
|
82
|
+
bold: !0,
|
|
83
|
+
variant: "body1",
|
|
84
|
+
children: l.transactions_title
|
|
85
|
+
}), x.length > 0 && /* @__PURE__ */ r(N, {
|
|
86
|
+
onClick: () => {
|
|
87
|
+
k(x, S);
|
|
88
|
+
},
|
|
89
|
+
startIcon: /* @__PURE__ */ r(R, { name: "ios_share" }),
|
|
90
|
+
sx: { height: 28 },
|
|
91
|
+
children: /* @__PURE__ */ r(d, {
|
|
92
|
+
bold: !0,
|
|
93
|
+
variant: "body2",
|
|
94
|
+
children: l.export_csv_btn
|
|
95
|
+
})
|
|
96
|
+
})]
|
|
97
|
+
}),
|
|
98
|
+
/* @__PURE__ */ r(P, { transaction: h })
|
|
99
|
+
]
|
|
100
|
+
})]
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
export {
|
|
104
|
+
ar as TransactionDrillDown,
|
|
105
|
+
ar as default
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=TransactionDrillDown.es.js.map
|
|
@@ -0,0 +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":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { useInsightsV2Store as E } from "../../../common/context/hooks.es.js";
|
|
2
|
+
import { formatCurrency as M } from "../../../core/utils/NumberFormatting.es.js";
|
|
3
|
+
import { BarChartV2 as N } from "../../components/chartblocks/BarchartV2.es.js";
|
|
4
|
+
import { EmptyBarChart as P } from "../../components/chartblocks/EmptyBarChart.es.js";
|
|
5
|
+
import { TransactionDrillDown as R } from "./TransactionDrillDown.es.js";
|
|
6
|
+
import { useTransactionHistory as q } from "./useTransactionHistory.es.js";
|
|
7
|
+
import { getDefaultSelection as z, getDrillDownConfig as J, getFlattenedDataSeries as O, toStoreFilter as Q } from "./utils.es.js";
|
|
8
|
+
import { useLayoutEffect as U, useState as W } from "react";
|
|
9
|
+
import { observer as X } from "mobx-react-lite";
|
|
10
|
+
import { jsx as m } from "react/jsx-runtime";
|
|
11
|
+
import { useTheme as Y } from "@mui/material/styles";
|
|
12
|
+
var ct = X(({ beat: e }) => {
|
|
13
|
+
const g = Y(), { instanceSlotData: a, beatTransactions: n, primaryTransaction: T, spendCategoryGuids: u, allAccountGuids: p, categoryName: C, displayedDateRange: l, transactionStore: v } = q(e), { actionDrawer: h } = E(), { insights_payload: y } = e, D = h.trigger === "secondaryCta" ? y?.secondary_cta?.variant : y?.primary_cta?.variant, { top: c, filterMode: i, header: S, colors: x, filterStrategy: L } = J(D ?? ""), { dataSeries: s, chartData: o, comparisonBars: B } = O({
|
|
14
|
+
data: a?.data_series,
|
|
15
|
+
ariaLabel: a?.ariaLabel ?? "",
|
|
16
|
+
top: c,
|
|
17
|
+
beatTransactions: n,
|
|
18
|
+
payload: a
|
|
19
|
+
}), { chartBarIndex: I, subTabIndex: _ } = z({
|
|
20
|
+
chartTabCount: o.length,
|
|
21
|
+
comparisonTabCount: B.length,
|
|
22
|
+
actionDrawer: h,
|
|
23
|
+
beatGuid: e.guid
|
|
24
|
+
}), [r, b] = W(I), f = (t) => L({
|
|
25
|
+
beat: e,
|
|
26
|
+
beatTransactions: n,
|
|
27
|
+
dataSeries: s,
|
|
28
|
+
selectedIndex: t,
|
|
29
|
+
subIndex: _,
|
|
30
|
+
isLastTab: t === s.length - 1,
|
|
31
|
+
instanceSlotData: a,
|
|
32
|
+
spendCategoryGuids: u,
|
|
33
|
+
displayedDateRange: l
|
|
34
|
+
}), G = n.map((t) => t.guid).join(","), A = u.join(","), F = p.join(",");
|
|
35
|
+
U(() => {
|
|
36
|
+
i !== "store" || !s.length || v.setFilter(Q(f(r), {
|
|
37
|
+
allAccountGuids: p,
|
|
38
|
+
displayedDateRange: l
|
|
39
|
+
}));
|
|
40
|
+
}, [
|
|
41
|
+
e.guid,
|
|
42
|
+
r,
|
|
43
|
+
i,
|
|
44
|
+
s.length,
|
|
45
|
+
a,
|
|
46
|
+
l,
|
|
47
|
+
A,
|
|
48
|
+
F,
|
|
49
|
+
G
|
|
50
|
+
]);
|
|
51
|
+
const d = S?.({
|
|
52
|
+
htmlTitle: e.html_title,
|
|
53
|
+
primaryTransaction: T,
|
|
54
|
+
categoryName: C,
|
|
55
|
+
selectedDate: o[r]?.date ?? void 0
|
|
56
|
+
}), j = x(g, a?.category_guid), [H, w] = (a?.legends ?? []).map((t) => t.label), K = i === "local" ? (t) => f(t).custom ?? (() => !0) : void 0, V = i === "local" ? n : void 0, k = c === "singleBar" || c === "upcomingBill" ? o.length ? /* @__PURE__ */ m(N, {
|
|
57
|
+
amounts: {
|
|
58
|
+
average: a?.average_amount,
|
|
59
|
+
formattedAverage: M(a?.average_amount ?? 0, "0,0.00")
|
|
60
|
+
},
|
|
61
|
+
color: j[0] ?? g.palette.primary.main,
|
|
62
|
+
data: o,
|
|
63
|
+
legendPosition: "top",
|
|
64
|
+
monthlyAmountLabel: H,
|
|
65
|
+
onBarClick: b,
|
|
66
|
+
selectedTabIndex: r,
|
|
67
|
+
trendAmountLabel: w
|
|
68
|
+
}) : /* @__PURE__ */ m(P, {}) : null;
|
|
69
|
+
return /* @__PURE__ */ m(R, {
|
|
70
|
+
ariaLabel: a?.ariaLabel,
|
|
71
|
+
baseTransactions: V,
|
|
72
|
+
heading: d?.heading,
|
|
73
|
+
icon: d?.icon,
|
|
74
|
+
onSelectionChange: b,
|
|
75
|
+
selectedIndex: r,
|
|
76
|
+
subHeadingText: d?.subHeadingText,
|
|
77
|
+
tabs: o.map((t) => ({
|
|
78
|
+
ariaLabel: t.ariaLabel,
|
|
79
|
+
label: t.label
|
|
80
|
+
})),
|
|
81
|
+
top: k,
|
|
82
|
+
transactionFilter: K
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
export {
|
|
86
|
+
ct as TransactionHistoryBlock
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=TransactionHistoryBlock.es.js.map
|
package/dist/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TransactionHistoryBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.tsx"],"sourcesContent":["import { useLayoutEffect, useState } from 'react'\n\nimport { useTheme } from '@mui/material/styles'\nimport { observer } from 'mobx-react-lite'\n\nimport type { Beat, DataSeries, Transaction } from '../../../core'\nimport { formatCurrency } from '../../../core/utils/NumberFormatting'\nimport { BarChartV2 } from '../../components/chartblocks/BarchartV2'\nimport { EmptyBarChart } from '../../components/chartblocks/EmptyBarChart'\n\nimport { TransactionDrillDown } from './TransactionDrillDown'\nimport { useTransactionHistory } from './useTransactionHistory'\nimport {\n getDefaultSelection,\n getDrillDownConfig,\n getFlattenedDataSeries,\n toStoreFilter,\n} from './utils'\nimport { useInsightsV2Store } from '../../../common'\n\ninterface TransactionHistoryProp {\n beat: Beat\n}\n\nexport const TransactionHistoryBlock = observer(({ beat }: TransactionHistoryProp) => {\n const theme = useTheme()\n const {\n instanceSlotData,\n beatTransactions,\n primaryTransaction,\n spendCategoryGuids,\n allAccountGuids,\n categoryName,\n displayedDateRange,\n transactionStore,\n } = useTransactionHistory(beat)\n\n const { actionDrawer } = useInsightsV2Store()\n\n const { insights_payload } = beat\n\n const dynamicCtaVariant =\n actionDrawer.trigger === 'secondaryCta'\n ? insights_payload?.secondary_cta?.variant\n : insights_payload?.primary_cta?.variant\n\n const { top, filterMode, header, colors, filterStrategy } = getDrillDownConfig(\n dynamicCtaVariant ?? '',\n )\n\n const { dataSeries, chartData, comparisonBars } = getFlattenedDataSeries({\n data: instanceSlotData?.data_series as DataSeries,\n ariaLabel: instanceSlotData?.ariaLabel ?? '',\n top,\n beatTransactions,\n payload: instanceSlotData,\n })\n\n const { chartBarIndex, subTabIndex } = getDefaultSelection({\n chartTabCount: chartData.length,\n comparisonTabCount: comparisonBars.length,\n actionDrawer,\n beatGuid: beat.guid,\n })\n\n const [selectedIndex, setSelectedIndex] = useState(chartBarIndex)\n\n const resolveFilter = (index: number) =>\n filterStrategy({\n beat,\n beatTransactions,\n dataSeries,\n selectedIndex: index,\n subIndex: subTabIndex,\n isLastTab: index === dataSeries.length - 1,\n instanceSlotData,\n spendCategoryGuids,\n displayedDateRange,\n })\n\n // Apply the current selection's filter. Store variants route through the store filter; local\n // (upcomingBill) variants filter beatTransactions directly and only backfill the cache when the\n // Stable primitive keys for the collections below: beatTransactions/spendCategoryGuids/\n // allAccountGuids are recomputed (new array identity) every render, so depending on them directly\n // re-fires the effect each render (REVIEW.md MEW-3732). Key on content instead.\n const beatTransactionGuidsKey = beatTransactions.map((transaction) => transaction.guid).join(',')\n const spendCategoryGuidsKey = spendCategoryGuids.join(',')\n const allAccountGuidsKey = allAccountGuids.join(',')\n\n // store variants route the selection through the shared store filter; local (upcomingBill) variants\n // filter beatTransactions directly, so there's nothing to push to the store for them.\n useLayoutEffect(() => {\n if (filterMode !== 'store' || !dataSeries.length) return\n transactionStore.setFilter(\n toStoreFilter(resolveFilter(selectedIndex), { allAccountGuids, displayedDateRange }),\n )\n }, [\n beat.guid,\n selectedIndex,\n filterMode,\n dataSeries.length,\n instanceSlotData,\n displayedDateRange,\n spendCategoryGuidsKey,\n allAccountGuidsKey,\n beatTransactionGuidsKey,\n ])\n\n const headerContent = header?.({\n htmlTitle: beat.html_title,\n primaryTransaction,\n categoryName,\n selectedDate: chartData[selectedIndex]?.date ?? undefined,\n })\n\n const barColors = colors(theme, instanceSlotData?.category_guid)\n const [monthlyAmountLabel, trendAmountLabel] = (instanceSlotData?.legends ?? []).map(\n (legend) => legend.label,\n )\n\n const transactionFilter =\n filterMode === 'local'\n ? (index: number) => resolveFilter(index).custom ?? (() => true)\n : undefined\n\n const baseTransactions: Transaction[] | undefined =\n filterMode === 'local' ? beatTransactions : undefined\n\n const isBarTop = top === 'singleBar' || top === 'upcomingBill'\n const chartTop = !isBarTop ? null : chartData.length ? (\n <BarChartV2\n amounts={{\n average: instanceSlotData?.average_amount,\n formattedAverage: formatCurrency(instanceSlotData?.average_amount ?? 0, '0,0.00'),\n }}\n color={barColors[0] ?? theme.palette.primary.main}\n data={chartData}\n legendPosition=\"top\"\n monthlyAmountLabel={monthlyAmountLabel}\n onBarClick={setSelectedIndex}\n selectedTabIndex={selectedIndex}\n trendAmountLabel={trendAmountLabel}\n />\n ) : (\n <EmptyBarChart />\n )\n\n return (\n <TransactionDrillDown\n ariaLabel={instanceSlotData?.ariaLabel}\n baseTransactions={baseTransactions}\n heading={headerContent?.heading}\n icon={headerContent?.icon}\n onSelectionChange={setSelectedIndex}\n selectedIndex={selectedIndex}\n subHeadingText={headerContent?.subHeadingText}\n tabs={chartData.map((bar) => ({\n ariaLabel: bar.ariaLabel,\n label: bar.label,\n }))}\n top={chartTop}\n transactionFilter={transactionFilter}\n />\n )\n})\n"],"mappings":";;;;;;;;;;;AAwBA,IAAa,KAA0B,EAAA,CAAU,EAAE,MAAA,EAAA,MAAmC;AACpF,QAAM,IAAQ,EAAS,GACjB,EACJ,kBAAA,GACA,kBAAA,GACA,oBAAA,GACA,oBAAA,GACA,iBAAA,GACA,cAAA,GACA,oBAAA,GACA,kBAAA,EAAA,IACE,EAAsB,CAAI,GAExB,EAAE,cAAA,EAAA,IAAiB,EAAmB,GAEtC,EAAE,kBAAA,EAAA,IAAqB,GAEvB,IACJ,EAAa,YAAY,iBACrB,GAAkB,eAAe,UACjC,GAAkB,aAAa,SAE/B,EAAE,KAAA,GAAK,YAAA,GAAY,QAAA,GAAQ,QAAA,GAAQ,gBAAA,EAAA,IAAmB,EAC1D,KAAqB,EACvB,GAEM,EAAE,YAAA,GAAY,WAAA,GAAW,gBAAA,EAAA,IAAmB,EAAuB;AAAA,IACvE,MAAM,GAAkB;AAAA,IACxB,WAAW,GAAkB,aAAa;AAAA,IAC1C,KAAA;AAAA,IACA,kBAAA;AAAA,IACA,SAAS;AAAA,EACX,CAAC,GAEK,EAAE,eAAA,GAAe,aAAA,EAAA,IAAgB,EAAoB;AAAA,IACzD,eAAe,EAAU;AAAA,IACzB,oBAAoB,EAAe;AAAA,IACnC,cAAA;AAAA,IACA,UAAU,EAAK;AAAA,EACjB,CAAC,GAEK,CAAC,GAAe,CAAA,IAAoB,EAAS,CAAa,GAE1D,IAAA,CAAiB,MACrB,EAAe;AAAA,IACb,MAAA;AAAA,IACA,kBAAA;AAAA,IACA,YAAA;AAAA,IACA,eAAe;AAAA,IACf,UAAU;AAAA,IACV,WAAW,MAAU,EAAW,SAAS;AAAA,IACzC,kBAAA;AAAA,IACA,oBAAA;AAAA,IACA,oBAAA;AAAA,EACF,CAAC,GAOG,IAA0B,EAAiB,IAAA,CAAK,MAAgB,EAAY,IAAI,EAAE,KAAK,GAAG,GAC1F,IAAwB,EAAmB,KAAK,GAAG,GACnD,IAAqB,EAAgB,KAAK,GAAG;AAInD,EAAA,EAAA,MAAsB;AACpB,IAAI,MAAe,WAAW,CAAC,EAAW,UAC1C,EAAiB,UACf,EAAc,EAAc,CAAa,GAAG;AAAA,MAAE,iBAAA;AAAA,MAAiB,oBAAA;AAAA,IAAmB,CAAC,CACrF;AAAA,EACF,GAAG;AAAA,IACD,EAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,IAAgB,IAAS;AAAA,IAC7B,WAAW,EAAK;AAAA,IAChB,oBAAA;AAAA,IACA,cAAA;AAAA,IACA,cAAc,EAAU,CAAA,GAAgB,QAAQ;AAAA,EAClD,CAAC,GAEK,IAAY,EAAO,GAAO,GAAkB,aAAa,GACzD,CAAC,GAAoB,CAAA,KAAqB,GAAkB,WAAW,CAAC,GAAG,IAAA,CAC9E,MAAW,EAAO,KACrB,GAEM,IACJ,MAAe,UAAA,CACV,MAAkB,EAAc,CAAK,EAAE,WAAA,MAAiB,MACzD,QAEA,IACJ,MAAe,UAAU,IAAmB,QAGxC,IADW,MAAQ,eAAe,MAAQ,iBACZ,EAAU,SAC5C,gBAAA,EAAC,GAAD;AAAA,IACE,SAAS;AAAA,MACP,SAAS,GAAkB;AAAA,MAC3B,kBAAkB,EAAe,GAAkB,kBAAkB,GAAG,QAAQ;AAAA,IAClF;AAAA,IACA,OAAO,EAAU,CAAA,KAAM,EAAM,QAAQ,QAAQ;AAAA,IAC7C,MAAM;AAAA,IACN,gBAAe;AAAA,IACK,oBAAA;AAAA,IACpB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IACA,kBAAA;AAAA,EACnB,CAAA,IAED,gBAAA,EAAC,GAAD,CAAgB,CAAA,IAfW;AAkB7B,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,WAAW,GAAkB;AAAA,IACX,kBAAA;AAAA,IAClB,SAAS,GAAe;AAAA,IACxB,MAAM,GAAe;AAAA,IACrB,mBAAmB;AAAA,IACJ,eAAA;AAAA,IACf,gBAAgB,GAAe;AAAA,IAC/B,MAAM,EAAU,IAAA,CAAK,OAAS;AAAA,MAC5B,WAAW,EAAI;AAAA,MACf,OAAO,EAAI;AAAA,IACb,EAAE;AAAA,IACF,KAAK;AAAA,IACc,mBAAA;AAAA,EACpB,CAAA;AAEL,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { Theme } from '@mui/material/styles';
|
|
3
|
+
import { Beat, Transaction } from '../../../core';
|
|
4
|
+
import { TransactionFilter } from '../../../core/stores/TransactionStore';
|
|
5
|
+
import { InsightsInstanceSlotData } from '../../../core/types/InsightsInstanceSlotData';
|
|
6
|
+
import { ChartDataSeriesItem } from '../../blocks';
|
|
7
|
+
export interface DrillDownHeader {
|
|
8
|
+
heading?: string;
|
|
9
|
+
subHeadingText?: string;
|
|
10
|
+
icon?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export interface DrillDownHeaderContext {
|
|
13
|
+
htmlTitle?: string;
|
|
14
|
+
primaryTransaction?: Transaction;
|
|
15
|
+
categoryName: string;
|
|
16
|
+
selectedDate?: string | Date;
|
|
17
|
+
}
|
|
18
|
+
export declare const DRILLDOWN_VARIANTS: {
|
|
19
|
+
readonly TRANSACTION: "bill_amount_not_standard";
|
|
20
|
+
readonly CATEGORY_SPEND: "category_spend";
|
|
21
|
+
readonly MONTHLY_SPEND: "monthly_spend_comparison";
|
|
22
|
+
readonly ACCOUNT_BALANCE: "savings_account_balances_summary";
|
|
23
|
+
readonly UPCOMING_BILL: "upcoming_bill";
|
|
24
|
+
readonly SPEND_TO_INCOME: "monthly_spend_to_income";
|
|
25
|
+
readonly SAVINGS_TO_INCOME: "monthly_savings_to_income";
|
|
26
|
+
readonly DEBT_TO_INCOME: "monthly_debt_to_income";
|
|
27
|
+
readonly COST_OF_LIVING: "cost_living_to_income";
|
|
28
|
+
readonly NON_ESSENTIAL_CATEGORY: "non_essential_category_summary";
|
|
29
|
+
readonly DEPOSIT_SUMMARY: "monthly_deposit_summary";
|
|
30
|
+
};
|
|
31
|
+
export type DrillDownVariant = (typeof DRILLDOWN_VARIANTS)[keyof typeof DRILLDOWN_VARIANTS];
|
|
32
|
+
/**
|
|
33
|
+
* One row of the flattened data_series a filterStrategy indexes into: a single-bar monthly total or a
|
|
34
|
+
* synthesized upcoming-bill bar. Fields are optional because the backend keys each row dynamically
|
|
35
|
+
* from data_series.names and not every variant carries a guid/category. Double-bar comparison rows
|
|
36
|
+
* will extend this in the next MR.
|
|
37
|
+
*/
|
|
38
|
+
export type ColorKind = (theme: Theme, categoryGuid?: string) => string[];
|
|
39
|
+
export type HeaderKind = (ctx: DrillDownHeaderContext) => DrillDownHeader;
|
|
40
|
+
/**
|
|
41
|
+
* Everything a filterStrategy needs to turn the currently-selected bar/sub-tab into a
|
|
42
|
+
* TransactionFilter. Data-only so strategies stay pure and testable.
|
|
43
|
+
*/
|
|
44
|
+
export interface FilterContext {
|
|
45
|
+
beat: Beat;
|
|
46
|
+
beatTransactions: Transaction[];
|
|
47
|
+
dataSeries: ChartDataSeriesItem[];
|
|
48
|
+
selectedIndex: number;
|
|
49
|
+
subIndex: number;
|
|
50
|
+
isLastTab: boolean;
|
|
51
|
+
instanceSlotData: InsightsInstanceSlotData;
|
|
52
|
+
spendCategoryGuids: string[];
|
|
53
|
+
displayedDateRange: {
|
|
54
|
+
start: Date;
|
|
55
|
+
end: Date;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export type FilterStrategy = (ctx: FilterContext) => TransactionFilter;
|
|
59
|
+
export interface DrillDownVariantConfig {
|
|
60
|
+
top: 'singleBar' | 'upcomingBill' | 'doubleBar' | 'tabsOnly';
|
|
61
|
+
filterStrategy: FilterStrategy;
|
|
62
|
+
colors: ColorKind;
|
|
63
|
+
header?: HeaderKind;
|
|
64
|
+
scope: 'store' | 'beat';
|
|
65
|
+
filterMode: 'store' | 'local';
|
|
66
|
+
}
|
|
67
|
+
export declare const layout: Partial<Record<DrillDownVariant, DrillDownVariantConfig>>;
|
|
68
|
+
export declare const FALLBACK: DrillDownVariantConfig;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { DATE_FORMATS_INTL as p, formatDate as u } from "../../../core/constants/DateFormats.es.js";
|
|
2
|
+
import { getCategoryColor as y } from "../../../core/utils/CategoryUtil.es.js";
|
|
3
|
+
import { MerchantLogo as N } from "@mxenabled/mxui";
|
|
4
|
+
import { Icon as T } from "@mxenabled/mx-icons";
|
|
5
|
+
import { jsx as g } from "react/jsx-runtime";
|
|
6
|
+
import { endOfMonth as S, startOfMonth as O } from "date-fns";
|
|
7
|
+
var i = {
|
|
8
|
+
TRANSACTION: "bill_amount_not_standard",
|
|
9
|
+
CATEGORY_SPEND: "category_spend",
|
|
10
|
+
MONTHLY_SPEND: "monthly_spend_comparison",
|
|
11
|
+
ACCOUNT_BALANCE: "savings_account_balances_summary",
|
|
12
|
+
UPCOMING_BILL: "upcoming_bill",
|
|
13
|
+
SPEND_TO_INCOME: "monthly_spend_to_income",
|
|
14
|
+
SAVINGS_TO_INCOME: "monthly_savings_to_income",
|
|
15
|
+
DEBT_TO_INCOME: "monthly_debt_to_income",
|
|
16
|
+
COST_OF_LIVING: "cost_living_to_income",
|
|
17
|
+
NON_ESSENTIAL_CATEGORY: "non_essential_category_summary",
|
|
18
|
+
DEPOSIT_SUMMARY: "monthly_deposit_summary"
|
|
19
|
+
}, c = (e, t) => t && y(t, e) || e.palette.primary.main, _ = (e) => ({
|
|
20
|
+
start: O(new Date(e ?? NaN)),
|
|
21
|
+
end: S(new Date(e ?? NaN))
|
|
22
|
+
}), d = (e) => e?.length ? { accounts: e } : {}, l = ({ beatTransactions: e, dataSeries: t, selectedIndex: n }) => {
|
|
23
|
+
const o = t[n], r = o?.guid, a = e.find((s) => s.guid === r)?.has_been_split;
|
|
24
|
+
return {
|
|
25
|
+
custom: (s) => s.guid === r,
|
|
26
|
+
dateRange: _(o?.date),
|
|
27
|
+
showSplits: !a
|
|
28
|
+
};
|
|
29
|
+
}, I = ({ dataSeries: e, selectedIndex: t, instanceSlotData: n }) => {
|
|
30
|
+
const o = e[t], r = n.category_guid ?? o?.guid;
|
|
31
|
+
return {
|
|
32
|
+
custom: (a) => a.category_guid === r || a.top_level_category_guid === r,
|
|
33
|
+
dateRange: _(o?.date)
|
|
34
|
+
};
|
|
35
|
+
}, f = ({ dataSeries: e, selectedIndex: t, spendCategoryGuids: n, instanceSlotData: o }) => {
|
|
36
|
+
const r = e[t];
|
|
37
|
+
return {
|
|
38
|
+
custom: (a) => !!a.top_level_category_guid && n.includes(a.top_level_category_guid),
|
|
39
|
+
dateRange: _(r?.date),
|
|
40
|
+
...d(o.account_guids)
|
|
41
|
+
};
|
|
42
|
+
}, A = ({ beat: e, dataSeries: t, selectedIndex: n, isLastTab: o, instanceSlotData: r }) => {
|
|
43
|
+
const a = t[n], { start: s, end: m } = _(a?.date);
|
|
44
|
+
return {
|
|
45
|
+
dateRange: {
|
|
46
|
+
start: s,
|
|
47
|
+
end: o && e.created_at ? new Date(e.created_at) : m
|
|
48
|
+
},
|
|
49
|
+
...d(r.account_guids)
|
|
50
|
+
};
|
|
51
|
+
}, L = {
|
|
52
|
+
[i.TRANSACTION]: {
|
|
53
|
+
top: "singleBar",
|
|
54
|
+
scope: "store",
|
|
55
|
+
filterMode: "store",
|
|
56
|
+
filterStrategy: l,
|
|
57
|
+
colors: (e, t) => [c(e, t)],
|
|
58
|
+
header: (e) => ({
|
|
59
|
+
heading: e.htmlTitle,
|
|
60
|
+
subHeadingText: e.primaryTransaction?.description || void 0,
|
|
61
|
+
icon: /* @__PURE__ */ g(N, {
|
|
62
|
+
alt: e.primaryTransaction?.description,
|
|
63
|
+
categoryGuid: e.primaryTransaction?.category_guid || "",
|
|
64
|
+
merchantGuid: e.primaryTransaction?.merchant_guid || "",
|
|
65
|
+
size: 16
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
},
|
|
69
|
+
[i.CATEGORY_SPEND]: {
|
|
70
|
+
top: "singleBar",
|
|
71
|
+
filterStrategy: I,
|
|
72
|
+
scope: "store",
|
|
73
|
+
filterMode: "store",
|
|
74
|
+
colors: (e, t) => [c(e, t)],
|
|
75
|
+
header: (e) => ({
|
|
76
|
+
heading: e.categoryName,
|
|
77
|
+
subHeadingText: e.selectedDate && u(e.selectedDate, p.MONTH_LONG) || "",
|
|
78
|
+
icon: /* @__PURE__ */ g(T, {
|
|
79
|
+
name: "calendar_month",
|
|
80
|
+
size: 16
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
},
|
|
84
|
+
[i.MONTHLY_SPEND]: {
|
|
85
|
+
top: "singleBar",
|
|
86
|
+
filterStrategy: f,
|
|
87
|
+
scope: "store",
|
|
88
|
+
filterMode: "store",
|
|
89
|
+
colors: (e) => [e.palette.chart.chart2 ?? e.palette.primary.main]
|
|
90
|
+
},
|
|
91
|
+
[i.ACCOUNT_BALANCE]: {
|
|
92
|
+
top: "singleBar",
|
|
93
|
+
filterStrategy: A,
|
|
94
|
+
scope: "store",
|
|
95
|
+
filterMode: "store",
|
|
96
|
+
colors: (e) => [e.palette.success.main]
|
|
97
|
+
},
|
|
98
|
+
[i.UPCOMING_BILL]: {
|
|
99
|
+
top: "upcomingBill",
|
|
100
|
+
filterStrategy: l,
|
|
101
|
+
scope: "beat",
|
|
102
|
+
filterMode: "local",
|
|
103
|
+
colors: (e, t) => [c(e, t)]
|
|
104
|
+
}
|
|
105
|
+
}, R = {
|
|
106
|
+
top: "singleBar",
|
|
107
|
+
filterStrategy: l,
|
|
108
|
+
scope: "store",
|
|
109
|
+
filterMode: "store",
|
|
110
|
+
colors: (e, t) => [c(e, t)]
|
|
111
|
+
};
|
|
112
|
+
export {
|
|
113
|
+
i as DRILLDOWN_VARIANTS,
|
|
114
|
+
R as FALLBACK,
|
|
115
|
+
L as layout
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=layout.es.js.map
|