@mx-cartographer/experiences 9.6.14 → 9.7.0

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 (25) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/core/types/Insights.d.ts +3 -2
  3. package/dist/core/types/Insights.es.js.map +1 -1
  4. package/dist/core/types/localization/InsightsFeedCopy.d.ts +2 -0
  5. package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js +67 -67
  6. package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js.map +1 -1
  7. package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/DebtsBlock.d.ts +16 -12
  8. package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/DebtsBlock.es.js +67 -46
  9. package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/DebtsBlock.es.js.map +1 -1
  10. package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/layout.d.ts +17 -0
  11. package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/layout.es.js +24 -0
  12. package/dist/insights-v2/blocks/ComponentBlocks/DebtsBlock/layout.es.js.map +1 -0
  13. package/dist/insights-v2/components/BaseLayout.es.js +1 -1
  14. package/dist/insights-v2/components/BaseLayout.es.js.map +1 -1
  15. package/dist/insights-v2/components/TransactionListCard.es.js +15 -14
  16. package/dist/insights-v2/components/TransactionListCard.es.js.map +1 -1
  17. package/dist/insights-v2/components/statusIcon.d.ts +8 -0
  18. package/dist/insights-v2/components/statusIcon.es.js +11 -6
  19. package/dist/insights-v2/components/statusIcon.es.js.map +1 -1
  20. package/dist/insights-v2/ctaActions/ctaPostMessages.es.js +15 -14
  21. package/dist/insights-v2/ctaActions/ctaPostMessages.es.js.map +1 -1
  22. package/dist/insights-v2/index.es.js +18 -18
  23. package/dist/microinsights/cards/InsightCard.es.js +38 -38
  24. package/dist/microinsights/cards/InsightCard.es.js.map +1 -1
  25. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [9.7.0] - 10-17-2026
2
+
3
+ - **ADDED** - `PaydayCashLeftOverStatus` in `ctaPostMessages`: the primary CTA ("Transfer to Savings" / "Transfer Funds") posts `beat/cta` `op_1` on both variants (WEC-1916)
4
+ - **ADDED** - `statusIconPalette` beside `statusIconName`: the micro card's status tile takes the palette its slot names (`success.main`, `warning.main`, `error.main`), so Payday Cash Left Over Status's on-track check is green; any other value keeps the error tint (WEC-1916)
5
+ - **CHANGED** - `account_block`'s `status_on_track` / `status_off_track` tiles read `amount` and `sub_text` from `instance_slot.data` (on the confetti tile the line under the amount takes `sub_text` in place of `label`). When `data` is sent it is the only source: a missing or wrongly typed slot draws nothing — no `$0.00`, no stale flat value. Envelopes without `data` render as before (WEC-1916)
6
+ - **FIXED** - The mini (`BaseLayout`) and micro (`InsightCard`) action label falls back to `in_description_cta.label` when `primary_cta.label` is an empty string, not only when it is absent (`||` rather than `??`), matching copy that sends `call_to_action: ""` (WEC-1916)
7
+ - **CHANGED** - Exported type `Footer.account` widens from `string | undefined` to `string | null | undefined`: tupac sends `null` for a beat with no accounts. Consumers that type `footer.account` as `string | undefined` need to accept `null` (`Footer` already reads it with `?? ''`) (WEC-1916)
8
+ - **CHANGED** - The Payday Cash Left Over Status fixtures (`RemainingCashBlockPayload.json`) carry full, mini and micro envelopes per variant; "View Details" is the secondary CTA that opens the Remaining Cash drawer under both variants, and the micro envelope names its status icon as the `icon` slot (WEC-1916)
9
+
10
+ ## [9.6.15] - 10-15-2026
11
+
12
+ - **ADDED** - `debts_block` `debt_summary` variant for the Debt Payoff Strategies beat when it spans several accounts (the architecture doc's Debts "Debt Summary" branch): a `TransactionListCard` on a primary-tinted slot with one row per debt account from `instance_slot.data.series` (pre-localized `logo`, `primary_text` name, `secondary_text` rate, `amount` balance, in the order sent; a row without a name is dropped), an optional `header_text`, and the total owed (`amount`) as the footer under a new optional `insights_feed.debts_block.total_balance_label` caption. With no rows the block renders nothing. Stories, fixtures and tests (WEC-1311)
13
+ - **CHANGED** - `DebtsBlock` now resolves its card per `instance_slot.variant` through a `layout.ts` table and `resolveVariantConfig` (the `AccountBlock` pattern; an unknown variant warns and renders the payoff card). Each variant needs only its own copy keys, so a host that has shipped the payoff labels but not `total_balance_label` keeps the payoff card intact. `projected_payoff` still reads its facts flat on `instance_slot` and renders exactly as before (WEC-1311)
14
+
1
15
  ## [9.6.14] - 10-15-2026
2
16
 
3
17
  - **ADDED** - `onAnalyticsEvent` callback on `BeatActions` (WEC-1849)
@@ -225,9 +225,10 @@ export interface Footer {
225
225
  /**
226
226
  * The account label, on both V1 and V2. The backend resolves the plurality: one account sends
227
227
  * its name (e.g. `Epic Bank`), several send a localized count (e.g. `2 Accounts`), none sends
228
- * nothing. There is deliberately no separate `accounts` key — see tupac's `footer_account_label`.
228
+ * `null` (tupac's `footer_account_label` returns nil for a beat with no accounts, as Payday Cash
229
+ * Left Over Status does). There is deliberately no separate `accounts` key.
229
230
  */
230
- account?: string;
231
+ account?: string | null;
231
232
  /**
232
233
  * V2 (LargeTransactionV2 onward): unix seconds, formatted by `Footer` for display.
233
234
  * Replaces `date`; `date` wins when a beat somehow sends both.
@@ -1 +1 @@
1
- {"version":3,"file":"Insights.es.js","names":[],"sources":["../../../src/core/types/Insights.ts"],"sourcesContent":["// ============ Core InsightsV2 Types ============\n\nimport { InsightsInstanceSlotData } from './InsightsInstanceSlotData'\n\nexport interface ThemedSVGImageProps {\n divProps?: React.HTMLAttributes<HTMLDivElement>\n image: React.ComponentType<React.SVGProps<SVGSVGElement>>\n isMini?: boolean\n}\n\n/**\n * Emitted by a block when the user drills into a specific datum (e.g. clicks a\n * chart bar). Named fields rather than positional args so blocks with differing\n * shapes can extend this without the call sites transposing values.\n */\nexport interface DrilldownPayload {\n chartBarIndex: number\n tabIndex?: number\n transaction_guid?: string\n block?: string\n}\n\n/**\n * Which envelope a beat was fetched with. `embedded` (the transaction-row pill + details-drawer\n * card) and `notification` are V2 additions; a surface asks for one with `widget_type=` on the fetch.\n */\nexport type WidgetType = 'full' | 'mini' | 'micro' | 'embedded' | 'notification'\n\n/**\n * V2: the transaction-row tag, its own small section of the `embedded` envelope (the same grammar\n * as `description` / `footer`, with room for a tone or an icon later). Omitted for an insight that\n * tags no transaction row. It deliberately is *not* `short_title`, which stays a per-variant\n * attribute with a second consumer (the bank-holiday sub-header).\n */\nexport interface Pill {\n text: string\n}\n\n/**\n * V2: facts a drilldown shows that the card does not (e.g. the account number for the Transaction\n * Details drawer). A flat hash shared by every CTA of the card, omitted when the insight has none.\n * Never carries copy or user actions (memo, tags, hide, flag come from the transaction store).\n */\nexport type DrilldownData = Record<string, string | number | boolean | null>\n\nexport interface InsightsPayload {\n widget_type: WidgetType\n instance_slot: InstanceSlot\n /**\n * V1 only. The v2 contract carries everything a block needs on `instance_slot.data`,\n * and omits this key entirely (see the LargeTransactionV2 payload). Blocks that still require it\n * get it as a required field through `BlockProps`, which re-declares it.\n */\n instance_slot_data?: InsightsInstanceSlotData\n description: Description\n primary_cta?: PrimaryCTA\n secondary_cta?: SecondaryCTA\n title?: string\n sub_title?: Subtitle\n /**\n * V2 rename of `sub_title`: a flat string, with the logo promoted to the payload-level `logo`\n * field below. `sub_title` wins when both are present.\n */\n subtitle?: string\n /** V2: header logo paired with the flat `subtitle`: an entity guid or a status icon (`LogoRef`). */\n logo?: LogoRef\n /** V2: which design branch the backend picked (e.g. `no_merchant`). */\n variant?: string\n /** V2, `embedded` envelope only: the transaction-row pill. */\n pill?: Pill\n /** V2: drilldown-only facts, e.g. `{ account_number: 'XXXXXXXX043' }`. */\n drilldown_data?: DrilldownData\n footer?: Footer\n /**\n * V2: the link inside the description: on the full card a drawer of its own (Low Account\n * Balance's \"Transactions ›\"); on mini and micro the card's action, sent instead of `primary_cta`.\n * Absent when the beat has no link.\n */\n in_description_cta?: InDescriptionCTA\n guid: string\n user_guid: string\n client_guid?: string\n /** Template name, e.g. `LargeTransactionV2`. */\n template?: string\n revision?: number\n /** Unix seconds. */\n created_at?: number\n /** Unix seconds. */\n updated_at?: number\n /** Unix seconds. */\n active_at?: number\n displayed_at?: number | null\n dismissed_at: number | null\n cta_clicked_at?: number | null\n has_been_displayed?: boolean\n is_dismissed: boolean\n is_deleted?: boolean\n is_hidden_by_system?: boolean\n is_obsolete?: boolean\n is_refreshable?: boolean\n is_sampled?: boolean\n is_zero_state?: boolean\n status?: string | null\n /**\n * V2 (LargeTransactionV2 onward): the entities the beat is about, carried on the payload so\n * action blocks do not have to reach back out to the beat envelope.\n */\n primary_account_guid?: string | null\n primary_transaction_guid?: string | null\n primary_category_guid?: string | null\n primary_merchant_guid?: string | null\n /**\n * V2: the repeating transaction a subscription beat is about (Upcoming Subscription, Subscription\n * Price Increase). Read by `recurring_transaction_block`, see\n * `actionBlocks/RecurringTransactionBlock/subscriptionBeats.ts`.\n */\n primary_repeating_transaction_guid?: string | null\n}\n\nexport interface Legends {\n label: string\n value: number\n additional_value?: number\n additional_value_type?: string\n value_type?: string\n}\n\nexport interface Logo {\n category_guid?: string\n category_name?: string\n institution_guid?: string\n institution_name?: string\n logo_color?: string\n /** Draw the `logo_name` icon filled (V2 `ICO-` logos). */\n logo_fill?: boolean\n logo_name?: string\n merchant_guid?: string\n merchant_name?: string\n}\n\nexport interface Subtitle {\n logo?: Logo\n text: string\n}\n\n/**\n * A V2 logo, shared by the header (`InsightsPayload.logo`) and every instance-slot row. It takes\n * one of two shapes:\n *\n * - **Entity**: `guid`, whose prefix (`INS-` / `MCH-` / `CAT-`) picks the logo component, plus an\n * optional `fallback_guid` for when that component's asset cannot load. Today that is the\n * category behind an `MCH-` guid, which `MerchantLogo` shows as a tile when the merchant image\n * is missing.\n * - **Status icon**: `icon` (an mx-icons name, e.g. `warning`) and `color` (a theme palette path,\n * e.g. `error.main`), for subheaders that show a state rather than an entity (V1's\n * `logo_name` / `logo_color`).\n *\n * `alt` is the accessible name for either shape. A logo sends one shape; if it sends both, `icon`\n * wins, as `logo_name` does in V1's `SubHeader`.\n */\nexport interface LogoRef {\n alt?: string\n color?: string\n fallback_guid?: string\n guid?: string\n icon?: string\n}\n\nexport interface CategoryLogo {\n category_guid: string\n category_name: string\n}\n\nexport interface MerchantLogo {\n merchant_guid: string\n merchant_name: string\n}\n\nexport interface InstitutionLogo {\n institution_guid: string\n institution_name: string\n}\n\nexport interface Description {\n text: string\n html_text: string\n}\n\n/**\n * Post message a CTA press sends to the host, resolved by the backend for the beat's current\n * state. Absent/null = the backend has not described one: the frontend uses the template's\n * interim `ctaPostMessages` entry if there is one, else sends no message. `payload` carries only\n * beat-specific extras; the frontend always adds `beat_guid`, `beat_template`, `user_guid` and\n * `action_string`.\n */\nexport interface CtaPostMessageMetadata {\n /** Post message event; defaults to `beat/cta`. */\n event?: string | null\n /** Operation the host should perform, e.g. `op_1`, `op_2`, `op_3`. Defaults to `op_1`. */\n action?: string | null\n /** Beat-specific fields merged into the message metadata (account ids, amounts, ...). */\n payload?: Record<string, unknown> | null\n}\n\nexport interface PrimaryCTA {\n label: string\n block: string\n variant?: string | null\n /**\n * What pressing the CTA does beyond opening its block, named by the backend (ditto\n * `primary_cta_action`, passed through by tupac). Looked up in `insights-v2/ctaActions`;\n * null / absent / unknown means the CTA only opens its block or posts its message.\n */\n action_key?: string | null\n metadata?: CtaPostMessageMetadata | null\n}\n\nexport interface SecondaryCTA {\n label: string\n /**\n * Drawer block to open. `null` when the CTA opens nothing (ditto `secondary_cta_block: null`,\n * e.g. Fee Detected's \"Contact Support\"): the press posts its message to the host instead.\n */\n block: string | null\n variant?: string | null\n /** See `PrimaryCTA.action_key` (ditto `secondary_cta_action`). */\n action_key?: string | null\n metadata?: CtaPostMessageMetadata | null\n}\n\n/**\n * The description link: its label, the action block it opens and, like a CTA's, the variant that\n * tells that block what to show (ditto's `in_description_cta_variant`, e.g. `low_balance`). On mini\n * and micro it words the card's action; `block` is empty when that action opens no drawer.\n */\nexport interface InDescriptionCTA {\n label: string\n block?: string\n variant?: string | null\n action_key?: string | null\n}\n\nexport interface Footer {\n /** V1: a pre-formatted date string. */\n date?: string\n /**\n * The account label, on both V1 and V2. The backend resolves the plurality: one account sends\n * its name (e.g. `Epic Bank`), several send a localized count (e.g. `2 Accounts`), none sends\n * nothing. There is deliberately no separate `accounts` key — see tupac's `footer_account_label`.\n */\n account?: string\n /**\n * V2 (LargeTransactionV2 onward): unix seconds, formatted by `Footer` for display.\n * Replaces `date`; `date` wins when a beat somehow sends both.\n */\n timestamp?: number\n}\n\n// ============ Instance Slot Types ============\n// Values are the snake_case block names the backend sends on a beat's instance slot; the PascalCase\n// keys stay as friendly references (e.g. BlockType.BarChartBlock === 'bar_chart_block').\nexport const BlockType = {\n AccountBlock: 'account_block',\n AccountSwitchBlock: 'account_switch_block',\n BarChartBlock: 'bar_chart_block',\n BudgetBlock: 'budget_block',\n ImageBlock: 'image_block',\n TransactionBlock: 'transaction_block',\n DonutChartBlock: 'donut_chart_block',\n DoubleBarChartBlock: 'double_bar_chart_block',\n DoubleProgressBarBlock: 'double_progress_bar_block',\n DebtsBlock: 'debts_block',\n SaveExtraBlock: 'save_extra_block',\n SavingsOpportunityBlock: 'savings_opportunity_block',\n StepChartBlock: 'step_chart_block',\n SVGImageBlock: 'svg_image_block',\n UpcomingBillBlock: 'upcoming_bill_block',\n UpcomingSubscriptionBlock: 'upcoming_subscription_block',\n WithdrawalBlock: 'withdrawal_block',\n} as const\n\nexport type BlockType = (typeof BlockType)[keyof typeof BlockType]\n\n/**\n * A pre-localized row on a V2 instance slot. The backend resolves the copy and formatting; the\n * logo is a `LogoRef` (an entity guid or a status icon, see `logoFromRef`).\n */\nexport interface InstanceSlotRow {\n amount?: number\n logo?: LogoRef\n primary_text?: string\n secondary_text?: string\n}\n\n/**\n * V2: the slots a block's variant filled, keyed by slot name; ditto owns the names and omits any\n * slot it has no value for (`lib/ditto/blocks/<block>.yml`). Read with `slot()`, which names the\n * kind the caller expects.\n */\nexport interface InstanceSlotData {\n [slot: string]: unknown\n}\n\n/**\n * Reads one slot off a block's `data`; undefined when ditto did not fill it.\n *\n * The caller names the kind, because the slot's kind lives in the block's ditto schema and not\n * here — a block fills slots with whatever its card needs, so no fixed list of kinds would hold\n * (`account_switch_block` alone carries a boolean and `budget_block` a nested object).\n */\nexport const slot = <T = unknown>(\n data: InstanceSlotData | undefined,\n name: string,\n): T | undefined => data?.[name] as T | undefined\n\n/**\n * V2: which block renders this beat's content, and what it renders.\n *\n * `block` is optional: a beat whose template has no ditto config arrives as an empty `{}` and the\n * card renders its copy and CTAs alone, so a reader cannot assume a block is named. One interface\n * with `block` optional rather than a union with `Record<string, never>`, which TypeScript absorbs\n * — that union left `block` reading as required and typed a promise it did not keep.\n *\n * `variant` is optional for the same reason — the empty `{}` carries neither. Every ditto beat\n * file that names a block also names a variant, so a *filled* slot always has one; ditto drops a\n * nil variant rather than sending null, which is why the type is `string | null | undefined`.\n */\nexport interface InstanceSlot {\n block?: BlockType\n variant?: string | null\n /** The slots this block's variant declares in ditto. */\n data?: InstanceSlotData\n // Direct Deposit block (Set Up Direct Deposit, Switch Direct Deposit, Missing\n // Interest Rate): account facts carried flat on the slot, beside `data`.\n /** Primary line on the hero card, e.g. \"Epic Bank Checking, *1234\". */\n account_name?: string\n /** Secondary line beneath the name, e.g. \"Checking Account\" / \"Credit Card\". */\n account_type?: string\n /** Status pill label, e.g. \"Direct Deposit Not Set Up\" / \"Interest Rate: 19.99% APR\". */\n status_text?: string\n institution_guid?: string\n institution_name?: string\n // Shared across multiple V2 component blocks:\n // `amount` — UpcomingBillBlock (projected bill), SavingsOpportunityBlock (coupon),\n // UpcomingSubscriptionBlock (price per cadence).\n // `merchant_guid` / `merchant_name` — UpcomingBillBlock (bill row logo + name),\n // UpcomingSubscriptionBlock (hero logo + name).\n /** Dollar amount (unformatted); the block formats it as currency. */\n amount?: number\n /** Merchant guid used to render the inline / hero logo via `LogoFromGuid` (`MCH-...`). */\n merchant_guid?: string\n /** Merchant display name — shown as logo alt text and as the merchant/hero label. */\n merchant_name?: string\n // Upcoming Bill block (Projected Bill Payment): the block derives the Sun→Sat week strip\n // around `due_date` at render time.\n /** Due date of the projected bill in ISO form (e.g. `2025-10-30`). */\n due_date?: string\n // Savings Opportunity block (Save An Extra, Potential Savings, Embedded): purely data-driven\n // coupon card. Backend sends the caption and the amount, plus `slot` to toggle the green\n // gradient background when the card is embedded in a parent surface that supplies its own.\n /** Caption shown above the amount, e.g. `Save an extra` or `Potential savings`. */\n label?: string\n /**\n * Whether to render the green gradient slot behind the coupon. Defaults to true. Backend sends\n * `false` when the coupon is embedded in a parent surface that supplies its own background.\n */\n slot?: boolean\n // Upcoming Subscription block: billing cadence for the price pill (`${amount} / ${cadence}`).\n /** Billing cadence word that trails the price, e.g. `month` or `year`. */\n cadence?: string\n // Account block (status on/off-track, deposit, payoff variants): card content carried flat on\n // the slot (the V2 contract drops `instance_slot_data`). `amount`, `label`, `merchant_guid`,\n // `merchant_name`, `institution_guid`, `institution_name` are shared fields declared above.\n /** Secondary line beneath the amount on the standard card, e.g. \"Remaining after expenses\". */\n sub_text?: string\n /** Header bar text (standard card) or the colored category strip label (deposit cards). */\n header_text?: string\n /** Generic-tile icon name used when no merchant/institution logo is available. */\n icon_name?: string\n /** Category guid used to render the deposit-card logo fallback. */\n category_guid?: string\n // Debts block: `amount` is the current balance; the shared account/institution fields above.\n /** Projected payoff date in ISO form (e.g. `2027-03-01`); the block formats it as month + year. */\n payoff_date?: string\n /** Monthly payment toward the debt (unformatted); the block formats it as currency. */\n monthly_payment?: number\n /** Annual interest rate as a percentage (e.g. `19.99`); the block formats it as a percent. */\n interest_rate?: number\n}\n"],"mappings":"AAsTA,IAAa,IAAA,CACX,GACA,MACkB,IAAO,CAAA"}
1
+ {"version":3,"file":"Insights.es.js","names":[],"sources":["../../../src/core/types/Insights.ts"],"sourcesContent":["// ============ Core InsightsV2 Types ============\n\nimport { InsightsInstanceSlotData } from './InsightsInstanceSlotData'\n\nexport interface ThemedSVGImageProps {\n divProps?: React.HTMLAttributes<HTMLDivElement>\n image: React.ComponentType<React.SVGProps<SVGSVGElement>>\n isMini?: boolean\n}\n\n/**\n * Emitted by a block when the user drills into a specific datum (e.g. clicks a\n * chart bar). Named fields rather than positional args so blocks with differing\n * shapes can extend this without the call sites transposing values.\n */\nexport interface DrilldownPayload {\n chartBarIndex: number\n tabIndex?: number\n transaction_guid?: string\n block?: string\n}\n\n/**\n * Which envelope a beat was fetched with. `embedded` (the transaction-row pill + details-drawer\n * card) and `notification` are V2 additions; a surface asks for one with `widget_type=` on the fetch.\n */\nexport type WidgetType = 'full' | 'mini' | 'micro' | 'embedded' | 'notification'\n\n/**\n * V2: the transaction-row tag, its own small section of the `embedded` envelope (the same grammar\n * as `description` / `footer`, with room for a tone or an icon later). Omitted for an insight that\n * tags no transaction row. It deliberately is *not* `short_title`, which stays a per-variant\n * attribute with a second consumer (the bank-holiday sub-header).\n */\nexport interface Pill {\n text: string\n}\n\n/**\n * V2: facts a drilldown shows that the card does not (e.g. the account number for the Transaction\n * Details drawer). A flat hash shared by every CTA of the card, omitted when the insight has none.\n * Never carries copy or user actions (memo, tags, hide, flag come from the transaction store).\n */\nexport type DrilldownData = Record<string, string | number | boolean | null>\n\nexport interface InsightsPayload {\n widget_type: WidgetType\n instance_slot: InstanceSlot\n /**\n * V1 only. The v2 contract carries everything a block needs on `instance_slot.data`,\n * and omits this key entirely (see the LargeTransactionV2 payload). Blocks that still require it\n * get it as a required field through `BlockProps`, which re-declares it.\n */\n instance_slot_data?: InsightsInstanceSlotData\n description: Description\n primary_cta?: PrimaryCTA\n secondary_cta?: SecondaryCTA\n title?: string\n sub_title?: Subtitle\n /**\n * V2 rename of `sub_title`: a flat string, with the logo promoted to the payload-level `logo`\n * field below. `sub_title` wins when both are present.\n */\n subtitle?: string\n /** V2: header logo paired with the flat `subtitle`: an entity guid or a status icon (`LogoRef`). */\n logo?: LogoRef\n /** V2: which design branch the backend picked (e.g. `no_merchant`). */\n variant?: string\n /** V2, `embedded` envelope only: the transaction-row pill. */\n pill?: Pill\n /** V2: drilldown-only facts, e.g. `{ account_number: 'XXXXXXXX043' }`. */\n drilldown_data?: DrilldownData\n footer?: Footer\n /**\n * V2: the link inside the description: on the full card a drawer of its own (Low Account\n * Balance's \"Transactions ›\"); on mini and micro the card's action, sent instead of `primary_cta`.\n * Absent when the beat has no link.\n */\n in_description_cta?: InDescriptionCTA\n guid: string\n user_guid: string\n client_guid?: string\n /** Template name, e.g. `LargeTransactionV2`. */\n template?: string\n revision?: number\n /** Unix seconds. */\n created_at?: number\n /** Unix seconds. */\n updated_at?: number\n /** Unix seconds. */\n active_at?: number\n displayed_at?: number | null\n dismissed_at: number | null\n cta_clicked_at?: number | null\n has_been_displayed?: boolean\n is_dismissed: boolean\n is_deleted?: boolean\n is_hidden_by_system?: boolean\n is_obsolete?: boolean\n is_refreshable?: boolean\n is_sampled?: boolean\n is_zero_state?: boolean\n status?: string | null\n /**\n * V2 (LargeTransactionV2 onward): the entities the beat is about, carried on the payload so\n * action blocks do not have to reach back out to the beat envelope.\n */\n primary_account_guid?: string | null\n primary_transaction_guid?: string | null\n primary_category_guid?: string | null\n primary_merchant_guid?: string | null\n /**\n * V2: the repeating transaction a subscription beat is about (Upcoming Subscription, Subscription\n * Price Increase). Read by `recurring_transaction_block`, see\n * `actionBlocks/RecurringTransactionBlock/subscriptionBeats.ts`.\n */\n primary_repeating_transaction_guid?: string | null\n}\n\nexport interface Legends {\n label: string\n value: number\n additional_value?: number\n additional_value_type?: string\n value_type?: string\n}\n\nexport interface Logo {\n category_guid?: string\n category_name?: string\n institution_guid?: string\n institution_name?: string\n logo_color?: string\n /** Draw the `logo_name` icon filled (V2 `ICO-` logos). */\n logo_fill?: boolean\n logo_name?: string\n merchant_guid?: string\n merchant_name?: string\n}\n\nexport interface Subtitle {\n logo?: Logo\n text: string\n}\n\n/**\n * A V2 logo, shared by the header (`InsightsPayload.logo`) and every instance-slot row. It takes\n * one of two shapes:\n *\n * - **Entity**: `guid`, whose prefix (`INS-` / `MCH-` / `CAT-`) picks the logo component, plus an\n * optional `fallback_guid` for when that component's asset cannot load. Today that is the\n * category behind an `MCH-` guid, which `MerchantLogo` shows as a tile when the merchant image\n * is missing.\n * - **Status icon**: `icon` (an mx-icons name, e.g. `warning`) and `color` (a theme palette path,\n * e.g. `error.main`), for subheaders that show a state rather than an entity (V1's\n * `logo_name` / `logo_color`).\n *\n * `alt` is the accessible name for either shape. A logo sends one shape; if it sends both, `icon`\n * wins, as `logo_name` does in V1's `SubHeader`.\n */\nexport interface LogoRef {\n alt?: string\n color?: string\n fallback_guid?: string\n guid?: string\n icon?: string\n}\n\nexport interface CategoryLogo {\n category_guid: string\n category_name: string\n}\n\nexport interface MerchantLogo {\n merchant_guid: string\n merchant_name: string\n}\n\nexport interface InstitutionLogo {\n institution_guid: string\n institution_name: string\n}\n\nexport interface Description {\n text: string\n html_text: string\n}\n\n/**\n * Post message a CTA press sends to the host, resolved by the backend for the beat's current\n * state. Absent/null = the backend has not described one: the frontend uses the template's\n * interim `ctaPostMessages` entry if there is one, else sends no message. `payload` carries only\n * beat-specific extras; the frontend always adds `beat_guid`, `beat_template`, `user_guid` and\n * `action_string`.\n */\nexport interface CtaPostMessageMetadata {\n /** Post message event; defaults to `beat/cta`. */\n event?: string | null\n /** Operation the host should perform, e.g. `op_1`, `op_2`, `op_3`. Defaults to `op_1`. */\n action?: string | null\n /** Beat-specific fields merged into the message metadata (account ids, amounts, ...). */\n payload?: Record<string, unknown> | null\n}\n\nexport interface PrimaryCTA {\n label: string\n block: string\n variant?: string | null\n /**\n * What pressing the CTA does beyond opening its block, named by the backend (ditto\n * `primary_cta_action`, passed through by tupac). Looked up in `insights-v2/ctaActions`;\n * null / absent / unknown means the CTA only opens its block or posts its message.\n */\n action_key?: string | null\n metadata?: CtaPostMessageMetadata | null\n}\n\nexport interface SecondaryCTA {\n label: string\n /**\n * Drawer block to open. `null` when the CTA opens nothing (ditto `secondary_cta_block: null`,\n * e.g. Fee Detected's \"Contact Support\"): the press posts its message to the host instead.\n */\n block: string | null\n variant?: string | null\n /** See `PrimaryCTA.action_key` (ditto `secondary_cta_action`). */\n action_key?: string | null\n metadata?: CtaPostMessageMetadata | null\n}\n\n/**\n * The description link: its label, the action block it opens and, like a CTA's, the variant that\n * tells that block what to show (ditto's `in_description_cta_variant`, e.g. `low_balance`). On mini\n * and micro it words the card's action; `block` is empty when that action opens no drawer.\n */\nexport interface InDescriptionCTA {\n label: string\n block?: string\n variant?: string | null\n action_key?: string | null\n}\n\nexport interface Footer {\n /** V1: a pre-formatted date string. */\n date?: string\n /**\n * The account label, on both V1 and V2. The backend resolves the plurality: one account sends\n * its name (e.g. `Epic Bank`), several send a localized count (e.g. `2 Accounts`), none sends\n * `null` (tupac's `footer_account_label` returns nil for a beat with no accounts, as Payday Cash\n * Left Over Status does). There is deliberately no separate `accounts` key.\n */\n account?: string | null\n /**\n * V2 (LargeTransactionV2 onward): unix seconds, formatted by `Footer` for display.\n * Replaces `date`; `date` wins when a beat somehow sends both.\n */\n timestamp?: number\n}\n\n// ============ Instance Slot Types ============\n// Values are the snake_case block names the backend sends on a beat's instance slot; the PascalCase\n// keys stay as friendly references (e.g. BlockType.BarChartBlock === 'bar_chart_block').\nexport const BlockType = {\n AccountBlock: 'account_block',\n AccountSwitchBlock: 'account_switch_block',\n BarChartBlock: 'bar_chart_block',\n BudgetBlock: 'budget_block',\n ImageBlock: 'image_block',\n TransactionBlock: 'transaction_block',\n DonutChartBlock: 'donut_chart_block',\n DoubleBarChartBlock: 'double_bar_chart_block',\n DoubleProgressBarBlock: 'double_progress_bar_block',\n DebtsBlock: 'debts_block',\n SaveExtraBlock: 'save_extra_block',\n SavingsOpportunityBlock: 'savings_opportunity_block',\n StepChartBlock: 'step_chart_block',\n SVGImageBlock: 'svg_image_block',\n UpcomingBillBlock: 'upcoming_bill_block',\n UpcomingSubscriptionBlock: 'upcoming_subscription_block',\n WithdrawalBlock: 'withdrawal_block',\n} as const\n\nexport type BlockType = (typeof BlockType)[keyof typeof BlockType]\n\n/**\n * A pre-localized row on a V2 instance slot. The backend resolves the copy and formatting; the\n * logo is a `LogoRef` (an entity guid or a status icon, see `logoFromRef`).\n */\nexport interface InstanceSlotRow {\n amount?: number\n logo?: LogoRef\n primary_text?: string\n secondary_text?: string\n}\n\n/**\n * V2: the slots a block's variant filled, keyed by slot name; ditto owns the names and omits any\n * slot it has no value for (`lib/ditto/blocks/<block>.yml`). Read with `slot()`, which names the\n * kind the caller expects.\n */\nexport interface InstanceSlotData {\n [slot: string]: unknown\n}\n\n/**\n * Reads one slot off a block's `data`; undefined when ditto did not fill it.\n *\n * The caller names the kind, because the slot's kind lives in the block's ditto schema and not\n * here — a block fills slots with whatever its card needs, so no fixed list of kinds would hold\n * (`account_switch_block` alone carries a boolean and `budget_block` a nested object).\n */\nexport const slot = <T = unknown>(\n data: InstanceSlotData | undefined,\n name: string,\n): T | undefined => data?.[name] as T | undefined\n\n/**\n * V2: which block renders this beat's content, and what it renders.\n *\n * `block` is optional: a beat whose template has no ditto config arrives as an empty `{}` and the\n * card renders its copy and CTAs alone, so a reader cannot assume a block is named. One interface\n * with `block` optional rather than a union with `Record<string, never>`, which TypeScript absorbs\n * — that union left `block` reading as required and typed a promise it did not keep.\n *\n * `variant` is optional for the same reason — the empty `{}` carries neither. Every ditto beat\n * file that names a block also names a variant, so a *filled* slot always has one; ditto drops a\n * nil variant rather than sending null, which is why the type is `string | null | undefined`.\n */\nexport interface InstanceSlot {\n block?: BlockType\n variant?: string | null\n /** The slots this block's variant declares in ditto. */\n data?: InstanceSlotData\n // Direct Deposit block (Set Up Direct Deposit, Switch Direct Deposit, Missing\n // Interest Rate): account facts carried flat on the slot, beside `data`.\n /** Primary line on the hero card, e.g. \"Epic Bank Checking, *1234\". */\n account_name?: string\n /** Secondary line beneath the name, e.g. \"Checking Account\" / \"Credit Card\". */\n account_type?: string\n /** Status pill label, e.g. \"Direct Deposit Not Set Up\" / \"Interest Rate: 19.99% APR\". */\n status_text?: string\n institution_guid?: string\n institution_name?: string\n // Shared across multiple V2 component blocks:\n // `amount` — UpcomingBillBlock (projected bill), SavingsOpportunityBlock (coupon),\n // UpcomingSubscriptionBlock (price per cadence).\n // `merchant_guid` / `merchant_name` — UpcomingBillBlock (bill row logo + name),\n // UpcomingSubscriptionBlock (hero logo + name).\n /** Dollar amount (unformatted); the block formats it as currency. */\n amount?: number\n /** Merchant guid used to render the inline / hero logo via `LogoFromGuid` (`MCH-...`). */\n merchant_guid?: string\n /** Merchant display name — shown as logo alt text and as the merchant/hero label. */\n merchant_name?: string\n // Upcoming Bill block (Projected Bill Payment): the block derives the Sun→Sat week strip\n // around `due_date` at render time.\n /** Due date of the projected bill in ISO form (e.g. `2025-10-30`). */\n due_date?: string\n // Savings Opportunity block (Save An Extra, Potential Savings, Embedded): purely data-driven\n // coupon card. Backend sends the caption and the amount, plus `slot` to toggle the green\n // gradient background when the card is embedded in a parent surface that supplies its own.\n /** Caption shown above the amount, e.g. `Save an extra` or `Potential savings`. */\n label?: string\n /**\n * Whether to render the green gradient slot behind the coupon. Defaults to true. Backend sends\n * `false` when the coupon is embedded in a parent surface that supplies its own background.\n */\n slot?: boolean\n // Upcoming Subscription block: billing cadence for the price pill (`${amount} / ${cadence}`).\n /** Billing cadence word that trails the price, e.g. `month` or `year`. */\n cadence?: string\n // Account block (status on/off-track, deposit, payoff variants): card content carried flat on\n // the slot (the V2 contract drops `instance_slot_data`). `amount`, `label`, `merchant_guid`,\n // `merchant_name`, `institution_guid`, `institution_name` are shared fields declared above.\n /** Secondary line beneath the amount on the standard card, e.g. \"Remaining after expenses\". */\n sub_text?: string\n /** Header bar text (standard card) or the colored category strip label (deposit cards). */\n header_text?: string\n /** Generic-tile icon name used when no merchant/institution logo is available. */\n icon_name?: string\n /** Category guid used to render the deposit-card logo fallback. */\n category_guid?: string\n // Debts block: `amount` is the current balance; the shared account/institution fields above.\n /** Projected payoff date in ISO form (e.g. `2027-03-01`); the block formats it as month + year. */\n payoff_date?: string\n /** Monthly payment toward the debt (unformatted); the block formats it as currency. */\n monthly_payment?: number\n /** Annual interest rate as a percentage (e.g. `19.99`); the block formats it as a percent. */\n interest_rate?: number\n}\n"],"mappings":"AAuTA,IAAa,IAAA,CACX,GACA,MACkB,IAAO,CAAA"}
@@ -251,6 +251,8 @@ export interface DebtsBlockCopy {
251
251
  payoff_date_label: string;
252
252
  monthly_payment_label: string;
253
253
  interest_rate_label: string;
254
+ /** Footer caption for the `debt_summary` total, e.g. "Total balance". Optional until the service ships it. */
255
+ total_balance_label?: string;
254
256
  }
255
257
  export interface InsightsFeedCopy {
256
258
  general: GeneralInsightsFeedCopy;
@@ -1,36 +1,36 @@
1
- import { slot as m } from "../../../../core/types/Insights.es.js";
2
- import { formatCurrency as R } from "../../../../core/utils/NumberFormatting.es.js";
3
- import { useContainerDimensions as L } from "../../../hooks/useContainerDimensions.es.js";
4
- import { DepositLogo as $ } from "../../../components/ComponentBlocks/DepositLogo.es.js";
5
- import { Confetti as B } from "../../../components/shared/Confetti.es.js";
6
- import { ReactComponent as G } from "../../../components/shared/images/PaidOffCard.es.js";
7
- import { ReactComponent as N } from "../../../components/shared/images/SavingsAccountDeposit.es.js";
8
- import { resolveVariantConfig as P } from "../../resolveVariantConfig.es.js";
9
- import { HeaderComponent as V } from "./HeaderComponent.es.js";
10
- import { getLayoutConfig as j } from "./layout.es.js";
11
- import { IconComponent as A } from "./IconComponent.es.js";
12
- import { useRef as F } from "react";
13
- import t from "@mui/material/Stack";
1
+ import { slot as p } from "../../../../core/types/Insights.es.js";
2
+ import { formatCurrency as k } from "../../../../core/utils/NumberFormatting.es.js";
3
+ import { useContainerDimensions as B } from "../../../hooks/useContainerDimensions.es.js";
4
+ import { DepositLogo as F } from "../../../components/ComponentBlocks/DepositLogo.es.js";
5
+ import { Confetti as G } from "../../../components/shared/Confetti.es.js";
6
+ import { ReactComponent as P } from "../../../components/shared/images/PaidOffCard.es.js";
7
+ import { ReactComponent as V } from "../../../components/shared/images/SavingsAccountDeposit.es.js";
8
+ import { resolveVariantConfig as j } from "../../resolveVariantConfig.es.js";
9
+ import { HeaderComponent as E } from "./HeaderComponent.es.js";
10
+ import { getLayoutConfig as H } from "./layout.es.js";
11
+ import { IconComponent as O } from "./IconComponent.es.js";
12
+ import { useRef as W } from "react";
13
+ import r from "@mui/material/Stack";
14
14
  import { Text as s } from "@mxenabled/mxui";
15
- import { Icon as E } from "@mxenabled/mx-icons";
16
- import { jsx as o, jsxs as r } from "react/jsx-runtime";
17
- import { useTheme as H } from "@mui/material/styles";
18
- import i from "@mui/material/Box";
19
- var O = {
15
+ import { Icon as q } from "@mxenabled/mx-icons";
16
+ import { jsx as o, jsxs as t } from "react/jsx-runtime";
17
+ import { useTheme as J } from "@mui/material/styles";
18
+ import n from "@mui/material/Box";
19
+ var K = {
20
20
  deposit_received: "payments",
21
21
  status_on_track: "monetization_on"
22
- }, co = ({ payload: _ }) => {
23
- const C = H(), p = F(null), { height: u, width: h } = L(p), { instance_slot: n } = _, { variant: c, header_text: a, institution_guid: f, institution_name: g, icon_name: k, label: T, merchant_guid: I, merchant_name: x, category_guid: S } = n, { data: d } = n, l = m(d, "amount") ?? n.amount, b = m(d, "sub_text") ?? n.sub_text, y = m(d, "logo"), e = P(j(C), c, "default", "AccountBlock");
22
+ }, po = ({ payload: I }) => {
23
+ const S = J(), h = W(null), { height: f, width: g } = B(h), { instance_slot: i } = I, { variant: l, header_text: a, institution_guid: x, institution_name: b, icon_name: D, merchant_guid: z, merchant_name: v, category_guid: L } = i, { data: c } = i, m = c !== void 0, u = p(c, "amount"), d = m ? typeof u == "number" && Number.isFinite(u) ? u : void 0 : i.amount, y = p(c, "sub_text"), w = typeof y == "string" ? y : void 0, R = m ? w : i.sub_text, N = m ? w : i.label, _ = p(c, "logo"), e = j(H(S), l, "default", "AccountBlock");
24
24
  if (e?.isConfetti) {
25
- const D = {
26
- paidOffCard: /* @__PURE__ */ o(i, {
25
+ const $ = {
26
+ paidOffCard: /* @__PURE__ */ o(n, {
27
27
  sx: {
28
28
  flexShrink: 0,
29
29
  height: 32,
30
30
  position: "relative",
31
31
  width: 44
32
32
  },
33
- children: /* @__PURE__ */ o(G, {
33
+ children: /* @__PURE__ */ o(P, {
34
34
  "aria-hidden": !0,
35
35
  role: "presentation",
36
36
  style: {
@@ -40,13 +40,13 @@ var O = {
40
40
  }
41
41
  })
42
42
  }),
43
- savings: /* @__PURE__ */ o(N, {
43
+ savings: /* @__PURE__ */ o(V, {
44
44
  "aria-hidden": !0,
45
45
  height: 55,
46
46
  role: "presentation",
47
47
  width: 55
48
48
  }),
49
- logo: /* @__PURE__ */ o(i, {
49
+ logo: /* @__PURE__ */ o(n, {
50
50
  sx: {
51
51
  borderRadius: "4px",
52
52
  flexShrink: 0,
@@ -54,27 +54,27 @@ var O = {
54
54
  overflow: "hidden",
55
55
  width: 48
56
56
  },
57
- children: /* @__PURE__ */ o($, {
58
- categoryGuid: S,
59
- iconName: O[c] ?? "payments",
60
- institutionGuid: f,
61
- institutionName: g,
62
- merchantGuid: I,
63
- merchantName: x
57
+ children: /* @__PURE__ */ o(F, {
58
+ categoryGuid: L,
59
+ iconName: K[l] ?? "payments",
60
+ institutionGuid: x,
61
+ institutionName: b,
62
+ merchantGuid: z,
63
+ merchantName: v
64
64
  })
65
65
  })
66
- }[e.graphic ?? "logo"], v = e.secondarySource === "merchant" ? x ?? g : T, w = v ? /* @__PURE__ */ o(s, {
66
+ }[e.graphic ?? "logo"], C = e.secondarySource === "merchant" ? v ?? b : N, T = C ? /* @__PURE__ */ o(s, {
67
67
  color: e.secondaryColor,
68
68
  variant: e.secondaryVariant,
69
- children: v
70
- }) : null, z = /* @__PURE__ */ o(s, {
69
+ children: C
70
+ }) : null, A = d != null ? /* @__PURE__ */ o(s, {
71
71
  bold: !0,
72
72
  color: "success.dark",
73
73
  variant: e.amountVariant,
74
- children: `${e.amountPrefix ?? ""}${R(l, "0,0.00")}`
75
- });
76
- return /* @__PURE__ */ r(i, {
77
- ref: p,
74
+ children: `${e.amountPrefix ?? ""}${k(d, "0,0.00")}`
75
+ }) : null;
76
+ return /* @__PURE__ */ t(n, {
77
+ ref: h,
78
78
  sx: {
79
79
  backgroundImage: e.gradient,
80
80
  bgcolor: "background.paper",
@@ -83,19 +83,19 @@ var O = {
83
83
  p: 16,
84
84
  width: "100%"
85
85
  },
86
- children: [/* @__PURE__ */ o(i, {
86
+ children: [/* @__PURE__ */ o(n, {
87
87
  sx: {
88
88
  inset: 0,
89
89
  pointerEvents: "none",
90
90
  position: "absolute",
91
91
  zIndex: 1
92
92
  },
93
- children: /* @__PURE__ */ o(B, {
94
- height: u,
95
- shouldRun: u > 0 && h > 0,
96
- width: h
93
+ children: /* @__PURE__ */ o(G, {
94
+ height: f,
95
+ shouldRun: f > 0 && g > 0,
96
+ width: g
97
97
  })
98
- }), /* @__PURE__ */ r(t, {
98
+ }), /* @__PURE__ */ t(r, {
99
99
  sx: {
100
100
  borderRadius: "8px",
101
101
  overflow: "hidden",
@@ -103,7 +103,7 @@ var O = {
103
103
  width: "100%",
104
104
  zIndex: 2
105
105
  },
106
- children: [e.categoryStrip && a && /* @__PURE__ */ o(i, {
106
+ children: [e.categoryStrip && a && /* @__PURE__ */ o(n, {
107
107
  sx: {
108
108
  bgcolor: "success.main",
109
109
  px: 12,
@@ -114,7 +114,7 @@ var O = {
114
114
  variant: "caption",
115
115
  children: a
116
116
  })
117
- }), /* @__PURE__ */ r(t, {
117
+ }), /* @__PURE__ */ t(r, {
118
118
  sx: {
119
119
  alignItems: "center",
120
120
  bgcolor: "success.lighter",
@@ -129,33 +129,33 @@ var O = {
129
129
  flexDirection: "row",
130
130
  ...e.rowSx
131
131
  },
132
- children: [/* @__PURE__ */ o(i, {
132
+ children: [/* @__PURE__ */ o(n, {
133
133
  sx: {
134
134
  display: "flex",
135
135
  flexShrink: 0
136
136
  },
137
- children: D
138
- }), /* @__PURE__ */ r(t, {
137
+ children: $
138
+ }), /* @__PURE__ */ t(r, {
139
139
  sx: {
140
140
  flex: "1 0 0",
141
141
  minWidth: 0
142
142
  },
143
143
  children: [
144
- e.secondaryPosition === "above" && w,
145
- z,
146
- e.secondaryPosition === "below" && w
144
+ e.secondaryPosition === "above" && T,
145
+ A,
146
+ e.secondaryPosition === "below" && T
147
147
  ]
148
148
  })]
149
149
  })]
150
150
  })]
151
151
  });
152
152
  }
153
- return /* @__PURE__ */ r(t, {
153
+ return /* @__PURE__ */ t(r, {
154
154
  sx: {
155
155
  p: 16,
156
156
  ...e
157
157
  },
158
- children: [a && /* @__PURE__ */ o(V, { headerText: a }), /* @__PURE__ */ r(t, {
158
+ children: [a && /* @__PURE__ */ o(E, { headerText: a }), /* @__PURE__ */ t(r, {
159
159
  sx: {
160
160
  alignItems: "center",
161
161
  bgcolor: "background.paper",
@@ -167,36 +167,36 @@ var O = {
167
167
  gap: 16,
168
168
  p: 16,
169
169
  width: "100%",
170
- ...(f || k || y?.guid) && { flexDirection: "row" }
170
+ ...(x || D || _?.guid) && { flexDirection: "row" }
171
171
  },
172
- children: [/* @__PURE__ */ o(A, {
173
- logo: y,
174
- slot: n,
175
- variant: c
176
- }), /* @__PURE__ */ r(t, { children: [l != null && /* @__PURE__ */ o(s, {
172
+ children: [/* @__PURE__ */ o(O, {
173
+ logo: _,
174
+ slot: i,
175
+ variant: l
176
+ }), /* @__PURE__ */ t(r, { children: [d != null && /* @__PURE__ */ o(s, {
177
177
  variant: "h1",
178
- children: R(l, "0,0.00")
179
- }), /* @__PURE__ */ r(t, {
178
+ children: k(d, "0,0.00")
179
+ }), /* @__PURE__ */ t(r, {
180
180
  sx: {
181
181
  gap: 8,
182
182
  flexDirection: "row",
183
183
  alignItems: "center"
184
184
  },
185
- children: [e?.sub_logo && /* @__PURE__ */ o(E, {
185
+ children: [e?.sub_logo && /* @__PURE__ */ o(q, {
186
186
  color: "warning",
187
187
  fill: !0,
188
188
  name: e.sub_logo,
189
189
  size: 20
190
- }), b && /* @__PURE__ */ o(s, {
190
+ }), R && /* @__PURE__ */ o(s, {
191
191
  variant: "body2",
192
- children: b
192
+ children: R
193
193
  })]
194
194
  })] })]
195
195
  })]
196
196
  });
197
197
  };
198
198
  export {
199
- co as default
199
+ po as default
200
200
  };
201
201
 
202
202
  //# sourceMappingURL=AccountBlock.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccountBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/AccountBlock/AccountBlock.tsx"],"sourcesContent":["import Box from '@mui/material/Box'\nimport Stack from '@mui/material/Stack'\nimport { useRef } from 'react'\nimport { useTheme } from '@mui/material/styles'\n\nimport { Text } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport { slot, type InsightsPayload, type LogoRef } from '../../../../core'\nimport { formatCurrency } from '../../../../core/utils/NumberFormatting'\nimport { DepositLogo } from '../../../components/ComponentBlocks/DepositLogo'\nimport { Confetti } from '../../../components/shared/Confetti'\nimport { ReactComponent as PaidOffCardGraphic } from '../../../components/shared/images/PaidOffCard.svg'\nimport { ReactComponent as SavingsGraphic } from '../../../components/shared/images/SavingsAccountDeposit.svg'\nimport { useContainerDimensions } from '../../../hooks/useContainerDimensions'\n\nimport { resolveVariantConfig } from '../../resolveVariantConfig'\n\nimport { HeaderComponent } from './HeaderComponent'\nimport { IconComponent } from './IconComponent'\nimport { getLayoutConfig } from './layout'\n\n/** Default generic-tile icon per deposit variant, used when no merchant/institution logo. */\nconst depositIcons: Record<string, string> = {\n deposit_received: 'payments',\n status_on_track: 'monetization_on',\n}\n\nconst AccountBlock = ({ payload }: { payload: InsightsPayload; beatGuid?: string }) => {\n const theme = useTheme()\n const containerRef = useRef<HTMLDivElement>(null)\n const { height, width } = useContainerDimensions(containerRef)\n const { instance_slot } = payload\n const {\n variant,\n header_text,\n institution_guid,\n institution_name,\n icon_name,\n label,\n merchant_guid,\n merchant_name,\n category_guid,\n } = instance_slot\n // V2 variants fill `instance_slot.data` (ditto's account_block slots); the rest still send the\n // flat legacy fields, so each value falls back to its flat field.\n const { data } = instance_slot\n const amount = slot<number>(data, 'amount') ?? instance_slot.amount\n const sub_text = slot<string>(data, 'sub_text') ?? instance_slot.sub_text\n const logo = slot<LogoRef>(data, 'logo')\n const layoutConfig = resolveVariantConfig(\n getLayoutConfig(theme),\n variant,\n 'default',\n 'AccountBlock',\n )\n\n // Confetti-backed celebration variants (deposits, payoff, savings) — a success-tinted card\n // on a gradient + confetti wash. Everything variant-specific is flat on `layoutConfig`.\n if (layoutConfig?.isConfetti) {\n const graphics: Record<string, React.ReactNode> = {\n paidOffCard: (\n // SVG is 58x46 but the card sits at (0,14) with the check badge overflowing top-right.\n // Box it to the card's real 44x32 footprint and shift the SVG up so it aligns with the text.\n <Box sx={{ flexShrink: 0, height: 32, position: 'relative', width: 44 }}>\n <PaidOffCardGraphic\n aria-hidden={true}\n role=\"presentation\"\n style={{ left: 0, position: 'absolute', top: -14 }}\n />\n </Box>\n ),\n savings: <SavingsGraphic aria-hidden={true} height={55} role=\"presentation\" width={55} />,\n logo: (\n <Box\n sx={{\n borderRadius: '4px',\n flexShrink: 0,\n height: 48,\n overflow: 'hidden',\n width: 48,\n }}\n >\n <DepositLogo\n categoryGuid={category_guid}\n iconName={depositIcons[variant as keyof typeof depositIcons] ?? 'payments'}\n institutionGuid={institution_guid}\n institutionName={institution_name}\n merchantGuid={merchant_guid}\n merchantName={merchant_name}\n />\n </Box>\n ),\n }\n const graphic = graphics[layoutConfig.graphic ?? 'logo']\n\n // Deposit cards show the payer name — a merchant when we have one, otherwise the institution.\n const secondaryText =\n layoutConfig.secondarySource === 'merchant' ? (merchant_name ?? institution_name) : label\n const secondary = secondaryText ? (\n <Text color={layoutConfig.secondaryColor} variant={layoutConfig.secondaryVariant}>\n {secondaryText}\n </Text>\n ) : null\n const amountText = (\n <Text bold={true} color=\"success.dark\" variant={layoutConfig.amountVariant}>\n {`${layoutConfig.amountPrefix ?? ''}${formatCurrency(amount, '0,0.00')}`}\n </Text>\n )\n\n return (\n <Box\n ref={containerRef}\n sx={{\n backgroundImage: layoutConfig.gradient,\n bgcolor: 'background.paper',\n overflow: 'hidden',\n position: 'relative',\n p: 16,\n width: '100%',\n }}\n >\n <Box\n sx={{\n inset: 0,\n pointerEvents: 'none',\n position: 'absolute',\n zIndex: 1,\n }}\n >\n <Confetti height={height} shouldRun={height > 0 && width > 0} width={width} />\n </Box>\n\n <Stack\n sx={{\n borderRadius: '8px',\n overflow: 'hidden',\n position: 'relative',\n width: '100%',\n zIndex: 2,\n }}\n >\n {layoutConfig.categoryStrip && header_text && (\n <Box sx={{ bgcolor: 'success.main', px: 12, py: 4 }}>\n <Text color=\"success.contrastText\" variant=\"caption\">\n {header_text}\n </Text>\n </Box>\n )}\n\n <Stack\n sx={{\n alignItems: 'center',\n bgcolor: 'success.lighter',\n border: '1px solid',\n borderColor: 'success.main',\n borderRadius: '8px',\n // With a strip above, the body's top corners tuck under it (no double border line).\n ...(layoutConfig.categoryStrip && {\n borderTopLeftRadius: 0,\n borderTopRightRadius: 0,\n borderTop: 0,\n }),\n flexDirection: 'row',\n ...layoutConfig.rowSx,\n }}\n >\n <Box sx={{ display: 'flex', flexShrink: 0 }}>{graphic}</Box>\n\n <Stack sx={{ flex: '1 0 0', minWidth: 0 }}>\n {layoutConfig.secondaryPosition === 'above' && secondary}\n {amountText}\n {layoutConfig.secondaryPosition === 'below' && secondary}\n </Stack>\n </Stack>\n </Stack>\n </Box>\n )\n }\n\n return (\n <Stack\n sx={{\n p: 16,\n ...layoutConfig,\n }}\n >\n {header_text && <HeaderComponent headerText={header_text} />}\n <Stack\n sx={{\n alignItems: 'center',\n bgcolor: 'background.paper',\n borderRadius: '8px',\n ...(header_text && {\n borderTopLeftRadius: '0',\n borderTopRightRadius: '0',\n }),\n gap: 16,\n p: 16,\n width: '100%',\n ...((institution_guid || icon_name || logo?.guid) && {\n flexDirection: 'row',\n }),\n }}\n >\n <IconComponent logo={logo} slot={instance_slot} variant={variant} />\n\n <Stack>\n {amount != null && <Text variant=\"h1\">{formatCurrency(amount, '0,0.00')}</Text>}\n <Stack sx={{ gap: 8, flexDirection: 'row', alignItems: 'center' }}>\n {layoutConfig?.sub_logo && (\n <Icon color=\"warning\" fill={true} name={layoutConfig.sub_logo} size={20} />\n )}\n {sub_text && <Text variant=\"body2\">{sub_text}</Text>}\n </Stack>\n </Stack>\n </Stack>\n </Stack>\n )\n}\n\nexport default AccountBlock\n"],"mappings":"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"}
1
+ {"version":3,"file":"AccountBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/AccountBlock/AccountBlock.tsx"],"sourcesContent":["import Box from '@mui/material/Box'\nimport Stack from '@mui/material/Stack'\nimport { useRef } from 'react'\nimport { useTheme } from '@mui/material/styles'\n\nimport { Text } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport { slot, type InsightsPayload, type LogoRef } from '../../../../core'\nimport { formatCurrency } from '../../../../core/utils/NumberFormatting'\nimport { DepositLogo } from '../../../components/ComponentBlocks/DepositLogo'\nimport { Confetti } from '../../../components/shared/Confetti'\nimport { ReactComponent as PaidOffCardGraphic } from '../../../components/shared/images/PaidOffCard.svg'\nimport { ReactComponent as SavingsGraphic } from '../../../components/shared/images/SavingsAccountDeposit.svg'\nimport { useContainerDimensions } from '../../../hooks/useContainerDimensions'\n\nimport { resolveVariantConfig } from '../../resolveVariantConfig'\n\nimport { HeaderComponent } from './HeaderComponent'\nimport { IconComponent } from './IconComponent'\nimport { getLayoutConfig } from './layout'\n\n/** Default generic-tile icon per deposit variant, used when no merchant/institution logo. */\nconst depositIcons: Record<string, string> = {\n deposit_received: 'payments',\n status_on_track: 'monetization_on',\n}\n\nconst AccountBlock = ({ payload }: { payload: InsightsPayload; beatGuid?: string }) => {\n const theme = useTheme()\n const containerRef = useRef<HTMLDivElement>(null)\n const { height, width } = useContainerDimensions(containerRef)\n const { instance_slot } = payload\n const {\n variant,\n header_text,\n institution_guid,\n institution_name,\n icon_name,\n merchant_guid,\n merchant_name,\n category_guid,\n } = instance_slot\n // V2 variants fill `instance_slot.data` (ditto's account_block slots) and it is then the whole\n // truth: a slot it leaves empty, or sends with the wrong kind, draws nothing rather than falling\n // back to the stale flat field it supersedes. Beats not yet migrated send no `data` and keep the\n // flat fields.\n const { data } = instance_slot\n const v2 = data !== undefined\n const dataAmount = slot<unknown>(data, 'amount')\n const amount = v2\n ? typeof dataAmount === 'number' && Number.isFinite(dataAmount)\n ? dataAmount\n : undefined\n : instance_slot.amount\n // One V2 slot feeds the line under the amount on both tiles. V1 called it `sub_text` on the\n // standard tile and `label` on the confetti tile, so each keeps its own flat field.\n const dataSubText = slot<unknown>(data, 'sub_text')\n const v2SubText = typeof dataSubText === 'string' ? dataSubText : undefined\n const sub_text = v2 ? v2SubText : instance_slot.sub_text\n const label = v2 ? v2SubText : instance_slot.label\n const logo = slot<LogoRef>(data, 'logo')\n const layoutConfig = resolveVariantConfig(\n getLayoutConfig(theme),\n variant,\n 'default',\n 'AccountBlock',\n )\n\n // Confetti-backed celebration variants (deposits, payoff, savings) — a success-tinted card\n // on a gradient + confetti wash. Everything variant-specific is flat on `layoutConfig`.\n if (layoutConfig?.isConfetti) {\n const graphics: Record<string, React.ReactNode> = {\n paidOffCard: (\n // SVG is 58x46 but the card sits at (0,14) with the check badge overflowing top-right.\n // Box it to the card's real 44x32 footprint and shift the SVG up so it aligns with the text.\n <Box sx={{ flexShrink: 0, height: 32, position: 'relative', width: 44 }}>\n <PaidOffCardGraphic\n aria-hidden={true}\n role=\"presentation\"\n style={{ left: 0, position: 'absolute', top: -14 }}\n />\n </Box>\n ),\n savings: <SavingsGraphic aria-hidden={true} height={55} role=\"presentation\" width={55} />,\n logo: (\n <Box\n sx={{\n borderRadius: '4px',\n flexShrink: 0,\n height: 48,\n overflow: 'hidden',\n width: 48,\n }}\n >\n <DepositLogo\n categoryGuid={category_guid}\n iconName={depositIcons[variant as keyof typeof depositIcons] ?? 'payments'}\n institutionGuid={institution_guid}\n institutionName={institution_name}\n merchantGuid={merchant_guid}\n merchantName={merchant_name}\n />\n </Box>\n ),\n }\n const graphic = graphics[layoutConfig.graphic ?? 'logo']\n\n // Deposit cards show the payer name — a merchant when we have one, otherwise the institution.\n const secondaryText =\n layoutConfig.secondarySource === 'merchant' ? (merchant_name ?? institution_name) : label\n const secondary = secondaryText ? (\n <Text color={layoutConfig.secondaryColor} variant={layoutConfig.secondaryVariant}>\n {secondaryText}\n </Text>\n ) : null\n // No figure for a missing amount: `formatCurrency` would print a confident `$0.00`.\n const amountText =\n amount != null ? (\n <Text bold={true} color=\"success.dark\" variant={layoutConfig.amountVariant}>\n {`${layoutConfig.amountPrefix ?? ''}${formatCurrency(amount, '0,0.00')}`}\n </Text>\n ) : null\n\n return (\n <Box\n ref={containerRef}\n sx={{\n backgroundImage: layoutConfig.gradient,\n bgcolor: 'background.paper',\n overflow: 'hidden',\n position: 'relative',\n p: 16,\n width: '100%',\n }}\n >\n <Box\n sx={{\n inset: 0,\n pointerEvents: 'none',\n position: 'absolute',\n zIndex: 1,\n }}\n >\n <Confetti height={height} shouldRun={height > 0 && width > 0} width={width} />\n </Box>\n\n <Stack\n sx={{\n borderRadius: '8px',\n overflow: 'hidden',\n position: 'relative',\n width: '100%',\n zIndex: 2,\n }}\n >\n {layoutConfig.categoryStrip && header_text && (\n <Box sx={{ bgcolor: 'success.main', px: 12, py: 4 }}>\n <Text color=\"success.contrastText\" variant=\"caption\">\n {header_text}\n </Text>\n </Box>\n )}\n\n <Stack\n sx={{\n alignItems: 'center',\n bgcolor: 'success.lighter',\n border: '1px solid',\n borderColor: 'success.main',\n borderRadius: '8px',\n // With a strip above, the body's top corners tuck under it (no double border line).\n ...(layoutConfig.categoryStrip && {\n borderTopLeftRadius: 0,\n borderTopRightRadius: 0,\n borderTop: 0,\n }),\n flexDirection: 'row',\n ...layoutConfig.rowSx,\n }}\n >\n <Box sx={{ display: 'flex', flexShrink: 0 }}>{graphic}</Box>\n\n <Stack sx={{ flex: '1 0 0', minWidth: 0 }}>\n {layoutConfig.secondaryPosition === 'above' && secondary}\n {amountText}\n {layoutConfig.secondaryPosition === 'below' && secondary}\n </Stack>\n </Stack>\n </Stack>\n </Box>\n )\n }\n\n return (\n <Stack\n sx={{\n p: 16,\n ...layoutConfig,\n }}\n >\n {header_text && <HeaderComponent headerText={header_text} />}\n <Stack\n sx={{\n alignItems: 'center',\n bgcolor: 'background.paper',\n borderRadius: '8px',\n ...(header_text && {\n borderTopLeftRadius: '0',\n borderTopRightRadius: '0',\n }),\n gap: 16,\n p: 16,\n width: '100%',\n ...((institution_guid || icon_name || logo?.guid) && {\n flexDirection: 'row',\n }),\n }}\n >\n <IconComponent logo={logo} slot={instance_slot} variant={variant} />\n\n <Stack>\n {amount != null && <Text variant=\"h1\">{formatCurrency(amount, '0,0.00')}</Text>}\n <Stack sx={{ gap: 8, flexDirection: 'row', alignItems: 'center' }}>\n {layoutConfig?.sub_logo && (\n <Icon color=\"warning\" fill={true} name={layoutConfig.sub_logo} size={20} />\n )}\n {sub_text && <Text variant=\"body2\">{sub_text}</Text>}\n </Stack>\n </Stack>\n </Stack>\n </Stack>\n )\n}\n\nexport default AccountBlock\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuBA,IAAM,IAAuC;AAAA,EAC3C,kBAAkB;AAAA,EAClB,iBAAiB;AACnB,GAEM,KAAA,CAAgB,EAAE,SAAA,EAAA,MAA+D;AACrF,QAAM,IAAQ,EAAS,GACjB,IAAe,EAAuB,IAAI,GAC1C,EAAE,QAAA,GAAQ,OAAA,EAAA,IAAU,EAAuB,CAAY,GACvD,EAAE,eAAA,EAAA,IAAkB,GACpB,EACJ,SAAA,GACA,aAAA,GACA,kBAAA,GACA,kBAAA,GACA,WAAA,GACA,eAAA,GACA,eAAA,GACA,eAAA,EAAA,IACE,GAKE,EAAE,MAAA,EAAA,IAAS,GACX,IAAK,MAAS,QACd,IAAa,EAAc,GAAM,QAAQ,GACzC,IAAS,IACX,OAAO,KAAe,YAAY,OAAO,SAAS,CAAU,IAC1D,IACA,SACF,EAAc,QAGZ,IAAc,EAAc,GAAM,UAAU,GAC5C,IAAY,OAAO,KAAgB,WAAW,IAAc,QAC5D,IAAW,IAAK,IAAY,EAAc,UAC1C,IAAQ,IAAK,IAAY,EAAc,OACvC,IAAO,EAAc,GAAM,MAAM,GACjC,IAAe,EACnB,EAAgB,CAAK,GACrB,GACA,WACA,cACF;AAIA,MAAI,GAAc,YAAY;AAmC5B,UAAM,IAAU;AAAA,MAjCd,aAGE,gBAAA,EAAC,GAAD;AAAA,QAAK,IAAI;AAAA,UAAE,YAAY;AAAA,UAAG,QAAQ;AAAA,UAAI,UAAU;AAAA,UAAY,OAAO;AAAA,QAAG;AAAA,QACpE,UAAA,gBAAA,EAAC,GAAD;AAAA,UACE,eAAa;AAAA,UACb,MAAK;AAAA,UACL,OAAO;AAAA,YAAE,MAAM;AAAA,YAAG,UAAU;AAAA,YAAY,KAAK;AAAA,UAAI;AAAA,QAClD,CAAA;AAAA,MACE,CAAA;AAAA,MAEP,SAAS,gBAAA,EAAC,GAAD;AAAA,QAAgB,eAAa;AAAA,QAAM,QAAQ;AAAA,QAAI,MAAK;AAAA,QAAe,OAAO;AAAA,MAAK,CAAA;AAAA,MACxF,MACE,gBAAA,EAAC,GAAD;AAAA,QACE,IAAI;AAAA,UACF,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,OAAO;AAAA,QACT;AAAA,QAEA,UAAA,gBAAA,EAAC,GAAD;AAAA,UACE,cAAc;AAAA,UACd,UAAU,EAAa,CAAA,KAAyC;AAAA,UAChE,iBAAiB;AAAA,UACjB,iBAAiB;AAAA,UACjB,cAAc;AAAA,UACd,cAAc;AAAA,QACf,CAAA;AAAA,MACE,CAAA;AAAA,IAGO,EAAS,EAAa,WAAW,MAAA,GAG3C,IACJ,EAAa,oBAAoB,aAAc,KAAiB,IAAoB,GAChF,IAAY,IAChB,gBAAA,EAAC,GAAD;AAAA,MAAM,OAAO,EAAa;AAAA,MAAgB,SAAS,EAAa;AAAA,MAC7D,UAAA;AAAA,IACG,CAAA,IACJ,MAEE,IACJ,KAAU,OACR,gBAAA,EAAC,GAAD;AAAA,MAAM,MAAM;AAAA,MAAM,OAAM;AAAA,MAAe,SAAS,EAAa;AAAA,MAC1D,UAAA,GAAG,EAAa,gBAAgB,EAAA,GAAK,EAAe,GAAQ,QAAQ,CAAA;AAAA,IACjE,CAAA,IACJ;AAEN,WACE,gBAAA,EAAC,GAAD;AAAA,MACE,KAAK;AAAA,MACL,IAAI;AAAA,QACF,iBAAiB,EAAa;AAAA,QAC9B,SAAS;AAAA,QACT,UAAU;AAAA,QACV,UAAU;AAAA,QACV,GAAG;AAAA,QACH,OAAO;AAAA,MACT;AAAA,MATF,UAAA,CAWE,gBAAA,EAAC,GAAD;AAAA,QACE,IAAI;AAAA,UACF,OAAO;AAAA,UACP,eAAe;AAAA,UACf,UAAU;AAAA,UACV,QAAQ;AAAA,QACV;AAAA,QAEA,UAAA,gBAAA,EAAC,GAAD;AAAA,UAAkB,QAAA;AAAA,UAAQ,WAAW,IAAS,KAAK,IAAQ;AAAA,UAAU,OAAA;AAAA,QAAQ,CAAA;AAAA,MAC1E,CAAA,GAEL,gBAAA,EAAC,GAAD;AAAA,QACE,IAAI;AAAA,UACF,cAAc;AAAA,UACd,UAAU;AAAA,UACV,UAAU;AAAA,UACV,OAAO;AAAA,UACP,QAAQ;AAAA,QACV;AAAA,QAPF,UAAA,CASG,EAAa,iBAAiB,KAC7B,gBAAA,EAAC,GAAD;AAAA,UAAK,IAAI;AAAA,YAAE,SAAS;AAAA,YAAgB,IAAI;AAAA,YAAI,IAAI;AAAA,UAAE;AAAA,UAChD,UAAA,gBAAA,EAAC,GAAD;AAAA,YAAM,OAAM;AAAA,YAAuB,SAAQ;AAAA,YACxC,UAAA;AAAA,UACG,CAAA;AAAA,QACH,CAAA,GAGP,gBAAA,EAAC,GAAD;AAAA,UACE,IAAI;AAAA,YACF,YAAY;AAAA,YACZ,SAAS;AAAA,YACT,QAAQ;AAAA,YACR,aAAa;AAAA,YACb,cAAc;AAAA,YAEd,GAAI,EAAa,iBAAiB;AAAA,cAChC,qBAAqB;AAAA,cACrB,sBAAsB;AAAA,cACtB,WAAW;AAAA,YACb;AAAA,YACA,eAAe;AAAA,YACf,GAAG,EAAa;AAAA,UAClB;AAAA,UAfF,UAAA,CAiBE,gBAAA,EAAC,GAAD;AAAA,YAAK,IAAI;AAAA,cAAE,SAAS;AAAA,cAAQ,YAAY;AAAA,YAAE;AAAA,YAAI,UAAA;AAAA,UAAa,CAAA,GAE3D,gBAAA,EAAC,GAAD;AAAA,YAAO,IAAI;AAAA,cAAE,MAAM;AAAA,cAAS,UAAU;AAAA,YAAE;AAAA,YAAxC,UAAA;AAAA,cACG,EAAa,sBAAsB,WAAW;AAAA,cAC9C;AAAA,cACA,EAAa,sBAAsB,WAAW;AAAA,YAC1C;AAAA,UACF,CAAA,CAAA;AAAA,QACF,CAAA,CAAA;AAAA,MACJ,CAAA,CAAA;AAAA;EAET;AAEA,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,IAAI;AAAA,MACF,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,IAJF,UAAA,CAMG,KAAe,gBAAA,EAAC,GAAD,EAAiB,YAAY,EAAc,CAAA,GAC3D,gBAAA,EAAC,GAAD;AAAA,MACE,IAAI;AAAA,QACF,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,cAAc;AAAA,QACd,GAAI,KAAe;AAAA,UACjB,qBAAqB;AAAA,UACrB,sBAAsB;AAAA,QACxB;AAAA,QACA,KAAK;AAAA,QACL,GAAG;AAAA,QACH,OAAO;AAAA,QACP,IAAK,KAAoB,KAAa,GAAM,SAAS,EACnD,eAAe,MACjB;AAAA,MACF;AAAA,MAfF,UAAA,CAiBE,gBAAA,EAAC,GAAD;AAAA,QAAqB,MAAA;AAAA,QAAM,MAAM;AAAA,QAAwB,SAAA;AAAA,MAAU,CAAA,GAEnE,gBAAA,EAAC,GAAD,EAAA,UAAA,CACG,KAAU,QAAQ,gBAAA,EAAC,GAAD;AAAA,QAAM,SAAQ;AAAA,QAAM,UAAA,EAAe,GAAQ,QAAQ;AAAA,MAAQ,CAAA,GAC9E,gBAAA,EAAC,GAAD;AAAA,QAAO,IAAI;AAAA,UAAE,KAAK;AAAA,UAAG,eAAe;AAAA,UAAO,YAAY;AAAA,QAAS;AAAA,QAAhE,UAAA,CACG,GAAc,YACb,gBAAA,EAAC,GAAD;AAAA,UAAM,OAAM;AAAA,UAAU,MAAM;AAAA,UAAM,MAAM,EAAa;AAAA,UAAU,MAAM;AAAA,QAAK,CAAA,GAE3E,KAAY,gBAAA,EAAC,GAAD;AAAA,UAAM,SAAQ;AAAA,UAAS,UAAA;AAAA,QAAe,CAAA,CAC9C;AAAA,MACF,CAAA,CAAA,EAAA,CAAA,CACF;AAAA,IACF,CAAA,CAAA;AAAA;AAEX"}
@@ -1,24 +1,28 @@
1
1
  import { InsightsPayload } from '../../../../core';
2
- import { DebtPayoffCardStyleProps } from '../../../components/DebtPayoffCard';
2
+ export { PAYOFF_STYLE } from './layout';
3
3
  interface DebtsBlockProps {
4
4
  payload: InsightsPayload;
5
5
  beatGuid?: string;
6
6
  }
7
- /** `projected_payoff` look: primary-tinted slot and pill. The card story mirrors it from here. */
8
- export declare const PAYOFF_STYLE: DebtPayoffCardStyleProps;
9
7
  /**
10
8
  * Debts component block — the content card for the Debt Payoff Strategies beat.
9
+ * `instance_slot.variant` picks the card from `./layout.ts` through `resolveVariantConfig`, as
10
+ * `AccountBlock` does:
11
11
  *
12
- * The debt account's facts arrive flat on `instance_slot` (V2 contract — no `instance_slot_data`):
13
- * the balance (`amount`), `payoff_date`, `monthly_payment`, `interest_rate`, plus the shared
14
- * account/institution fields. Row labels come from `insights_feed.debts_block` copy, which
15
- * ships separately: until it has, the card shows the account row only (never an unlabelled number)
16
- * and warns once per mount so the rollout gap is traceable.
12
+ * - `projected_payoff` — one account on the `DebtPayoffCard`. Its facts arrive flat on
13
+ * `instance_slot` (the shape it shipped with): the balance (`amount`), `payoff_date`,
14
+ * `monthly_payment`, `interest_rate`, plus the shared account/institution fields.
15
+ * - `debt_summary` — the beat's several debt accounts on a `TransactionListCard`, read from
16
+ * `instance_slot.data`: one row per account from `series` (pre-localized `logo`, `primary_text`
17
+ * name, `secondary_text` rate, `amount` balance, in the order sent), an optional `header_text`,
18
+ * and the total owed (`amount`) as the footer. With no rows there is nothing to summarize and the
19
+ * block renders nothing.
17
20
  *
18
- * `instance_slot.variant` is not read yet: the architecture doc's other Debts branches (Debt
19
- * Summary, Interest Summary) have no design, so there is one look. Introduce a per-variant
20
- * registry (`createVariantBlock` + a `layout.ts` table, as `AccountBlock` does) with the second
21
- * variant, not before.
21
+ * Captions and payoff row labels come from `insights_feed.debts_block` copy, which ships
22
+ * separately. Each variant needs only its own keys: until they have shipped, the card shows what
23
+ * needs no copy (the account row, the summary rows) but never an unlabelled figure, and warns once
24
+ * per mount so the rollout gap is traceable. A row with no value (or an unparseable date) is
25
+ * dropped rather than rendered blank.
22
26
  */
23
27
  declare const DebtsBlock: ({ payload }: DebtsBlockProps) => import("react/jsx-runtime").JSX.Element;
24
28
  export default DebtsBlock;
@@ -1,56 +1,77 @@
1
- import { DATE_FORMATS_INTL as y, formatDate as h } from "../../../../core/constants/DateFormats.es.js";
2
- import { useGlobalCopyStore as v } from "../../../../common/context/hooks.es.js";
3
- import { formatCurrency as _, formatPercentage as g } from "../../../../core/utils/NumberFormatting.es.js";
4
- import { DepositLogo as D } from "../../../components/ComponentBlocks/DepositLogo.es.js";
5
- import T from "../../../components/DebtPayoffCard.es.js";
6
- import { parseDueDate as C } from "../UpcomingBillBlock/UpcomingBillBlock.es.js";
7
- import L from "react";
8
- import { jsx as b } from "react/jsx-runtime";
9
- var A = {
10
- bgcolor: "primary.lighter",
11
- pill: {
12
- bgcolor: "primary.lighter",
13
- labelColor: "text.primary"
14
- }
15
- }, E = /* @__PURE__ */ new Set([
1
+ import { DATE_FORMATS_INTL as R, formatDate as k } from "../../../../core/constants/DateFormats.es.js";
2
+ import { useGlobalCopyStore as F } from "../../../../common/context/hooks.es.js";
3
+ import { slot as f } from "../../../../core/types/Insights.es.js";
4
+ import { formatCurrency as i, formatPercentage as N } from "../../../../core/utils/NumberFormatting.es.js";
5
+ import P from "../../../components/LogoFromGuid.es.js";
6
+ import { DepositLogo as B } from "../../../components/ComponentBlocks/DepositLogo.es.js";
7
+ import { resolveVariantConfig as Y } from "../../resolveVariantConfig.es.js";
8
+ import G from "../../../components/DebtPayoffCard.es.js";
9
+ import j from "../../../components/TransactionListCard.es.js";
10
+ import { parseDueDate as I } from "../UpcomingBillBlock/UpcomingBillBlock.es.js";
11
+ import { DEBTS_LAYOUT as H, debtsBlockVariant as M } from "./layout.es.js";
12
+ import V from "react";
13
+ import { jsx as l } from "react/jsx-runtime";
14
+ import { useTheme as z } from "@mui/material/styles";
15
+ var U = 32, W = /* @__PURE__ */ new Set([
16
16
  "credit card",
17
17
  "credit_card",
18
18
  "creditcard"
19
- ]), R = (e) => E.has((e ?? "").trim().toLowerCase()) ? "credit_card" : "account_balance", S = (e) => !!e?.balance_label && !!e.payoff_date_label && !!e.monthly_payment_label && !!e.interest_rate_label, B = ({ payload: e }) => {
20
- const a = v().insights_feed?.debts_block, t = S(a) ? a : void 0, { account_name: u, account_type: l, amount: r, institution_guid: f, institution_name: p, interest_rate: n, monthly_payment: i, payoff_date: s, status_text: d } = e.instance_slot;
21
- L.useEffect(() => {
22
- t || console.warn(`debts_block: ${a ? "copy incomplete" : "copy namespace missing"}; rendering the account row only`);
23
- }, [a, t]);
24
- const c = s ? C(s) : null, o = [];
25
- t && c && o.push({
26
- label: t.payoff_date_label,
27
- value: h(c, y.MONTH_SHORT_YEAR)
28
- }), t && i != null && o.push({
29
- label: t.monthly_payment_label,
30
- value: _(i, "0,0.00")
31
- }), t && n != null && o.push({
32
- label: t.interest_rate_label,
33
- value: g(n / 100)
34
- });
35
- const m = t !== void 0 && r != null;
36
- return /* @__PURE__ */ b(T, {
37
- ...A,
38
- balance: m ? _(r, "0,0.00") : void 0,
39
- balanceLabel: m ? t.balance_label : void 0,
40
- logo: /* @__PURE__ */ b(D, {
41
- iconName: R(l),
42
- institutionGuid: f ?? "",
43
- institutionName: p ?? ""
19
+ ]), Z = (t) => W.has((t ?? "").trim().toLowerCase()) ? "credit_card" : "account_balance", $ = (t) => typeof t == "object" && t !== null && typeof t.primary_text == "string", q = (t) => !!t?.balance_label && !!t.payoff_date_label && !!t.monthly_payment_label && !!t.interest_rate_label, ct = ({ payload: t }) => {
20
+ const T = z(), o = F().insights_feed?.debts_block, { instance_slot: u } = t, { data: s, variant: A } = u, _ = Y(H, A, M.ProjectedPayoff, "DebtsBlock"), p = _.card === "summary", e = q(o) ? o : void 0, m = o?.total_balance_label, b = p ? !!m : !!e;
21
+ if (V.useEffect(() => {
22
+ b || console.warn(`debts_block: ${o ? "copy incomplete" : "copy namespace missing"}; rendering without its labelled figures`);
23
+ }, [o, b]), p) {
24
+ const r = f(s, "series"), O = (Array.isArray(r) ? r : []).filter($).map((a) => ({
25
+ amount: typeof a.amount == "number" ? i(a.amount, "0,0.00") : "",
26
+ leading: /* @__PURE__ */ l(P, {
27
+ logo: a.logo,
28
+ size: U
29
+ }),
30
+ subtitle: typeof a.secondary_text == "string" ? a.secondary_text : "",
31
+ title: a.primary_text
32
+ })), L = f(s, "header_text"), c = f(s, "amount");
33
+ return /* @__PURE__ */ l(j, {
34
+ background: T.palette.primary.lighter,
35
+ footer: m && typeof c == "number" && Number.isFinite(c) ? {
36
+ amount: i(c, "0,0.00"),
37
+ label: m
38
+ } : void 0,
39
+ header: typeof L == "string" ? L : void 0,
40
+ rows: O
41
+ });
42
+ }
43
+ const { account_name: C, account_type: d, amount: y, institution_guid: S, institution_name: x, interest_rate: g, monthly_payment: h, payoff_date: v, status_text: E } = u, n = [];
44
+ if (e) {
45
+ const r = v ? I(v) : null;
46
+ r && n.push({
47
+ label: e.payoff_date_label,
48
+ value: k(r, R.MONTH_SHORT_YEAR)
49
+ }), h != null && n.push({
50
+ label: e.monthly_payment_label,
51
+ value: i(h, "0,0.00")
52
+ }), g != null && n.push({
53
+ label: e.interest_rate_label,
54
+ value: N(g / 100)
55
+ });
56
+ }
57
+ const D = e !== void 0 && y != null;
58
+ return /* @__PURE__ */ l(G, {
59
+ ..._.style,
60
+ balance: D ? i(y, "0,0.00") : void 0,
61
+ balanceLabel: D ? e.balance_label : void 0,
62
+ logo: /* @__PURE__ */ l(B, {
63
+ iconName: Z(d),
64
+ institutionGuid: S ?? "",
65
+ institutionName: x ?? ""
44
66
  }),
45
- name: u,
46
- stats: o,
47
- statusLabel: d,
48
- subtitle: l
67
+ name: C,
68
+ stats: n,
69
+ statusLabel: E,
70
+ subtitle: d
49
71
  });
50
72
  };
51
73
  export {
52
- A as PAYOFF_STYLE,
53
- B as default
74
+ ct as default
54
75
  };
55
76
 
56
77
  //# sourceMappingURL=DebtsBlock.es.js.map