@mx-cartographer/experiences 9.6.1 → 9.6.3

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 (50) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/core/types/Insights.d.ts +20 -0
  3. package/dist/core/types/Insights.es.js.map +1 -1
  4. package/dist/core/types/InsightsInstanceSlotData.d.ts +0 -1
  5. package/dist/core/types/InsightsInstanceSlotData.es.js.map +1 -1
  6. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.d.ts +2 -4
  7. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.es.js +24 -33
  8. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.es.js.map +1 -1
  9. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.d.ts +36 -0
  10. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.es.js +40 -0
  11. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.es.js.map +1 -0
  12. package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/SavingsOpportunityBlock.d.ts +18 -0
  13. package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/SavingsOpportunityBlock.es.js +33 -0
  14. package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/SavingsOpportunityBlock.es.js.map +1 -0
  15. package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/index.d.ts +1 -0
  16. package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/layout.d.ts +18 -0
  17. package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/layout.es.js +13 -0
  18. package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/layout.es.js.map +1 -0
  19. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.d.ts +8 -18
  20. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js +43 -42
  21. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js.map +1 -1
  22. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/index.d.ts +2 -1
  23. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.d.ts +30 -0
  24. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js +29 -0
  25. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js.map +1 -0
  26. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/UpcomingBillBlock.d.ts +53 -0
  27. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/UpcomingBillBlock.es.js +79 -0
  28. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/UpcomingBillBlock.es.js.map +1 -0
  29. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/index.d.ts +1 -0
  30. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/layout.d.ts +13 -0
  31. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/layout.es.js +6 -0
  32. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/layout.es.js.map +1 -0
  33. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/UpcomingSubscriptionBlock.d.ts +23 -0
  34. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/UpcomingSubscriptionBlock.es.js +143 -0
  35. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/UpcomingSubscriptionBlock.es.js.map +1 -0
  36. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/index.d.ts +1 -0
  37. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.d.ts +13 -0
  38. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.es.js +6 -0
  39. package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.es.js.map +1 -0
  40. package/dist/insights-v2/blocks/ComponentBlocks/index.d.ts +3 -0
  41. package/dist/insights-v2/blocks/resolveVariantConfig.d.ts +10 -0
  42. package/dist/insights-v2/blocks/resolveVariantConfig.es.js +6 -0
  43. package/dist/insights-v2/blocks/resolveVariantConfig.es.js.map +1 -0
  44. package/dist/insights-v2/components/celebrationGradients.d.ts +19 -7
  45. package/dist/insights-v2/components/celebrationGradients.es.js +7 -4
  46. package/dist/insights-v2/components/celebrationGradients.es.js.map +1 -1
  47. package/dist/insights-v2/index.es.js +92 -85
  48. package/dist/insights-v2/mappings/blocks.es.js +56 -50
  49. package/dist/insights-v2/mappings/blocks.es.js.map +1 -1
  50. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## [9.6.3] - 10-12-2026
2
+
3
+ - **ADDED** - `upcoming_bill_block`, `savings_opportunity_block` and `upcoming_subscription_block` component blocks, registered through `BlockType`, the `blocks` registry and the shared `createVariantBlock` dispatcher so a beat's `instance_slot.block` resolves to the matching content card inside `BaseLayout`. Each reuses its already-built content component (`UpcomingBillCard`, `SavingsOpportunityCard`, `SubscriptionHeroCard`) unmodified. `SavingsOpportunityBlock` ships all six Figma states (`{generic, savings, specific} × {safety_net_not_set, safety_net_set}`); `SavingsSafetyNetSet` is the only variant without a secondary CTA. `UpcomingSubscriptionBlock`'s `View Details` secondary CTA wires to the already-registered `recurring_transaction_block` drilldown via `primary_repeating_transaction_guid`. Mock payloads, beats fixtures and Storybook stories for each (WEC-1890).
4
+
5
+ ## [9.6.2] - 10-12-2026
6
+
7
+ - **CHANGED** - `AccountSwitchBlock` reads its per-variant props from a new `layout.ts` keyed by `instance_slot.variant` (`account_connect`, `account_connected`, `switch_direct_deposit`), so Switch Direct Deposit's pending state shares the block with Discovered Accounts. `account_connect` now renders the Figma blue slot gradient; unknown variants fall back to it (WEC-1891)
8
+ - **REMOVED** - `is_connected` from the exported `AccountSwitchBlockData` type. The connect / connected state comes from `instance_slot.variant`, which ditto has sent since 1.0; no host read the flag (WEC-1891)
9
+ - **CHANGED** - `TransactionBlock` reads header and slot treatment from a new `layout.ts` keyed by `instance_slot.variant`. Adds `uncategorized_transaction` (filled primary header), `subscription_detected` (blue slot wash) and `unexpected_subscription_payment` (warning slot wash) alongside `with_header` / `no_header`; unknown variants fall back to the plain row. Shared `getPrimaryWashGradient` and `WARNING_WASH_GRADIENT` added to `celebrationGradients` (WEC-1891)
10
+ - **ADDED** - `resolveVariantConfig` (insights-v2 blocks): shared lookup from a block's `layout.ts` table by `instance_slot.variant`, guarded with `Object.hasOwn` so a backend-controlled key can never resolve to an inherited object property, and warning on an unknown variant before falling back (same contract as `createVariantBlock`). Both blocks above use it (WEC-1891)
11
+
1
12
  ## [9.6.1] - 10-12-2026
2
13
 
3
14
  - **ADDED** - Three Insights V2 CTA action blocks, registered in `actionBlocksKey`/`blocks`: `feedback_modal_block` (`FeedbackModalActionBlock`) renders a survey dialog with a success/error `StatusSnackbar` on top of the action drawer; `connection_detail_block` (`ConnectionDetailActionBlock`) shows the connection-details education drilldown (`ConnectionDetailDrillDown`); and `connect_widget_block` (`ConnectWidgetActionBlock`) boots MX's Connect widget (web-widget-sdk iframe) inside the drawer. Added `feedback_modal` and `connection_details` copy under `insights_feed`, exported the new `FeedbackModal`, `StatusSnackbar`, and `ConnectionDetailDrillDown` components, and added tests and stories (WEC-1879)
@@ -222,8 +222,11 @@ export declare const BlockType: {
222
222
  readonly DoubleBarChartBlock: "double_bar_chart_block";
223
223
  readonly DoubleProgressBarBlock: "double_progress_bar_block";
224
224
  readonly SaveExtraBlock: "save_extra_block";
225
+ readonly SavingsOpportunityBlock: "savings_opportunity_block";
225
226
  readonly StepChartBlock: "step_chart_block";
226
227
  readonly SVGImageBlock: "svg_image_block";
228
+ readonly UpcomingBillBlock: "upcoming_bill_block";
229
+ readonly UpcomingSubscriptionBlock: "upcoming_subscription_block";
227
230
  readonly WithdrawalBlock: "withdrawal_block";
228
231
  };
229
232
  export type BlockType = (typeof BlockType)[keyof typeof BlockType];
@@ -278,4 +281,21 @@ export interface InstanceSlot {
278
281
  status_text?: string;
279
282
  institution_guid?: string;
280
283
  institution_name?: string;
284
+ /** Dollar amount (unformatted); the block formats it as currency. */
285
+ amount?: number;
286
+ /** Merchant guid used to render the inline / hero logo via `LogoFromGuid` (`MCH-...`). */
287
+ merchant_guid?: string;
288
+ /** Merchant display name — shown as logo alt text and as the merchant/hero label. */
289
+ merchant_name?: string;
290
+ /** Due date of the projected bill in ISO form (e.g. `2025-10-30`). */
291
+ due_date?: string;
292
+ /** Caption shown above the amount, e.g. `Save an extra` or `Potential savings`. */
293
+ label?: string;
294
+ /**
295
+ * Whether to render the green gradient slot behind the coupon. Defaults to true. Backend sends
296
+ * `false` when the coupon is embedded in a parent surface that supplies its own background.
297
+ */
298
+ slot?: boolean;
299
+ /** Billing cadence word that trails the price, e.g. `month` or `year`. */
300
+ cadence?: string;
281
301
  }
@@ -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 // TODO: Add in_description_cta to insights_payload from backend\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 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 block: string\n variant?: string | null\n /** See `PrimaryCTA.action_key` (ditto `secondary_cta_action`). */\n action_key?: string | null\n metadata?: CtaPostMessageMetadata | 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 SaveExtraBlock: 'save_extra_block',\n StepChartBlock: 'step_chart_block',\n SVGImageBlock: 'svg_image_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}\n"],"mappings":"AA2RA,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 // TODO: Add in_description_cta to insights_payload from backend\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 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 block: string\n variant?: string | null\n /** See `PrimaryCTA.action_key` (ditto `secondary_cta_action`). */\n action_key?: string | null\n metadata?: CtaPostMessageMetadata | 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 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}\n"],"mappings":"AA8RA,IAAa,IAAA,CACX,GACA,MACkB,IAAO,CAAA"}
@@ -88,7 +88,6 @@ export interface AccountSwitchBlockData {
88
88
  discovered_institution_name: string;
89
89
  held_institution_guid: string;
90
90
  held_institution_name: string;
91
- is_connected: boolean;
92
91
  }
93
92
  export interface StepChartBlockData {
94
93
  completed_steps: number;
@@ -1 +1 @@
1
- {"version":3,"file":"InsightsInstanceSlotData.es.js","names":[],"sources":["../../../src/core/types/InsightsInstanceSlotData.ts"],"sourcesContent":["import type { DataSeries, Legends } from '../../core'\n\nexport interface InsightsInstanceSlotData\n extends\n Partial<BarChartBlockData>,\n Partial<BudgetBlockData>,\n Partial<DonutChartBlockData>,\n Partial<DoubleProgressBarBlockData>,\n Partial<ImageBlockData>,\n Partial<AccountBlockData>,\n Partial<SaveExtraBlockData>,\n Partial<StepChartBlockData>,\n Partial<SVGImageBlockData>,\n Partial<AccountSwitchBlockData>,\n Partial<TransactionDetailsBlockData>,\n Partial<CommonProps> {}\n\n//when any of the type is used more than one times, we can use the common props\ninterface CommonProps {\n amount?: number\n date?: string\n legends?: Legends[]\n category_guid?: string\n data_series?: DataSeries | DataSet[]\n transaction_guids?: string[]\n account_guids?: string[]\n primary_transaction_guid?: string\n}\n\n//BarChart Block\nexport interface BarChartBlockData {\n average_amount?: number\n ariaLabel?: string\n}\n\n//DonutChart Block\ninterface Main {\n value: string\n value_type: string\n label: string\n}\nexport interface DonutChartBlockData {\n main: Main\n}\n\n//DoubleBarChart Block\n// TODO : This has to be revisited again to update the below types based on API response once we have the final shape of the data_series for double bar chart from BE\nexport interface LegendProps extends Legends {\n amount: number\n formattedAmount: string\n label: string\n color?: string\n}\n\nexport interface DataSet extends DataSeries {\n ariaLabelComparison: string\n ariaLabelMain: string\n comparison: number\n formattedComparison: string\n formattedMain: string\n label: string\n main: number\n}\n\n//DoubleProgressBar Block\n\ninterface DoubleProgressBarProps {\n label: string\n value: number\n}\nexport interface DoubleProgressBarBlockData {\n doubleProgressBar: {\n previous: DoubleProgressBarProps\n latest: DoubleProgressBarProps\n }\n}\n\n//Image Block\nexport interface ImageBlockData {\n image: string\n}\n\n//Account Block\nexport interface AccountBlockData {\n sub_text: string\n institution_guid?: string\n institution_name?: string\n icon_name?: string\n /** Header bar text (standard card), or the colored category strip label (deposit cards). */\n header_text?: string\n // Deposit variants (Unified Deposit, Unified Deposit Emergency Fund, Savings Account Deposit)\n /** Merchant guid — renders a real merchant logo in the deposit card when present. */\n merchant_guid?: string\n /** Merchant display name — logo alt text and the payer line under the amount. */\n merchant_name?: string\n /** Secondary label beside the amount, e.g. `On {date}, you saved` or `Balance as of MM/DD/YY`. */\n label?: string\n}\n\nexport interface SaveExtraBlockData {\n /** Styled segments `[lead-in, amount digits, trailing copy]`, e.g. `['Save an extra', '100', 'to help your funds grow']`. */\n primary_text?: string[]\n /** Styled segments `[projected balance, caption]`, e.g. `['$8,313.87', 'After payday & projected expenses']`. */\n secondary_text?: string[]\n /** MakeTransfer drilldown: available balance (both variants). */\n available_balance?: number\n /** SAVE_ENOUGH_TO_LIVE_ON: average monthly spend. */\n avg_monthly_spend?: number\n /** SAVE_ENOUGH_TO_LIVE_ON: how long the balance lasts, overlaid on the timeline SVG (e.g. \"2 months, 11 days\"). */\n time_period?: string\n /** SAVE_AN_EXTRA_100: upcoming expenses (the \"Expenses\" figure). */\n upcoming_expenses?: number\n /** SAVE_AN_EXTRA_100: total remaining after expenses. */\n total_remaining?: number\n /** SAVE_ENOUGH_TO_LIVE_ON: date for the \"Your available balances as of {date}\" line. */\n date?: string\n}\n\n//AccountSwitch Block\nexport interface AccountSwitchBlockData {\n discovered_institution_guid: string\n discovered_institution_name: string\n held_institution_guid: string\n held_institution_name: string\n is_connected: boolean\n}\n\n// StepChart Block\nexport interface StepChartBlockData {\n completed_steps: number\n label_1: string\n label_2?: string\n}\n\n//Budgets Blocks\nexport enum BudgetTierType {\n LOW_BUDGET_TIER = 'LOW',\n MEDIUM_BUDGET_TIER = 'MEDIUM',\n OFF_TRACK_BUDGET_TIER = 'OFF_TRACK',\n}\n\nexport type BudgetTierValue = `${BudgetTierType}`\n\nexport interface BudgetLocalizedPayload {\n primary_text?: string\n amount_left_label?: string\n spent_label?: string\n budgeted_label?: string\n}\n\nexport interface BudgetBlockData {\n budget_percent: number\n budget_tier: BudgetTierValue\n category_guid?: string\n merchant_guid?: string\n spent_amount: number\n budgeted_amount: number\n localized_payload: BudgetLocalizedPayload\n}\n\nexport interface SVGImageBlockData {\n isCIBC?: boolean\n}\n\n// TransactionDetails Action Block\n// The drawer's subject is `InsightsPayload.primary_transaction_guid`; only action configuration\n// lives here.\nexport interface TransactionDetailsBlockData {\n /** `TopActions` member names, e.g. `['Category', 'Date', 'Memo']`. Omit for the defaults. */\n top_actions?: string[]\n /** `BottomActions` member names, e.g. `['MerchantBudget', 'HideTransaction']`. Omit for defaults. */\n bottom_actions?: string[]\n}\n"],"mappings":"AAuIA,IAAY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,kBAAA,OACA,EAAA,qBAAA,UACA,EAAA,wBAAA;AACF,GAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"InsightsInstanceSlotData.es.js","names":[],"sources":["../../../src/core/types/InsightsInstanceSlotData.ts"],"sourcesContent":["import type { DataSeries, Legends } from '../../core'\n\nexport interface InsightsInstanceSlotData\n extends\n Partial<BarChartBlockData>,\n Partial<BudgetBlockData>,\n Partial<DonutChartBlockData>,\n Partial<DoubleProgressBarBlockData>,\n Partial<ImageBlockData>,\n Partial<AccountBlockData>,\n Partial<SaveExtraBlockData>,\n Partial<StepChartBlockData>,\n Partial<SVGImageBlockData>,\n Partial<AccountSwitchBlockData>,\n Partial<TransactionDetailsBlockData>,\n Partial<CommonProps> {}\n\n//when any of the type is used more than one times, we can use the common props\ninterface CommonProps {\n amount?: number\n date?: string\n legends?: Legends[]\n category_guid?: string\n data_series?: DataSeries | DataSet[]\n transaction_guids?: string[]\n account_guids?: string[]\n primary_transaction_guid?: string\n}\n\n//BarChart Block\nexport interface BarChartBlockData {\n average_amount?: number\n ariaLabel?: string\n}\n\n//DonutChart Block\ninterface Main {\n value: string\n value_type: string\n label: string\n}\nexport interface DonutChartBlockData {\n main: Main\n}\n\n//DoubleBarChart Block\n// TODO : This has to be revisited again to update the below types based on API response once we have the final shape of the data_series for double bar chart from BE\nexport interface LegendProps extends Legends {\n amount: number\n formattedAmount: string\n label: string\n color?: string\n}\n\nexport interface DataSet extends DataSeries {\n ariaLabelComparison: string\n ariaLabelMain: string\n comparison: number\n formattedComparison: string\n formattedMain: string\n label: string\n main: number\n}\n\n//DoubleProgressBar Block\n\ninterface DoubleProgressBarProps {\n label: string\n value: number\n}\nexport interface DoubleProgressBarBlockData {\n doubleProgressBar: {\n previous: DoubleProgressBarProps\n latest: DoubleProgressBarProps\n }\n}\n\n//Image Block\nexport interface ImageBlockData {\n image: string\n}\n\n//Account Block\nexport interface AccountBlockData {\n sub_text: string\n institution_guid?: string\n institution_name?: string\n icon_name?: string\n /** Header bar text (standard card), or the colored category strip label (deposit cards). */\n header_text?: string\n // Deposit variants (Unified Deposit, Unified Deposit Emergency Fund, Savings Account Deposit)\n /** Merchant guid — renders a real merchant logo in the deposit card when present. */\n merchant_guid?: string\n /** Merchant display name — logo alt text and the payer line under the amount. */\n merchant_name?: string\n /** Secondary label beside the amount, e.g. `On {date}, you saved` or `Balance as of MM/DD/YY`. */\n label?: string\n}\n\nexport interface SaveExtraBlockData {\n /** Styled segments `[lead-in, amount digits, trailing copy]`, e.g. `['Save an extra', '100', 'to help your funds grow']`. */\n primary_text?: string[]\n /** Styled segments `[projected balance, caption]`, e.g. `['$8,313.87', 'After payday & projected expenses']`. */\n secondary_text?: string[]\n /** MakeTransfer drilldown: available balance (both variants). */\n available_balance?: number\n /** SAVE_ENOUGH_TO_LIVE_ON: average monthly spend. */\n avg_monthly_spend?: number\n /** SAVE_ENOUGH_TO_LIVE_ON: how long the balance lasts, overlaid on the timeline SVG (e.g. \"2 months, 11 days\"). */\n time_period?: string\n /** SAVE_AN_EXTRA_100: upcoming expenses (the \"Expenses\" figure). */\n upcoming_expenses?: number\n /** SAVE_AN_EXTRA_100: total remaining after expenses. */\n total_remaining?: number\n /** SAVE_ENOUGH_TO_LIVE_ON: date for the \"Your available balances as of {date}\" line. */\n date?: string\n}\n\n// AccountSwitch Block. State comes from `instance_slot.variant`, not a data flag.\nexport interface AccountSwitchBlockData {\n discovered_institution_guid: string\n discovered_institution_name: string\n held_institution_guid: string\n held_institution_name: string\n}\n\n// StepChart Block\nexport interface StepChartBlockData {\n completed_steps: number\n label_1: string\n label_2?: string\n}\n\n//Budgets Blocks\nexport enum BudgetTierType {\n LOW_BUDGET_TIER = 'LOW',\n MEDIUM_BUDGET_TIER = 'MEDIUM',\n OFF_TRACK_BUDGET_TIER = 'OFF_TRACK',\n}\n\nexport type BudgetTierValue = `${BudgetTierType}`\n\nexport interface BudgetLocalizedPayload {\n primary_text?: string\n amount_left_label?: string\n spent_label?: string\n budgeted_label?: string\n}\n\nexport interface BudgetBlockData {\n budget_percent: number\n budget_tier: BudgetTierValue\n category_guid?: string\n merchant_guid?: string\n spent_amount: number\n budgeted_amount: number\n localized_payload: BudgetLocalizedPayload\n}\n\nexport interface SVGImageBlockData {\n isCIBC?: boolean\n}\n\n// TransactionDetails Action Block\n// The drawer's subject is `InsightsPayload.primary_transaction_guid`; only action configuration\n// lives here.\nexport interface TransactionDetailsBlockData {\n /** `TopActions` member names, e.g. `['Category', 'Date', 'Memo']`. Omit for the defaults. */\n top_actions?: string[]\n /** `BottomActions` member names, e.g. `['MerchantBudget', 'HideTransaction']`. Omit for defaults. */\n bottom_actions?: string[]\n}\n"],"mappings":"AAsIA,IAAY,IAAL,0BAAA,GAAA;AACL,SAAA,EAAA,kBAAA,OACA,EAAA,qBAAA,UACA,EAAA,wBAAA;AACF,GAAA,CAAA,CAAA"}
@@ -1,10 +1,8 @@
1
1
  import { AccountSwitchBlockData } from '../../../../core/types/InsightsInstanceSlotData';
2
2
  import { BlockProps } from '../../types';
3
3
  /**
4
- * Discovered-accounts connect visual: two institution logos on a transfer track.
5
- * The pending state (`is_connected: false`) shows a link badge on the default
6
- * slot; the connected state (`is_connected: true`) switches to a success badge
7
- * with the discovered-accounts gradient and a confetti wash.
4
+ * Two institution logos on a transfer track, shared by Discovered Accounts and Switch
5
+ * Direct Deposit. `instance_slot.variant` picks the design branch from `./layout.ts`.
8
6
  */
9
7
  declare const AccountSwitchBlock: ({ payload }: BlockProps<AccountSwitchBlockData>) => import("react/jsx-runtime").JSX.Element;
10
8
  export default AccountSwitchBlock;
@@ -1,43 +1,34 @@
1
- import "../../../components/celebrationGradients.es.js";
2
- import u from "../../../components/TransferLogoCard.es.js";
1
+ import _ from "../../../components/TransferLogoCard.es.js";
2
+ import { resolveVariantConfig as l } from "../../resolveVariantConfig.es.js";
3
+ import { accountSwitchVariant as g, getLayoutConfig as h } from "./layout.es.js";
3
4
  import { InstitutionLogo as i } from "@mxenabled/mxui";
4
- import { Icon as e } from "@mxenabled/mx-icons";
5
- import { jsx as o } from "react/jsx-runtime";
6
- var r = 64, m = /* @__PURE__ */ o(e, {
7
- "aria-hidden": !0,
8
- name: "link",
9
- size: 20,
10
- sx: { color: "primary.contrastText" }
11
- }), g = /* @__PURE__ */ o(e, {
12
- "aria-hidden": !0,
13
- name: "check_circle",
14
- size: 20,
15
- sx: { color: "common.white" }
16
- }), x = ({ payload: n }) => {
17
- const { discovered_institution_guid: a, discovered_institution_name: s, held_institution_guid: c, held_institution_name: d, is_connected: t } = n.instance_slot_data;
18
- return /* @__PURE__ */ o(u, {
19
- badgeBgColor: t ? "success.main" : "text.secondary",
20
- dotColor: "text.secondary",
21
- from: /* @__PURE__ */ o(i, {
5
+ import { Icon as p } from "@mxenabled/mx-icons";
6
+ import { jsx as t } from "react/jsx-runtime";
7
+ import { useTheme as v } from "@mui/material/styles";
8
+ var n = 64, A = ({ payload: o }) => {
9
+ const r = v(), { variant: e } = o.instance_slot, { discovered_institution_guid: c, discovered_institution_name: s, held_institution_guid: a, held_institution_name: m } = o.instance_slot_data, { badgeIcon: u, badgeIconColor: d, ...f } = l(h(r), e, g.AccountConnect, "AccountSwitchBlock");
10
+ return /* @__PURE__ */ t(_, {
11
+ ...f,
12
+ from: /* @__PURE__ */ t(i, {
22
13
  alt: s,
23
- institutionGuid: a,
24
- size: r
25
- }),
26
- icon: t ? g : m,
27
- to: /* @__PURE__ */ o(i, {
28
- alt: d,
29
14
  institutionGuid: c,
30
- size: r
15
+ size: n
31
16
  }),
32
- ...t && {
33
- backgroundImage: "linear-gradient(257deg, rgba(255, 224, 153, 0.2) 1.86%, rgba(255, 129, 230, 0.2) 101.54%)",
34
- bgcolor: "background.paper",
35
- showConfetti: !0
36
- }
17
+ icon: /* @__PURE__ */ t(p, {
18
+ "aria-hidden": !0,
19
+ name: u,
20
+ size: 20,
21
+ sx: { color: d }
22
+ }),
23
+ to: /* @__PURE__ */ t(i, {
24
+ alt: m,
25
+ institutionGuid: a,
26
+ size: n
27
+ })
37
28
  });
38
29
  };
39
30
  export {
40
- x as default
31
+ A as default
41
32
  };
42
33
 
43
34
  //# sourceMappingURL=AccountSwitchBlock.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccountSwitchBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.tsx"],"sourcesContent":["import { InstitutionLogo } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport type { AccountSwitchBlockData } from '../../../../core/types/InsightsInstanceSlotData'\n\nimport TransferLogoCard from '../../../components/TransferLogoCard'\nimport { ACCOUNT_CONNECTED_GRADIENT } from '../../../components/celebrationGradients'\n\nimport type { BlockProps } from '../../types'\n\nconst LOGO_SIZE = 64\n\n// Center-badge glyphs, hoisted to stable module-scope references so they aren't\n// re-created each render: `link` for the pending \"connect\" state and\n// `check_circle` for the connected success state (mirrors TransferLogoCard's\n// Discovered Accounts default/success states).\nconst linkBadge = (\n <Icon aria-hidden={true} name=\"link\" size={20} sx={{ color: 'primary.contrastText' }} />\n)\nconst successBadge = (\n <Icon aria-hidden={true} name=\"check_circle\" size={20} sx={{ color: 'common.white' }} />\n)\n\n/**\n * Discovered-accounts connect visual: two institution logos on a transfer track.\n * The pending state (`is_connected: false`) shows a link badge on the default\n * slot; the connected state (`is_connected: true`) switches to a success badge\n * with the discovered-accounts gradient and a confetti wash.\n */\nconst AccountSwitchBlock = ({ payload }: BlockProps<AccountSwitchBlockData>) => {\n const {\n discovered_institution_guid,\n discovered_institution_name,\n held_institution_guid,\n held_institution_name,\n is_connected,\n } = payload.instance_slot_data\n\n const from = (\n <InstitutionLogo\n alt={discovered_institution_name}\n institutionGuid={discovered_institution_guid}\n size={LOGO_SIZE}\n />\n )\n const to = (\n <InstitutionLogo\n alt={held_institution_name}\n institutionGuid={held_institution_guid}\n size={LOGO_SIZE}\n />\n )\n\n return (\n <TransferLogoCard\n badgeBgColor={is_connected ? 'success.main' : 'text.secondary'}\n dotColor=\"text.secondary\"\n from={from}\n icon={is_connected ? successBadge : linkBadge}\n to={to}\n {...(is_connected && {\n backgroundImage: ACCOUNT_CONNECTED_GRADIENT,\n bgcolor: 'background.paper',\n showConfetti: true,\n })}\n />\n )\n}\n\nexport default AccountSwitchBlock\n"],"mappings":";;;;;AAUA,IAAM,IAAY,IAMZ,IACJ,gBAAA,EAAC,GAAD;AAAA,EAAM,eAAa;AAAA,EAAM,MAAK;AAAA,EAAO,MAAM;AAAA,EAAI,IAAI,EAAE,OAAO,uBAAuB;AAAI,CAAA,GAEnF,IACJ,gBAAA,EAAC,GAAD;AAAA,EAAM,eAAa;AAAA,EAAM,MAAK;AAAA,EAAe,MAAM;AAAA,EAAI,IAAI,EAAE,OAAO,eAAe;AAAI,CAAA,GASnF,IAAA,CAAsB,EAAE,SAAA,EAAA,MAAkD;AAC9E,QAAM,EACJ,6BAAA,GACA,6BAAA,GACA,uBAAA,GACA,uBAAA,GACA,cAAA,EAAA,IACE,EAAQ;AAiBZ,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,cAAc,IAAe,iBAAiB;AAAA,IAC9C,UAAS;AAAA,IACH,MAlBR,gBAAA,EAAC,GAAD;AAAA,MACE,KAAK;AAAA,MACL,iBAAiB;AAAA,MACjB,MAAM;AAAA,IACP,CAcO;AAAA,IACN,MAAM,IAAe,IAAe;AAAA,IAChC,IAbN,gBAAA,EAAC,GAAD;AAAA,MACE,KAAK;AAAA,MACL,iBAAiB;AAAA,MACjB,MAAM;AAAA,IACP,CASK;AAAA,IACJ,GAAK,KAAgB;AAAA,MACnB,iBAAA;AAAA,MACA,SAAS;AAAA,MACT,cAAc;AAAA,IAChB;AAAA,EACD,CAAA;AAEL"}
1
+ {"version":3,"file":"AccountSwitchBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.tsx"],"sourcesContent":["import { useTheme } from '@mui/material/styles'\nimport { InstitutionLogo } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport type { AccountSwitchBlockData } from '../../../../core/types/InsightsInstanceSlotData'\n\nimport TransferLogoCard from '../../../components/TransferLogoCard'\n\nimport type { BlockProps } from '../../types'\nimport { resolveVariantConfig } from '../../resolveVariantConfig'\nimport { accountSwitchVariant, getLayoutConfig } from './layout'\n\nconst LOGO_SIZE = 64\n\n/**\n * Two institution logos on a transfer track, shared by Discovered Accounts and Switch\n * Direct Deposit. `instance_slot.variant` picks the design branch from `./layout.ts`.\n */\nconst AccountSwitchBlock = ({ payload }: BlockProps<AccountSwitchBlockData>) => {\n const theme = useTheme()\n const { variant } = payload.instance_slot\n const {\n discovered_institution_guid,\n discovered_institution_name,\n held_institution_guid,\n held_institution_name,\n } = payload.instance_slot_data\n\n // Pending connect is the safe default: it promises nothing (no success badge, no confetti).\n const { badgeIcon, badgeIconColor, ...cardProps } = resolveVariantConfig(\n getLayoutConfig(theme),\n variant,\n accountSwitchVariant.AccountConnect,\n 'AccountSwitchBlock',\n )\n\n return (\n <TransferLogoCard\n {...cardProps}\n from={\n <InstitutionLogo\n alt={discovered_institution_name}\n institutionGuid={discovered_institution_guid}\n size={LOGO_SIZE}\n />\n }\n icon={<Icon aria-hidden={true} name={badgeIcon} size={20} sx={{ color: badgeIconColor }} />}\n to={\n <InstitutionLogo\n alt={held_institution_name}\n institutionGuid={held_institution_guid}\n size={LOGO_SIZE}\n />\n }\n />\n )\n}\n\nexport default AccountSwitchBlock\n"],"mappings":";;;;;;;AAYA,IAAM,IAAY,IAMZ,IAAA,CAAsB,EAAE,SAAA,EAAA,MAAkD;AAC9E,QAAM,IAAQ,EAAS,GACjB,EAAE,SAAA,EAAA,IAAY,EAAQ,eACtB,EACJ,6BAAA,GACA,6BAAA,GACA,uBAAA,GACA,uBAAA,EAAA,IACE,EAAQ,oBAGN,EAAE,WAAA,GAAW,gBAAA,GAAgB,GAAG,EAAA,IAAc,EAClD,EAAgB,CAAK,GACrB,GACA,EAAqB,gBACrB,oBACF;AAEA,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,GAAI;AAAA,IACJ,MACE,gBAAA,EAAC,GAAD;AAAA,MACE,KAAK;AAAA,MACL,iBAAiB;AAAA,MACjB,MAAM;AAAA,IACP,CAAA;AAAA,IAEH,MAAM,gBAAA,EAAC,GAAD;AAAA,MAAM,eAAa;AAAA,MAAM,MAAM;AAAA,MAAW,MAAM;AAAA,MAAI,IAAI,EAAE,OAAO,EAAe;AAAA,IAAI,CAAA;AAAA,IAC1F,IACE,gBAAA,EAAC,GAAD;AAAA,MACE,KAAK;AAAA,MACL,iBAAiB;AAAA,MACjB,MAAM;AAAA,IACP,CAAA;AAAA,EAEJ,CAAA;AAEL"}
@@ -0,0 +1,36 @@
1
+ import { Theme } from '@mui/material/styles';
2
+ /**
3
+ * Account Switch block variants, keyed by the backend `instance_slot.variant`. All share
4
+ * `TransferLogoCard`; only the slot surface, center badge and connector dots differ.
5
+ *
6
+ * - `AccountConnect` — Discovered Accounts pending: blue gradient, link badge.
7
+ * - `AccountConnected` — Discovered Accounts success: pink wash, confetti, check badge.
8
+ * - `SwitchDirectDeposit` — Switch Direct Deposit pending: flat tinted slot, arrow badge.
9
+ * Its complete state is a different layout, served by `direct_deposit_block`.
10
+ */
11
+ export declare const accountSwitchVariant: {
12
+ readonly AccountConnect: "account_connect";
13
+ readonly AccountConnected: "account_connected";
14
+ readonly SwitchDirectDeposit: "switch_direct_deposit";
15
+ };
16
+ export type AccountSwitchVariant = (typeof accountSwitchVariant)[keyof typeof accountSwitchVariant];
17
+ export interface AccountSwitchLayoutConfig {
18
+ /** Slot surface color token. */
19
+ bgcolor: string;
20
+ /** Optional gradient layered over `bgcolor`. */
21
+ backgroundImage?: string;
22
+ /** Center badge background color token. */
23
+ badgeBgColor: string;
24
+ /** mx-icons glyph rendered in the center badge. */
25
+ badgeIcon: string;
26
+ /** Color token for the badge glyph. */
27
+ badgeIconColor: string;
28
+ /** Connector-dot color token. */
29
+ dotColor: string;
30
+ /** Enlarge the inner connector dots (6px vs 4px). */
31
+ hasBigDots: boolean;
32
+ /** Confetti burst filling the slot (success states). */
33
+ showConfetti?: boolean;
34
+ }
35
+ /** Per-variant `TransferLogoCard` props (mirrors DirectDepositBlock's `getLayoutConfig`). */
36
+ export declare const getLayoutConfig: (theme: Theme) => Record<AccountSwitchVariant, AccountSwitchLayoutConfig>;
@@ -0,0 +1,40 @@
1
+ import { ACCOUNT_CONNECTED_GRADIENT as r, getPrimaryWashGradient as e } from "../../../components/celebrationGradients.es.js";
2
+ var o = {
3
+ AccountConnect: "account_connect",
4
+ AccountConnected: "account_connected",
5
+ SwitchDirectDeposit: "switch_direct_deposit"
6
+ }, a = (t) => ({
7
+ [o.AccountConnect]: {
8
+ backgroundImage: e(t),
9
+ bgcolor: "background.paper",
10
+ badgeBgColor: "text.secondary",
11
+ badgeIcon: "link",
12
+ badgeIconColor: "primary.contrastText",
13
+ dotColor: "text.secondary",
14
+ hasBigDots: !0
15
+ },
16
+ [o.AccountConnected]: {
17
+ backgroundImage: r,
18
+ bgcolor: "background.paper",
19
+ badgeBgColor: "success.main",
20
+ badgeIcon: "check",
21
+ badgeIconColor: "common.white",
22
+ dotColor: "text.secondary",
23
+ hasBigDots: !0,
24
+ showConfetti: !0
25
+ },
26
+ [o.SwitchDirectDeposit]: {
27
+ bgcolor: "primary.lighter",
28
+ badgeBgColor: "neutral.darker",
29
+ badgeIcon: "arrow_forward",
30
+ badgeIconColor: "neutral.lighter",
31
+ dotColor: "neutral.darker",
32
+ hasBigDots: !1
33
+ }
34
+ });
35
+ export {
36
+ o as accountSwitchVariant,
37
+ a as getLayoutConfig
38
+ };
39
+
40
+ //# sourceMappingURL=layout.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.ts"],"sourcesContent":["import type { Theme } from '@mui/material/styles'\n\nimport {\n ACCOUNT_CONNECTED_GRADIENT,\n getPrimaryWashGradient,\n} from '../../../components/celebrationGradients'\n\n/**\n * Account Switch block variants, keyed by the backend `instance_slot.variant`. All share\n * `TransferLogoCard`; only the slot surface, center badge and connector dots differ.\n *\n * - `AccountConnect` — Discovered Accounts pending: blue gradient, link badge.\n * - `AccountConnected` — Discovered Accounts success: pink wash, confetti, check badge.\n * - `SwitchDirectDeposit` — Switch Direct Deposit pending: flat tinted slot, arrow badge.\n * Its complete state is a different layout, served by `direct_deposit_block`.\n */\nexport const accountSwitchVariant = {\n AccountConnect: 'account_connect',\n AccountConnected: 'account_connected',\n SwitchDirectDeposit: 'switch_direct_deposit',\n} as const\n\nexport type AccountSwitchVariant = (typeof accountSwitchVariant)[keyof typeof accountSwitchVariant]\n\nexport interface AccountSwitchLayoutConfig {\n /** Slot surface color token. */\n bgcolor: string\n /** Optional gradient layered over `bgcolor`. */\n backgroundImage?: string\n /** Center badge background color token. */\n badgeBgColor: string\n /** mx-icons glyph rendered in the center badge. */\n badgeIcon: string\n /** Color token for the badge glyph. */\n badgeIconColor: string\n /** Connector-dot color token. */\n dotColor: string\n /** Enlarge the inner connector dots (6px vs 4px). */\n hasBigDots: boolean\n /** Confetti burst filling the slot (success states). */\n showConfetti?: boolean\n}\n\n/** Per-variant `TransferLogoCard` props (mirrors DirectDepositBlock's `getLayoutConfig`). */\nexport const getLayoutConfig = (\n theme: Theme,\n): Record<AccountSwitchVariant, AccountSwitchLayoutConfig> => {\n return {\n [accountSwitchVariant.AccountConnect]: {\n backgroundImage: getPrimaryWashGradient(theme),\n bgcolor: 'background.paper',\n badgeBgColor: 'text.secondary',\n badgeIcon: 'link',\n badgeIconColor: 'primary.contrastText',\n dotColor: 'text.secondary',\n hasBigDots: true,\n },\n [accountSwitchVariant.AccountConnected]: {\n backgroundImage: ACCOUNT_CONNECTED_GRADIENT,\n bgcolor: 'background.paper',\n badgeBgColor: 'success.main',\n // Figma \"Common/Check\": a bare check on the solid success badge (not `check_circle`).\n badgeIcon: 'check',\n badgeIconColor: 'common.white',\n dotColor: 'text.secondary',\n hasBigDots: true,\n showConfetti: true,\n },\n [accountSwitchVariant.SwitchDirectDeposit]: {\n bgcolor: 'primary.lighter',\n badgeBgColor: 'neutral.darker',\n badgeIcon: 'arrow_forward',\n badgeIconColor: 'neutral.lighter',\n dotColor: 'neutral.darker',\n hasBigDots: false,\n },\n }\n}\n"],"mappings":";AAgBA,IAAa,IAAuB;AAAA,EAClC,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,qBAAqB;AACvB,GAwBa,IAAA,CACX,OAEO;AAAA,EACJ,CAAA,EAAqB,cAAA,GAAiB;AAAA,IACrC,iBAAiB,EAAuB,CAAK;AAAA,IAC7C,SAAS;AAAA,IACT,cAAc;AAAA,IACd,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AAAA,EACC,CAAA,EAAqB,gBAAA,GAAmB;AAAA,IACvC,iBAAiB;AAAA,IACjB,SAAS;AAAA,IACT,cAAc;AAAA,IAEd,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACC,CAAA,EAAqB,mBAAA,GAAsB;AAAA,IAC1C,SAAS;AAAA,IACT,cAAc;AAAA,IACd,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF"}
@@ -0,0 +1,18 @@
1
+ import { InsightsPayload } from '../../../../core';
2
+ interface SavingsOpportunityBlockProps {
3
+ payload: InsightsPayload;
4
+ beatGuid?: string;
5
+ }
6
+ /**
7
+ * Savings Opportunity component block (Figma frame 1276-45997). Reads `amount`, `label`, and
8
+ * `slot` off `instance_slot` (V2 flat shape — no `instance_slot_data`), and renders the shared
9
+ * `SavingsOpportunityCard` wrapped in the standard content-section padding.
10
+ *
11
+ * Wrapped in `createVariantBlock` so an added design branch is a new registry entry rather than a
12
+ * rewrite of dispatch logic. Six variants are defined today, formed by
13
+ * `{generic, savings, specific} × {safety_net_not_set, safety_net_set}`; copy/CTA differences
14
+ * live in the payload, not here. An unknown variant degrades to the default
15
+ * (`generic_safety_net_not_set`).
16
+ */
17
+ declare const SavingsOpportunityBlock: ({ payload, beatGuid }: SavingsOpportunityBlockProps) => import("react/jsx-runtime").JSX.Element;
18
+ export default SavingsOpportunityBlock;
@@ -0,0 +1,33 @@
1
+ import { formatCurrency as m } from "../../../../core/utils/NumberFormatting.es.js";
2
+ import { createVariantBlock as p } from "../../createVariantBlock.es.js";
3
+ import l from "../../../components/SavingsOpportunityCard.es.js";
4
+ import { savingsOpportunityVariant as c } from "./layout.es.js";
5
+ import v from "@mui/material/Stack";
6
+ import { jsx as o } from "react/jsx-runtime";
7
+ var u = (r) => {
8
+ const { instance_slot: t } = r, { amount: a, label: i, slot: s } = t, e = s ?? !0;
9
+ return /* @__PURE__ */ o(v, {
10
+ sx: { px: 16 },
11
+ children: /* @__PURE__ */ o(l, {
12
+ amount: m(a ?? 0, "0,0.00"),
13
+ label: i ?? "",
14
+ slot: e
15
+ })
16
+ });
17
+ }, n = ({ payload: r }) => u(r), y = ({ payload: r, beatGuid: t }) => {
18
+ const a = r.instance_slot.variant ?? void 0;
19
+ return /* @__PURE__ */ o(f, {
20
+ beatGuid: t,
21
+ payload: r,
22
+ variant: a
23
+ });
24
+ }, f = p({
25
+ variants: Object.fromEntries(Object.values(c).map((r) => [r, n])),
26
+ fallback: n,
27
+ name: "SavingsOpportunityBlock"
28
+ });
29
+ export {
30
+ y as default
31
+ };
32
+
33
+ //# sourceMappingURL=SavingsOpportunityBlock.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SavingsOpportunityBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/SavingsOpportunityBlock.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport type { InsightsPayload } from '../../../../core'\nimport { formatCurrency } from '../../../../core/utils/NumberFormatting'\n\nimport SavingsOpportunityCard from '../../../components/SavingsOpportunityCard'\nimport { createVariantBlock } from '../../createVariantBlock'\n\nimport { savingsOpportunityVariant, type SavingsOpportunityVariant } from './layout'\n\ninterface SavingsOpportunityBlockProps {\n payload: InsightsPayload\n beatGuid?: string\n}\n\nconst renderCard = (payload: InsightsPayload) => {\n const { instance_slot } = payload\n const { amount, label, slot } = instance_slot\n\n // Backend-sent `slot` wins; defaults to true so a payload that omits it still shows the gradient.\n const resolvedSlot = slot ?? true\n\n return (\n <Stack sx={{ px: 16 }}>\n <SavingsOpportunityCard\n amount={formatCurrency(amount ?? 0, '0,0.00')}\n label={label ?? ''}\n slot={resolvedSlot}\n />\n </Stack>\n )\n}\n\n// All six variants ({generic, savings, specific} × {safety_net_not_set, safety_net_set}) share\n// identical card visuals — copy/CTA differences live in the payload. We register the same\n// renderer under every key so the dispatcher still fires on each known variant (and a non-\n// registered backend variant hits the fallback with the standard dev warning from createVariantBlock).\nconst SavingsOpportunityVariantCard = ({ payload }: SavingsOpportunityBlockProps) =>\n renderCard(payload)\n\n/**\n * Savings Opportunity component block (Figma frame 1276-45997). Reads `amount`, `label`, and\n * `slot` off `instance_slot` (V2 flat shape — no `instance_slot_data`), and renders the shared\n * `SavingsOpportunityCard` wrapped in the standard content-section padding.\n *\n * Wrapped in `createVariantBlock` so an added design branch is a new registry entry rather than a\n * rewrite of dispatch logic. Six variants are defined today, formed by\n * `{generic, savings, specific} × {safety_net_not_set, safety_net_set}`; copy/CTA differences\n * live in the payload, not here. An unknown variant degrades to the default\n * (`generic_safety_net_not_set`).\n */\nconst SavingsOpportunityBlock = ({ payload, beatGuid }: SavingsOpportunityBlockProps) => {\n const variant = payload.instance_slot.variant ?? undefined\n return <Variants beatGuid={beatGuid} payload={payload} variant={variant} />\n}\n\nconst Variants = createVariantBlock<SavingsOpportunityBlockProps>({\n variants: Object.fromEntries(\n Object.values(savingsOpportunityVariant).map((v) => [v, SavingsOpportunityVariantCard]),\n ) as Record<SavingsOpportunityVariant, typeof SavingsOpportunityVariantCard>,\n fallback: SavingsOpportunityVariantCard,\n name: 'SavingsOpportunityBlock',\n})\n\nexport default SavingsOpportunityBlock\n"],"mappings":";;;;;;AAeA,IAAM,IAAA,CAAc,MAA6B;AAC/C,QAAM,EAAE,eAAA,EAAA,IAAkB,GACpB,EAAE,QAAA,GAAQ,OAAA,GAAO,MAAA,EAAA,IAAS,GAG1B,IAAe,KAAQ;AAE7B,SACE,gBAAA,EAAC,GAAD;AAAA,IAAO,IAAI,EAAE,IAAI,GAAG;AAAA,IAClB,UAAA,gBAAA,EAAC,GAAD;AAAA,MACE,QAAQ,EAAe,KAAU,GAAG,QAAQ;AAAA,MAC5C,OAAO,KAAS;AAAA,MAChB,MAAM;AAAA,IACP,CAAA;AAAA,EACI,CAAA;AAEX,GAMM,IAAA,CAAiC,EAAE,SAAA,EAAA,MACvC,EAAW,CAAO,GAad,IAAA,CAA2B,EAAE,SAAA,GAAS,UAAA,EAAA,MAA6C;AACvF,QAAM,IAAU,EAAQ,cAAc,WAAW;AACjD,SAAO,gBAAA,EAAC,GAAD;AAAA,IAAoB,UAAA;AAAA,IAAmB,SAAA;AAAA,IAAkB,SAAA;AAAA,EAAU,CAAA;AAC5E,GAEM,IAAW,EAAiD;AAAA,EAChE,UAAU,OAAO,YACf,OAAO,OAAO,CAAyB,EAAE,IAAA,CAAK,MAAM,CAAC,GAAG,CAA6B,CAAC,CACxF;AAAA,EACA,UAAU;AAAA,EACV,MAAM;AACR,CAAC"}
@@ -0,0 +1 @@
1
+ export { default as SavingsOpportunityBlock } from './SavingsOpportunityBlock';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Design branches of the Savings Opportunity component block (Figma frame 1276-45997).
3
+ *
4
+ * Six variants formed by the backend axis `{generic, savings, specific} × {safety_net_not_set,
5
+ * safety_net_set}`. All six share the same card visuals (title, subtitle, label, amount, green
6
+ * gradient slot); the differentiators live in the payload — description text, primary CTA label,
7
+ * and whether a secondary CTA is present. The slot visual is backend-controlled via the flat
8
+ * `slot` field on `instance_slot` (defaults to true), so no per-variant layout map is needed.
9
+ */
10
+ export declare const savingsOpportunityVariant: {
11
+ readonly GenericSafetyNetNotSet: "generic_safety_net_not_set";
12
+ readonly SavingsSafetyNetNotSet: "savings_safety_net_not_set";
13
+ readonly SpecificSafetyNetNotSet: "specific_safety_net_not_set";
14
+ readonly GenericSafetyNetSet: "generic_safety_net_set";
15
+ readonly SavingsSafetyNetSet: "savings_safety_net_set";
16
+ readonly SpecificSafetyNetSet: "specific_safety_net_set";
17
+ };
18
+ export type SavingsOpportunityVariant = (typeof savingsOpportunityVariant)[keyof typeof savingsOpportunityVariant];
@@ -0,0 +1,13 @@
1
+ var e = {
2
+ GenericSafetyNetNotSet: "generic_safety_net_not_set",
3
+ SavingsSafetyNetNotSet: "savings_safety_net_not_set",
4
+ SpecificSafetyNetNotSet: "specific_safety_net_not_set",
5
+ GenericSafetyNetSet: "generic_safety_net_set",
6
+ SavingsSafetyNetSet: "savings_safety_net_set",
7
+ SpecificSafetyNetSet: "specific_safety_net_set"
8
+ };
9
+ export {
10
+ e as savingsOpportunityVariant
11
+ };
12
+
13
+ //# sourceMappingURL=layout.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/layout.ts"],"sourcesContent":["/**\n * Design branches of the Savings Opportunity component block (Figma frame 1276-45997).\n *\n * Six variants formed by the backend axis `{generic, savings, specific} × {safety_net_not_set,\n * safety_net_set}`. All six share the same card visuals (title, subtitle, label, amount, green\n * gradient slot); the differentiators live in the payload — description text, primary CTA label,\n * and whether a secondary CTA is present. The slot visual is backend-controlled via the flat\n * `slot` field on `instance_slot` (defaults to true), so no per-variant layout map is needed.\n */\nexport const savingsOpportunityVariant = {\n GenericSafetyNetNotSet: 'generic_safety_net_not_set',\n SavingsSafetyNetNotSet: 'savings_safety_net_not_set',\n SpecificSafetyNetNotSet: 'specific_safety_net_not_set',\n GenericSafetyNetSet: 'generic_safety_net_set',\n SavingsSafetyNetSet: 'savings_safety_net_set',\n SpecificSafetyNetSet: 'specific_safety_net_set',\n} as const\n\nexport type SavingsOpportunityVariant =\n (typeof savingsOpportunityVariant)[keyof typeof savingsOpportunityVariant]\n"],"mappings":"AASA,IAAa,IAA4B;AAAA,EACvC,wBAAwB;AAAA,EACxB,wBAAwB;AAAA,EACxB,yBAAyB;AAAA,EACzB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,sBAAsB;AACxB"}
@@ -4,28 +4,18 @@ interface TransactionBlockProps {
4
4
  beatGuid?: string;
5
5
  }
6
6
  /**
7
- * Variants from ditto `lib/ditto/beats/large_transaction_v2.yml`:
8
- * - `with_header` — transaction row under a date header (the `with_merchant` card).
9
- * - `no_header` — the row alone (the `no_merchant` card).
10
- */
11
- export declare const TransactionBlockVariant: {
12
- readonly WithHeader: "with_header";
13
- readonly NoHeader: "no_header";
14
- };
15
- /**
16
- * The `transaction_block` (ditto `blocks.name` for LargeTransactionV2).
17
- *
18
- * Renders rows the backend already localized and carried inline on `instance_slot.data.series`
19
- * (`logo`, `primary_text`, `secondary_text`, `amount`). Only the amount is formatted here,
20
- * because the contract sends it as a number.
7
+ * The `transaction_block`: rows the backend already localized, carried inline on
8
+ * `instance_slot.data.series` (`logo`, `primary_text`, `secondary_text`, `amount`). Only the
9
+ * amount is formatted here, because the contract sends it as a number. `instance_slot.variant`
10
+ * picks the header and slot treatment from `./layout.ts`.
21
11
  *
22
12
  * This is the full/mini shape. The reduced widgets (micro, embedded) resolve to the row logo
23
13
  * alone, carried flat on `data.logo` with no `series`, and are drawn by `CompactInsightCard`.
24
14
  *
25
- * Under `with_header` the card header comes from `instance_slot.data.header_text`, which tupac sends
26
- * as the transaction date. It deliberately does *not* come from the first row: on a `with_merchant`
27
- * card a row's `secondary_text` is the category, so reading it here rendered the category twice
28
- * and dropped the date entirely.
15
+ * A header, when the variant shows one, comes from `instance_slot.data.header_text` (the
16
+ * transaction date, or "{count} transactions"). It deliberately does *not* come from the first
17
+ * row: on a `with_merchant` card a row's `secondary_text` is the category, so reading it here
18
+ * rendered the category twice and dropped the date entirely.
29
19
  */
30
20
  export declare const TransactionBlock: (({ payload }: TransactionBlockProps) => import("react/jsx-runtime").JSX.Element | null) & {
31
21
  displayName: string;