@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.
- package/CHANGELOG.md +11 -0
- package/dist/core/types/Insights.d.ts +20 -0
- package/dist/core/types/Insights.es.js.map +1 -1
- package/dist/core/types/InsightsInstanceSlotData.d.ts +0 -1
- package/dist/core/types/InsightsInstanceSlotData.es.js.map +1 -1
- package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.d.ts +2 -4
- package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.es.js +24 -33
- package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.es.js.map +1 -1
- package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.d.ts +36 -0
- package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.es.js +40 -0
- package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.es.js.map +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/SavingsOpportunityBlock.d.ts +18 -0
- package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/SavingsOpportunityBlock.es.js +33 -0
- package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/SavingsOpportunityBlock.es.js.map +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/index.d.ts +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/layout.d.ts +18 -0
- package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/layout.es.js +13 -0
- package/dist/insights-v2/blocks/ComponentBlocks/SavingsOpportunityBlock/layout.es.js.map +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.d.ts +8 -18
- package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js +43 -42
- package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js.map +1 -1
- package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/index.d.ts +2 -1
- package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.d.ts +30 -0
- package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js +29 -0
- package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js.map +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/UpcomingBillBlock.d.ts +53 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/UpcomingBillBlock.es.js +79 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/UpcomingBillBlock.es.js.map +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/index.d.ts +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/layout.d.ts +13 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/layout.es.js +6 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/layout.es.js.map +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/UpcomingSubscriptionBlock.d.ts +23 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/UpcomingSubscriptionBlock.es.js +143 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/UpcomingSubscriptionBlock.es.js.map +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/index.d.ts +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.d.ts +13 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.es.js +6 -0
- package/dist/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.es.js.map +1 -0
- package/dist/insights-v2/blocks/ComponentBlocks/index.d.ts +3 -0
- package/dist/insights-v2/blocks/resolveVariantConfig.d.ts +10 -0
- package/dist/insights-v2/blocks/resolveVariantConfig.es.js +6 -0
- package/dist/insights-v2/blocks/resolveVariantConfig.es.js.map +1 -0
- package/dist/insights-v2/components/celebrationGradients.d.ts +19 -7
- package/dist/insights-v2/components/celebrationGradients.es.js +7 -4
- package/dist/insights-v2/components/celebrationGradients.es.js.map +1 -1
- package/dist/insights-v2/index.es.js +92 -85
- package/dist/insights-v2/mappings/blocks.es.js +56 -50
- package/dist/insights-v2/mappings/blocks.es.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,73 +1,74 @@
|
|
|
1
|
-
import { useCategoryStore as
|
|
1
|
+
import { useCategoryStore as p } from "../../../../common/context/hooks.es.js";
|
|
2
2
|
import { slot as c } from "../../../../core/types/Insights.es.js";
|
|
3
|
-
import { formatCurrency as
|
|
4
|
-
import { logoFromRef as
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const t =
|
|
3
|
+
import { formatCurrency as _ } from "../../../../core/utils/NumberFormatting.es.js";
|
|
4
|
+
import { logoFromRef as y } from "../../../components/shared/EntityLogo.es.js";
|
|
5
|
+
import { resolveVariantConfig as h } from "../../resolveVariantConfig.es.js";
|
|
6
|
+
import x from "../../../components/TransactionListCard.es.js";
|
|
7
|
+
import { getLayoutConfig as v, transactionBlockVariant as C } from "./layout.es.js";
|
|
8
|
+
import { observer as I } from "mobx-react-lite";
|
|
9
|
+
import { CategoryIcon as G, InstitutionLogo as L, MerchantLogo as O } from "@mxenabled/mxui";
|
|
10
|
+
import { Icon as T } from "@mxenabled/mx-icons";
|
|
11
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
12
|
+
import { useTheme as b } from "@mui/material/styles";
|
|
13
|
+
import u from "@mui/material/Box";
|
|
14
|
+
var r = 32, k = Math.round(r * 0.625), z = (n, a) => {
|
|
15
|
+
const t = y(n.logo, n.primary_text);
|
|
16
16
|
if (t) {
|
|
17
|
-
if (t.logo_name) return /* @__PURE__ */
|
|
17
|
+
if (t.logo_name) return /* @__PURE__ */ o(u, {
|
|
18
18
|
sx: {
|
|
19
19
|
alignItems: "center",
|
|
20
20
|
display: "flex",
|
|
21
|
-
height:
|
|
21
|
+
height: r,
|
|
22
22
|
justifyContent: "center",
|
|
23
|
-
width:
|
|
23
|
+
width: r
|
|
24
24
|
},
|
|
25
|
-
children: /* @__PURE__ */
|
|
25
|
+
children: /* @__PURE__ */ o(T, {
|
|
26
26
|
name: t.logo_name,
|
|
27
|
-
size:
|
|
27
|
+
size: k,
|
|
28
28
|
sx: { color: t.logo_color }
|
|
29
29
|
})
|
|
30
30
|
});
|
|
31
|
-
if (t.merchant_guid) return /* @__PURE__ */
|
|
31
|
+
if (t.merchant_guid) return /* @__PURE__ */ o(O, {
|
|
32
32
|
alt: t.merchant_name ?? "",
|
|
33
|
-
categoryGuid: t.category_guid ?
|
|
33
|
+
categoryGuid: t.category_guid ? a(t.category_guid) : "",
|
|
34
34
|
merchantGuid: t.merchant_guid,
|
|
35
|
-
size:
|
|
35
|
+
size: r
|
|
36
36
|
});
|
|
37
|
-
if (t.institution_guid) return /* @__PURE__ */
|
|
37
|
+
if (t.institution_guid) return /* @__PURE__ */ o(L, {
|
|
38
38
|
alt: t.institution_name ?? "",
|
|
39
39
|
institutionGuid: t.institution_guid,
|
|
40
|
-
size:
|
|
40
|
+
size: r
|
|
41
41
|
});
|
|
42
42
|
if (t.category_guid) {
|
|
43
|
-
const
|
|
44
|
-
return /* @__PURE__ */
|
|
45
|
-
"data-testid": `category-icon-${
|
|
43
|
+
const e = a(t.category_guid);
|
|
44
|
+
return /* @__PURE__ */ o(u, {
|
|
45
|
+
"data-testid": `category-icon-${e}`,
|
|
46
46
|
sx: { display: "flex" },
|
|
47
|
-
children: /* @__PURE__ */
|
|
48
|
-
categoryGuid:
|
|
49
|
-
size:
|
|
47
|
+
children: /* @__PURE__ */ o(G, {
|
|
48
|
+
categoryGuid: e,
|
|
49
|
+
size: r
|
|
50
50
|
})
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
},
|
|
55
|
-
const { getTopLevelCategoryGuid:
|
|
54
|
+
}, F = I(({ payload: n }) => {
|
|
55
|
+
const a = b(), { getTopLevelCategoryGuid: t } = p(), { data: e, variant: d } = n.instance_slot, s = c(e, "series"), m = c(e, "header_text");
|
|
56
56
|
if (!Array.isArray(s) || !s.length) return null;
|
|
57
|
-
const
|
|
58
|
-
return /* @__PURE__ */
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
const { background: g, cardVariant: l, showHeader: f } = h(v(a), d, C.NoHeader, "TransactionBlock");
|
|
58
|
+
return /* @__PURE__ */ o(x, {
|
|
59
|
+
background: g,
|
|
60
|
+
header: f && typeof m == "string" ? m : void 0,
|
|
61
|
+
variant: l,
|
|
62
|
+
rows: s.map((i) => ({
|
|
63
|
+
amount: typeof i.amount == "number" ? _(i.amount, "0,0.00") : "",
|
|
64
|
+
leading: z(i, t),
|
|
65
|
+
subtitle: i.secondary_text ?? "",
|
|
66
|
+
title: i.primary_text ?? ""
|
|
65
67
|
}))
|
|
66
68
|
});
|
|
67
69
|
});
|
|
68
70
|
export {
|
|
69
|
-
|
|
70
|
-
I as TransactionBlockVariant
|
|
71
|
+
F as TransactionBlock
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
//# sourceMappingURL=TransactionBlock.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\n\nimport Box from '@mui/material/Box'\n\nimport { CategoryIcon, InstitutionLogo, MerchantLogo } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport { useCategoryStore } from '../../../../common'\nimport { slot } from '../../../../core'\nimport type { InsightsPayload, InstanceSlotRow } from '../../../../core'\nimport { formatCurrency } from '../../../../core/utils/NumberFormatting'\n\nimport TransactionListCard from '../../../components/TransactionListCard'\nimport { logoFromRef } from '../../../components/shared/EntityLogo'\n\
|
|
1
|
+
{"version":3,"file":"TransactionBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\n\nimport Box from '@mui/material/Box'\nimport { useTheme } from '@mui/material/styles'\n\nimport { CategoryIcon, InstitutionLogo, MerchantLogo } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport { useCategoryStore } from '../../../../common'\nimport { slot } from '../../../../core'\nimport type { InsightsPayload, InstanceSlotRow } from '../../../../core'\nimport { formatCurrency } from '../../../../core/utils/NumberFormatting'\n\nimport TransactionListCard from '../../../components/TransactionListCard'\nimport { logoFromRef } from '../../../components/shared/EntityLogo'\n\nimport { resolveVariantConfig } from '../../resolveVariantConfig'\nimport { getLayoutConfig, transactionBlockVariant } from './layout'\n\ninterface TransactionBlockProps {\n payload: InsightsPayload\n beatGuid?: string\n}\n\nconst ROW_LOGO_SIZE = 32\n// Same glyph-to-tile ratio mxui's `CategoryIcon` uses, so a status icon sits like the other logos.\nconst ROW_ICON_SIZE = Math.round(ROW_LOGO_SIZE * 0.625)\n\n/**\n * Renders the row's leading logo from its `LogoRef`: a status icon, or an entity guid whose prefix\n * names the entity. An unrecognized prefix renders no logo rather than guessing.\n *\n * `resolveTopLevelCategory`: mxui's `CategoryIcon` only knows the top-level category guids and\n * silently falls back to the Uncategorized icon for a sub-category. The details drawer avoids\n * this by passing `transaction.top_level_category_guid`; the row only has the raw guid, so it is\n * walked up to its parent here (identity until categories load). That applies both to a `CAT-`\n * row logo and to a merchant's `fallback_guid`, which `MerchantLogo` draws through the same\n * `CategoryIcon` when the merchant image fails to load.\n */\nconst renderRowLogo = (row: InstanceSlotRow, resolveTopLevelCategory: (guid: string) => string) => {\n const logo = logoFromRef(row.logo, row.primary_text)\n\n if (!logo) return undefined\n\n if (logo.logo_name) {\n // A fixed box the size of the other logos keeps the row's text column aligned.\n return (\n <Box\n sx={{\n alignItems: 'center',\n display: 'flex',\n height: ROW_LOGO_SIZE,\n justifyContent: 'center',\n width: ROW_LOGO_SIZE,\n }}\n >\n <Icon name={logo.logo_name} size={ROW_ICON_SIZE} sx={{ color: logo.logo_color }} />\n </Box>\n )\n }\n\n if (logo.merchant_guid) {\n return (\n <MerchantLogo\n alt={logo.merchant_name ?? ''}\n categoryGuid={logo.category_guid ? resolveTopLevelCategory(logo.category_guid) : ''}\n merchantGuid={logo.merchant_guid}\n size={ROW_LOGO_SIZE}\n />\n )\n }\n\n if (logo.institution_guid) {\n return (\n <InstitutionLogo\n alt={logo.institution_name ?? ''}\n institutionGuid={logo.institution_guid}\n size={ROW_LOGO_SIZE}\n />\n )\n }\n\n if (logo.category_guid) {\n const topLevelGuid = resolveTopLevelCategory(logo.category_guid)\n return (\n <Box data-testid={`category-icon-${topLevelGuid}`} sx={{ display: 'flex' }}>\n <CategoryIcon categoryGuid={topLevelGuid} size={ROW_LOGO_SIZE} />\n </Box>\n )\n }\n\n return undefined\n}\n\n/**\n * The `transaction_block`: rows the backend already localized, carried inline on\n * `instance_slot.data.series` (`logo`, `primary_text`, `secondary_text`, `amount`). Only the\n * amount is formatted here, because the contract sends it as a number. `instance_slot.variant`\n * picks the header and slot treatment from `./layout.ts`.\n *\n * This is the full/mini shape. The reduced widgets (micro, embedded) resolve to the row logo\n * alone, carried flat on `data.logo` with no `series`, and are drawn by `CompactInsightCard`.\n *\n * A header, when the variant shows one, comes from `instance_slot.data.header_text` (the\n * transaction date, or \"{count} transactions\"). It deliberately does *not* come from the first\n * row: on a `with_merchant` card a row's `secondary_text` is the category, so reading it here\n * rendered the category twice and dropped the date entirely.\n */\nexport const TransactionBlock = observer(({ payload }: TransactionBlockProps) => {\n const theme = useTheme()\n const { getTopLevelCategoryGuid } = useCategoryStore()\n const { data, variant } = payload.instance_slot\n const series = slot<InstanceSlotRow[]>(data, 'series')\n const headerText = slot<string>(data, 'header_text')\n\n if (!Array.isArray(series) || !series.length) return null\n\n // The plain row is the safe default: it adds nothing a wrong variant could misstate.\n const { background, cardVariant, showHeader } = resolveVariantConfig(\n getLayoutConfig(theme),\n variant,\n transactionBlockVariant.NoHeader,\n 'TransactionBlock',\n )\n const header = showHeader && typeof headerText === 'string' ? headerText : undefined\n\n return (\n <TransactionListCard\n background={background}\n header={header}\n variant={cardVariant}\n rows={series.map((row) => ({\n amount: typeof row.amount === 'number' ? formatCurrency(row.amount, '0,0.00') : '',\n leading: renderRowLogo(row, getTopLevelCategoryGuid),\n subtitle: row.secondary_text ?? '',\n title: row.primary_text ?? '',\n }))}\n />\n )\n})\n"],"mappings":";;;;;;;;;;;;;AAwBA,IAAM,IAAgB,IAEhB,IAAgB,KAAK,MAAM,IAAgB,KAAK,GAahD,IAAA,CAAiB,GAAsB,MAAsD;AACjG,QAAM,IAAO,EAAY,EAAI,MAAM,EAAI,YAAY;AAEnD,MAAK,GAEL;AAAA,QAAI,EAAK,UAEP,QACE,gBAAA,EAAC,GAAD;AAAA,MACE,IAAI;AAAA,QACF,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,gBAAgB;AAAA,QAChB,OAAO;AAAA,MACT;AAAA,MAEA,UAAA,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAM,EAAK;AAAA,QAAW,MAAM;AAAA,QAAe,IAAI,EAAE,OAAO,EAAK,WAAW;AAAA,MAAI,CAAA;AAAA,IAC/E,CAAA;AAIT,QAAI,EAAK,cACP,QACE,gBAAA,EAAC,GAAD;AAAA,MACE,KAAK,EAAK,iBAAiB;AAAA,MAC3B,cAAc,EAAK,gBAAgB,EAAwB,EAAK,aAAa,IAAI;AAAA,MACjF,cAAc,EAAK;AAAA,MACnB,MAAM;AAAA,IACP,CAAA;AAIL,QAAI,EAAK,iBACP,QACE,gBAAA,EAAC,GAAD;AAAA,MACE,KAAK,EAAK,oBAAoB;AAAA,MAC9B,iBAAiB,EAAK;AAAA,MACtB,MAAM;AAAA,IACP,CAAA;AAIL,QAAI,EAAK,eAAe;AACtB,YAAM,IAAe,EAAwB,EAAK,aAAa;AAC/D,aACE,gBAAA,EAAC,GAAD;AAAA,QAAK,eAAa,iBAAiB,CAAA;AAAA,QAAgB,IAAI,EAAE,SAAS,OAAO;AAAA,QACvE,UAAA,gBAAA,EAAC,GAAD;AAAA,UAAc,cAAc;AAAA,UAAc,MAAM;AAAA,QAAgB,CAAA;AAAA,MAC7D,CAAA;AAAA,IAET;AAAA;AAGF,GAgBa,IAAmB,EAAA,CAAU,EAAE,SAAA,EAAA,MAAqC;AAC/E,QAAM,IAAQ,EAAS,GACjB,EAAE,yBAAA,EAAA,IAA4B,EAAiB,GAC/C,EAAE,MAAA,GAAM,SAAA,EAAA,IAAY,EAAQ,eAC5B,IAAS,EAAwB,GAAM,QAAQ,GAC/C,IAAa,EAAa,GAAM,aAAa;AAEnD,MAAI,CAAC,MAAM,QAAQ,CAAM,KAAK,CAAC,EAAO,OAAQ,QAAO;AAGrD,QAAM,EAAE,YAAA,GAAY,aAAA,GAAa,YAAA,EAAA,IAAe,EAC9C,EAAgB,CAAK,GACrB,GACA,EAAwB,UACxB,kBACF;AAGA,SACE,gBAAA,EAAC,GAAD;AAAA,IACc,YAAA;AAAA,IACJ,QALG,KAAc,OAAO,KAAe,WAAW,IAAa;AAAA,IAMvE,SAAS;AAAA,IACT,MAAM,EAAO,IAAA,CAAK,OAAS;AAAA,MACzB,QAAQ,OAAO,EAAI,UAAW,WAAW,EAAe,EAAI,QAAQ,QAAQ,IAAI;AAAA,MAChF,SAAS,EAAc,GAAK,CAAuB;AAAA,MACnD,UAAU,EAAI,kBAAkB;AAAA,MAChC,OAAO,EAAI,gBAAgB;AAAA,IAC7B,EAAE;AAAA,EACH,CAAA;AAEL,CAAC"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { TransactionBlock
|
|
1
|
+
export { TransactionBlock } from './TransactionBlock';
|
|
2
|
+
export { transactionBlockVariant } from './layout';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Theme } from '@mui/material/styles';
|
|
2
|
+
/**
|
|
3
|
+
* Transaction block variants, keyed by the backend `instance_slot.variant`. All render the same
|
|
4
|
+
* pre-localized rows through `TransactionListCard`; only the header and the slot differ.
|
|
5
|
+
*
|
|
6
|
+
* - `WithHeader` — row under a date header (Fee Detected, Large Transaction).
|
|
7
|
+
* - `NoHeader` — the row alone (Large Transaction without a merchant).
|
|
8
|
+
* - `UncategorizedTransaction` — filled primary header ("{count} transactions").
|
|
9
|
+
* - `SubscriptionDetected` — borderless row on the blue slot wash.
|
|
10
|
+
* - `UnexpectedSubscriptionPayment` — borderless row on the warning slot wash. Its flag badge and
|
|
11
|
+
* subscribed / not-subscribed status row are not drawn yet.
|
|
12
|
+
*/
|
|
13
|
+
export declare const transactionBlockVariant: {
|
|
14
|
+
readonly WithHeader: "with_header";
|
|
15
|
+
readonly NoHeader: "no_header";
|
|
16
|
+
readonly UncategorizedTransaction: "uncategorized_transaction";
|
|
17
|
+
readonly SubscriptionDetected: "subscription_detected";
|
|
18
|
+
readonly UnexpectedSubscriptionPayment: "unexpected_subscription_payment";
|
|
19
|
+
};
|
|
20
|
+
export type TransactionBlockVariant = (typeof transactionBlockVariant)[keyof typeof transactionBlockVariant];
|
|
21
|
+
export interface TransactionLayoutConfig {
|
|
22
|
+
/** Show `instance_slot.data.header_text` above the rows. */
|
|
23
|
+
showHeader: boolean;
|
|
24
|
+
/** `TransactionListCard` style: grey utility header, or filled primary header. */
|
|
25
|
+
cardVariant?: 'default' | 'primary';
|
|
26
|
+
/** CSS background for the slot behind the card; the card then renders borderless on paper. */
|
|
27
|
+
background?: string;
|
|
28
|
+
}
|
|
29
|
+
/** Per-variant `TransactionListCard` props (mirrors DirectDepositBlock's `getLayoutConfig`). */
|
|
30
|
+
export declare const getLayoutConfig: (theme: Theme) => Record<TransactionBlockVariant, TransactionLayoutConfig>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { WARNING_WASH_GRADIENT as r, getPrimaryWashGradient as t } from "../../../components/celebrationGradients.es.js";
|
|
2
|
+
var e = {
|
|
3
|
+
WithHeader: "with_header",
|
|
4
|
+
NoHeader: "no_header",
|
|
5
|
+
UncategorizedTransaction: "uncategorized_transaction",
|
|
6
|
+
SubscriptionDetected: "subscription_detected",
|
|
7
|
+
UnexpectedSubscriptionPayment: "unexpected_subscription_payment"
|
|
8
|
+
}, i = (a) => ({
|
|
9
|
+
[e.WithHeader]: { showHeader: !0 },
|
|
10
|
+
[e.NoHeader]: { showHeader: !1 },
|
|
11
|
+
[e.UncategorizedTransaction]: {
|
|
12
|
+
showHeader: !0,
|
|
13
|
+
cardVariant: "primary"
|
|
14
|
+
},
|
|
15
|
+
[e.SubscriptionDetected]: {
|
|
16
|
+
showHeader: !1,
|
|
17
|
+
background: t(a)
|
|
18
|
+
},
|
|
19
|
+
[e.UnexpectedSubscriptionPayment]: {
|
|
20
|
+
showHeader: !1,
|
|
21
|
+
background: r
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
export {
|
|
25
|
+
i as getLayoutConfig,
|
|
26
|
+
e as transactionBlockVariant
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=layout.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.ts"],"sourcesContent":["import type { Theme } from '@mui/material/styles'\n\nimport {\n WARNING_WASH_GRADIENT,\n getPrimaryWashGradient,\n} from '../../../components/celebrationGradients'\n\n/**\n * Transaction block variants, keyed by the backend `instance_slot.variant`. All render the same\n * pre-localized rows through `TransactionListCard`; only the header and the slot differ.\n *\n * - `WithHeader` — row under a date header (Fee Detected, Large Transaction).\n * - `NoHeader` — the row alone (Large Transaction without a merchant).\n * - `UncategorizedTransaction` — filled primary header (\"{count} transactions\").\n * - `SubscriptionDetected` — borderless row on the blue slot wash.\n * - `UnexpectedSubscriptionPayment` — borderless row on the warning slot wash. Its flag badge and\n * subscribed / not-subscribed status row are not drawn yet.\n */\nexport const transactionBlockVariant = {\n WithHeader: 'with_header',\n NoHeader: 'no_header',\n UncategorizedTransaction: 'uncategorized_transaction',\n SubscriptionDetected: 'subscription_detected',\n UnexpectedSubscriptionPayment: 'unexpected_subscription_payment',\n} as const\n\nexport type TransactionBlockVariant =\n (typeof transactionBlockVariant)[keyof typeof transactionBlockVariant]\n\nexport interface TransactionLayoutConfig {\n /** Show `instance_slot.data.header_text` above the rows. */\n showHeader: boolean\n /** `TransactionListCard` style: grey utility header, or filled primary header. */\n cardVariant?: 'default' | 'primary'\n /** CSS background for the slot behind the card; the card then renders borderless on paper. */\n background?: string\n}\n\n/** Per-variant `TransactionListCard` props (mirrors DirectDepositBlock's `getLayoutConfig`). */\nexport const getLayoutConfig = (\n theme: Theme,\n): Record<TransactionBlockVariant, TransactionLayoutConfig> => ({\n [transactionBlockVariant.WithHeader]: { showHeader: true },\n [transactionBlockVariant.NoHeader]: { showHeader: false },\n [transactionBlockVariant.UncategorizedTransaction]: { showHeader: true, cardVariant: 'primary' },\n [transactionBlockVariant.SubscriptionDetected]: {\n showHeader: false,\n background: getPrimaryWashGradient(theme),\n },\n [transactionBlockVariant.UnexpectedSubscriptionPayment]: {\n showHeader: false,\n background: WARNING_WASH_GRADIENT,\n },\n})\n"],"mappings":";AAkBA,IAAa,IAA0B;AAAA,EACrC,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,0BAA0B;AAAA,EAC1B,sBAAsB;AAAA,EACtB,+BAA+B;AACjC,GAea,IAAA,CACX,OAC8D;AAAA,EAC7D,CAAA,EAAwB,UAAA,GAAa,EAAE,YAAY,GAAK;AAAA,EACxD,CAAA,EAAwB,QAAA,GAAW,EAAE,YAAY,GAAM;AAAA,EACvD,CAAA,EAAwB,wBAAA,GAA2B;AAAA,IAAE,YAAY;AAAA,IAAM,aAAa;AAAA,EAAU;AAAA,EAC9F,CAAA,EAAwB,oBAAA,GAAuB;AAAA,IAC9C,YAAY;AAAA,IACZ,YAAY,EAAuB,CAAK;AAAA,EAC1C;AAAA,EACC,CAAA,EAAwB,6BAAA,GAAgC;AAAA,IACvD,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { InsightsPayload } from '../../../../core';
|
|
2
|
+
import { UpcomingBillDay } from '../../../components/UpcomingBillCard';
|
|
3
|
+
interface UpcomingBillBlockProps {
|
|
4
|
+
payload: InsightsPayload;
|
|
5
|
+
beatGuid?: string;
|
|
6
|
+
}
|
|
7
|
+
type SevenDays = [
|
|
8
|
+
UpcomingBillDay,
|
|
9
|
+
UpcomingBillDay,
|
|
10
|
+
UpcomingBillDay,
|
|
11
|
+
UpcomingBillDay,
|
|
12
|
+
UpcomingBillDay,
|
|
13
|
+
UpcomingBillDay,
|
|
14
|
+
UpcomingBillDay
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Parse an ISO `YYYY-MM-DD` into a local-time Date, dodging the UTC-midnight parse
|
|
18
|
+
* that `new Date('2025-10-30')` performs (which drifts a day in negative offsets).
|
|
19
|
+
* Any other string shape (full ISO datetime) falls through to the native parser.
|
|
20
|
+
*
|
|
21
|
+
* Returns `null` for anything that doesn't resolve to a valid Date — including a
|
|
22
|
+
* `YYYY-MM-DD`-shaped string whose year/month/day segments produce `Invalid Date`
|
|
23
|
+
* (e.g. `'2026-13-40'`) and arbitrary strings the native parser rejects. Callers
|
|
24
|
+
* must handle `null` so a bad backend value cannot propagate `NaN` into the UI
|
|
25
|
+
* via `getDay()` and render `NaN` day numbers.
|
|
26
|
+
*/
|
|
27
|
+
export declare const parseDueDate: (iso: string) => Date | null;
|
|
28
|
+
/**
|
|
29
|
+
* Build the Sun→Sat week around a due date with the due day marked `highlighted`.
|
|
30
|
+
* Column index is the local day-of-week (0=Sun..6=Sat) so the strip always lines up
|
|
31
|
+
* under the weekday labels regardless of which weekday the bill lands on.
|
|
32
|
+
*/
|
|
33
|
+
export declare const buildWeekStrip: (dueDate: Date) => SevenDays;
|
|
34
|
+
/**
|
|
35
|
+
* Upcoming Bill component block (Figma: "Full | Upcoming Bill"). Reads `due_date`,
|
|
36
|
+
* `amount` and merchant facts off `instance_slot` (V2 flat shape — no
|
|
37
|
+
* `instance_slot_data`), derives the Sun→Sat week around the due date, and renders
|
|
38
|
+
* the shared `UpcomingBillCard`.
|
|
39
|
+
*
|
|
40
|
+
* Wrapped in `createVariantBlock` from day one so an added design branch is a new
|
|
41
|
+
* registry entry, not a rewrite of dispatch logic. Today only
|
|
42
|
+
* `projected_bill_payment` is defined; an unknown variant degrades to it.
|
|
43
|
+
*
|
|
44
|
+
* Degraded-date rendering: if `due_date` is missing or doesn't parse to a valid
|
|
45
|
+
* Date (e.g. `'2026-13-40'`, `''`, an unparseable arbitrary string), the card
|
|
46
|
+
* still renders — merchant row + amount — but with a neutral current-week strip
|
|
47
|
+
* (no highlighted cell). `UpcomingBillCard` requires a 7-tuple `days` prop so we
|
|
48
|
+
* cannot omit the strip without modifying the shared component; the "no highlighted
|
|
49
|
+
* cell" fallback keeps the useful info visible without pretending today is the
|
|
50
|
+
* due day.
|
|
51
|
+
*/
|
|
52
|
+
declare const UpcomingBillBlock: ({ payload, beatGuid }: UpcomingBillBlockProps) => import("react/jsx-runtime").JSX.Element;
|
|
53
|
+
export default UpcomingBillBlock;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { formatCurrency as u } from "../../../../core/utils/NumberFormatting.es.js";
|
|
2
|
+
import { createVariantBlock as d } from "../../createVariantBlock.es.js";
|
|
3
|
+
import g from "../../../components/LogoFromGuid.es.js";
|
|
4
|
+
import D from "../../../components/UpcomingBillCard.es.js";
|
|
5
|
+
import { upcomingBillVariant as p } from "./layout.es.js";
|
|
6
|
+
import f from "@mui/material/Stack";
|
|
7
|
+
import { jsx as l } from "react/jsx-runtime";
|
|
8
|
+
var s = [
|
|
9
|
+
"Sun",
|
|
10
|
+
"Mon",
|
|
11
|
+
"Tue",
|
|
12
|
+
"Wed",
|
|
13
|
+
"Thu",
|
|
14
|
+
"Fri",
|
|
15
|
+
"Sat"
|
|
16
|
+
], h = (t) => {
|
|
17
|
+
const a = /^(\d{4})-(\d{2})-(\d{2})$/.exec(t);
|
|
18
|
+
if (a) {
|
|
19
|
+
const [, o, n, r] = a, i = new Date(Number(o), Number(n) - 1, Number(r));
|
|
20
|
+
return Number.isNaN(i.getTime()) ? null : i;
|
|
21
|
+
}
|
|
22
|
+
const e = new Date(t);
|
|
23
|
+
return Number.isNaN(e.getTime()) ? null : e;
|
|
24
|
+
}, v = (t) => {
|
|
25
|
+
const a = t.getDay(), e = new Date(t);
|
|
26
|
+
return e.setDate(t.getDate() - a), s.map((o, n) => {
|
|
27
|
+
const r = new Date(e);
|
|
28
|
+
r.setDate(e.getDate() + n);
|
|
29
|
+
const i = {
|
|
30
|
+
label: o,
|
|
31
|
+
date: String(r.getDate())
|
|
32
|
+
};
|
|
33
|
+
return n === a && (i.highlighted = !0), i;
|
|
34
|
+
});
|
|
35
|
+
}, y = () => {
|
|
36
|
+
const t = /* @__PURE__ */ new Date(), a = t.getDay(), e = new Date(t);
|
|
37
|
+
return e.setDate(t.getDate() - a), s.map((o, n) => {
|
|
38
|
+
const r = new Date(e);
|
|
39
|
+
return r.setDate(e.getDate() + n), {
|
|
40
|
+
label: o,
|
|
41
|
+
date: String(r.getDate())
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
}, m = ({ payload: t }) => {
|
|
45
|
+
const { instance_slot: a } = t, { amount: e, due_date: o, merchant_guid: n, merchant_name: r } = a, i = o ? h(o) : null, c = i ? v(i) : y();
|
|
46
|
+
return /* @__PURE__ */ l(f, {
|
|
47
|
+
sx: { px: 16 },
|
|
48
|
+
children: /* @__PURE__ */ l(D, {
|
|
49
|
+
amount: u(e ?? 0, "0,0.00"),
|
|
50
|
+
days: c,
|
|
51
|
+
logo: n ? /* @__PURE__ */ l(g, {
|
|
52
|
+
logo: {
|
|
53
|
+
alt: r ?? "",
|
|
54
|
+
guid: n
|
|
55
|
+
},
|
|
56
|
+
size: 24
|
|
57
|
+
}) : null,
|
|
58
|
+
merchantName: r ?? ""
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
}, P = ({ payload: t, beatGuid: a }) => {
|
|
62
|
+
const e = t.instance_slot.variant ?? void 0;
|
|
63
|
+
return /* @__PURE__ */ l(B, {
|
|
64
|
+
beatGuid: a,
|
|
65
|
+
payload: t,
|
|
66
|
+
variant: e
|
|
67
|
+
});
|
|
68
|
+
}, B = d({
|
|
69
|
+
variants: { [p.ProjectedBillPayment]: m },
|
|
70
|
+
fallback: m,
|
|
71
|
+
name: "UpcomingBillBlock"
|
|
72
|
+
});
|
|
73
|
+
export {
|
|
74
|
+
v as buildWeekStrip,
|
|
75
|
+
P as default,
|
|
76
|
+
h as parseDueDate
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=UpcomingBillBlock.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UpcomingBillBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/UpcomingBillBlock.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport type { InsightsPayload } from '../../../../core'\nimport { formatCurrency } from '../../../../core/utils/NumberFormatting'\n\nimport LogoFromGuid from '../../../components/LogoFromGuid'\nimport UpcomingBillCard, { type UpcomingBillDay } from '../../../components/UpcomingBillCard'\nimport { createVariantBlock } from '../../createVariantBlock'\n\nimport { upcomingBillVariant } from './layout'\n\ninterface UpcomingBillBlockProps {\n payload: InsightsPayload\n beatGuid?: string\n}\n\nconst DAY_LABELS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] as const\ntype SevenDays = [\n UpcomingBillDay,\n UpcomingBillDay,\n UpcomingBillDay,\n UpcomingBillDay,\n UpcomingBillDay,\n UpcomingBillDay,\n UpcomingBillDay,\n]\n\n/**\n * Parse an ISO `YYYY-MM-DD` into a local-time Date, dodging the UTC-midnight parse\n * that `new Date('2025-10-30')` performs (which drifts a day in negative offsets).\n * Any other string shape (full ISO datetime) falls through to the native parser.\n *\n * Returns `null` for anything that doesn't resolve to a valid Date — including a\n * `YYYY-MM-DD`-shaped string whose year/month/day segments produce `Invalid Date`\n * (e.g. `'2026-13-40'`) and arbitrary strings the native parser rejects. Callers\n * must handle `null` so a bad backend value cannot propagate `NaN` into the UI\n * via `getDay()` and render `NaN` day numbers.\n */\nexport const parseDueDate = (iso: string): Date | null => {\n const dateOnly = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(iso)\n if (dateOnly) {\n const [, y, m, d] = dateOnly\n const parsed = new Date(Number(y), Number(m) - 1, Number(d))\n return Number.isNaN(parsed.getTime()) ? null : parsed\n }\n const parsed = new Date(iso)\n return Number.isNaN(parsed.getTime()) ? null : parsed\n}\n\n/**\n * Build the Sun→Sat week around a due date with the due day marked `highlighted`.\n * Column index is the local day-of-week (0=Sun..6=Sat) so the strip always lines up\n * under the weekday labels regardless of which weekday the bill lands on.\n */\nexport const buildWeekStrip = (dueDate: Date): SevenDays => {\n const dow = dueDate.getDay()\n const sunday = new Date(dueDate)\n sunday.setDate(dueDate.getDate() - dow)\n\n const days = DAY_LABELS.map((label, idx): UpcomingBillDay => {\n const cell = new Date(sunday)\n cell.setDate(sunday.getDate() + idx)\n const day: UpcomingBillDay = { label, date: String(cell.getDate()) }\n if (idx === dow) day.highlighted = true\n return day\n })\n\n return days as unknown as SevenDays\n}\n\n/**\n * Build the current Sun→Sat week with NO cell highlighted. Used as the degraded\n * strip when `due_date` is missing or unparseable — the card still renders\n * (merchant row with name + amount) but the strip has no \"due day\" callout.\n */\nconst buildUnhighlightedCurrentWeek = (): SevenDays => {\n const base = new Date()\n const dow = base.getDay()\n const sunday = new Date(base)\n sunday.setDate(base.getDate() - dow)\n\n const days = DAY_LABELS.map((label, idx): UpcomingBillDay => {\n const cell = new Date(sunday)\n cell.setDate(sunday.getDate() + idx)\n return { label, date: String(cell.getDate()) }\n })\n\n return days as unknown as SevenDays\n}\n\nconst ProjectedBillPaymentVariant = ({ payload }: UpcomingBillBlockProps) => {\n const { instance_slot } = payload\n const { amount, due_date, merchant_guid, merchant_name } = instance_slot\n\n // Both missing and malformed `due_date` degrade to the same \"no highlighted cell\" case —\n // we never want to silently show today's week as if it were due today. UpcomingBillCard\n // requires a 7-tuple, so we still render a neutral current-week strip so the merchant row\n // (name + amount) stays visible. Returning null would hide the whole insight for just a\n // bad date, which costs the user more information than it saves.\n const parsed = due_date ? parseDueDate(due_date) : null\n const days = parsed ? buildWeekStrip(parsed) : buildUnhighlightedCurrentWeek()\n\n return (\n <Stack sx={{ px: 16 }}>\n <UpcomingBillCard\n amount={formatCurrency(amount ?? 0, '0,0.00')}\n days={days}\n logo={\n merchant_guid ? (\n <LogoFromGuid logo={{ alt: merchant_name ?? '', guid: merchant_guid }} size={24} />\n ) : null\n }\n merchantName={merchant_name ?? ''}\n />\n </Stack>\n )\n}\n\n/**\n * Upcoming Bill component block (Figma: \"Full | Upcoming Bill\"). Reads `due_date`,\n * `amount` and merchant facts off `instance_slot` (V2 flat shape — no\n * `instance_slot_data`), derives the Sun→Sat week around the due date, and renders\n * the shared `UpcomingBillCard`.\n *\n * Wrapped in `createVariantBlock` from day one so an added design branch is a new\n * registry entry, not a rewrite of dispatch logic. Today only\n * `projected_bill_payment` is defined; an unknown variant degrades to it.\n *\n * Degraded-date rendering: if `due_date` is missing or doesn't parse to a valid\n * Date (e.g. `'2026-13-40'`, `''`, an unparseable arbitrary string), the card\n * still renders — merchant row + amount — but with a neutral current-week strip\n * (no highlighted cell). `UpcomingBillCard` requires a 7-tuple `days` prop so we\n * cannot omit the strip without modifying the shared component; the \"no highlighted\n * cell\" fallback keeps the useful info visible without pretending today is the\n * due day.\n */\nconst UpcomingBillBlock = ({ payload, beatGuid }: UpcomingBillBlockProps) => {\n const variant = payload.instance_slot.variant ?? undefined\n return <Variants beatGuid={beatGuid} payload={payload} variant={variant} />\n}\n\nconst Variants = createVariantBlock<UpcomingBillBlockProps>({\n variants: {\n [upcomingBillVariant.ProjectedBillPayment]: ProjectedBillPaymentVariant,\n },\n fallback: ProjectedBillPaymentVariant,\n name: 'UpcomingBillBlock',\n})\n\nexport default UpcomingBillBlock\n"],"mappings":";;;;;;;AAgBA,IAAM,IAAa;AAAA,EAAC;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAK,GAsBtD,IAAA,CAAgB,MAA6B;AACxD,QAAM,IAAW,4BAA4B,KAAK,CAAG;AACrD,MAAI,GAAU;AACZ,UAAM,CAAA,EAAG,GAAG,GAAG,CAAA,IAAK,GACd,IAAS,IAAI,KAAK,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;AAC3D,WAAO,OAAO,MAAM,EAAO,QAAQ,CAAC,IAAI,OAAO;AAAA,EACjD;AACA,QAAM,IAAS,IAAI,KAAK,CAAG;AAC3B,SAAO,OAAO,MAAM,EAAO,QAAQ,CAAC,IAAI,OAAO;AACjD,GAOa,IAAA,CAAkB,MAA6B;AAC1D,QAAM,IAAM,EAAQ,OAAO,GACrB,IAAS,IAAI,KAAK,CAAO;AAC/B,SAAA,EAAO,QAAQ,EAAQ,QAAQ,IAAI,CAAG,GAEzB,EAAW,IAAA,CAAK,GAAO,MAAyB;AAC3D,UAAM,IAAO,IAAI,KAAK,CAAM;AAC5B,IAAA,EAAK,QAAQ,EAAO,QAAQ,IAAI,CAAG;AACnC,UAAM,IAAuB;AAAA,MAAE,OAAA;AAAA,MAAO,MAAM,OAAO,EAAK,QAAQ,CAAC;AAAA,IAAE;AACnE,WAAI,MAAQ,MAAK,EAAI,cAAc,KAC5B;AAAA,EACT,CAEO;AACT,GAOM,IAAA,MAAiD;AACrD,QAAM,IAAO,oBAAI,KAAK,GAChB,IAAM,EAAK,OAAO,GAClB,IAAS,IAAI,KAAK,CAAI;AAC5B,SAAA,EAAO,QAAQ,EAAK,QAAQ,IAAI,CAAG,GAEtB,EAAW,IAAA,CAAK,GAAO,MAAyB;AAC3D,UAAM,IAAO,IAAI,KAAK,CAAM;AAC5B,WAAA,EAAK,QAAQ,EAAO,QAAQ,IAAI,CAAG,GAC5B;AAAA,MAAE,OAAA;AAAA,MAAO,MAAM,OAAO,EAAK,QAAQ,CAAC;AAAA,IAAE;AAAA,EAC/C,CAEO;AACT,GAEM,IAAA,CAA+B,EAAE,SAAA,EAAA,MAAsC;AAC3E,QAAM,EAAE,eAAA,EAAA,IAAkB,GACpB,EAAE,QAAA,GAAQ,UAAA,GAAU,eAAA,GAAe,eAAA,EAAA,IAAkB,GAOrD,IAAS,IAAW,EAAa,CAAQ,IAAI,MAC7C,IAAO,IAAS,EAAe,CAAM,IAAI,EAA8B;AAE7E,SACE,gBAAA,EAAC,GAAD;AAAA,IAAO,IAAI,EAAE,IAAI,GAAG;AAAA,IAClB,UAAA,gBAAA,EAAC,GAAD;AAAA,MACE,QAAQ,EAAe,KAAU,GAAG,QAAQ;AAAA,MACtC,MAAA;AAAA,MACN,MACE,IACE,gBAAA,EAAC,GAAD;AAAA,QAAc,MAAM;AAAA,UAAE,KAAK,KAAiB;AAAA,UAAI,MAAM;AAAA,QAAc;AAAA,QAAG,MAAM;AAAA,MAAK,CAAA,IAChF;AAAA,MAEN,cAAc,KAAiB;AAAA,IAChC,CAAA;AAAA,EACI,CAAA;AAEX,GAoBM,IAAA,CAAqB,EAAE,SAAA,GAAS,UAAA,EAAA,MAAuC;AAC3E,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,EAA2C;AAAA,EAC1D,UAAU,EAAA,CACP,EAAoB,oBAAA,GAAuB,EAC9C;AAAA,EACA,UAAU;AAAA,EACV,MAAM;AACR,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as UpcomingBillBlock } from './UpcomingBillBlock';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design branches of the Upcoming Bill component block.
|
|
3
|
+
*
|
|
4
|
+
* - `ProjectedBillPayment` — the only variant today (Figma: "Full | Upcoming Bill"):
|
|
5
|
+
* week strip + merchant row + amount.
|
|
6
|
+
*
|
|
7
|
+
* Scaffolded through `createVariantBlock` so adding a future design branch is a new
|
|
8
|
+
* registry entry rather than editing dispatch logic.
|
|
9
|
+
*/
|
|
10
|
+
export declare const upcomingBillVariant: {
|
|
11
|
+
readonly ProjectedBillPayment: "projected_bill_payment";
|
|
12
|
+
};
|
|
13
|
+
export type UpcomingBillVariant = (typeof upcomingBillVariant)[keyof typeof upcomingBillVariant];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/UpcomingBillBlock/layout.ts"],"sourcesContent":["/**\n * Design branches of the Upcoming Bill component block.\n *\n * - `ProjectedBillPayment` — the only variant today (Figma: \"Full | Upcoming Bill\"):\n * week strip + merchant row + amount.\n *\n * Scaffolded through `createVariantBlock` so adding a future design branch is a new\n * registry entry rather than editing dispatch logic.\n */\nexport const upcomingBillVariant = {\n ProjectedBillPayment: 'projected_bill_payment',\n} as const\n\nexport type UpcomingBillVariant = (typeof upcomingBillVariant)[keyof typeof upcomingBillVariant]\n"],"mappings":"AASA,IAAa,IAAsB,EACjC,sBAAsB,yBACxB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { InsightsPayload } from '../../../../core';
|
|
2
|
+
interface UpcomingSubscriptionBlockProps {
|
|
3
|
+
payload: InsightsPayload;
|
|
4
|
+
beatGuid?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const BACKDROP_TILES: {
|
|
7
|
+
size: number;
|
|
8
|
+
opacity: number;
|
|
9
|
+
left: number;
|
|
10
|
+
top: number;
|
|
11
|
+
}[];
|
|
12
|
+
/**
|
|
13
|
+
* Upcoming Subscription component block (Figma: "Full | Upcoming Subscription"). Reads
|
|
14
|
+
* `amount`, `cadence`, and merchant facts off `instance_slot` (V2 flat shape — no
|
|
15
|
+
* `instance_slot_data`) and renders the shared `SubscriptionHeroCard` with the scattered
|
|
16
|
+
* faded-logo backdrop.
|
|
17
|
+
*
|
|
18
|
+
* Wrapped in `createVariantBlock` from day one so an added design branch is a new registry
|
|
19
|
+
* entry, not a rewrite of dispatch logic. Today only `upcoming_subscription` is defined; an
|
|
20
|
+
* unknown variant degrades to it.
|
|
21
|
+
*/
|
|
22
|
+
declare const UpcomingSubscriptionBlock: ({ payload, beatGuid }: UpcomingSubscriptionBlockProps) => import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export default UpcomingSubscriptionBlock;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { formatCurrency as d } from "../../../../core/utils/NumberFormatting.es.js";
|
|
2
|
+
import { createVariantBlock as y } from "../../createVariantBlock.es.js";
|
|
3
|
+
import l from "../../../components/LogoFromGuid.es.js";
|
|
4
|
+
import g from "../../../components/SubscriptionHeroCard.es.js";
|
|
5
|
+
import { upcomingSubscriptionVariant as b } from "./layout.es.js";
|
|
6
|
+
import x from "@mui/material/Stack";
|
|
7
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
8
|
+
import m from "@mui/material/Box";
|
|
9
|
+
var h = [
|
|
10
|
+
{
|
|
11
|
+
size: 51,
|
|
12
|
+
opacity: 0.5,
|
|
13
|
+
left: 6.9,
|
|
14
|
+
top: -13.7
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
size: 51,
|
|
18
|
+
opacity: 0.5,
|
|
19
|
+
left: 82.8,
|
|
20
|
+
top: 75.9
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
size: 33,
|
|
24
|
+
opacity: 0.35,
|
|
25
|
+
left: 15.9,
|
|
26
|
+
top: 35.7
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
size: 33,
|
|
30
|
+
opacity: 0.35,
|
|
31
|
+
left: -5,
|
|
32
|
+
top: 57.1
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
size: 33,
|
|
36
|
+
opacity: 0.35,
|
|
37
|
+
left: 9.3,
|
|
38
|
+
top: 89.8
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
size: 33,
|
|
42
|
+
opacity: 0.35,
|
|
43
|
+
left: 96,
|
|
44
|
+
top: 48.8
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
size: 33,
|
|
48
|
+
opacity: 0.35,
|
|
49
|
+
left: 69.7,
|
|
50
|
+
top: -9.3
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
size: 26,
|
|
54
|
+
opacity: 0.25,
|
|
55
|
+
left: 33.1,
|
|
56
|
+
top: 76.4
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
size: 26,
|
|
60
|
+
opacity: 0.25,
|
|
61
|
+
left: 0.6,
|
|
62
|
+
top: 24.8
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
size: 26,
|
|
66
|
+
opacity: 0.25,
|
|
67
|
+
left: 94.1,
|
|
68
|
+
top: 5.5
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
size: 26,
|
|
72
|
+
opacity: 0.25,
|
|
73
|
+
left: 75.4,
|
|
74
|
+
top: 27.5
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
size: 16,
|
|
78
|
+
opacity: 0.1,
|
|
79
|
+
left: 59.7,
|
|
80
|
+
top: 88.8
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
size: 16,
|
|
84
|
+
opacity: 0.1,
|
|
85
|
+
left: 72.3,
|
|
86
|
+
top: 57.9
|
|
87
|
+
}
|
|
88
|
+
], f = ({ payload: i }) => {
|
|
89
|
+
const { instance_slot: a } = i, { amount: p, cadence: r, merchant_guid: c, merchant_name: n } = a, e = c ? {
|
|
90
|
+
alt: n ?? "",
|
|
91
|
+
guid: c
|
|
92
|
+
} : null, s = d(p ?? 0, "0,0.00"), u = r ? `${s} / ${r}` : s, z = e ? /* @__PURE__ */ o(m, {
|
|
93
|
+
"aria-hidden": !0,
|
|
94
|
+
"data-testid": "upcoming-subscription-backdrop",
|
|
95
|
+
children: h.map((t) => /* @__PURE__ */ o(m, {
|
|
96
|
+
sx: {
|
|
97
|
+
alignItems: "center",
|
|
98
|
+
display: "flex",
|
|
99
|
+
height: t.size,
|
|
100
|
+
justifyContent: "center",
|
|
101
|
+
left: `${t.left}%`,
|
|
102
|
+
opacity: t.opacity,
|
|
103
|
+
position: "absolute",
|
|
104
|
+
top: `${t.top}%`,
|
|
105
|
+
width: t.size
|
|
106
|
+
},
|
|
107
|
+
children: /* @__PURE__ */ o(l, {
|
|
108
|
+
logo: e,
|
|
109
|
+
size: t.size
|
|
110
|
+
})
|
|
111
|
+
}, `${t.size}-${t.left}-${t.top}`))
|
|
112
|
+
}) : null;
|
|
113
|
+
return /* @__PURE__ */ o(x, {
|
|
114
|
+
sx: { px: 16 },
|
|
115
|
+
children: /* @__PURE__ */ o(g, {
|
|
116
|
+
backdrop: z,
|
|
117
|
+
logo: e ? /* @__PURE__ */ o(l, {
|
|
118
|
+
logo: e,
|
|
119
|
+
size: 64
|
|
120
|
+
}) : null,
|
|
121
|
+
name: n ?? "",
|
|
122
|
+
price: u,
|
|
123
|
+
sx: { px: 0 }
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
}, j = ({ payload: i, beatGuid: a }) => {
|
|
127
|
+
const p = i.instance_slot.variant ?? void 0;
|
|
128
|
+
return /* @__PURE__ */ o(v, {
|
|
129
|
+
beatGuid: a,
|
|
130
|
+
payload: i,
|
|
131
|
+
variant: p
|
|
132
|
+
});
|
|
133
|
+
}, v = y({
|
|
134
|
+
variants: { [b.UpcomingSubscription]: f },
|
|
135
|
+
fallback: f,
|
|
136
|
+
name: "UpcomingSubscriptionBlock"
|
|
137
|
+
});
|
|
138
|
+
export {
|
|
139
|
+
h as BACKDROP_TILES,
|
|
140
|
+
j as default
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
//# sourceMappingURL=UpcomingSubscriptionBlock.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UpcomingSubscriptionBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/UpcomingSubscriptionBlock.tsx"],"sourcesContent":["import Box from '@mui/material/Box'\nimport Stack from '@mui/material/Stack'\n\nimport type { InsightsPayload } from '../../../../core'\nimport { formatCurrency } from '../../../../core/utils/NumberFormatting'\n\nimport LogoFromGuid from '../../../components/LogoFromGuid'\nimport SubscriptionHeroCard from '../../../components/SubscriptionHeroCard'\nimport { createVariantBlock } from '../../createVariantBlock'\n\nimport { upcomingSubscriptionVariant } from './layout'\n\ninterface UpcomingSubscriptionBlockProps {\n payload: InsightsPayload\n beatGuid?: string\n}\n\n// Fixed tile positions for the scattered merchant-logo backdrop. Each cell sits over the\n// 320x182-ish hero slot in CSS percentages; the card's `overflow: hidden` clips any that fall\n// partly off-frame, which matches the Figma design.\nexport const BACKDROP_TILES: { size: number; opacity: number; left: number; top: number }[] = [\n { size: 51, opacity: 0.5, left: 6.9, top: -13.7 },\n { size: 51, opacity: 0.5, left: 82.8, top: 75.9 },\n { size: 33, opacity: 0.35, left: 15.9, top: 35.7 },\n { size: 33, opacity: 0.35, left: -5.0, top: 57.1 },\n { size: 33, opacity: 0.35, left: 9.3, top: 89.8 },\n { size: 33, opacity: 0.35, left: 96.0, top: 48.8 },\n { size: 33, opacity: 0.35, left: 69.7, top: -9.3 },\n { size: 26, opacity: 0.25, left: 33.1, top: 76.4 },\n { size: 26, opacity: 0.25, left: 0.6, top: 24.8 },\n { size: 26, opacity: 0.25, left: 94.1, top: 5.5 },\n { size: 26, opacity: 0.25, left: 75.4, top: 27.5 },\n { size: 16, opacity: 0.1, left: 59.7, top: 88.8 },\n { size: 16, opacity: 0.1, left: 72.3, top: 57.9 },\n]\n\nconst UpcomingSubscriptionVariant = ({ payload }: UpcomingSubscriptionBlockProps) => {\n const { instance_slot } = payload\n const { amount, cadence, merchant_guid, merchant_name } = instance_slot\n\n const logoRef = merchant_guid ? { alt: merchant_name ?? '', guid: merchant_guid } : null\n const amountText = formatCurrency(amount ?? 0, '0,0.00')\n const price = cadence ? `${amountText} / ${cadence}` : amountText\n\n const backdrop = logoRef ? (\n // Defensive: SubscriptionHeroCard already wraps `backdrop` in an aria-hidden container, but\n // we mark the inner cluster aria-hidden too so AT skips the 13 tiles even if the shared\n // card's wrapper is refactored.\n <Box aria-hidden={true} data-testid=\"upcoming-subscription-backdrop\">\n {BACKDROP_TILES.map((t) => (\n <Box\n key={`${t.size}-${t.left}-${t.top}`}\n sx={{\n alignItems: 'center',\n display: 'flex',\n height: t.size,\n justifyContent: 'center',\n left: `${t.left}%`,\n opacity: t.opacity,\n position: 'absolute',\n top: `${t.top}%`,\n width: t.size,\n }}\n >\n <LogoFromGuid logo={logoRef} size={t.size} />\n </Box>\n ))}\n </Box>\n ) : null\n\n return (\n <Stack sx={{ px: 16 }}>\n <SubscriptionHeroCard\n backdrop={backdrop}\n logo={logoRef ? <LogoFromGuid logo={logoRef} size={64} /> : null}\n name={merchant_name ?? ''}\n price={price}\n sx={{ px: 0 }}\n />\n </Stack>\n )\n}\n\n/**\n * Upcoming Subscription component block (Figma: \"Full | Upcoming Subscription\"). Reads\n * `amount`, `cadence`, and merchant facts off `instance_slot` (V2 flat shape — no\n * `instance_slot_data`) and renders the shared `SubscriptionHeroCard` with the scattered\n * faded-logo backdrop.\n *\n * Wrapped in `createVariantBlock` from day one so an added design branch is a new registry\n * entry, not a rewrite of dispatch logic. Today only `upcoming_subscription` is defined; an\n * unknown variant degrades to it.\n */\nconst UpcomingSubscriptionBlock = ({ payload, beatGuid }: UpcomingSubscriptionBlockProps) => {\n const variant = payload.instance_slot.variant ?? undefined\n return <Variants beatGuid={beatGuid} payload={payload} variant={variant} />\n}\n\nconst Variants = createVariantBlock<UpcomingSubscriptionBlockProps>({\n variants: {\n [upcomingSubscriptionVariant.UpcomingSubscription]: UpcomingSubscriptionVariant,\n },\n fallback: UpcomingSubscriptionVariant,\n name: 'UpcomingSubscriptionBlock',\n})\n\nexport default UpcomingSubscriptionBlock\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as UpcomingSubscriptionBlock } from './UpcomingSubscriptionBlock';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design branches of the Upcoming Subscription component block.
|
|
3
|
+
*
|
|
4
|
+
* - `UpcomingSubscription` — the only variant today (Figma: "Full | Upcoming Subscription"):
|
|
5
|
+
* 64px hero merchant logo + name (h2) + price pill, over a scattered faded-logo backdrop.
|
|
6
|
+
*
|
|
7
|
+
* Scaffolded through `createVariantBlock` so adding a future design branch is a new registry entry
|
|
8
|
+
* rather than editing dispatch logic.
|
|
9
|
+
*/
|
|
10
|
+
export declare const upcomingSubscriptionVariant: {
|
|
11
|
+
readonly UpcomingSubscription: "upcoming_subscription";
|
|
12
|
+
};
|
|
13
|
+
export type UpcomingSubscriptionVariant = (typeof upcomingSubscriptionVariant)[keyof typeof upcomingSubscriptionVariant];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/UpcomingSubscriptionBlock/layout.ts"],"sourcesContent":["/**\n * Design branches of the Upcoming Subscription component block.\n *\n * - `UpcomingSubscription` — the only variant today (Figma: \"Full | Upcoming Subscription\"):\n * 64px hero merchant logo + name (h2) + price pill, over a scattered faded-logo backdrop.\n *\n * Scaffolded through `createVariantBlock` so adding a future design branch is a new registry entry\n * rather than editing dispatch logic.\n */\nexport const upcomingSubscriptionVariant = {\n UpcomingSubscription: 'upcoming_subscription',\n} as const\n\nexport type UpcomingSubscriptionVariant =\n (typeof upcomingSubscriptionVariant)[keyof typeof upcomingSubscriptionVariant]\n"],"mappings":"AASA,IAAa,IAA8B,EACzC,sBAAsB,wBACxB"}
|