@mx-cartographer/experiences 9.4.68 → 9.4.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cashflow/context/hooks.d.ts +3 -0
  3. package/dist/core/stores/CashflowStore.d.ts +3 -0
  4. package/dist/core/stores/CashflowStore.es.js +9 -0
  5. package/dist/core/stores/CashflowStore.es.js.map +1 -1
  6. package/dist/core/types/localization/InsightsFeedCopy.d.ts +15 -0
  7. package/dist/core/types/localization/index.d.ts +1 -1
  8. package/dist/insights-v2/actionBlocks/RecurringTransactionBlock/index.d.ts +1 -1
  9. package/dist/insights-v2/actionBlocks/RemainingCashBlock/RemainingCashBlock.d.ts +11 -0
  10. package/dist/insights-v2/actionBlocks/RemainingCashBlock/RemainingCashBlock.es.js +89 -0
  11. package/dist/insights-v2/actionBlocks/RemainingCashBlock/RemainingCashBlock.es.js.map +1 -0
  12. package/dist/insights-v2/actionBlocks/RemainingCashBlock/RemainingCashContent.d.ts +32 -0
  13. package/dist/insights-v2/actionBlocks/RemainingCashBlock/RemainingCashContent.es.js +169 -0
  14. package/dist/insights-v2/actionBlocks/RemainingCashBlock/RemainingCashContent.es.js.map +1 -0
  15. package/dist/insights-v2/actionBlocks/RemainingCashBlock/index.d.ts +1 -0
  16. package/dist/insights-v2/actionBlocks/RemainingCashBlock/layout.d.ts +27 -0
  17. package/dist/insights-v2/actionBlocks/RemainingCashBlock/layout.es.js +26 -0
  18. package/dist/insights-v2/actionBlocks/RemainingCashBlock/layout.es.js.map +1 -0
  19. package/dist/insights-v2/mappings/actionBlocksKey.d.ts +1 -0
  20. package/dist/insights-v2/mappings/actionBlocksKey.es.js +2 -1
  21. package/dist/insights-v2/mappings/actionBlocksKey.es.js.map +1 -1
  22. package/dist/insights-v2/mappings/blocks.es.js +48 -42
  23. package/dist/insights-v2/mappings/blocks.es.js.map +1 -1
  24. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [9.4.69] - 10-09-2026
2
+
3
+ - **ADDED** - `remaining_cash_block` (Remaining Cash) action block for the Payday Cash Left Over Status beat: summary card (remaining until payday, days, cash on hand, upcoming expenses) plus cash accounts and recurring expenses before payday, each capped at two rows with an "Other (#)" row. Store-driven from `CashflowStore`; loads through `useRecurringTransactionPrepare` with an `ErrorCard` retry on failure (WEC-1880)
4
+ - **ADDED** - `CashflowStore.uiStore` computeds `upcomingExpensesTotal`, `remainingUntilPayday`, `hasUpcomingPayday`; `insights_feed.remaining_cash` copy (WEC-1880)
5
+ - **ADDED** - Payday Cash Left Over Status beat fixtures, `InsightsV2/ActionBlock/RemainingCashBlock` stories, and `docs/action-blocks/remaining-cash-block.md` (WEC-1880)
6
+
1
7
  ## [9.4.68] - 10-09-2026
2
8
 
3
9
  - **ADDED** - `transaction_list_block` (Transaction List) action block: opens a date-grouped drawer of the transactions a beat points at, with a nested Transaction Details drawer stacked on row click. Resolves rows via `instance_slot_data.transaction_guids` (id-list path), guarded by `Array.isArray` at the untrusted-payload boundary. `usePrepare` shares `useTransactionDetailsPrepare` so `detailedTransactions` is loaded on open — the drawer never opens on a permanent spinner. The registry entry titles the drawer from `insights_payload.title` (matching the WEC-1804 move off `beat.html_title`, which carries HTML entities); when the resolver returns an empty string, `ActionBlockLayer` falls back to the CTA label. Nested close clears the shared `transaction_guid` from action context, matching the sibling `TransactionHistoryBlock` convention. Only the `Standard` variant ships in this MR; the other three variants (`w/Summary`, `w/Status`, `w/Help`) are deferred to a follow-up MR after Figma review surfaced structural mismatches. Unblocks WEC-1461 and WEC-1462. (WEC-1425)
@@ -13,4 +13,7 @@ export declare const useCashflowUiStore: () => {
13
13
  get selectedCashBalance(): number;
14
14
  get daysUntilNextIncome(): number;
15
15
  get expensesTilNextIncome(): import('../../core').Recurrence[];
16
+ get upcomingExpensesTotal(): number;
17
+ get remainingUntilPayday(): number;
18
+ get hasUpcomingPayday(): boolean;
16
19
  };
@@ -22,5 +22,8 @@ declare class UiStore {
22
22
  get selectedCashBalance(): number;
23
23
  get daysUntilNextIncome(): number;
24
24
  get expensesTilNextIncome(): Recurrence[];
25
+ get upcomingExpensesTotal(): number;
26
+ get remainingUntilPayday(): number;
27
+ get hasUpcomingPayday(): boolean;
25
28
  }
26
29
  export {};
@@ -54,6 +54,15 @@ var f = class {
54
54
  get expensesTilNextIncome() {
55
55
  return this.upcomingExpenses.filter((e) => c(e.expectedDate, this.nextIncome?.expectedDate || i(/* @__PURE__ */ new Date())));
56
56
  }
57
+ get upcomingExpensesTotal() {
58
+ return this.expensesTilNextIncome.reduce((e, t) => e + t.amount, 0);
59
+ }
60
+ get remainingUntilPayday() {
61
+ return this.selectedCashBalance - this.upcomingExpensesTotal;
62
+ }
63
+ get hasUpcomingPayday() {
64
+ return this.nextIncome !== void 0;
65
+ }
57
66
  };
58
67
  export {
59
68
  f as CashflowStore
@@ -1 +1 @@
1
- {"version":3,"file":"CashflowStore.es.js","names":[],"sources":["../../../src/core/stores/CashflowStore.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\nimport { addDays } from 'date-fns/addDays'\nimport { differenceInDays } from 'date-fns/differenceInDays'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { isBefore } from 'date-fns/isBefore'\nimport { startOfToday } from 'date-fns/startOfToday'\n\nimport type { Account, Recurrence, UserProfile } from '../types'\nimport { getAccountStartingBalance } from '../utils/AccountUtils'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class CashflowStore {\n globalStore: GlobalStore\n uiStore: UiStore\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.uiStore = new UiStore(globalStore)\n\n makeAutoObservable(this)\n }\n\n completeOnboarding = async () => {\n const updatedUserProfile = {\n ...this.globalStore.userStore.userProfile,\n has_completed_cash_flow_onboarding: true,\n } as UserProfile\n\n await this.globalStore.userStore.updateUserProfile(updatedUserProfile)\n }\n}\n\nclass UiStore {\n globalStore: GlobalStore\n\n // Cashflow is hard-coded to display 30 days starting from today. This is the\n // single source of truth for Cash Flow's window; it intentionally does NOT\n // mutate RecurringTransactionsStore.dateRange, so Cash Flow stays decoupled\n // from other widgets (e.g. Recurring Transactions) that drive that shared range.\n dateRange = { start: startOfToday(), end: addDays(startOfToday(), 30) }\n isDirty = false\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n\n makeAutoObservable(this)\n }\n\n // Recurrence data scoped to Cash Flow's own dateRange, sourced from the\n // range-parameterized helpers on RecurringTransactionsStore. Computeds (not\n // component state) per the project's MobX conventions.\n get income(): Recurrence[] {\n return this.globalStore.recurringTransactionsStore.incomeForRange(this.dateRange)\n }\n\n get upcomingIncome(): Recurrence[] {\n return this.globalStore.recurringTransactionsStore.upcomingIncomeForRange(this.dateRange)\n }\n\n get upcomingExpenses(): Recurrence[] {\n return this.globalStore.recurringTransactionsStore.upcomingExpensesForRange(this.dateRange)\n }\n\n get nextIncome(): Recurrence | undefined {\n return this.globalStore.recurringTransactionsStore.nextIncomeForRange(this.dateRange)\n }\n\n // Visible cash accounts that are currently selected in the account filter.\n // Computed (single source of truth) so it stays in sync with account data and\n // the filter without effect-based syncing in components.\n get selectedCashAccounts(): Account[] {\n const { selectedAccountGuids } = this.globalStore.globalUiStore\n return this.globalStore.accountStore.visibleCashAccounts.filter((account) =>\n selectedAccountGuids.includes(account.guid),\n )\n }\n\n // Total spendable/starting balance across the selected cash accounts, using\n // the shared per-account balance rule (available vs current balance).\n get selectedCashBalance(): number {\n const showAvailableBalance =\n this.globalStore.appConfig.config.display_available_balance_in_accounts\n return this.selectedCashAccounts.reduce(\n (total, account) => total + getAccountStartingBalance(account, showAvailableBalance),\n 0,\n )\n }\n // Returns the number of days until the next income activity or 0 if there is no income activity\n get daysUntilNextIncome() {\n return this.nextIncome\n ? Math.abs(differenceInDays(startOfToday(), this.nextIncome.expectedDate))\n : 0\n }\n\n // Returns the expenses (Activities) until the next income activity or the end of the month\n // if there is no income activity\n get expensesTilNextIncome() {\n return this.upcomingExpenses.filter((a) =>\n isBefore(a.expectedDate, this.nextIncome?.expectedDate || endOfMonth(new Date())),\n )\n }\n}\n"],"mappings":";;;;;;;AAYA,IAAa,IAAb,MAA2B;AAAA,EACzB;AAAA,EACA;AAAA,EAEA,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,UAAU,IAAI,EAAQ,CAAW,GAEtC,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,qBAAqB,YAAY;AAC/B,UAAM,IAAqB;AAAA,MACzB,GAAG,KAAK,YAAY,UAAU;AAAA,MAC9B,oCAAoC;AAAA,IACtC;AAEA,UAAM,KAAK,YAAY,UAAU,kBAAkB,CAAkB;AAAA,EACvE;AACF,GAEM,IAAN,MAAc;AAAA,EACZ;AAAA,EAMA,YAAY;AAAA,IAAE,OAAO,EAAa;AAAA,IAAG,KAAK,EAAQ,EAAa,GAAG,EAAE;AAAA,EAAE;AAAA,EACtE,UAAU;AAAA,EAEV,YAAY,GAA0B;AACpC,SAAK,cAAc,GAEnB,EAAmB,IAAI;AAAA,EACzB;AAAA,EAKA,IAAI,SAAuB;AACzB,WAAO,KAAK,YAAY,2BAA2B,eAAe,KAAK,SAAS;AAAA,EAClF;AAAA,EAEA,IAAI,iBAA+B;AACjC,WAAO,KAAK,YAAY,2BAA2B,uBAAuB,KAAK,SAAS;AAAA,EAC1F;AAAA,EAEA,IAAI,mBAAiC;AACnC,WAAO,KAAK,YAAY,2BAA2B,yBAAyB,KAAK,SAAS;AAAA,EAC5F;AAAA,EAEA,IAAI,aAAqC;AACvC,WAAO,KAAK,YAAY,2BAA2B,mBAAmB,KAAK,SAAS;AAAA,EACtF;AAAA,EAKA,IAAI,uBAAkC;AACpC,UAAM,EAAE,sBAAA,EAAA,IAAyB,KAAK,YAAY;AAClD,WAAO,KAAK,YAAY,aAAa,oBAAoB,OAAA,CAAQ,MAC/D,EAAqB,SAAS,EAAQ,IAAI,CAC5C;AAAA,EACF;AAAA,EAIA,IAAI,sBAA8B;AAChC,UAAM,IACJ,KAAK,YAAY,UAAU,OAAO;AACpC,WAAO,KAAK,qBAAqB,OAAA,CAC9B,GAAO,MAAY,IAAQ,EAA0B,GAAS,CAAoB,GACnF,CACF;AAAA,EACF;AAAA,EAEA,IAAI,sBAAsB;AACxB,WAAO,KAAK,aACR,KAAK,IAAI,EAAiB,EAAa,GAAG,KAAK,WAAW,YAAY,CAAC,IACvE;AAAA,EACN;AAAA,EAIA,IAAI,wBAAwB;AAC1B,WAAO,KAAK,iBAAiB,OAAA,CAAQ,MACnC,EAAS,EAAE,cAAc,KAAK,YAAY,gBAAgB,EAAW,oBAAI,KAAK,CAAC,CAAC,CAClF;AAAA,EACF;AACF"}
1
+ {"version":3,"file":"CashflowStore.es.js","names":[],"sources":["../../../src/core/stores/CashflowStore.ts"],"sourcesContent":["import { makeAutoObservable } from 'mobx'\nimport { addDays } from 'date-fns/addDays'\nimport { differenceInDays } from 'date-fns/differenceInDays'\nimport { endOfMonth } from 'date-fns/endOfMonth'\nimport { isBefore } from 'date-fns/isBefore'\nimport { startOfToday } from 'date-fns/startOfToday'\n\nimport type { Account, Recurrence, UserProfile } from '../types'\nimport { getAccountStartingBalance } from '../utils/AccountUtils'\n\nimport { GlobalStore } from './GlobalStore'\n\nexport class CashflowStore {\n globalStore: GlobalStore\n uiStore: UiStore\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n this.uiStore = new UiStore(globalStore)\n\n makeAutoObservable(this)\n }\n\n completeOnboarding = async () => {\n const updatedUserProfile = {\n ...this.globalStore.userStore.userProfile,\n has_completed_cash_flow_onboarding: true,\n } as UserProfile\n\n await this.globalStore.userStore.updateUserProfile(updatedUserProfile)\n }\n}\n\nclass UiStore {\n globalStore: GlobalStore\n\n // Cashflow is hard-coded to display 30 days starting from today. This is the\n // single source of truth for Cash Flow's window; it intentionally does NOT\n // mutate RecurringTransactionsStore.dateRange, so Cash Flow stays decoupled\n // from other widgets (e.g. Recurring Transactions) that drive that shared range.\n dateRange = { start: startOfToday(), end: addDays(startOfToday(), 30) }\n isDirty = false\n\n constructor(globalStore: GlobalStore) {\n this.globalStore = globalStore\n\n makeAutoObservable(this)\n }\n\n // Recurrence data scoped to Cash Flow's own dateRange, sourced from the\n // range-parameterized helpers on RecurringTransactionsStore. Computeds (not\n // component state) per the project's MobX conventions.\n get income(): Recurrence[] {\n return this.globalStore.recurringTransactionsStore.incomeForRange(this.dateRange)\n }\n\n get upcomingIncome(): Recurrence[] {\n return this.globalStore.recurringTransactionsStore.upcomingIncomeForRange(this.dateRange)\n }\n\n get upcomingExpenses(): Recurrence[] {\n return this.globalStore.recurringTransactionsStore.upcomingExpensesForRange(this.dateRange)\n }\n\n get nextIncome(): Recurrence | undefined {\n return this.globalStore.recurringTransactionsStore.nextIncomeForRange(this.dateRange)\n }\n\n // Visible cash accounts that are currently selected in the account filter.\n // Computed (single source of truth) so it stays in sync with account data and\n // the filter without effect-based syncing in components.\n get selectedCashAccounts(): Account[] {\n const { selectedAccountGuids } = this.globalStore.globalUiStore\n return this.globalStore.accountStore.visibleCashAccounts.filter((account) =>\n selectedAccountGuids.includes(account.guid),\n )\n }\n\n // Total spendable/starting balance across the selected cash accounts, using\n // the shared per-account balance rule (available vs current balance).\n get selectedCashBalance(): number {\n const showAvailableBalance =\n this.globalStore.appConfig.config.display_available_balance_in_accounts\n return this.selectedCashAccounts.reduce(\n (total, account) => total + getAccountStartingBalance(account, showAvailableBalance),\n 0,\n )\n }\n // Returns the number of days until the next income activity or 0 if there is no income activity\n get daysUntilNextIncome() {\n return this.nextIncome\n ? Math.abs(differenceInDays(startOfToday(), this.nextIncome.expectedDate))\n : 0\n }\n\n // Returns the expenses (Activities) until the next income activity or the end of the month\n // if there is no income activity\n get expensesTilNextIncome() {\n return this.upcomingExpenses.filter((a) =>\n isBefore(a.expectedDate, this.nextIncome?.expectedDate || endOfMonth(new Date())),\n )\n }\n\n // Sum of the expenses due before the next income (end of month when there is none).\n get upcomingExpensesTotal(): number {\n return this.expensesTilNextIncome.reduce((total, expense) => total + expense.amount, 0)\n }\n\n // Cash left once the upcoming expenses are paid; negative when short before payday.\n get remainingUntilPayday(): number {\n return this.selectedCashBalance - this.upcomingExpensesTotal\n }\n\n get hasUpcomingPayday(): boolean {\n return this.nextIncome !== undefined\n }\n}\n"],"mappings":";;;;;;;AAYA,IAAa,IAAb,MAA2B;AAAA,EACzB;AAAA,EACA;AAAA,EAEA,YAAY,GAA0B;AACpC,SAAK,cAAc,GACnB,KAAK,UAAU,IAAI,EAAQ,CAAW,GAEtC,EAAmB,IAAI;AAAA,EACzB;AAAA,EAEA,qBAAqB,YAAY;AAC/B,UAAM,IAAqB;AAAA,MACzB,GAAG,KAAK,YAAY,UAAU;AAAA,MAC9B,oCAAoC;AAAA,IACtC;AAEA,UAAM,KAAK,YAAY,UAAU,kBAAkB,CAAkB;AAAA,EACvE;AACF,GAEM,IAAN,MAAc;AAAA,EACZ;AAAA,EAMA,YAAY;AAAA,IAAE,OAAO,EAAa;AAAA,IAAG,KAAK,EAAQ,EAAa,GAAG,EAAE;AAAA,EAAE;AAAA,EACtE,UAAU;AAAA,EAEV,YAAY,GAA0B;AACpC,SAAK,cAAc,GAEnB,EAAmB,IAAI;AAAA,EACzB;AAAA,EAKA,IAAI,SAAuB;AACzB,WAAO,KAAK,YAAY,2BAA2B,eAAe,KAAK,SAAS;AAAA,EAClF;AAAA,EAEA,IAAI,iBAA+B;AACjC,WAAO,KAAK,YAAY,2BAA2B,uBAAuB,KAAK,SAAS;AAAA,EAC1F;AAAA,EAEA,IAAI,mBAAiC;AACnC,WAAO,KAAK,YAAY,2BAA2B,yBAAyB,KAAK,SAAS;AAAA,EAC5F;AAAA,EAEA,IAAI,aAAqC;AACvC,WAAO,KAAK,YAAY,2BAA2B,mBAAmB,KAAK,SAAS;AAAA,EACtF;AAAA,EAKA,IAAI,uBAAkC;AACpC,UAAM,EAAE,sBAAA,EAAA,IAAyB,KAAK,YAAY;AAClD,WAAO,KAAK,YAAY,aAAa,oBAAoB,OAAA,CAAQ,MAC/D,EAAqB,SAAS,EAAQ,IAAI,CAC5C;AAAA,EACF;AAAA,EAIA,IAAI,sBAA8B;AAChC,UAAM,IACJ,KAAK,YAAY,UAAU,OAAO;AACpC,WAAO,KAAK,qBAAqB,OAAA,CAC9B,GAAO,MAAY,IAAQ,EAA0B,GAAS,CAAoB,GACnF,CACF;AAAA,EACF;AAAA,EAEA,IAAI,sBAAsB;AACxB,WAAO,KAAK,aACR,KAAK,IAAI,EAAiB,EAAa,GAAG,KAAK,WAAW,YAAY,CAAC,IACvE;AAAA,EACN;AAAA,EAIA,IAAI,wBAAwB;AAC1B,WAAO,KAAK,iBAAiB,OAAA,CAAQ,MACnC,EAAS,EAAE,cAAc,KAAK,YAAY,gBAAgB,EAAW,oBAAI,KAAK,CAAC,CAAC,CAClF;AAAA,EACF;AAAA,EAGA,IAAI,wBAAgC;AAClC,WAAO,KAAK,sBAAsB,OAAA,CAAQ,GAAO,MAAY,IAAQ,EAAQ,QAAQ,CAAC;AAAA,EACxF;AAAA,EAGA,IAAI,uBAA+B;AACjC,WAAO,KAAK,sBAAsB,KAAK;AAAA,EACzC;AAAA,EAEA,IAAI,oBAA6B;AAC/B,WAAO,KAAK,eAAe;AAAA,EAC7B;AACF"}
@@ -132,10 +132,25 @@ export interface FeedbackCopy {
132
132
  /** ARIA label for the close button. */
133
133
  close_aria: string;
134
134
  }
135
+ export interface RemainingCashCopy {
136
+ title: string;
137
+ remaining_until_payday: string;
138
+ remaining_until_payday_one: string;
139
+ cash_on_hand: string;
140
+ upcoming_expenses: string;
141
+ accounts_header: string;
142
+ recurring_expenses_header: string;
143
+ other_accounts: string;
144
+ other_accounts_one: string;
145
+ other_expenses: string;
146
+ other_expenses_one: string;
147
+ }
135
148
  export interface InsightsFeedCopy {
136
149
  general: GeneralInsightsFeedCopy;
137
150
  settings_menu: SettingsMenuCopy;
138
151
  make_transfer: MakeTransferCopy;
152
+ /** Optional until the localized-content service ships it; the drawer shows an error without it. */
153
+ remaining_cash?: RemainingCashCopy;
139
154
  overflow_menu: OverflowMenuCopy;
140
155
  transaction_history_block: TransactionHistoryBlock;
141
156
  hidden_confirmation: HiddenConfirmationCopy;
@@ -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, OverflowMenuCopy, DismissInsightCopy, DismissInsightOptionCopy, HiddenConfirmationCopy, HideFeedbackCopy, FeedbackCopy, FeedbackBarCopy, } from './InsightsFeedCopy';
16
+ export type { InsightsFeedCopy, MakeTransferCopy, RemainingCashCopy, OverflowMenuCopy, DismissInsightCopy, DismissInsightOptionCopy, HiddenConfirmationCopy, HideFeedbackCopy, FeedbackCopy, FeedbackBarCopy, } from './InsightsFeedCopy';
17
17
  export type { InvestmentsCopy } from './InvestmentsCopy';
18
18
  export type { MicroInsightsCopy } from './MicroInsightsCopy';
19
19
  export type { NetWorthCopy } from './NetWorthCopy';
@@ -1,2 +1,2 @@
1
1
  export { RecurringTransactionBlock } from './RecurringTransactionBlock';
2
- export { useRecurringTransactionPrepare } from './useRecurringTransactionPrepare';
2
+ export { type RecurringTransactionActionContext, useRecurringTransactionLoad, useRecurringTransactionPrepare, } from './useRecurringTransactionPrepare';
@@ -0,0 +1,11 @@
1
+ import { ActionBlockProps } from '../../mappings/blocks';
2
+ /**
3
+ * Remaining Cash drawer (WEC-1880) for the Payday Cash Left Over Status beat. Store-driven: the
4
+ * figures are today's, from CashflowStore's UiStore, not the card's generation-time numbers
5
+ * (accepted trade-off, see docs/action-blocks/remaining-cash-block.md).
6
+ *
7
+ * `observer` is required: everything rendered is read from MobX stores and computeds.
8
+ */
9
+ export declare const RemainingCashBlock: ((_props: ActionBlockProps) => import("react/jsx-runtime").JSX.Element) & {
10
+ displayName: string;
11
+ };
@@ -0,0 +1,89 @@
1
+ import { CategoryGuids as T } from "../../../core/constants/Category.es.js";
2
+ import R from "../../../common/utils/AccountDisplayName.es.js";
3
+ import { useAccountStore as G, useActionContext as S, useAppConfig as w, useCashflowStore as A, useCategoryStore as I, useGlobalCopyStore as U, useRecurringTransactionsStore as v, useTransactionStore as E } from "../../../common/context/hooks.es.js";
4
+ import { getAccountStartingBalance as O } from "../../../core/utils/AccountUtils.es.js";
5
+ import b from "../../../common/components/Loader.es.js";
6
+ import { ErrorCard as k } from "../../components/ErrorCard.es.js";
7
+ import { useRecurringTransactionLoad as N } from "../RecurringTransactionBlock/useRecurringTransactionPrepare.es.js";
8
+ import { DEFAULT_INSTITUTION_LOGO_URL as D, getCaption as F, getOtherLabel as z, groupRows as B } from "./layout.es.js";
9
+ import H from "./RemainingCashContent.es.js";
10
+ import { observer as P } from "mobx-react-lite";
11
+ import $ from "@mui/material/Stack";
12
+ import { CategoryIcon as d, InstitutionLogo as g, Text as j } from "@mxenabled/mxui";
13
+ import { jsx as n } from "react/jsx-runtime";
14
+ var p = (m, i, s) => {
15
+ const { others: a, shown: r } = B(m);
16
+ return a ? [...r, {
17
+ amount: a.total,
18
+ key: "other",
19
+ leading: s,
20
+ name: z(i.one, i.multi, a.count)
21
+ }] : r;
22
+ }, to = P(function(i) {
23
+ const { common: s, insights_feed: a } = U(), { config: r } = w(), { uiStore: t } = A(), { getTopLevelCategoryGuid: l } = I(), { accountsLoaded: h } = G(), { transactionsLoaded: u, transactionsLoading: y } = E(), { isDataLoaded: c } = v(), _ = S()?.recurringLoadFailed === !0, f = N(), C = c && !u && !y, o = a?.remaining_cash;
24
+ if (a?.general && !o) return /* @__PURE__ */ n($, {
25
+ sx: { p: 24 },
26
+ children: /* @__PURE__ */ n(j, { children: s?.error_message })
27
+ });
28
+ if (_ && !c || C) return /* @__PURE__ */ n(k, { onRetry: () => {
29
+ f();
30
+ } });
31
+ if (!c || !h || !u || !o) return /* @__PURE__ */ n(b, {});
32
+ const L = p(t.selectedCashAccounts.map((e) => ({
33
+ amount: O(e, r.display_available_balance_in_accounts),
34
+ key: e.guid,
35
+ leading: /* @__PURE__ */ n(g, {
36
+ alt: "",
37
+ institutionGuid: e.institution_guid ?? "",
38
+ size: 32
39
+ }),
40
+ name: R(e)
41
+ })), {
42
+ multi: o.other_accounts,
43
+ one: o.other_accounts_one
44
+ }, /* @__PURE__ */ n(g, {
45
+ alt: "",
46
+ institutionGuid: "",
47
+ logoUrl: D,
48
+ size: 32
49
+ })), x = p(t.expensesTilNextIncome.map((e) => ({
50
+ amount: e.amount,
51
+ key: `${e.repeatingTransactionGuid}-${e.expectedDate.getTime()}`,
52
+ leading: /* @__PURE__ */ n(d, {
53
+ categoryGuid: l(e.categoryGuid),
54
+ size: 32
55
+ }),
56
+ name: e.name
57
+ })), {
58
+ multi: o.other_expenses,
59
+ one: o.other_expenses_one
60
+ }, /* @__PURE__ */ n(d, {
61
+ categoryGuid: T.UNCATEGORIZED,
62
+ size: 32
63
+ }));
64
+ return /* @__PURE__ */ n(H, {
65
+ accounts: {
66
+ header: o.accounts_header,
67
+ rows: L
68
+ },
69
+ expenses: {
70
+ header: o.recurring_expenses_header,
71
+ rows: x
72
+ },
73
+ summary: {
74
+ remaining: t.hasUpcomingPayday ? {
75
+ amount: t.remainingUntilPayday,
76
+ caption: F(o, t.daysUntilNextIncome)
77
+ } : void 0,
78
+ cashOnHand: t.selectedCashBalance,
79
+ cashOnHandLabel: o.cash_on_hand,
80
+ upcomingExpenses: t.upcomingExpensesTotal,
81
+ upcomingExpensesLabel: o.upcoming_expenses
82
+ }
83
+ });
84
+ });
85
+ export {
86
+ to as RemainingCashBlock
87
+ };
88
+
89
+ //# sourceMappingURL=RemainingCashBlock.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RemainingCashBlock.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/RemainingCashBlock/RemainingCashBlock.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\nimport Stack from '@mui/material/Stack'\n\nimport { CategoryIcon, InstitutionLogo, Text } from '@mxenabled/mxui'\nimport { observer } from 'mobx-react-lite'\n\nimport {\n Loader,\n useAccountStore,\n useActionContext,\n useAppConfig,\n useCashflowStore,\n useCategoryStore,\n useGlobalCopyStore,\n useRecurringTransactionsStore,\n useTransactionStore,\n} from '../../../common'\nimport getAccountDisplayName from '../../../common/utils/AccountDisplayName'\nimport { CategoryGuids } from '../../../core/constants/Category'\nimport { getAccountStartingBalance } from '../../../core/utils/AccountUtils'\nimport { ErrorCard } from '../../components/ErrorCard'\nimport type { ActionBlockProps } from '../../mappings/blocks'\nimport {\n type RecurringTransactionActionContext,\n useRecurringTransactionLoad,\n} from '../RecurringTransactionBlock'\n\nimport { DEFAULT_INSTITUTION_LOGO_URL, getCaption, getOtherLabel, groupRows } from './layout'\nimport RemainingCashContent from './RemainingCashContent'\nimport type { RemainingCashRow } from './RemainingCashContent'\n\n/** Top rows by amount, then one \"Other (#)\" row with the rest's count and total. */\nconst toSectionRows = (\n rows: RemainingCashRow[],\n otherLabel: { one: string; multi: string },\n otherLeading: ReactNode,\n): RemainingCashRow[] => {\n const { others, shown } = groupRows(rows)\n\n if (!others) return shown\n\n return [\n ...shown,\n {\n amount: others.total,\n key: 'other',\n leading: otherLeading,\n name: getOtherLabel(otherLabel.one, otherLabel.multi, others.count),\n },\n ]\n}\n\n/**\n * Remaining Cash drawer (WEC-1880) for the Payday Cash Left Over Status beat. Store-driven: the\n * figures are today's, from CashflowStore's UiStore, not the card's generation-time numbers\n * (accepted trade-off, see docs/action-blocks/remaining-cash-block.md).\n *\n * `observer` is required: everything rendered is read from MobX stores and computeds.\n */\nexport const RemainingCashBlock = observer(function RemainingCashBlock(_props: ActionBlockProps) {\n const { common: commonCopy, insights_feed: insightsFeedCopy } = useGlobalCopyStore()\n const { config } = useAppConfig()\n const { uiStore } = useCashflowStore()\n const { getTopLevelCategoryGuid } = useCategoryStore()\n const { accountsLoaded } = useAccountStore()\n const { transactionsLoaded, transactionsLoading } = useTransactionStore()\n const { isDataLoaded } = useRecurringTransactionsStore()\n const loadFailed =\n useActionContext<RecurringTransactionActionContext>()?.recurringLoadFailed === true\n const retryLoad = useRecurringTransactionLoad()\n\n // TransactionStore swallows a failed request, which would silently zero every expense (see the\n // States table in docs/action-blocks/remaining-cash-block.md). `transactionsLoading` excludes another\n // widget's request still in flight: loadTransactions returns early without awaiting it.\n const transactionsFailed = isDataLoaded && !transactionsLoaded && !transactionsLoading\n const copy = insightsFeedCopy?.remaining_cash\n\n // Copy loaded but without this namespace (the copy service has not shipped it). Copy loads once at\n // app start, so a retry cannot clear it: a plain message like ActionBlockLayer's unknown-block\n // state, not ErrorCard's Try Again, and never an endless loader.\n if (insightsFeedCopy?.general && !copy) {\n return (\n <Stack sx={{ p: 24 }}>\n <Text>{commonCopy?.error_message}</Text>\n </Stack>\n )\n }\n\n if ((loadFailed && !isDataLoaded) || transactionsFailed) {\n return <ErrorCard onRetry={() => void retryLoad()} />\n }\n\n // `accountsLoaded` / `transactionsLoaded` cover another widget's request still in flight.\n if (!isDataLoaded || !accountsLoaded || !transactionsLoaded || !copy) return <Loader />\n\n const accountRows = toSectionRows(\n uiStore.selectedCashAccounts.map((account) => ({\n amount: getAccountStartingBalance(account, config.display_available_balance_in_accounts),\n key: account.guid,\n // Decorative: the row's visible name already says which account it is.\n leading: (\n <InstitutionLogo alt=\"\" institutionGuid={account.institution_guid ?? ''} size={32} />\n ),\n name: getAccountDisplayName(account),\n })),\n { multi: copy.other_accounts, one: copy.other_accounts_one },\n <InstitutionLogo alt=\"\" institutionGuid=\"\" logoUrl={DEFAULT_INSTITUTION_LOGO_URL} size={32} />,\n )\n const expenseRows = toSectionRows(\n uiStore.expensesTilNextIncome.map((expense) => ({\n amount: expense.amount,\n key: `${expense.repeatingTransactionGuid}-${expense.expectedDate.getTime()}`,\n leading: (\n <CategoryIcon categoryGuid={getTopLevelCategoryGuid(expense.categoryGuid)} size={32} />\n ),\n name: expense.name,\n })),\n { multi: copy.other_expenses, one: copy.other_expenses_one },\n <CategoryIcon categoryGuid={CategoryGuids.UNCATEGORIZED} size={32} />,\n )\n\n return (\n <RemainingCashContent\n accounts={{ header: copy.accounts_header, rows: accountRows }}\n expenses={{ header: copy.recurring_expenses_header, rows: expenseRows }}\n summary={{\n remaining: uiStore.hasUpcomingPayday\n ? {\n amount: uiStore.remainingUntilPayday,\n caption: getCaption(copy, uiStore.daysUntilNextIncome),\n }\n : undefined,\n cashOnHand: uiStore.selectedCashBalance,\n cashOnHandLabel: copy.cash_on_hand,\n upcomingExpenses: uiStore.upcomingExpensesTotal,\n upcomingExpensesLabel: copy.upcoming_expenses,\n }}\n />\n )\n})\n"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { ReactNode } from 'react';
2
+ export interface RemainingCashRow {
3
+ key: string;
4
+ name: string;
5
+ amount: number;
6
+ /** The row's 32px logo: an account's institution or an expense's category. */
7
+ leading: ReactNode;
8
+ }
9
+ interface RemainingCashSectionProps {
10
+ header: string;
11
+ /** Already grouped and ordered, including any "Other (#)" row. */
12
+ rows: RemainingCashRow[];
13
+ }
14
+ interface RemainingCashSummaryProps {
15
+ /** Omitted when there is no upcoming payday: a "remaining until payday" figure has no meaning. */
16
+ remaining?: {
17
+ amount: number;
18
+ caption: string;
19
+ };
20
+ cashOnHand: number;
21
+ upcomingExpenses: number;
22
+ cashOnHandLabel: string;
23
+ upcomingExpensesLabel: string;
24
+ }
25
+ export interface RemainingCashContentProps {
26
+ summary: RemainingCashSummaryProps;
27
+ accounts: RemainingCashSectionProps;
28
+ expenses: RemainingCashSectionProps;
29
+ }
30
+ /** Presentational body of the Remaining Cash drawer (Figma 9936:39163, minus the drawer header). */
31
+ declare const RemainingCashContent: ({ accounts, expenses, summary }: RemainingCashContentProps) => import("react/jsx-runtime").JSX.Element;
32
+ export default RemainingCashContent;
@@ -0,0 +1,169 @@
1
+ import { getLogoElevation as x } from "../../components/logoShadow.es.js";
2
+ import { formatSignedCurrency as d } from "./layout.es.js";
3
+ import { createElement as b } from "react";
4
+ import i from "@mui/material/Stack";
5
+ import { Text as a } from "@mxenabled/mxui";
6
+ import { jsx as r, jsxs as n } from "react/jsx-runtime";
7
+ import p from "@mui/material/Box";
8
+ import s from "@mui/material/Divider";
9
+ var h = ({ label: t, value: e }) => /* @__PURE__ */ n(i, {
10
+ sx: {
11
+ alignItems: "center",
12
+ flexDirection: "row",
13
+ gap: 16,
14
+ minHeight: 44,
15
+ px: 24
16
+ },
17
+ children: [/* @__PURE__ */ r(a, {
18
+ sx: { flexGrow: 1 },
19
+ variant: "body1",
20
+ children: t
21
+ }), /* @__PURE__ */ r(a, {
22
+ bold: !0,
23
+ sx: { fontVariantNumeric: "tabular-nums" },
24
+ variant: "body1",
25
+ children: e
26
+ })]
27
+ }), u = ({ cashOnHand: t, cashOnHandLabel: e, remaining: o, upcomingExpenses: l, upcomingExpensesLabel: c }) => /* @__PURE__ */ r(i, {
28
+ sx: {
29
+ pb: 8,
30
+ pt: 24,
31
+ px: 24
32
+ },
33
+ children: /* @__PURE__ */ n(i, {
34
+ sx: {
35
+ bgcolor: "background.paper",
36
+ borderRadius: "8px",
37
+ boxShadow: x,
38
+ gap: 16,
39
+ p: 16
40
+ },
41
+ children: [o && /* @__PURE__ */ n(i, {
42
+ "aria-label": `${d(o.amount)}, ${o.caption}`,
43
+ role: "group",
44
+ sx: {
45
+ alignItems: "center",
46
+ justifyContent: "center",
47
+ minHeight: 72,
48
+ p: 12
49
+ },
50
+ children: [/* @__PURE__ */ r(a, {
51
+ "aria-hidden": !0,
52
+ bold: !0,
53
+ component: "p",
54
+ variant: "h2",
55
+ children: d(o.amount)
56
+ }), /* @__PURE__ */ r(a, {
57
+ "aria-hidden": !0,
58
+ color: "text.secondary",
59
+ variant: "subtitle2",
60
+ children: o.caption
61
+ })]
62
+ }), /* @__PURE__ */ n(i, {
63
+ sx: {
64
+ border: "1px solid",
65
+ borderColor: "divider",
66
+ borderRadius: "8px",
67
+ overflow: "hidden"
68
+ },
69
+ children: [
70
+ /* @__PURE__ */ r(h, {
71
+ label: e,
72
+ value: d(t)
73
+ }),
74
+ /* @__PURE__ */ r(s, {}),
75
+ /* @__PURE__ */ r(h, {
76
+ label: c,
77
+ value: d(-l)
78
+ })
79
+ ]
80
+ })]
81
+ })
82
+ }), f = ({ amount: t, isLast: e, leading: o, name: l }) => /* @__PURE__ */ n(p, {
83
+ component: "li",
84
+ sx: { position: "relative" },
85
+ children: [/* @__PURE__ */ n(i, {
86
+ sx: {
87
+ alignItems: "center",
88
+ flexDirection: "row",
89
+ gap: 16,
90
+ px: 24,
91
+ py: 14
92
+ },
93
+ children: [/* @__PURE__ */ n(i, {
94
+ sx: {
95
+ alignItems: "center",
96
+ flexDirection: "row",
97
+ flexGrow: 1,
98
+ gap: 12,
99
+ minWidth: 0
100
+ },
101
+ children: [/* @__PURE__ */ r(p, {
102
+ sx: {
103
+ display: "flex",
104
+ flexShrink: 0,
105
+ height: 32,
106
+ width: 32
107
+ },
108
+ children: o
109
+ }), /* @__PURE__ */ r(a, {
110
+ truncate: !0,
111
+ variant: "body1",
112
+ children: l
113
+ })]
114
+ }), /* @__PURE__ */ r(a, {
115
+ bold: !0,
116
+ sx: {
117
+ flexShrink: 0,
118
+ fontVariantNumeric: "tabular-nums"
119
+ },
120
+ variant: "body1",
121
+ children: d(t)
122
+ })]
123
+ }), /* @__PURE__ */ r(s, { sx: {
124
+ bottom: 0,
125
+ left: e ? 0 : 24,
126
+ position: "absolute",
127
+ right: 0
128
+ } })]
129
+ }), m = ({ header: t, rows: e }) => /* @__PURE__ */ n(i, { children: [/* @__PURE__ */ r(p, {
130
+ sx: {
131
+ pb: 4,
132
+ pt: 16,
133
+ px: 24
134
+ },
135
+ children: /* @__PURE__ */ r(a, {
136
+ bold: !0,
137
+ component: "h3",
138
+ variant: "body1",
139
+ children: t
140
+ })
141
+ }), /* @__PURE__ */ r(i, {
142
+ component: "ul",
143
+ sx: {
144
+ bgcolor: "background.paper",
145
+ listStyle: "none",
146
+ m: 0,
147
+ p: 0
148
+ },
149
+ children: e.map(({ key: o, ...l }, c) => /* @__PURE__ */ b(f, {
150
+ ...l,
151
+ isLast: c === e.length - 1,
152
+ key: o
153
+ }))
154
+ })] }), R = ({ accounts: t, expenses: e, summary: o }) => /* @__PURE__ */ n(i, {
155
+ sx: {
156
+ bgcolor: "background.default",
157
+ pb: 24
158
+ },
159
+ children: [
160
+ /* @__PURE__ */ r(u, { ...o }),
161
+ t.rows.length > 0 && /* @__PURE__ */ r(m, { ...t }),
162
+ e.rows.length > 0 && /* @__PURE__ */ r(m, { ...e })
163
+ ]
164
+ });
165
+ export {
166
+ R as default
167
+ };
168
+
169
+ //# sourceMappingURL=RemainingCashContent.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RemainingCashContent.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/RemainingCashBlock/RemainingCashContent.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\n\nimport Box from '@mui/material/Box'\nimport Divider from '@mui/material/Divider'\nimport Stack from '@mui/material/Stack'\n\nimport { Text } from '@mxenabled/mxui'\n\nimport { getLogoElevation } from '../../components/logoShadow'\nimport { formatSignedCurrency } from './layout'\n\nexport interface RemainingCashRow {\n key: string\n name: string\n amount: number\n /** The row's 32px logo: an account's institution or an expense's category. */\n leading: ReactNode\n}\n\ninterface RemainingCashSectionProps {\n header: string\n /** Already grouped and ordered, including any \"Other (#)\" row. */\n rows: RemainingCashRow[]\n}\n\ninterface RemainingCashSummaryProps {\n /** Omitted when there is no upcoming payday: a \"remaining until payday\" figure has no meaning. */\n remaining?: { amount: number; caption: string }\n cashOnHand: number\n upcomingExpenses: number\n cashOnHandLabel: string\n upcomingExpensesLabel: string\n}\n\nexport interface RemainingCashContentProps {\n summary: RemainingCashSummaryProps\n accounts: RemainingCashSectionProps\n expenses: RemainingCashSectionProps\n}\n\nconst BreakdownRow = ({ label, value }: { label: string; value: string }) => (\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', gap: 16, minHeight: 44, px: 24 }}>\n <Text sx={{ flexGrow: 1 }} variant=\"body1\">\n {label}\n </Text>\n <Text bold={true} sx={{ fontVariantNumeric: 'tabular-nums' }} variant=\"body1\">\n {value}\n </Text>\n </Stack>\n)\n\nconst Summary = ({\n cashOnHand,\n cashOnHandLabel,\n remaining,\n upcomingExpenses,\n upcomingExpensesLabel,\n}: RemainingCashSummaryProps) => (\n <Stack sx={{ pb: 8, pt: 24, px: 24 }}>\n <Stack\n sx={{\n bgcolor: 'background.paper',\n borderRadius: '8px',\n boxShadow: getLogoElevation,\n gap: 16,\n p: 16,\n }}\n >\n {remaining && (\n // One announcement (\"$2,350.00, Remaining until payday (7 days)\") instead of two loose text\n // nodes. The amount keeps the h2 look but is a paragraph: it is a value, not a heading.\n <Stack\n aria-label={`${formatSignedCurrency(remaining.amount)}, ${remaining.caption}`}\n role=\"group\"\n sx={{ alignItems: 'center', justifyContent: 'center', minHeight: 72, p: 12 }}\n >\n <Text aria-hidden={true} bold={true} component=\"p\" variant=\"h2\">\n {formatSignedCurrency(remaining.amount)}\n </Text>\n <Text aria-hidden={true} color=\"text.secondary\" variant=\"subtitle2\">\n {remaining.caption}\n </Text>\n </Stack>\n )}\n <Stack\n sx={{\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: '8px',\n overflow: 'hidden',\n }}\n >\n <BreakdownRow label={cashOnHandLabel} value={formatSignedCurrency(cashOnHand)} />\n <Divider />\n {/* Shown as a deduction (-$1,200.00) per Figma; the expense rows below show positive amounts. */}\n <BreakdownRow\n label={upcomingExpensesLabel}\n value={formatSignedCurrency(-upcomingExpenses)}\n />\n </Stack>\n </Stack>\n </Stack>\n)\n\n/** One 64px row. The last row's divider runs full width; the rest are inset 24px (Figma). */\nconst RowItem = ({\n amount,\n isLast,\n leading,\n name,\n}: Omit<RemainingCashRow, 'key'> & { isLast: boolean }) => (\n <Box component=\"li\" sx={{ position: 'relative' }}>\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', gap: 16, px: 24, py: 14 }}>\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', flexGrow: 1, gap: 12, minWidth: 0 }}>\n <Box sx={{ display: 'flex', flexShrink: 0, height: 32, width: 32 }}>{leading}</Box>\n <Text truncate={true} variant=\"body1\">\n {name}\n </Text>\n </Stack>\n <Text bold={true} sx={{ flexShrink: 0, fontVariantNumeric: 'tabular-nums' }} variant=\"body1\">\n {formatSignedCurrency(amount)}\n </Text>\n </Stack>\n <Divider sx={{ bottom: 0, left: isLast ? 0 : 24, position: 'absolute', right: 0 }} />\n </Box>\n)\n\n// The drawer title is the h2, so section headers are h3 and each section is a real list.\nconst Section = ({ header, rows }: RemainingCashSectionProps) => (\n <Stack>\n <Box sx={{ pb: 4, pt: 16, px: 24 }}>\n <Text bold={true} component=\"h3\" variant=\"body1\">\n {header}\n </Text>\n </Box>\n <Stack component=\"ul\" sx={{ bgcolor: 'background.paper', listStyle: 'none', m: 0, p: 0 }}>\n {rows.map(({ key, ...row }, index) => (\n <RowItem {...row} isLast={index === rows.length - 1} key={key} />\n ))}\n </Stack>\n </Stack>\n)\n\n/** Presentational body of the Remaining Cash drawer (Figma 9936:39163, minus the drawer header). */\nconst RemainingCashContent = ({ accounts, expenses, summary }: RemainingCashContentProps) => (\n <Stack sx={{ bgcolor: 'background.default', pb: 24 }}>\n <Summary {...summary} />\n {accounts.rows.length > 0 && <Section {...accounts} />}\n {expenses.rows.length > 0 && <Section {...expenses} />}\n </Stack>\n)\n\nexport default RemainingCashContent\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { RemainingCashBlock } from './RemainingCashBlock';
@@ -0,0 +1,27 @@
1
+ import { RemainingCashCopy } from '../../../core';
2
+ /** Rows shown per section before the rest fold into an "Other (#)" row (Figma shows two). */
3
+ export declare const ROW_LIMIT = 2;
4
+ /**
5
+ * The grey bank tile on the "Other Accounts" row (Figma). It is MXUI's own `InstitutionLogo` fallback
6
+ * image; passing it as `logoUrl` shows it straight away, instead of after a failed request for an
7
+ * empty institution guid.
8
+ */
9
+ export declare const DEFAULT_INSTITUTION_LOGO_URL = "https://content.moneydesktop.com/storage/MD_Assets/serenity/default_institution_logo.png";
10
+ export interface GroupedRows<T> {
11
+ shown: T[];
12
+ others?: {
13
+ count: number;
14
+ total: number;
15
+ };
16
+ }
17
+ /** Largest rows first (stable for ties), capped at `ROW_LIMIT`; the remainder as a count and total. */
18
+ export declare const groupRows: <T extends {
19
+ amount: number;
20
+ }>(rows: T[]) => GroupedRows<T>;
21
+ /**
22
+ * `-$220.00`, not `$-220.00`: the sign goes before the currency symbol. Rounded to cents first so a
23
+ * sub-cent negative (or `-0`) reads `$0.00`, never `-$0.00`.
24
+ */
25
+ export declare const formatSignedCurrency: (amount: number) => string;
26
+ export declare const getCaption: (copy: RemainingCashCopy, days: number) => string;
27
+ export declare const getOtherLabel: (templateOne: string, templateMulti: string, count: number) => string;
@@ -0,0 +1,26 @@
1
+ import { buildDynamicCopy as a, buildPluralCopy as i } from "../../../core/utils/Localization.es.js";
2
+ import { formatCurrency as s } from "../../../core/utils/NumberFormatting.es.js";
3
+ var m = "https://content.moneydesktop.com/storage/MD_Assets/serenity/default_institution_logo.png", g = (r) => {
4
+ const t = [...r].sort((e, o) => o.amount - e.amount);
5
+ if (t.length <= 2) return { shown: t };
6
+ const n = t.slice(2);
7
+ return {
8
+ shown: t.slice(0, 2),
9
+ others: {
10
+ count: n.length,
11
+ total: n.reduce((e, o) => e + o.amount, 0)
12
+ }
13
+ };
14
+ }, c = (r) => {
15
+ const t = Math.round(Math.abs(r) * 100), n = s(t / 100, "0,0.00");
16
+ return r < 0 && t > 0 ? `-${n}` : n;
17
+ }, _ = (r, t) => t === 1 ? r.remaining_until_payday_one : a(r.remaining_until_payday, String(t)), p = (r, t, n) => i(r, t, n, String(n));
18
+ export {
19
+ m as DEFAULT_INSTITUTION_LOGO_URL,
20
+ c as formatSignedCurrency,
21
+ _ as getCaption,
22
+ p as getOtherLabel,
23
+ g as groupRows
24
+ };
25
+
26
+ //# sourceMappingURL=layout.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.es.js","names":[],"sources":["../../../../src/insights-v2/actionBlocks/RemainingCashBlock/layout.ts"],"sourcesContent":["import type { RemainingCashCopy } from '../../../core'\nimport { buildDynamicCopy, buildPluralCopy } from '../../../core/utils/Localization'\nimport { formatCurrency } from '../../../core/utils/NumberFormatting'\n\n/** Rows shown per section before the rest fold into an \"Other (#)\" row (Figma shows two). */\nexport const ROW_LIMIT = 2\n\n/**\n * The grey bank tile on the \"Other Accounts\" row (Figma). It is MXUI's own `InstitutionLogo` fallback\n * image; passing it as `logoUrl` shows it straight away, instead of after a failed request for an\n * empty institution guid.\n */\nexport const DEFAULT_INSTITUTION_LOGO_URL =\n 'https://content.moneydesktop.com/storage/MD_Assets/serenity/default_institution_logo.png'\n\nexport interface GroupedRows<T> {\n shown: T[]\n others?: { count: number; total: number }\n}\n\n/** Largest rows first (stable for ties), capped at `ROW_LIMIT`; the remainder as a count and total. */\nexport const groupRows = <T extends { amount: number }>(rows: T[]): GroupedRows<T> => {\n const sorted = [...rows].sort((a, b) => b.amount - a.amount)\n\n if (sorted.length <= ROW_LIMIT) return { shown: sorted }\n\n const rest = sorted.slice(ROW_LIMIT)\n\n return {\n shown: sorted.slice(0, ROW_LIMIT),\n others: { count: rest.length, total: rest.reduce((total, r) => total + r.amount, 0) },\n }\n}\n\n/**\n * `-$220.00`, not `$-220.00`: the sign goes before the currency symbol. Rounded to cents first so a\n * sub-cent negative (or `-0`) reads `$0.00`, never `-$0.00`.\n */\nexport const formatSignedCurrency = (amount: number): string => {\n const cents = Math.round(Math.abs(amount) * 100)\n const formatted = formatCurrency(cents / 100, '0,0.00')\n\n return amount < 0 && cents > 0 ? `-${formatted}` : formatted\n}\n\nexport const getCaption = (copy: RemainingCashCopy, days: number): string => {\n if (days === 1) return copy.remaining_until_payday_one\n\n return buildDynamicCopy(copy.remaining_until_payday, String(days)) as string\n}\n\nexport const getOtherLabel = (templateOne: string, templateMulti: string, count: number): string =>\n buildPluralCopy(templateOne, templateMulti, count, String(count)) as string\n"],"mappings":";;AAYA,IAAa,IACX,4FAQW,IAAA,CAA2C,MAA8B;AACpF,QAAM,IAAS,CAAC,GAAG,CAAI,EAAE,KAAA,CAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAE3D,MAAI,EAAO,UAAA,EAAqB,QAAO,EAAE,OAAO,EAAO;AAEvD,QAAM,IAAO,EAAO,MAAA,CAAe;AAEnC,SAAO;AAAA,IACL,OAAO,EAAO,MAAM,GAAA,CAAY;AAAA,IAChC,QAAQ;AAAA,MAAE,OAAO,EAAK;AAAA,MAAQ,OAAO,EAAK,OAAA,CAAQ,GAAO,MAAM,IAAQ,EAAE,QAAQ,CAAC;AAAA,IAAE;AAAA,EACtF;AACF,GAMa,IAAA,CAAwB,MAA2B;AAC9D,QAAM,IAAQ,KAAK,MAAM,KAAK,IAAI,CAAM,IAAI,GAAG,GACzC,IAAY,EAAe,IAAQ,KAAK,QAAQ;AAEtD,SAAO,IAAS,KAAK,IAAQ,IAAI,IAAI,CAAA,KAAc;AACrD,GAEa,IAAA,CAAc,GAAyB,MAC9C,MAAS,IAAU,EAAK,6BAErB,EAAiB,EAAK,wBAAwB,OAAO,CAAI,CAAC,GAGtD,IAAA,CAAiB,GAAqB,GAAuB,MACxE,EAAgB,GAAa,GAAe,GAAO,OAAO,CAAK,CAAC"}
@@ -6,4 +6,5 @@ export declare const actionBlocksKey: {
6
6
  CONTACT_SUPPORT_ACTION_BLOCK: string;
7
7
  RECURRING_TRANSACTION_ACTION_BLOCK: string;
8
8
  TRANSACTION_LIST_ACTION_BLOCK: string;
9
+ REMAINING_CASH_ACTION_BLOCK: string;
9
10
  };
@@ -5,7 +5,8 @@ var _ = {
5
5
  TRANSACTION_DETAILS_ACTION_BLOCK: "transaction_details_block",
6
6
  CONTACT_SUPPORT_ACTION_BLOCK: "contact_support_block",
7
7
  RECURRING_TRANSACTION_ACTION_BLOCK: "recurring_transaction_block",
8
- TRANSACTION_LIST_ACTION_BLOCK: "transaction_list_block"
8
+ TRANSACTION_LIST_ACTION_BLOCK: "transaction_list_block",
9
+ REMAINING_CASH_ACTION_BLOCK: "remaining_cash_block"
9
10
  };
10
11
  export {
11
12
  _ as actionBlocksKey
@@ -1 +1 @@
1
- {"version":3,"file":"actionBlocksKey.es.js","names":[],"sources":["../../../src/insights-v2/mappings/actionBlocksKey.ts"],"sourcesContent":["// Keys for the drawer drilldown registry in `blocks.ts`, extracted into their own module.\n//\n// Why: chart blocks (e.g. BarchartBlock, DoubleBarChartBlock) need\n// `TRANSCATION_HISTORY_ACTION_BLOCK` to tag a chart bar's drilldown context, but they are\n// themselves re-exported through `../blocks` -> `mappings/blocks.ts` imports from that same\n// barrel to build its `blocks` registry. Importing the key straight from `mappings/blocks.ts`\n// closed that loop into a circular import: evaluating `mappings/blocks.ts` pulled in the\n// `blocks` barrel, which (before it got to `ComponentBlocks`/`AccountBlock`) loaded\n// `BarchartBlock`, which imported back into the still-initializing `mappings/blocks.ts` —\n// tripping a \"Cannot access 'AccountBlock' before initialization\" TDZ error in Storybook/Vite.\n//\n// Keeping the keys here (no dependency on `mappings/blocks.ts`) lets chart blocks reference\n// them without re-entering that module.\n//\n// Names follow ditto: its registry ends every CTA block in `_block` and the V2 envelope copies those\n// names verbatim (`transaction_details_block`, `contact_support_block`). `make_transfer` is a legacy\n// name that stays as an alias until the last legacy payload is gone.\nexport const actionBlocksKey = {\n PLACEHOLDER_ACTION_BLOCK: 'PlaceholderActionBlock',\n MAKE_TRANSFER_ACTION_BLOCK: 'make_transfer',\n TRANSCATION_HISTORY_ACTION_BLOCK: 'transaction_history_block',\n TRANSACTION_DETAILS_ACTION_BLOCK: 'transaction_details_block',\n CONTACT_SUPPORT_ACTION_BLOCK: 'contact_support_block',\n RECURRING_TRANSACTION_ACTION_BLOCK: 'recurring_transaction_block',\n TRANSACTION_LIST_ACTION_BLOCK: 'transaction_list_block',\n}\n"],"mappings":"AAiBA,IAAa,IAAkB;AAAA,EAC7B,0BAA0B;AAAA,EAC1B,4BAA4B;AAAA,EAC5B,kCAAkC;AAAA,EAClC,kCAAkC;AAAA,EAClC,8BAA8B;AAAA,EAC9B,oCAAoC;AAAA,EACpC,+BAA+B;AACjC"}
1
+ {"version":3,"file":"actionBlocksKey.es.js","names":[],"sources":["../../../src/insights-v2/mappings/actionBlocksKey.ts"],"sourcesContent":["// Keys for the drawer drilldown registry in `blocks.ts`, extracted into their own module.\n//\n// Why: chart blocks (e.g. BarchartBlock, DoubleBarChartBlock) need\n// `TRANSCATION_HISTORY_ACTION_BLOCK` to tag a chart bar's drilldown context, but they are\n// themselves re-exported through `../blocks` -> `mappings/blocks.ts` imports from that same\n// barrel to build its `blocks` registry. Importing the key straight from `mappings/blocks.ts`\n// closed that loop into a circular import: evaluating `mappings/blocks.ts` pulled in the\n// `blocks` barrel, which (before it got to `ComponentBlocks`/`AccountBlock`) loaded\n// `BarchartBlock`, which imported back into the still-initializing `mappings/blocks.ts` —\n// tripping a \"Cannot access 'AccountBlock' before initialization\" TDZ error in Storybook/Vite.\n//\n// Keeping the keys here (no dependency on `mappings/blocks.ts`) lets chart blocks reference\n// them without re-entering that module.\n//\n// Names follow ditto: its registry ends every CTA block in `_block` and the V2 envelope copies those\n// names verbatim (`transaction_details_block`, `contact_support_block`). `make_transfer` is a legacy\n// name that stays as an alias until the last legacy payload is gone.\nexport const actionBlocksKey = {\n PLACEHOLDER_ACTION_BLOCK: 'PlaceholderActionBlock',\n MAKE_TRANSFER_ACTION_BLOCK: 'make_transfer',\n TRANSCATION_HISTORY_ACTION_BLOCK: 'transaction_history_block',\n TRANSACTION_DETAILS_ACTION_BLOCK: 'transaction_details_block',\n CONTACT_SUPPORT_ACTION_BLOCK: 'contact_support_block',\n RECURRING_TRANSACTION_ACTION_BLOCK: 'recurring_transaction_block',\n TRANSACTION_LIST_ACTION_BLOCK: 'transaction_list_block',\n REMAINING_CASH_ACTION_BLOCK: 'remaining_cash_block',\n}\n"],"mappings":"AAiBA,IAAa,IAAkB;AAAA,EAC7B,0BAA0B;AAAA,EAC1B,4BAA4B;AAAA,EAC5B,kCAAkC;AAAA,EAClC,kCAAkC;AAAA,EAClC,8BAA8B;AAAA,EAC9B,oCAAoC;AAAA,EACpC,+BAA+B;AAAA,EAC/B,6BAA6B;AAC/B"}
@@ -1,91 +1,97 @@
1
- import { ContactSupportActionBlock as i } from "../actionBlocks/ContactSupportActionBlock.es.js";
1
+ import { ContactSupportActionBlock as n } from "../actionBlocks/ContactSupportActionBlock.es.js";
2
2
  import { actionBlocksKey as r } from "./actionBlocksKey.es.js";
3
3
  import { BarchartBlock as l } from "../blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js";
4
- import { DoubleBarChartBlock as n } from "../blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js";
5
- import m from "../blocks/ChartBlocks/StepChartBlock/StepChartBlock.es.js";
4
+ import { DoubleBarChartBlock as m } from "../blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js";
5
+ import _ from "../blocks/ChartBlocks/StepChartBlock/StepChartBlock.es.js";
6
6
  import p from "../blocks/ChartBlocks/DonutChartBlock/DonutChartBlock.es.js";
7
- import _ from "../blocks/ChartBlocks/DoubleProgressBarBlock/DoubleProgressBarBlock.es.js";
8
- import s from "../blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js";
9
- import k from "../blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.es.js";
7
+ import s from "../blocks/ChartBlocks/DoubleProgressBarBlock/DoubleProgressBarBlock.es.js";
8
+ import k from "../blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js";
9
+ import C from "../blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.es.js";
10
10
  import { BudgetBlock as B } from "../blocks/ComponentBlocks/BudgetBlock/BudgetBlock.es.js";
11
- import C from "../blocks/ComponentBlocks/SaveExtraBlock/SaveExtraBlock.es.js";
12
- import { TransactionBlock as T } from "../blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js";
13
- import u from "../blocks/ComponentBlocks/WithdrawalBlock/WithdrawalBlock.es.js";
14
- import f from "../blocks/ImageBlocks/ImageBlock.es.js";
15
- import { SVGImageBlock as A } from "../blocks/ImageBlocks/SVGImageBlock/SVGImageBlock.es.js";
16
- import { PlaceholderActionBlock as O } from "../actionBlocks/PlaceholderActionBlock.es.js";
11
+ import T from "../blocks/ComponentBlocks/SaveExtraBlock/SaveExtraBlock.es.js";
12
+ import { TransactionBlock as u } from "../blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js";
13
+ import f from "../blocks/ComponentBlocks/WithdrawalBlock/WithdrawalBlock.es.js";
14
+ import A from "../blocks/ImageBlocks/ImageBlock.es.js";
15
+ import { SVGImageBlock as O } from "../blocks/ImageBlocks/SVGImageBlock/SVGImageBlock.es.js";
16
+ import { PlaceholderActionBlock as N } from "../actionBlocks/PlaceholderActionBlock.es.js";
17
17
  import { getMakeTransferDrawerTitle as b } from "../actionBlocks/MakeTransferActionBlock/layout.es.js";
18
- import { MakeTransferActionBlockLayer as N } from "../actionBlocks/MakeTransferActionBlock/MakeTransferActionBlockLayer.es.js";
19
- import { getDrawerHeaderTitle as h } from "../actionBlocks/TransactionHistoryBlock/utils.es.js";
20
- import { TransactionDetailsBlock as I } from "../actionBlocks/TransactionDetailsBlock/TransactionDetailsBlock.es.js";
18
+ import { MakeTransferActionBlockLayer as h } from "../actionBlocks/MakeTransferActionBlock/MakeTransferActionBlockLayer.es.js";
19
+ import { getDrawerHeaderTitle as I } from "../actionBlocks/TransactionHistoryBlock/utils.es.js";
20
+ import { TransactionDetailsBlock as g } from "../actionBlocks/TransactionDetailsBlock/TransactionDetailsBlock.es.js";
21
21
  import { useTransactionDetailsPrepare as a } from "../actionBlocks/TransactionDetailsBlock/useTransactionDetailsPrepare.es.js";
22
22
  import { TransactionHistoryBlock as L } from "../actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock.es.js";
23
- import { useRecurringTransactionPrepare as S } from "../actionBlocks/RecurringTransactionBlock/useRecurringTransactionPrepare.es.js";
24
- import { RecurringTransactionBlock as d } from "../actionBlocks/RecurringTransactionBlock/RecurringTransactionBlock.es.js";
25
- import { TransactionListBlock as g } from "../actionBlocks/TransactionListBlock/TransactionListBlock.es.js";
23
+ import { useRecurringTransactionPrepare as i } from "../actionBlocks/RecurringTransactionBlock/useRecurringTransactionPrepare.es.js";
24
+ import { RecurringTransactionBlock as S } from "../actionBlocks/RecurringTransactionBlock/RecurringTransactionBlock.es.js";
25
+ import { TransactionListBlock as d } from "../actionBlocks/TransactionListBlock/TransactionListBlock.es.js";
26
+ import { RemainingCashBlock as R } from "../actionBlocks/RemainingCashBlock/RemainingCashBlock.es.js";
26
27
  var e = (t) => {
27
28
  }, P = /* @__PURE__ */ new Set([
28
29
  "",
29
30
  "null",
30
31
  "undefined"
31
- ]), ro = (t) => {
32
+ ]), eo = (t) => {
32
33
  const o = t?.trim().toLowerCase();
33
34
  return !!o && !P.has(o);
34
- }, to = {
35
+ }, ao = {
35
36
  [r.PLACEHOLDER_ACTION_BLOCK]: {
36
- Component: O,
37
+ Component: N,
37
38
  usePrepare: e,
38
39
  title: () => "Action Block Layer Drilldown"
39
40
  },
40
41
  [r.MAKE_TRANSFER_ACTION_BLOCK]: {
41
- Component: N,
42
+ Component: h,
42
43
  usePrepare: e,
43
44
  title: b
44
45
  },
45
46
  [r.TRANSCATION_HISTORY_ACTION_BLOCK]: {
46
47
  Component: L,
47
48
  usePrepare: e,
48
- title: h
49
+ title: I
49
50
  },
50
51
  [r.TRANSACTION_DETAILS_ACTION_BLOCK]: {
51
- Component: I,
52
+ Component: g,
52
53
  usePrepare: a,
53
54
  title: () => "Transaction Details"
54
55
  },
55
56
  [r.RECURRING_TRANSACTION_ACTION_BLOCK]: {
56
- Component: d,
57
- usePrepare: S,
57
+ Component: S,
58
+ usePrepare: i,
58
59
  title: (t, o) => o.recurring?.expense_details ?? ""
59
60
  },
61
+ [r.REMAINING_CASH_ACTION_BLOCK]: {
62
+ Component: R,
63
+ usePrepare: i,
64
+ title: (t, o) => o.insights_feed?.remaining_cash?.title ?? ""
65
+ },
60
66
  [r.CONTACT_SUPPORT_ACTION_BLOCK]: {
61
- Component: i,
67
+ Component: n,
62
68
  usePrepare: e,
63
69
  title: (t, o) => o.help?.request_support ?? ""
64
70
  },
65
71
  [r.TRANSACTION_LIST_ACTION_BLOCK]: {
66
- Component: g,
72
+ Component: d,
67
73
  usePrepare: a,
68
74
  title: (t, o, c) => c?.insights_payload?.title ?? ""
69
75
  }
70
- }, eo = {
71
- account_block: s,
72
- account_switch_block: k,
76
+ }, io = {
77
+ account_block: k,
78
+ account_switch_block: C,
73
79
  bar_chart_block: l,
74
80
  budget_block: B,
75
81
  donut_chart_block: p,
76
- double_bar_chart_block: n,
77
- double_progress_bar_block: _,
78
- image_block: f,
79
- save_extra_block: C,
80
- step_chart_block: m,
81
- svg_image_block: A,
82
- withdrawal_block: u,
83
- transaction_block: T
82
+ double_bar_chart_block: m,
83
+ double_progress_bar_block: s,
84
+ image_block: A,
85
+ save_extra_block: T,
86
+ step_chart_block: _,
87
+ svg_image_block: O,
88
+ withdrawal_block: f,
89
+ transaction_block: u
84
90
  };
85
91
  export {
86
- to as actionBlocks,
87
- eo as blocks,
88
- ro as hasDrawerBlock
92
+ ao as actionBlocks,
93
+ io as blocks,
94
+ eo as hasDrawerBlock
89
95
  };
90
96
 
91
97
  //# sourceMappingURL=blocks.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"blocks.es.js","names":[],"sources":["../../../src/insights-v2/mappings/blocks.ts"],"sourcesContent":["import {\n AccountBlock,\n AccountSwitchBlock,\n BarchartBlock,\n BudgetBlock,\n DonutChartBlock,\n DoubleBarChartBlock,\n DoubleProgressBarBlock,\n SaveExtraBlock,\n SVGImageBlock,\n WithdrawalBlock,\n TransactionBlock,\n} from '../blocks'\nimport StepChartBlock from '../blocks/ChartBlocks/StepChartBlock'\nimport ImageBlock from '../blocks/ImageBlocks/ImageBlock'\n\nimport type { Beat, GlobalCopy, InsightsPayload } from '../../core'\nimport { ContactSupportActionBlock } from '../actionBlocks/ContactSupportActionBlock'\nimport { PlaceholderActionBlock } from '../actionBlocks/PlaceholderActionBlock'\nimport { MakeTransferActionBlockLayer } from '../actionBlocks/MakeTransferActionBlock/MakeTransferActionBlockLayer'\nimport { getMakeTransferDrawerTitle } from '../actionBlocks/MakeTransferActionBlock/layout'\nimport { TransactionHistoryBlock } from '../actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock'\nimport { getDrawerHeaderTitle } from '../actionBlocks/TransactionHistoryBlock/utils'\nimport {\n TransactionDetailsBlock,\n useTransactionDetailsPrepare,\n} from '../actionBlocks/TransactionDetailsBlock'\nimport {\n RecurringTransactionBlock,\n useRecurringTransactionPrepare,\n} from '../actionBlocks/RecurringTransactionBlock'\nimport { TransactionListBlock } from '../actionBlocks/TransactionListBlock'\n// Keys live in ./actionBlocksKey (imported directly by chart blocks/tests too) to avoid a\n// circular import between this module and the chart blocks — see that file for details.\nimport { actionBlocksKey } from './actionBlocksKey'\n\n// Drilldown indexes are not passed down: action blocks read them from\n// InsightsV2Store (useInsightsV2Store().actionDrawer).\nexport interface ActionBlockProps {\n beat: Beat\n}\n\nconst noop = (_: ActionBlockProps) => {}\n\n// A CTA opens a drawer only when it carries a real `block`. The backend may send\n// an empty/absent block (or the literal strings \"null\"/\"undefined\") for CTAs\n// that trigger something else (e.g. a postMessage) instead of a drilldown.\nconst NON_BLOCK_VALUES = new Set(['', 'null', 'undefined'])\nexport const hasDrawerBlock = (block?: string | null): boolean => {\n const normalized = block?.trim().toLowerCase()\n return !!normalized && !NON_BLOCK_VALUES.has(normalized)\n}\n\nexport interface ActionBlockEntry {\n Component: React.ComponentType<ActionBlockProps>\n usePrepare: (props: ActionBlockProps) => void // required; default to noop in each entry\n // Resolves the drawer title from the clicked CTA's variant + copy, with the beat available\n // for blocks that title from beat fields (e.g. transaction-list reads insights_payload.title).\n // Falls back to the CTA label when the resolver returns an empty string / is absent.\n title?: (variant: string | null | undefined, copy: GlobalCopy, beat?: Beat) => string\n}\n\n// Registry of drawer drilldowns, keyed by the `block` name the backend sends\n// on a beat's CTA. To add one: create a component taking ActionBlockProps,\n// read the clicked indexes from useInsightsV2Store().actionDrawer, and\n// register it here. Add\n// `usePrepare` when the block needs to load data before rendering.\n\nexport const actionBlocks = {\n [actionBlocksKey.PLACEHOLDER_ACTION_BLOCK]: {\n Component: PlaceholderActionBlock,\n usePrepare: noop,\n title: () => 'Action Block Layer Drilldown',\n },\n [actionBlocksKey.MAKE_TRANSFER_ACTION_BLOCK]: {\n Component: MakeTransferActionBlockLayer,\n usePrepare: noop,\n title: getMakeTransferDrawerTitle,\n },\n [actionBlocksKey.TRANSCATION_HISTORY_ACTION_BLOCK]: {\n Component: TransactionHistoryBlock,\n usePrepare: noop,\n title: getDrawerHeaderTitle,\n },\n [actionBlocksKey.TRANSACTION_DETAILS_ACTION_BLOCK]: {\n Component: TransactionDetailsBlock,\n usePrepare: useTransactionDetailsPrepare,\n title: () => 'Transaction Details',\n },\n // Expense Details for one recurring subscription. Which subscription a beat names is resolved in\n // `RecurringTransactionBlock/subscriptionBeats.ts`, not through this registry.\n [actionBlocksKey.RECURRING_TRANSACTION_ACTION_BLOCK]: {\n Component: RecurringTransactionBlock,\n usePrepare: useRecurringTransactionPrepare,\n title: (_variant, copy) => copy.recurring?.expense_details ?? '',\n },\n // The block renders its own drawer (the help module's RequestSupport) on top of the action\n // drawer, so the action drawer's title is the CTA label.\n [actionBlocksKey.CONTACT_SUPPORT_ACTION_BLOCK]: {\n Component: ContactSupportActionBlock,\n usePrepare: noop,\n title: (_variant, copy) => copy.help?.request_support ?? '',\n },\n [actionBlocksKey.TRANSACTION_LIST_ACTION_BLOCK]: {\n Component: TransactionListBlock,\n usePrepare: useTransactionDetailsPrepare,\n title: (_variant, _copy, beat) => beat?.insights_payload?.title ?? '',\n },\n} as Record<string, ActionBlockEntry>\n\nexport const blocks = {\n account_block: AccountBlock,\n account_switch_block: AccountSwitchBlock,\n bar_chart_block: BarchartBlock,\n budget_block: BudgetBlock,\n donut_chart_block: DonutChartBlock,\n double_bar_chart_block: DoubleBarChartBlock,\n double_progress_bar_block: DoubleProgressBarBlock,\n image_block: ImageBlock,\n save_extra_block: SaveExtraBlock,\n step_chart_block: StepChartBlock,\n svg_image_block: SVGImageBlock,\n withdrawal_block: WithdrawalBlock,\n transaction_block: TransactionBlock,\n} as Record<string, React.ComponentType<{ payload: InsightsPayload; beatGuid?: string }>>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,IAAM,IAAA,CAAQ,MAAwB;AAAC,GAKjC,IAAmB,oBAAI,IAAI;AAAA,EAAC;AAAA,EAAI;AAAA,EAAQ;AAAW,CAAC,GAC7C,KAAA,CAAkB,MAAmC;AAChE,QAAM,IAAa,GAAO,KAAK,EAAE,YAAY;AAC7C,SAAO,CAAC,CAAC,KAAc,CAAC,EAAiB,IAAI,CAAU;AACzD,GAiBa,KAAe;AAAA,EACzB,CAAA,EAAgB,wBAAA,GAA2B;AAAA,IAC1C,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,MAAa;AAAA,EACf;AAAA,EACC,CAAA,EAAgB,0BAAA,GAA6B;AAAA,IAC5C,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAO;AAAA,EACT;AAAA,EACC,CAAA,EAAgB,gCAAA,GAAmC;AAAA,IAClD,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAO;AAAA,EACT;AAAA,EACC,CAAA,EAAgB,gCAAA,GAAmC;AAAA,IAClD,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,MAAa;AAAA,EACf;AAAA,EAGC,CAAA,EAAgB,kCAAA,GAAqC;AAAA,IACpD,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,CAAQ,GAAU,MAAS,EAAK,WAAW,mBAAmB;AAAA,EAChE;AAAA,EAGC,CAAA,EAAgB,4BAAA,GAA+B;AAAA,IAC9C,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,CAAQ,GAAU,MAAS,EAAK,MAAM,mBAAmB;AAAA,EAC3D;AAAA,EACC,CAAA,EAAgB,6BAAA,GAAgC;AAAA,IAC/C,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,CAAQ,GAAU,GAAO,MAAS,GAAM,kBAAkB,SAAS;AAAA,EACrE;AACF,GAEa,KAAS;AAAA,EACpB,eAAe;AAAA,EACf,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,mBAAmB;AACrB"}
1
+ {"version":3,"file":"blocks.es.js","names":[],"sources":["../../../src/insights-v2/mappings/blocks.ts"],"sourcesContent":["import {\n AccountBlock,\n AccountSwitchBlock,\n BarchartBlock,\n BudgetBlock,\n DonutChartBlock,\n DoubleBarChartBlock,\n DoubleProgressBarBlock,\n SaveExtraBlock,\n SVGImageBlock,\n WithdrawalBlock,\n TransactionBlock,\n} from '../blocks'\nimport StepChartBlock from '../blocks/ChartBlocks/StepChartBlock'\nimport ImageBlock from '../blocks/ImageBlocks/ImageBlock'\n\nimport type { Beat, GlobalCopy, InsightsPayload } from '../../core'\nimport { ContactSupportActionBlock } from '../actionBlocks/ContactSupportActionBlock'\nimport { PlaceholderActionBlock } from '../actionBlocks/PlaceholderActionBlock'\nimport { MakeTransferActionBlockLayer } from '../actionBlocks/MakeTransferActionBlock/MakeTransferActionBlockLayer'\nimport { getMakeTransferDrawerTitle } from '../actionBlocks/MakeTransferActionBlock/layout'\nimport { TransactionHistoryBlock } from '../actionBlocks/TransactionHistoryBlock/TransactionHistoryBlock'\nimport { getDrawerHeaderTitle } from '../actionBlocks/TransactionHistoryBlock/utils'\nimport {\n TransactionDetailsBlock,\n useTransactionDetailsPrepare,\n} from '../actionBlocks/TransactionDetailsBlock'\nimport {\n RecurringTransactionBlock,\n useRecurringTransactionPrepare,\n} from '../actionBlocks/RecurringTransactionBlock'\nimport { TransactionListBlock } from '../actionBlocks/TransactionListBlock'\nimport { RemainingCashBlock } from '../actionBlocks/RemainingCashBlock'\n// Keys live in ./actionBlocksKey (imported directly by chart blocks/tests too) to avoid a\n// circular import between this module and the chart blocks — see that file for details.\nimport { actionBlocksKey } from './actionBlocksKey'\n\n// Drilldown indexes are not passed down: action blocks read them from\n// InsightsV2Store (useInsightsV2Store().actionDrawer).\nexport interface ActionBlockProps {\n beat: Beat\n}\n\nconst noop = (_: ActionBlockProps) => {}\n\n// A CTA opens a drawer only when it carries a real `block`. The backend may send\n// an empty/absent block (or the literal strings \"null\"/\"undefined\") for CTAs\n// that trigger something else (e.g. a postMessage) instead of a drilldown.\nconst NON_BLOCK_VALUES = new Set(['', 'null', 'undefined'])\nexport const hasDrawerBlock = (block?: string | null): boolean => {\n const normalized = block?.trim().toLowerCase()\n return !!normalized && !NON_BLOCK_VALUES.has(normalized)\n}\n\nexport interface ActionBlockEntry {\n Component: React.ComponentType<ActionBlockProps>\n usePrepare: (props: ActionBlockProps) => void // required; default to noop in each entry\n // Resolves the drawer title from the clicked CTA's variant + copy, with the beat available\n // for blocks that title from beat fields (e.g. transaction-list reads insights_payload.title).\n // Falls back to the CTA label when the resolver returns an empty string / is absent.\n title?: (variant: string | null | undefined, copy: GlobalCopy, beat?: Beat) => string\n}\n\n// Registry of drawer drilldowns, keyed by the `block` name the backend sends\n// on a beat's CTA. To add one: create a component taking ActionBlockProps,\n// read the clicked indexes from useInsightsV2Store().actionDrawer, and\n// register it here. Add\n// `usePrepare` when the block needs to load data before rendering.\n\nexport const actionBlocks = {\n [actionBlocksKey.PLACEHOLDER_ACTION_BLOCK]: {\n Component: PlaceholderActionBlock,\n usePrepare: noop,\n title: () => 'Action Block Layer Drilldown',\n },\n [actionBlocksKey.MAKE_TRANSFER_ACTION_BLOCK]: {\n Component: MakeTransferActionBlockLayer,\n usePrepare: noop,\n title: getMakeTransferDrawerTitle,\n },\n [actionBlocksKey.TRANSCATION_HISTORY_ACTION_BLOCK]: {\n Component: TransactionHistoryBlock,\n usePrepare: noop,\n title: getDrawerHeaderTitle,\n },\n [actionBlocksKey.TRANSACTION_DETAILS_ACTION_BLOCK]: {\n Component: TransactionDetailsBlock,\n usePrepare: useTransactionDetailsPrepare,\n title: () => 'Transaction Details',\n },\n // Expense Details for one recurring subscription. Which subscription a beat names is resolved in\n // `RecurringTransactionBlock/subscriptionBeats.ts`, not through this registry.\n [actionBlocksKey.RECURRING_TRANSACTION_ACTION_BLOCK]: {\n Component: RecurringTransactionBlock,\n usePrepare: useRecurringTransactionPrepare,\n title: (_variant, copy) => copy.recurring?.expense_details ?? '',\n },\n // Remaining Cash for the Payday Cash Left Over Status beat. Store-driven: reuses the recurring\n // loader, which also loads accounts and categories, so CashflowStore's computeds are ready.\n [actionBlocksKey.REMAINING_CASH_ACTION_BLOCK]: {\n Component: RemainingCashBlock,\n usePrepare: useRecurringTransactionPrepare,\n title: (_variant, copy) => copy.insights_feed?.remaining_cash?.title ?? '',\n },\n // The block renders its own drawer (the help module's RequestSupport) on top of the action\n // drawer, so the action drawer's title is the CTA label.\n [actionBlocksKey.CONTACT_SUPPORT_ACTION_BLOCK]: {\n Component: ContactSupportActionBlock,\n usePrepare: noop,\n title: (_variant, copy) => copy.help?.request_support ?? '',\n },\n [actionBlocksKey.TRANSACTION_LIST_ACTION_BLOCK]: {\n Component: TransactionListBlock,\n usePrepare: useTransactionDetailsPrepare,\n title: (_variant, _copy, beat) => beat?.insights_payload?.title ?? '',\n },\n} as Record<string, ActionBlockEntry>\n\nexport const blocks = {\n account_block: AccountBlock,\n account_switch_block: AccountSwitchBlock,\n bar_chart_block: BarchartBlock,\n budget_block: BudgetBlock,\n donut_chart_block: DonutChartBlock,\n double_bar_chart_block: DoubleBarChartBlock,\n double_progress_bar_block: DoubleProgressBarBlock,\n image_block: ImageBlock,\n save_extra_block: SaveExtraBlock,\n step_chart_block: StepChartBlock,\n svg_image_block: SVGImageBlock,\n withdrawal_block: WithdrawalBlock,\n transaction_block: TransactionBlock,\n} as Record<string, React.ComponentType<{ payload: InsightsPayload; beatGuid?: string }>>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,IAAM,IAAA,CAAQ,MAAwB;AAAC,GAKjC,IAAmB,oBAAI,IAAI;AAAA,EAAC;AAAA,EAAI;AAAA,EAAQ;AAAW,CAAC,GAC7C,KAAA,CAAkB,MAAmC;AAChE,QAAM,IAAa,GAAO,KAAK,EAAE,YAAY;AAC7C,SAAO,CAAC,CAAC,KAAc,CAAC,EAAiB,IAAI,CAAU;AACzD,GAiBa,KAAe;AAAA,EACzB,CAAA,EAAgB,wBAAA,GAA2B;AAAA,IAC1C,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,MAAa;AAAA,EACf;AAAA,EACC,CAAA,EAAgB,0BAAA,GAA6B;AAAA,IAC5C,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAO;AAAA,EACT;AAAA,EACC,CAAA,EAAgB,gCAAA,GAAmC;AAAA,IAClD,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAO;AAAA,EACT;AAAA,EACC,CAAA,EAAgB,gCAAA,GAAmC;AAAA,IAClD,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,MAAa;AAAA,EACf;AAAA,EAGC,CAAA,EAAgB,kCAAA,GAAqC;AAAA,IACpD,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,CAAQ,GAAU,MAAS,EAAK,WAAW,mBAAmB;AAAA,EAChE;AAAA,EAGC,CAAA,EAAgB,2BAAA,GAA8B;AAAA,IAC7C,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,CAAQ,GAAU,MAAS,EAAK,eAAe,gBAAgB,SAAS;AAAA,EAC1E;AAAA,EAGC,CAAA,EAAgB,4BAAA,GAA+B;AAAA,IAC9C,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,CAAQ,GAAU,MAAS,EAAK,MAAM,mBAAmB;AAAA,EAC3D;AAAA,EACC,CAAA,EAAgB,6BAAA,GAAgC;AAAA,IAC/C,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,OAAA,CAAQ,GAAU,GAAO,MAAS,GAAM,kBAAkB,SAAS;AAAA,EACrE;AACF,GAEa,KAAS;AAAA,EACpB,eAAe;AAAA,EACf,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,mBAAmB;AACrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mx-cartographer/experiences",
3
- "version": "9.4.68",
3
+ "version": "9.4.69",
4
4
  "description": "Library containing experience widgets",
5
5
  "author": "MX",
6
6
  "license": "MIT",