@mx-cartographer/experiences 9.6.12 → 9.6.13

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 (28) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/core/types/Insights.d.ts +7 -1
  3. package/dist/core/types/Insights.es.js.map +1 -1
  4. package/dist/insights-v2/actionBlocks/AmountInputModalBlock/AmountInputModalBlock.es.js +38 -38
  5. package/dist/insights-v2/actionBlocks/AmountInputModalBlock/AmountInputModalBlock.es.js.map +1 -1
  6. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/layout.d.ts +27 -0
  7. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/layout.es.js +14 -0
  8. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/layout.es.js.map +1 -0
  9. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js +5 -5
  10. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/useTransactionDetailsBlock.es.js.map +1 -1
  11. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.d.ts +6 -2
  12. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js +7 -4
  13. package/dist/insights-v2/actionBlocks/TransactionDetailsBlock/util.es.js.map +1 -1
  14. package/dist/insights-v2/actionBlocks/util.d.ts +4 -3
  15. package/dist/insights-v2/actionBlocks/util.es.js.map +1 -1
  16. package/dist/insights-v2/components/CompactInsightCard.es.js +34 -24
  17. package/dist/insights-v2/components/CompactInsightCard.es.js.map +1 -1
  18. package/dist/insights-v2/components/LogoFromGuid.d.ts +2 -2
  19. package/dist/insights-v2/components/LogoFromGuid.es.js +44 -32
  20. package/dist/insights-v2/components/LogoFromGuid.es.js.map +1 -1
  21. package/dist/insights-v2/components/SubHeader.es.js +3 -2
  22. package/dist/insights-v2/components/SubHeader.es.js.map +1 -1
  23. package/dist/insights-v2/components/chartblocks/EmptyBarChart.es.js +4 -4
  24. package/dist/insights-v2/components/shared/EntityLogo.es.js +31 -21
  25. package/dist/insights-v2/components/shared/EntityLogo.es.js.map +1 -1
  26. package/dist/insights-v2/components/shared/images/FeeDetected.es.js +243 -0
  27. package/dist/insights-v2/components/shared/images/FeeDetected.es.js.map +1 -0
  28. package/package.json +1 -1
@@ -1,17 +1,19 @@
1
1
  import { slot as y } from "../../core/types/Insights.es.js";
2
2
  import { createVariantBlock as k } from "../blocks/createVariantBlock.es.js";
3
3
  import m from "./BadgedTile.es.js";
4
- import { InsightOptionsMenu as I } from "./InsightOptionsMenu.es.js";
5
- import w from "./LogoFromGuid.es.js";
6
- import v from "./StatusBadge.es.js";
4
+ import { InsightOptionsMenu as w } from "./InsightOptionsMenu.es.js";
5
+ import I from "./LogoFromGuid.es.js";
6
+ import { ReactComponent as v } from "./shared/images/FeeDetected.es.js";
7
+ import { ThemedSVGImage as C } from "./chartblocks/ThemedSVGImage.es.js";
8
+ import S from "./StatusBadge.es.js";
7
9
  import l from "@mui/material/Stack";
8
- import { P as C, Text as _ } from "@mxenabled/mxui";
9
- import S from "@mui/material/Button";
10
- import { Icon as B } from "@mxenabled/mx-icons";
10
+ import { P as _, Text as V } from "@mxenabled/mxui";
11
+ import B from "@mui/material/Button";
12
+ import { Icon as P } from "@mxenabled/mx-icons";
11
13
  import { jsx as t, jsxs as n } from "react/jsx-runtime";
12
14
  import p from "@mui/material/Box";
13
15
  import z from "@mui/material/Card";
14
- var a = 44, d = ({ logo: r }) => r ? /* @__PURE__ */ t(w, {
16
+ var a = 44, d = ({ logo: r }) => r ? /* @__PURE__ */ t(I, {
15
17
  logo: r,
16
18
  size: a
17
19
  }) : /* @__PURE__ */ t(p, {
@@ -24,7 +26,7 @@ var a = 44, d = ({ logo: r }) => r ? /* @__PURE__ */ t(w, {
24
26
  justifyContent: "center",
25
27
  width: a
26
28
  },
27
- children: /* @__PURE__ */ t(B, {
29
+ children: /* @__PURE__ */ t(P, {
28
30
  color: "primary",
29
31
  fill: !0,
30
32
  name: "lightbulb",
@@ -34,21 +36,29 @@ var a = 44, d = ({ logo: r }) => r ? /* @__PURE__ */ t(w, {
34
36
  center: /* @__PURE__ */ t(d, { logo: r }),
35
37
  size: a,
36
38
  sx: { flexShrink: 0 }
37
- }), P = ({ logo: r }) => /* @__PURE__ */ t(m, {
39
+ }), j = ({ logo: r }) => /* @__PURE__ */ t(m, {
38
40
  center: /* @__PURE__ */ t(d, { logo: r }),
39
41
  size: a,
40
42
  sx: { flexShrink: 0 },
41
- topRight: /* @__PURE__ */ t(v, { tone: "warning" })
42
- }), V = k({
43
+ topRight: /* @__PURE__ */ t(S, { tone: "warning" })
44
+ }), D = () => /* @__PURE__ */ t(C, {
45
+ divProps: { style: {
46
+ flexShrink: 0,
47
+ lineHeight: 0,
48
+ width: "max-content"
49
+ } },
50
+ image: v
51
+ }), L = k({
43
52
  variants: {
44
53
  minimal: c,
45
- with_warning_badge: P
54
+ with_illustration: D,
55
+ with_warning_badge: j
46
56
  },
47
57
  fallback: c,
48
58
  name: "InsightVisual"
49
- }), j = (r) => r.stopPropagation(), $ = ({ isCtaDisabled: r = !1, onCtaClick: g, onTap: e, payload: f }) => {
50
- const { description: h, instance_slot: s, primary_cta: o, title: x } = f, u = y(s.data, "logo"), b = (i) => {
51
- i.stopPropagation(), !(r || !o) && g?.(o);
59
+ }), F = (r) => r.stopPropagation(), U = ({ isCtaDisabled: r = !1, onCtaClick: f, onTap: e, payload: g }) => {
60
+ const { description: h, instance_slot: s, primary_cta: o, title: u } = g, x = y(s.data, "logo"), b = (i) => {
61
+ i.stopPropagation(), !(r || !o) && f?.(o);
52
62
  };
53
63
  return /* @__PURE__ */ n(z, {
54
64
  "data-testid": "compact-insight-card",
@@ -77,14 +87,14 @@ var a = 44, d = ({ logo: r }) => r ? /* @__PURE__ */ t(w, {
77
87
  pl: 8,
78
88
  pt: 4
79
89
  },
80
- children: [/* @__PURE__ */ t(_, {
90
+ children: [/* @__PURE__ */ t(V, {
81
91
  bold: !0,
82
92
  variant: "body1",
83
- children: x ?? ""
93
+ children: u ?? ""
84
94
  }), /* @__PURE__ */ t(p, {
85
- onClick: j,
95
+ onClick: F,
86
96
  sx: { display: "flex" },
87
- children: /* @__PURE__ */ t(I, {})
97
+ children: /* @__PURE__ */ t(w, {})
88
98
  })]
89
99
  }), /* @__PURE__ */ n(l, {
90
100
  sx: {
@@ -99,11 +109,11 @@ var a = 44, d = ({ logo: r }) => r ? /* @__PURE__ */ t(w, {
99
109
  gap: 8,
100
110
  minWidth: 0
101
111
  },
102
- children: [/* @__PURE__ */ t(C, {
112
+ children: [/* @__PURE__ */ t(_, {
103
113
  dangerouslySetInnerHTML: { __html: h.html_text },
104
114
  "data-testid": "compact-insight-card-description",
105
115
  variant: "subtitle2"
106
- }), o?.label && /* @__PURE__ */ t(S, {
116
+ }), o?.label && /* @__PURE__ */ t(B, {
107
117
  "aria-disabled": r,
108
118
  onClick: b,
109
119
  size: "small",
@@ -119,15 +129,15 @@ var a = 44, d = ({ logo: r }) => r ? /* @__PURE__ */ t(w, {
119
129
  variant: "text",
120
130
  children: o.label
121
131
  })]
122
- }), /* @__PURE__ */ t(V, {
123
- logo: u,
132
+ }), /* @__PURE__ */ t(L, {
133
+ logo: x,
124
134
  variant: s.variant
125
135
  })]
126
136
  })]
127
137
  });
128
138
  };
129
139
  export {
130
- $ as default
140
+ U as default
131
141
  };
132
142
 
133
143
  //# sourceMappingURL=CompactInsightCard.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CompactInsightCard.es.js","names":[],"sources":["../../../src/insights-v2/components/CompactInsightCard.tsx"],"sourcesContent":["import type { KeyboardEvent, MouseEvent } from 'react'\n\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport Stack from '@mui/material/Stack'\n\nimport { Icon } from '@mxenabled/mx-icons'\nimport { P, Text } from '@mxenabled/mxui'\n\nimport { slot } from '../../core'\nimport type { InsightsPayload, LogoRef, PrimaryCTA } from '../../core'\nimport { createVariantBlock } from '../blocks/createVariantBlock'\nimport BadgedTile from './BadgedTile'\nimport InsightOptionsMenu from './InsightOptionsMenu'\nimport LogoFromGuid from './LogoFromGuid'\nimport StatusBadge from './StatusBadge'\n\n/** Figma 1941:111897: the tile the logo fills is 44px (rows are 32, the notification row 33). */\nconst ICON_SIZE = 44\n\ninterface InsightVisualProps {\n /** The slot's `logo`, when ditto's variant declares and fills one. */\n logo?: LogoRef | null\n}\n\n/** The slot's logo, or the neutral insight glyph when the slot carries none. */\nconst LogoOrFallback = ({ logo }: InsightVisualProps) =>\n logo ? (\n <LogoFromGuid logo={logo} size={ICON_SIZE} />\n ) : (\n <Box\n data-testid=\"compact-insight-card-fallback-icon\"\n sx={{\n alignItems: 'center',\n bgcolor: 'primary.lighter',\n display: 'flex',\n height: ICON_SIZE,\n justifyContent: 'center',\n width: ICON_SIZE,\n }}\n >\n <Icon color=\"primary\" fill={true} name=\"lightbulb\" size={24} />\n </Box>\n )\n\n/** Micro, and any variant not registered below: the logo alone. */\nconst PlainVisual = ({ logo }: InsightVisualProps) => (\n <BadgedTile center={<LogoOrFallback logo={logo} />} size={ICON_SIZE} sx={{ flexShrink: 0 }} />\n)\n\n/** ditto `with_warning_badge`: the logo badged with a status glyph (Figma 1941:111897). */\nconst WarningBadgeVisual = ({ logo }: InsightVisualProps) => (\n <BadgedTile\n center={<LogoOrFallback logo={logo} />}\n size={ICON_SIZE}\n sx={{ flexShrink: 0 }}\n topRight={<StatusBadge tone=\"warning\" />}\n />\n)\n\n/**\n * The card's right-hand visual, one component per ditto layout variant.\n *\n * A variant names a rendering *shape*, not an insight or a surface — `with_header` already serves\n * both Large Transaction and Fee Detected — so an insight wanting the badged logo reuses\n * `with_warning_badge`. Only a genuinely different visual registers a new entry, and existing ones\n * are never touched.\n *\n * `minimal` draws the plain logo and is registered explicitly even though it matches the fallback:\n * micro and notification resolve it on every render, and an unregistered variant warns. The\n * fallback is for variants we genuinely do not know.\n */\nconst InsightVisual = createVariantBlock<InsightVisualProps>({\n variants: { minimal: PlainVisual, with_warning_badge: WarningBadgeVisual },\n fallback: PlainVisual,\n name: 'InsightVisual',\n})\n\nexport interface CompactInsightCardProps {\n /** A `micro` or `embedded` envelope. */\n payload: InsightsPayload\n /**\n * Makes the whole card the tap target. What a tap does is the host's decision (post to the\n * host app, open a drawer, …); the card never opens anything itself. Omit for a static card.\n */\n onTap?: () => void\n /** Receives the primary CTA when tapped. The card does not resolve the CTA's block itself. */\n onCtaClick?: (cta: PrimaryCTA) => void\n /**\n * Renders the CTA disabled — label shown, `aria-disabled`, not tappable — for a host that cannot\n * honour it (e.g. `contact_support_block` when the client's `enable_support_requests` is off).\n */\n isCtaDisabled?: boolean\n}\n\nconst stopPropagation = (event: MouseEvent) => event.stopPropagation()\n\n/**\n * The one compact renderer the micro and embedded envelopes share (`insights_v2.2.md` §8.3).\n *\n * Figma 1941:111897 (Embedded | Large Transaction): a title row with the overflow slot, the HTML\n * description with the primary CTA under it, and on the right the slot's `logo` in a\n * `<BadgedTile>`. Under ditto's `with_warning_badge` variant the tile takes a status badge; under\n * `minimal` it draws the logo alone. The card lays out from the envelope alone and never reads\n * `widget_type`.\n *\n * The icon falls back to the neutral insight glyph **here**, not in `LogoFromGuid`, when the slot\n * carries no logo. The `pill` on the same envelope is the transaction row's, not the card's.\n */\nconst CompactInsightCard = ({\n isCtaDisabled = false,\n onCtaClick,\n onTap,\n payload,\n}: CompactInsightCardProps) => {\n const { description, instance_slot, primary_cta, title } = payload\n // Reduced variants (`minimal`, `with_warning_badge`) declare a bare `logo` slot.\n const rowLogo = slot<LogoRef>(instance_slot.data, 'logo')\n\n const handleCtaClick = (event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation()\n if (isCtaDisabled || !primary_cta) return\n onCtaClick?.(primary_cta)\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n // Only the card itself: Enter on the CTA button is the button's own click.\n if (event.target !== event.currentTarget) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onTap?.()\n }\n }\n\n const interactiveProps = onTap\n ? { onClick: onTap, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 }\n : {}\n\n return (\n <Card\n data-testid=\"compact-insight-card\"\n {...interactiveProps}\n sx={{\n minWidth: 288,\n pb: 12,\n pl: 8,\n pr: 16,\n pt: 8,\n ...(onTap && { cursor: 'pointer' }),\n }}\n >\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n gap: 8,\n justifyContent: 'space-between',\n pl: 8,\n pt: 4,\n }}\n >\n <Text bold={true} variant=\"body1\">\n {title ?? ''}\n </Text>\n {/* The menu renders only when the host wired `onMenuAction` (BeatActionsProvider). */}\n <Box onClick={stopPropagation} sx={{ display: 'flex' }}>\n <InsightOptionsMenu />\n </Box>\n </Stack>\n\n <Stack sx={{ flexDirection: 'row', gap: 16, pl: 8, pt: 4 }}>\n <Stack sx={{ flex: 1, gap: 8, minWidth: 0 }}>\n {/* `html_text` is rendered server-side by mrs_content from the ditto copy template (bold\n amount / merchant), not user-authored input; painted the same way `BaseLayout` paints\n the full card's description. */}\n <P\n dangerouslySetInnerHTML={{ __html: description.html_text }}\n data-testid=\"compact-insight-card-description\"\n variant=\"subtitle2\"\n />\n {primary_cta?.label && (\n <Button\n aria-disabled={isCtaDisabled}\n onClick={handleCtaClick}\n size=\"small\"\n sx={{\n alignSelf: 'flex-start',\n // Figma 1941:111897 lines the CTA label up with the description's left edge. The\n // column already pads 8, so the button's own 8 is pulled back out — padding kept so\n // the tap target does not shrink.\n ml: -8,\n px: 8,\n ...(isCtaDisabled && {\n color: 'text.disabled',\n cursor: 'default',\n }),\n }}\n variant=\"text\"\n >\n {primary_cta.label}\n </Button>\n )}\n </Stack>\n\n <InsightVisual logo={rowLogo} variant={instance_slot.variant} />\n </Stack>\n </Card>\n )\n}\n\nexport default CompactInsightCard\n"],"mappings":"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"}
1
+ {"version":3,"file":"CompactInsightCard.es.js","names":[],"sources":["../../../src/insights-v2/components/CompactInsightCard.tsx"],"sourcesContent":["import type { KeyboardEvent, MouseEvent } from 'react'\n\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport Stack from '@mui/material/Stack'\n\nimport { Icon } from '@mxenabled/mx-icons'\nimport { P, Text } from '@mxenabled/mxui'\n\nimport { slot } from '../../core'\nimport type { InsightsPayload, LogoRef, PrimaryCTA } from '../../core'\nimport { createVariantBlock } from '../blocks/createVariantBlock'\nimport BadgedTile from './BadgedTile'\nimport InsightOptionsMenu from './InsightOptionsMenu'\nimport LogoFromGuid from './LogoFromGuid'\nimport { ReactComponent as FeeDetectedIllustration } from './shared/images/FeeDetected.svg'\nimport { ThemedSVGImage } from './chartblocks/ThemedSVGImage'\nimport StatusBadge from './StatusBadge'\n\n/** Figma 1941:111897: the tile the logo fills is 44px (rows are 32, the notification row 33). */\nconst ICON_SIZE = 44\n\ninterface InsightVisualProps {\n /** The slot's `logo`, when ditto's variant declares and fills one. */\n logo?: LogoRef | null\n}\n\n/** The slot's logo, or the neutral insight glyph when the slot carries none. */\nconst LogoOrFallback = ({ logo }: InsightVisualProps) =>\n logo ? (\n <LogoFromGuid logo={logo} size={ICON_SIZE} />\n ) : (\n <Box\n data-testid=\"compact-insight-card-fallback-icon\"\n sx={{\n alignItems: 'center',\n bgcolor: 'primary.lighter',\n display: 'flex',\n height: ICON_SIZE,\n justifyContent: 'center',\n width: ICON_SIZE,\n }}\n >\n <Icon color=\"primary\" fill={true} name=\"lightbulb\" size={24} />\n </Box>\n )\n\n/** Micro, and any variant not registered below: the logo alone. */\nconst PlainVisual = ({ logo }: InsightVisualProps) => (\n <BadgedTile center={<LogoOrFallback logo={logo} />} size={ICON_SIZE} sx={{ flexShrink: 0 }} />\n)\n\n/** ditto `with_warning_badge`: the logo badged with a status glyph (Figma 1941:111897). */\nconst WarningBadgeVisual = ({ logo }: InsightVisualProps) => (\n <BadgedTile\n center={<LogoOrFallback logo={logo} />}\n size={ICON_SIZE}\n sx={{ flexShrink: 0 }}\n topRight={<StatusBadge tone=\"warning\" />}\n />\n)\n\n/**\n * ditto `with_illustration`: artwork in place of the logo tile (Fee Detected's search illustration).\n * A single SVG themed at runtime by `ThemedSVGImage`: its `brand300` elements are recolored to the\n * theme's `primary.main` (so it follows dark mode), while `fill=\"white\"` areas stay white. The\n * slot's `logo` is deliberately unused: the illustration replaces the tile.\n */\nconst IllustrationVisual = () => {\n return (\n <ThemedSVGImage\n divProps={{ style: { flexShrink: 0, lineHeight: 0, width: 'max-content' } }}\n image={FeeDetectedIllustration}\n />\n )\n}\n\n/**\n * The card's right-hand visual, one component per ditto layout variant.\n *\n * A variant names a rendering *shape*, not an insight or a surface — `with_header` already serves\n * both Large Transaction and Fee Detected — so an insight wanting the badged logo reuses\n * `with_warning_badge`. Only a genuinely different visual registers a new entry, and existing ones\n * are never touched.\n *\n * `minimal` draws the plain logo and is registered explicitly even though it matches the fallback:\n * micro and notification resolve it on every render, and an unregistered variant warns. The\n * fallback is for variants we genuinely do not know.\n */\nconst InsightVisual = createVariantBlock<InsightVisualProps>({\n variants: {\n minimal: PlainVisual,\n with_illustration: IllustrationVisual,\n with_warning_badge: WarningBadgeVisual,\n },\n fallback: PlainVisual,\n name: 'InsightVisual',\n})\n\nexport interface CompactInsightCardProps {\n /** A `micro` or `embedded` envelope. */\n payload: InsightsPayload\n /**\n * Makes the whole card the tap target. What a tap does is the host's decision (post to the\n * host app, open a drawer, …); the card never opens anything itself. Omit for a static card.\n */\n onTap?: () => void\n /** Receives the primary CTA when tapped. The card does not resolve the CTA's block itself. */\n onCtaClick?: (cta: PrimaryCTA) => void\n /**\n * Renders the CTA disabled — label shown, `aria-disabled`, not tappable — for a host that cannot\n * honour it (e.g. `contact_support_block` when the client's `enable_support_requests` is off).\n */\n isCtaDisabled?: boolean\n}\n\nconst stopPropagation = (event: MouseEvent) => event.stopPropagation()\n\n/**\n * The one compact renderer the micro and embedded envelopes share (`insights_v2.2.md` §8.3).\n *\n * Figma 1941:111897 (Embedded | Large Transaction): a title row with the overflow slot, the HTML\n * description with the primary CTA under it, and on the right the slot's `logo` in a\n * `<BadgedTile>`. Under ditto's `with_warning_badge` variant the tile takes a status badge; under\n * `minimal` it draws the logo alone. The card lays out from the envelope alone and never reads\n * `widget_type`.\n *\n * The icon falls back to the neutral insight glyph **here**, not in `LogoFromGuid`, when the slot\n * carries no logo. The `pill` on the same envelope is the transaction row's, not the card's.\n */\nconst CompactInsightCard = ({\n isCtaDisabled = false,\n onCtaClick,\n onTap,\n payload,\n}: CompactInsightCardProps) => {\n const { description, instance_slot, primary_cta, title } = payload\n // Reduced variants (`minimal`, `with_warning_badge`) declare a bare `logo` slot.\n const rowLogo = slot<LogoRef>(instance_slot.data, 'logo')\n\n const handleCtaClick = (event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation()\n if (isCtaDisabled || !primary_cta) return\n onCtaClick?.(primary_cta)\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n // Only the card itself: Enter on the CTA button is the button's own click.\n if (event.target !== event.currentTarget) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onTap?.()\n }\n }\n\n const interactiveProps = onTap\n ? { onClick: onTap, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 }\n : {}\n\n return (\n <Card\n data-testid=\"compact-insight-card\"\n {...interactiveProps}\n sx={{\n minWidth: 288,\n pb: 12,\n pl: 8,\n pr: 16,\n pt: 8,\n ...(onTap && { cursor: 'pointer' }),\n }}\n >\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n gap: 8,\n justifyContent: 'space-between',\n pl: 8,\n pt: 4,\n }}\n >\n <Text bold={true} variant=\"body1\">\n {title ?? ''}\n </Text>\n {/* The menu renders only when the host wired `onMenuAction` (BeatActionsProvider). */}\n <Box onClick={stopPropagation} sx={{ display: 'flex' }}>\n <InsightOptionsMenu />\n </Box>\n </Stack>\n\n <Stack sx={{ flexDirection: 'row', gap: 16, pl: 8, pt: 4 }}>\n <Stack sx={{ flex: 1, gap: 8, minWidth: 0 }}>\n {/* `html_text` is rendered server-side by mrs_content from the ditto copy template (bold\n amount / merchant), not user-authored input; painted the same way `BaseLayout` paints\n the full card's description. */}\n <P\n dangerouslySetInnerHTML={{ __html: description.html_text }}\n data-testid=\"compact-insight-card-description\"\n variant=\"subtitle2\"\n />\n {primary_cta?.label && (\n <Button\n aria-disabled={isCtaDisabled}\n onClick={handleCtaClick}\n size=\"small\"\n sx={{\n alignSelf: 'flex-start',\n // Figma 1941:111897 lines the CTA label up with the description's left edge. The\n // column already pads 8, so the button's own 8 is pulled back out — padding kept so\n // the tap target does not shrink.\n ml: -8,\n px: 8,\n ...(isCtaDisabled && {\n color: 'text.disabled',\n cursor: 'default',\n }),\n }}\n variant=\"text\"\n >\n {primary_cta.label}\n </Button>\n )}\n </Stack>\n\n <InsightVisual logo={rowLogo} variant={instance_slot.variant} />\n </Stack>\n </Card>\n )\n}\n\nexport default CompactInsightCard\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { LogoRef } from '../../core';
2
2
  export declare const isLogoGuid: (guid?: string | null) => guid is string;
3
3
  export interface LogoFromGuidProps {
4
- /** The envelope's logo object: `{ guid, fallback_guid?, alt? }`. */
5
- logo?: Pick<LogoRef, 'alt' | 'fallback_guid' | 'guid'> | null;
4
+ /** The envelope's logo object: `{ guid, fallback_guid?, alt?, color? }` (`color` is read for `ICO-` icons). */
5
+ logo?: Pick<LogoRef, 'alt' | 'color' | 'fallback_guid' | 'guid'> | null;
6
6
  /** Rendered square size in px (32 on rows, 40 on the compact card, 33 on the notification row). */
7
7
  size: number;
8
8
  className?: string;
@@ -1,48 +1,60 @@
1
- import { useCategoryStore as a } from "../../common/context/hooks.es.js";
2
- import { logoFromRef as d } from "./shared/EntityLogo.es.js";
1
+ import { useCategoryStore as l } from "../../common/context/hooks.es.js";
2
+ import { logoFromRef as u } from "./shared/EntityLogo.es.js";
3
3
  import { observer as g } from "mobx-react-lite";
4
- import { CategoryIcon as l, InstitutionLogo as m, MerchantLogo as c } from "@mxenabled/mxui";
4
+ import { CategoryIcon as m, InstitutionLogo as c, MerchantLogo as d } from "@mxenabled/mxui";
5
+ import { Icon as f, IconList as s } from "@mxenabled/mx-icons";
5
6
  import { jsx as n } from "react/jsx-runtime";
6
- import f from "@mui/material/Box";
7
- var s = /^(MCH|CAT|INS)-/, _ = (o) => !!o && s.test(o), C = g(({ className: o, logo: i, size: r }) => {
8
- const { getTopLevelCategoryGuid: u } = a();
9
- if (!i || !_(i.guid)) return null;
10
- const t = d({
11
- alt: i.alt,
12
- fallback_guid: i.fallback_guid,
13
- guid: i.guid
7
+ import _ from "@mui/material/Box";
8
+ var h = /^(MCH|CAT|INS)-|^ICO-[a-z0-9_-]+$/, y = (e) => !!e && h.test(e), F = g(({ className: e, logo: t, size: i }) => {
9
+ const { getTopLevelCategoryGuid: a } = l();
10
+ if (!t || !y(t.guid)) return null;
11
+ const o = u({
12
+ alt: t.alt,
13
+ color: t.color,
14
+ fallback_guid: t.fallback_guid,
15
+ guid: t.guid
14
16
  });
15
- if (!t) return null;
16
- let e = null;
17
- return t.merchant_guid ? e = /* @__PURE__ */ n(c, {
18
- alt: t.merchant_name ?? "",
19
- categoryGuid: t.category_guid ? u(t.category_guid) : "",
20
- merchantGuid: t.merchant_guid,
21
- size: r
22
- }) : t.institution_guid ? e = /* @__PURE__ */ n(m, {
23
- alt: t.institution_name ?? "",
24
- institutionGuid: t.institution_guid,
25
- size: r
26
- }) : t.category_guid && (e = /* @__PURE__ */ n(l, {
27
- categoryGuid: u(t.category_guid),
28
- size: r
29
- })), e ? /* @__PURE__ */ n(f, {
30
- className: o,
17
+ if (!o) return null;
18
+ let r = null;
19
+ if (o.logo_name) {
20
+ if (!(o.logo_name in s))
21
+ return console.warn(`[LogoFromGuid] "${t.guid}" names no mx-icons icon — rendering nothing.`), null;
22
+ r = /* @__PURE__ */ n(f, {
23
+ fill: o.logo_fill,
24
+ name: o.logo_name,
25
+ size: i,
26
+ sx: { color: o.logo_color }
27
+ });
28
+ } else o.merchant_guid ? r = /* @__PURE__ */ n(d, {
29
+ alt: o.merchant_name ?? "",
30
+ categoryGuid: o.category_guid ? a(o.category_guid) : "",
31
+ merchantGuid: o.merchant_guid,
32
+ size: i
33
+ }) : o.institution_guid ? r = /* @__PURE__ */ n(c, {
34
+ alt: o.institution_name ?? "",
35
+ institutionGuid: o.institution_guid,
36
+ size: i
37
+ }) : o.category_guid && (r = /* @__PURE__ */ n(m, {
38
+ categoryGuid: a(o.category_guid),
39
+ size: i
40
+ }));
41
+ return r ? /* @__PURE__ */ n(_, {
42
+ className: e,
31
43
  "data-testid": "logo-from-guid",
32
44
  sx: {
33
45
  alignItems: "center",
34
46
  display: "flex",
35
47
  flexShrink: 0,
36
- height: r,
48
+ height: i,
37
49
  justifyContent: "center",
38
- width: r
50
+ width: i
39
51
  },
40
- children: e
52
+ children: r
41
53
  }) : null;
42
54
  });
43
55
  export {
44
- C as default,
45
- _ as isLogoGuid
56
+ F as default,
57
+ y as isLogoGuid
46
58
  };
47
59
 
48
60
  //# sourceMappingURL=LogoFromGuid.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LogoFromGuid.es.js","names":[],"sources":["../../../src/insights-v2/components/LogoFromGuid.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\n\nimport Box from '@mui/material/Box'\n\nimport { CategoryIcon, InstitutionLogo, MerchantLogo } from '@mxenabled/mxui'\n\nimport { useCategoryStore } from '../../common'\nimport type { LogoRef } from '../../core'\nimport { logoFromRef } from './shared/EntityLogo'\n\n/**\n * The guid prefixes that name a logo entity. A prefix heuristic by design: the V2 envelope carries\n * the entity only in the guid, and the notification row relies on non-insight rows carrying account\n * or budget guids and legacy insight rows carrying the `\"PARENT-ENTITY\"` sentinel. Exported beside\n * the component so a caller's branch (`NotificationCard`) and the dispatch here cannot drift apart.\n */\nconst LOGO_GUID_PREFIX = /^(MCH|CAT|INS)-/\n\nexport const isLogoGuid = (guid?: string | null): guid is string =>\n !!guid && LOGO_GUID_PREFIX.test(guid)\n\nexport interface LogoFromGuidProps {\n /** The envelope's logo object: `{ guid, fallback_guid?, alt? }`. */\n logo?: Pick<LogoRef, 'alt' | 'fallback_guid' | 'guid'> | null\n /** Rendered square size in px (32 on rows, 40 on the compact card, 33 on the notification row). */\n size: number\n className?: string\n}\n\n/**\n * One component for every V2 logo. The envelope sends a single `{ guid, fallback_guid?, alt? }`\n * object whose prefix says what it is; this maps it onto the mxui component's props and renders\n * nothing — never a guess — for anything else (`PARENT-ENTITY`, an `ACT-`/`BGT-` guid, an empty guid).\n *\n * The fallback chain is mxui's, not ours: asset for `guid` → category tile for `fallback_guid`\n * (`MerchantLogo`'s `categoryGuid`, applied only when it is a `CAT-` guid because a category tile is\n * the only fallback `MerchantLogo` has) → `alt`. Nothing here probes whether an asset exists.\n *\n * Categories are walked up to their top-level parent before reaching mxui: `CategoryIcon` only knows\n * the top-level guids and silently shows the Uncategorized glyph for a sub-category (identity until\n * categories load). That applies to a `CAT-` logo and to a merchant's `fallback_guid` alike.\n */\nconst LogoFromGuid = observer(({ className, logo, size }: LogoFromGuidProps) => {\n const { getTopLevelCategoryGuid } = useCategoryStore()\n\n if (!logo || !isLogoGuid(logo.guid)) return null\n\n // Guid-only on purpose: `logoFromRef` lets a status `icon` win over `guid`, which is right for a\n // row but would silently turn this component into an icon renderer.\n const resolved = logoFromRef({\n alt: logo.alt,\n fallback_guid: logo.fallback_guid,\n guid: logo.guid,\n })\n\n if (!resolved) return null\n\n let content: React.ReactNode = null\n\n if (resolved.merchant_guid) {\n content = (\n <MerchantLogo\n alt={resolved.merchant_name ?? ''}\n categoryGuid={resolved.category_guid ? getTopLevelCategoryGuid(resolved.category_guid) : ''}\n merchantGuid={resolved.merchant_guid}\n size={size}\n />\n )\n } else if (resolved.institution_guid) {\n content = (\n <InstitutionLogo\n alt={resolved.institution_name ?? ''}\n institutionGuid={resolved.institution_guid}\n size={size}\n />\n )\n } else if (resolved.category_guid) {\n content = (\n <CategoryIcon categoryGuid={getTopLevelCategoryGuid(resolved.category_guid)} size={size} />\n )\n }\n\n if (!content) return null\n\n return (\n <Box\n className={className}\n data-testid=\"logo-from-guid\"\n sx={{\n alignItems: 'center',\n display: 'flex',\n flexShrink: 0,\n height: size,\n justifyContent: 'center',\n width: size,\n }}\n >\n {content}\n </Box>\n )\n})\n\nexport default LogoFromGuid\n"],"mappings":";;;;;;AAgBA,IAAM,IAAmB,mBAEZ,IAAA,CAAc,MACzB,CAAC,CAAC,KAAQ,EAAiB,KAAK,CAAI,GAuBhC,IAAe,EAAA,CAAU,EAAE,WAAA,GAAW,MAAA,GAAM,MAAA,EAAA,MAA8B;AAC9E,QAAM,EAAE,yBAAA,EAAA,IAA4B,EAAiB;AAErD,MAAI,CAAC,KAAQ,CAAC,EAAW,EAAK,IAAI,EAAG,QAAO;AAI5C,QAAM,IAAW,EAAY;AAAA,IAC3B,KAAK,EAAK;AAAA,IACV,eAAe,EAAK;AAAA,IACpB,MAAM,EAAK;AAAA,EACb,CAAC;AAED,MAAI,CAAC,EAAU,QAAO;AAEtB,MAAI,IAA2B;AAyB/B,SAvBI,EAAS,gBACX,IACE,gBAAA,EAAC,GAAD;AAAA,IACE,KAAK,EAAS,iBAAiB;AAAA,IAC/B,cAAc,EAAS,gBAAgB,EAAwB,EAAS,aAAa,IAAI;AAAA,IACzF,cAAc,EAAS;AAAA,IACjB,MAAA;AAAA,EACP,CAAA,IAEM,EAAS,mBAClB,IACE,gBAAA,EAAC,GAAD;AAAA,IACE,KAAK,EAAS,oBAAoB;AAAA,IAClC,iBAAiB,EAAS;AAAA,IACpB,MAAA;AAAA,EACP,CAAA,IAEM,EAAS,kBAClB,IACE,gBAAA,EAAC,GAAD;AAAA,IAAc,cAAc,EAAwB,EAAS,aAAa;AAAA,IAAS,MAAA;AAAA,EAAO,CAAA,IAIzF,IAGH,gBAAA,EAAC,GAAD;AAAA,IACa,WAAA;AAAA,IACX,eAAY;AAAA,IACZ,IAAI;AAAA,MACF,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,OAAO;AAAA,IACT;AAAA,IAEC,UAAA;AAAA,EACE,CAAA,IAhBc;AAkBvB,CAAC"}
1
+ {"version":3,"file":"LogoFromGuid.es.js","names":[],"sources":["../../../src/insights-v2/components/LogoFromGuid.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\n\nimport Box from '@mui/material/Box'\n\nimport { Icon, IconList } from '@mxenabled/mx-icons'\nimport { CategoryIcon, InstitutionLogo, MerchantLogo } from '@mxenabled/mxui'\n\nimport { useCategoryStore } from '../../common'\nimport type { LogoRef } from '../../core'\nimport { logoFromRef } from './shared/EntityLogo'\n\n/**\n * The guid prefixes that name a logo entity. A prefix heuristic by design: the V2 envelope carries\n * the entity only in the guid, and the notification row relies on non-insight rows carrying account\n * or budget guids and legacy insight rows carrying the `\"PARENT-ENTITY\"` sentinel. Exported beside\n * the component so a caller's branch (`NotificationCard`) and the dispatch here cannot drift apart.\n */\nconst LOGO_GUID_PREFIX = /^(MCH|CAT|INS)-|^ICO-[a-z0-9_-]+$/\n\nexport const isLogoGuid = (guid?: string | null): guid is string =>\n !!guid && LOGO_GUID_PREFIX.test(guid)\n\nexport interface LogoFromGuidProps {\n /** The envelope's logo object: `{ guid, fallback_guid?, alt?, color? }` (`color` is read for `ICO-` icons). */\n logo?: Pick<LogoRef, 'alt' | 'color' | 'fallback_guid' | 'guid'> | null\n /** Rendered square size in px (32 on rows, 40 on the compact card, 33 on the notification row). */\n size: number\n className?: string\n}\n\n/**\n * One component for every V2 logo. The envelope sends a single `{ guid, fallback_guid?, alt? }`\n * object whose prefix says what it is; this maps it onto the mxui component's props and renders\n * nothing — never a guess — for anything else (`PARENT-ENTITY`, an `ACT-`/`BGT-` guid, an empty guid).\n *\n * The fallback chain is mxui's, not ours: asset for `guid` → category tile for `fallback_guid`\n * (`MerchantLogo`'s `categoryGuid`, applied only when it is a `CAT-` guid because a category tile is\n * the only fallback `MerchantLogo` has) → `alt`. Nothing here probes whether an asset exists.\n *\n * Categories are walked up to their top-level parent before reaching mxui: `CategoryIcon` only knows\n * the top-level guids and silently shows the Uncategorized glyph for a sub-category (identity until\n * categories load). That applies to a `CAT-` logo and to a merchant's `fallback_guid` alike.\n */\nconst LogoFromGuid = observer(({ className, logo, size }: LogoFromGuidProps) => {\n const { getTopLevelCategoryGuid } = useCategoryStore()\n\n if (!logo || !isLogoGuid(logo.guid)) return null\n\n // Guid-only on purpose: `logoFromRef` lets a status `icon` win over `guid`, which is right for a\n // row but would silently turn this component into an icon renderer.\n const resolved = logoFromRef({\n alt: logo.alt,\n color: logo.color,\n fallback_guid: logo.fallback_guid,\n guid: logo.guid,\n })\n\n if (!resolved) return null\n\n let content: React.ReactNode = null\n\n if (resolved.logo_name) {\n // An unmapped name would draw an empty box; say so and draw nothing instead.\n if (!(resolved.logo_name in IconList)) {\n console.warn(`[LogoFromGuid] \"${logo.guid}\" names no mx-icons icon — rendering nothing.`)\n return null\n }\n content = (\n <Icon\n fill={resolved.logo_fill}\n name={resolved.logo_name}\n size={size}\n sx={{ color: resolved.logo_color }}\n />\n )\n } else if (resolved.merchant_guid) {\n content = (\n <MerchantLogo\n alt={resolved.merchant_name ?? ''}\n categoryGuid={resolved.category_guid ? getTopLevelCategoryGuid(resolved.category_guid) : ''}\n merchantGuid={resolved.merchant_guid}\n size={size}\n />\n )\n } else if (resolved.institution_guid) {\n content = (\n <InstitutionLogo\n alt={resolved.institution_name ?? ''}\n institutionGuid={resolved.institution_guid}\n size={size}\n />\n )\n } else if (resolved.category_guid) {\n content = (\n <CategoryIcon categoryGuid={getTopLevelCategoryGuid(resolved.category_guid)} size={size} />\n )\n }\n\n if (!content) return null\n\n return (\n <Box\n className={className}\n data-testid=\"logo-from-guid\"\n sx={{\n alignItems: 'center',\n display: 'flex',\n flexShrink: 0,\n height: size,\n justifyContent: 'center',\n width: size,\n }}\n >\n {content}\n </Box>\n )\n})\n\nexport default LogoFromGuid\n"],"mappings":";;;;;;;AAiBA,IAAM,IAAmB,qCAEZ,IAAA,CAAc,MACzB,CAAC,CAAC,KAAQ,EAAiB,KAAK,CAAI,GAuBhC,IAAe,EAAA,CAAU,EAAE,WAAA,GAAW,MAAA,GAAM,MAAA,EAAA,MAA8B;AAC9E,QAAM,EAAE,yBAAA,EAAA,IAA4B,EAAiB;AAErD,MAAI,CAAC,KAAQ,CAAC,EAAW,EAAK,IAAI,EAAG,QAAO;AAI5C,QAAM,IAAW,EAAY;AAAA,IAC3B,KAAK,EAAK;AAAA,IACV,OAAO,EAAK;AAAA,IACZ,eAAe,EAAK;AAAA,IACpB,MAAM,EAAK;AAAA,EACb,CAAC;AAED,MAAI,CAAC,EAAU,QAAO;AAEtB,MAAI,IAA2B;AAE/B,MAAI,EAAS,WAAW;AAEtB,QAAI,EAAE,EAAS,aAAa;AAC1B,qBAAQ,KAAK,mBAAmB,EAAK,IAAA,+CAAmD,GACjF;AAET,IAAA,IACE,gBAAA,EAAC,GAAD;AAAA,MACE,MAAM,EAAS;AAAA,MACf,MAAM,EAAS;AAAA,MACT,MAAA;AAAA,MACN,IAAI,EAAE,OAAO,EAAS,WAAW;AAAA,IAClC,CAAA;AAAA,EAEL,MAAO,CAAI,EAAS,gBAClB,IACE,gBAAA,EAAC,GAAD;AAAA,IACE,KAAK,EAAS,iBAAiB;AAAA,IAC/B,cAAc,EAAS,gBAAgB,EAAwB,EAAS,aAAa,IAAI;AAAA,IACzF,cAAc,EAAS;AAAA,IACjB,MAAA;AAAA,EACP,CAAA,IAEM,EAAS,mBAClB,IACE,gBAAA,EAAC,GAAD;AAAA,IACE,KAAK,EAAS,oBAAoB;AAAA,IAClC,iBAAiB,EAAS;AAAA,IACpB,MAAA;AAAA,EACP,CAAA,IAEM,EAAS,kBAClB,IACE,gBAAA,EAAC,GAAD;AAAA,IAAc,cAAc,EAAwB,EAAS,aAAa;AAAA,IAAS,MAAA;AAAA,EAAO,CAAA;AAI9F,SAAK,IAGH,gBAAA,EAAC,GAAD;AAAA,IACa,WAAA;AAAA,IACX,eAAY;AAAA,IACZ,IAAI;AAAA,MACF,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,OAAO;AAAA,IACT;AAAA,IAEC,UAAA;AAAA,EACE,CAAA,IAhBc;AAkBvB,CAAC"}
@@ -3,6 +3,7 @@ import { CategoryIcon as a, InstitutionLogo as u, MerchantLogo as c, Text as o }
3
3
  import { Icon as s } from "@mxenabled/mx-icons";
4
4
  import { jsx as r, jsxs as d } from "react/jsx-runtime";
5
5
  var m = (t) => t ? t.logo_name ? /* @__PURE__ */ r(s, {
6
+ fill: t.logo_fill,
6
7
  name: t.logo_name,
7
8
  size: 16,
8
9
  sx: { color: t.logo_color }
@@ -18,7 +19,7 @@ var m = (t) => t ? t.logo_name ? /* @__PURE__ */ r(s, {
18
19
  }) : t.category_guid ? /* @__PURE__ */ r(a, {
19
20
  categoryGuid: t.category_guid,
20
21
  size: 16
21
- }) : null : null, p = ({ subtitle: t }) => {
22
+ }) : null : null, x = ({ subtitle: t }) => {
22
23
  const { logo: e, text: i } = t;
23
24
  return /* @__PURE__ */ d(n, {
24
25
  sx: {
@@ -36,7 +37,7 @@ var m = (t) => t ? t.logo_name ? /* @__PURE__ */ r(s, {
36
37
  });
37
38
  };
38
39
  export {
39
- p as default
40
+ x as default
40
41
  };
41
42
 
42
43
  //# sourceMappingURL=SubHeader.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SubHeader.es.js","names":[],"sources":["../../../src/insights-v2/components/SubHeader.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport { CategoryIcon, InstitutionLogo, MerchantLogo, Text } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\nimport type { Logo, Subtitle } from '../../core'\n\ninterface SubHeaderProps {\n subtitle: Subtitle\n}\n\n// TODO: Ask backend to send the correct guid (institution_guid, merchant_guid, or category_guid)\n// per beat's logo, matching what that beat's subtitle is actually about.\nconst renderLogo = (logo: Logo | undefined) => {\n if (!logo) return null\n\n if (logo.logo_name) {\n return <Icon name={logo.logo_name} size={16} sx={{ color: logo.logo_color }} />\n }\n\n if (logo.merchant_guid) {\n return (\n <MerchantLogo\n alt={logo.merchant_name as string}\n categoryGuid={logo.category_guid as string}\n merchantGuid={logo.merchant_guid}\n size={16}\n />\n )\n }\n\n if (logo.institution_guid) {\n return (\n <InstitutionLogo\n alt={logo.institution_name as string}\n institutionGuid={logo.institution_guid}\n size={16}\n />\n )\n }\n\n if (logo.category_guid) {\n return <CategoryIcon categoryGuid={logo.category_guid} size={16} />\n }\n\n return null\n}\n\nconst SubHeader = ({ subtitle }: SubHeaderProps) => {\n const { logo, text } = subtitle\n\n return (\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', gap: 8 }}>\n {renderLogo(logo)}\n {/* Figma `typography/body2 (upper)`: uppercased with 0.52px tracking. */}\n <Text\n color=\"text.secondary\"\n sx={{ letterSpacing: '0.52px' }}\n uppercase={true}\n variant=\"body2\"\n >\n {text}\n </Text>\n </Stack>\n )\n}\n\nexport default SubHeader\n"],"mappings":";;;;AAYA,IAAM,IAAA,CAAc,MACb,IAED,EAAK,YACA,gBAAA,EAAC,GAAD;AAAA,EAAM,MAAM,EAAK;AAAA,EAAW,MAAM;AAAA,EAAI,IAAI,EAAE,OAAO,EAAK,WAAW;AAAI,CAAA,IAG5E,EAAK,gBAEL,gBAAA,EAAC,GAAD;AAAA,EACE,KAAK,EAAK;AAAA,EACV,cAAc,EAAK;AAAA,EACnB,cAAc,EAAK;AAAA,EACnB,MAAM;AACP,CAAA,IAID,EAAK,mBAEL,gBAAA,EAAC,GAAD;AAAA,EACE,KAAK,EAAK;AAAA,EACV,iBAAiB,EAAK;AAAA,EACtB,MAAM;AACP,CAAA,IAID,EAAK,gBACA,gBAAA,EAAC,GAAD;AAAA,EAAc,cAAc,EAAK;AAAA,EAAe,MAAM;AAAK,CAAA,IAG7D,OA/BW,MAkCd,IAAA,CAAa,EAAE,UAAA,EAAA,MAA+B;AAClD,QAAM,EAAE,MAAA,GAAM,MAAA,EAAA,IAAS;AAEvB,SACE,gBAAA,EAAC,GAAD;AAAA,IAAO,IAAI;AAAA,MAAE,YAAY;AAAA,MAAU,eAAe;AAAA,MAAO,KAAK;AAAA,IAAE;AAAA,IAAhE,UAAA,CACG,EAAW,CAAI,GAEhB,gBAAA,EAAC,GAAD;AAAA,MACE,OAAM;AAAA,MACN,IAAI,EAAE,eAAe,SAAS;AAAA,MAC9B,WAAW;AAAA,MACX,SAAQ;AAAA,MAEP,UAAA;AAAA,IACG,CAAA,CACD;AAAA;AAEX"}
1
+ {"version":3,"file":"SubHeader.es.js","names":[],"sources":["../../../src/insights-v2/components/SubHeader.tsx"],"sourcesContent":["import Stack from '@mui/material/Stack'\n\nimport { CategoryIcon, InstitutionLogo, MerchantLogo, Text } from '@mxenabled/mxui'\nimport { Icon } from '@mxenabled/mx-icons'\nimport type { Logo, Subtitle } from '../../core'\n\ninterface SubHeaderProps {\n subtitle: Subtitle\n}\n\n// TODO: Ask backend to send the correct guid (institution_guid, merchant_guid, or category_guid)\n// per beat's logo, matching what that beat's subtitle is actually about.\nconst renderLogo = (logo: Logo | undefined) => {\n if (!logo) return null\n\n if (logo.logo_name) {\n return (\n <Icon fill={logo.logo_fill} name={logo.logo_name} size={16} sx={{ color: logo.logo_color }} />\n )\n }\n\n if (logo.merchant_guid) {\n return (\n <MerchantLogo\n alt={logo.merchant_name as string}\n categoryGuid={logo.category_guid as string}\n merchantGuid={logo.merchant_guid}\n size={16}\n />\n )\n }\n\n if (logo.institution_guid) {\n return (\n <InstitutionLogo\n alt={logo.institution_name as string}\n institutionGuid={logo.institution_guid}\n size={16}\n />\n )\n }\n\n if (logo.category_guid) {\n return <CategoryIcon categoryGuid={logo.category_guid} size={16} />\n }\n\n return null\n}\n\nconst SubHeader = ({ subtitle }: SubHeaderProps) => {\n const { logo, text } = subtitle\n\n return (\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', gap: 8 }}>\n {renderLogo(logo)}\n {/* Figma `typography/body2 (upper)`: uppercased with 0.52px tracking. */}\n <Text\n color=\"text.secondary\"\n sx={{ letterSpacing: '0.52px' }}\n uppercase={true}\n variant=\"body2\"\n >\n {text}\n </Text>\n </Stack>\n )\n}\n\nexport default SubHeader\n"],"mappings":";;;;AAYA,IAAM,IAAA,CAAc,MACb,IAED,EAAK,YAEL,gBAAA,EAAC,GAAD;AAAA,EAAM,MAAM,EAAK;AAAA,EAAW,MAAM,EAAK;AAAA,EAAW,MAAM;AAAA,EAAI,IAAI,EAAE,OAAO,EAAK,WAAW;AAAI,CAAA,IAI7F,EAAK,gBAEL,gBAAA,EAAC,GAAD;AAAA,EACE,KAAK,EAAK;AAAA,EACV,cAAc,EAAK;AAAA,EACnB,cAAc,EAAK;AAAA,EACnB,MAAM;AACP,CAAA,IAID,EAAK,mBAEL,gBAAA,EAAC,GAAD;AAAA,EACE,KAAK,EAAK;AAAA,EACV,iBAAiB,EAAK;AAAA,EACtB,MAAM;AACP,CAAA,IAID,EAAK,gBACA,gBAAA,EAAC,GAAD;AAAA,EAAc,cAAc,EAAK;AAAA,EAAe,MAAM;AAAK,CAAA,IAG7D,OAjCW,MAoCd,IAAA,CAAa,EAAE,UAAA,EAAA,MAA+B;AAClD,QAAM,EAAE,MAAA,GAAM,MAAA,EAAA,IAAS;AAEvB,SACE,gBAAA,EAAC,GAAD;AAAA,IAAO,IAAI;AAAA,MAAE,YAAY;AAAA,MAAU,eAAe;AAAA,MAAO,KAAK;AAAA,IAAE;AAAA,IAAhE,UAAA,CACG,EAAW,CAAI,GAEhB,gBAAA,EAAC,GAAD;AAAA,MACE,OAAM;AAAA,MACN,IAAI,EAAE,eAAe,SAAS;AAAA,MAC9B,WAAW;AAAA,MACX,SAAQ;AAAA,MAEP,UAAA;AAAA,IACG,CAAA,CACD;AAAA;AAEX"}
@@ -1,10 +1,10 @@
1
- import { ReactComponent as r } from "../../../insights/components/shared/images/EmptyBarChart.es.js";
2
- import { ThemedSVGImage as o } from "./ThemedSVGImage.es.js";
1
+ import { ThemedSVGImage as r } from "./ThemedSVGImage.es.js";
2
+ import { ReactComponent as o } from "../../../insights/components/shared/images/EmptyBarChart.es.js";
3
3
  import { jsx as m } from "react/jsx-runtime";
4
4
  function p() {
5
- return /* @__PURE__ */ m(o, {
5
+ return /* @__PURE__ */ m(r, {
6
6
  divProps: { style: {} },
7
- image: r
7
+ image: o
8
8
  });
9
9
  }
10
10
  export {
@@ -1,29 +1,39 @@
1
- var i = (t, o) => {
2
- if (t) {
3
- if (t.startsWith("INS-")) return {
4
- institution_guid: t,
5
- institution_name: o
1
+ var i = (o, r) => {
2
+ if (o) {
3
+ if (o.startsWith("INS-")) return {
4
+ institution_guid: o,
5
+ institution_name: r
6
6
  };
7
- if (t.startsWith("MCH-")) return {
8
- merchant_guid: t,
9
- merchant_name: o
7
+ if (o.startsWith("MCH-")) return {
8
+ merchant_guid: o,
9
+ merchant_name: r
10
10
  };
11
- if (t.startsWith("CAT-")) return {
12
- category_guid: t,
13
- category_name: o
11
+ if (o.startsWith("CAT-")) return {
12
+ category_guid: o,
13
+ category_name: r
14
14
  };
15
+ if (o.startsWith("ICO-")) {
16
+ const t = o.slice(4);
17
+ return /^[a-z0-9_-]+$/.test(t) ? {
18
+ logo_fill: !0,
19
+ logo_name: t
20
+ } : void 0;
21
+ }
15
22
  }
16
- }, n = (t, o) => {
17
- if (!t) return;
18
- if (t.icon) return {
19
- logo_color: t.color,
20
- logo_name: t.icon
23
+ }, n = (o, r) => {
24
+ if (!o) return;
25
+ if (o.icon) return {
26
+ logo_color: o.color,
27
+ logo_name: o.icon
21
28
  };
22
- const r = i(t.guid, t.alt ?? o);
23
- return r?.merchant_guid && t.fallback_guid?.startsWith("CAT-") ? {
24
- ...r,
25
- category_guid: t.fallback_guid
26
- } : r;
29
+ const t = i(o.guid, o.alt ?? r);
30
+ return t?.logo_name ? o.color ? {
31
+ ...t,
32
+ logo_color: o.color
33
+ } : t : t?.merchant_guid && o.fallback_guid?.startsWith("CAT-") ? {
34
+ ...t,
35
+ category_guid: o.fallback_guid
36
+ } : t;
27
37
  };
28
38
  export {
29
39
  i as logoFromEntityGuid,
@@ -1 +1 @@
1
- {"version":3,"file":"EntityLogo.es.js","names":[],"sources":["../../../../src/insights-v2/components/shared/EntityLogo.tsx"],"sourcesContent":["import type { Logo, LogoRef } from '../../../core'\n\n/**\n * The V2 beat envelope (LargeTransactionV2 onward) sends an entity logo as an opaque guid instead\n * of V1's named `institution_guid` / `merchant_guid` / `category_guid` fields. The entity is\n * carried only by the guid's prefix, so this maps a guid back onto the named `Logo` shape the\n * existing renderers (`SubHeader`, mxui logo components) already understand.\n *\n * An unrecognized prefix returns `undefined` rather than guessing: rendering a merchant logo for\n * an institution guid would silently show the wrong image.\n */\nexport const logoFromEntityGuid = (guid?: string, alt?: string): Logo | undefined => {\n if (!guid) return undefined\n\n if (guid.startsWith('INS-')) {\n return { institution_guid: guid, institution_name: alt }\n }\n\n if (guid.startsWith('MCH-')) {\n return { merchant_guid: guid, merchant_name: alt }\n }\n\n if (guid.startsWith('CAT-')) {\n return { category_guid: guid, category_name: alt }\n }\n\n return undefined\n}\n\n/**\n * Resolves a V2 `LogoRef` (header or row) onto the named `Logo` shape. The one mapping both the\n * header and the rows go through, so the two can never disagree about precedence:\n *\n * - `icon` becomes V1's `logo_name` / `logo_color` and wins over `guid`, as `logo_name` does in\n * `SubHeader`.\n * - Otherwise `guid` resolves by prefix (`logoFromEntityGuid`). For an `MCH-` guid, a `CAT-`\n * `fallback_guid` becomes the merchant's `category_guid`: `MerchantLogo` draws that category as a\n * tile when the merchant image fails to load, and without it the tile is the Uncategorized icon.\n * Only a category fallback is applied, because a category tile is the only fallback\n * `MerchantLogo` has.\n *\n * `fallbackAlt` names the logo when the ref carries no `alt` (rows pass their `primary_text`).\n */\nexport const logoFromRef = (ref?: LogoRef, fallbackAlt?: string): Logo | undefined => {\n if (!ref) return undefined\n\n if (ref.icon) {\n return { logo_color: ref.color, logo_name: ref.icon }\n }\n\n const logo = logoFromEntityGuid(ref.guid, ref.alt ?? fallbackAlt)\n\n if (logo?.merchant_guid && ref.fallback_guid?.startsWith('CAT-')) {\n return { ...logo, category_guid: ref.fallback_guid }\n }\n\n return logo\n}\n"],"mappings":"AAWA,IAAa,IAAA,CAAsB,GAAe,MAAmC;AACnF,MAAK,GAEL;AAAA,QAAI,EAAK,WAAW,MAAM,EACxB,QAAO;AAAA,MAAE,kBAAkB;AAAA,MAAM,kBAAkB;AAAA,IAAI;AAGzD,QAAI,EAAK,WAAW,MAAM,EACxB,QAAO;AAAA,MAAE,eAAe;AAAA,MAAM,eAAe;AAAA,IAAI;AAGnD,QAAI,EAAK,WAAW,MAAM,EACxB,QAAO;AAAA,MAAE,eAAe;AAAA,MAAM,eAAe;AAAA,IAAI;AAAA;AAIrD,GAgBa,IAAA,CAAe,GAAe,MAA2C;AACpF,MAAI,CAAC,EAAK;AAEV,MAAI,EAAI,KACN,QAAO;AAAA,IAAE,YAAY,EAAI;AAAA,IAAO,WAAW,EAAI;AAAA,EAAK;AAGtD,QAAM,IAAO,EAAmB,EAAI,MAAM,EAAI,OAAO,CAAW;AAEhE,SAAI,GAAM,iBAAiB,EAAI,eAAe,WAAW,MAAM,IACtD;AAAA,IAAE,GAAG;AAAA,IAAM,eAAe,EAAI;AAAA,EAAc,IAG9C;AACT"}
1
+ {"version":3,"file":"EntityLogo.es.js","names":[],"sources":["../../../../src/insights-v2/components/shared/EntityLogo.tsx"],"sourcesContent":["import type { Logo, LogoRef } from '../../../core'\n\n/**\n * The V2 beat envelope (LargeTransactionV2 onward) sends an entity logo as an opaque guid instead\n * of V1's named `institution_guid` / `merchant_guid` / `category_guid` fields. The entity is\n * carried only by the guid's prefix, so this maps a guid back onto the named `Logo` shape the\n * existing renderers (`SubHeader`, mxui logo components) already understand.\n *\n * An unrecognized prefix returns `undefined` rather than guessing: rendering a merchant logo for\n * an institution guid would silently show the wrong image.\n */\nexport const logoFromEntityGuid = (guid?: string, alt?: string): Logo | undefined => {\n if (!guid) return undefined\n\n if (guid.startsWith('INS-')) {\n return { institution_guid: guid, institution_name: alt }\n }\n\n if (guid.startsWith('MCH-')) {\n return { merchant_guid: guid, merchant_name: alt }\n }\n\n if (guid.startsWith('CAT-')) {\n return { category_guid: guid, category_name: alt }\n }\n\n // MXUI defines no `ICO-` prefix: `ICO-<name>` is our own contract for a filled mx-icons icon.\n // Unlike the entity prefixes above, the name (not the whole guid) becomes `logo_name`, and it must\n // be a non-empty icon slug, so the prefix is stripped and the remainder validated.\n if (guid.startsWith('ICO-')) {\n const icon = guid.slice(4)\n\n return /^[a-z0-9_-]+$/.test(icon) ? { logo_fill: true, logo_name: icon } : undefined\n }\n return undefined\n}\n\n/**\n * Resolves a V2 `LogoRef` (header or row) onto the named `Logo` shape. The one mapping both the\n * header and the rows go through, so the two can never disagree about precedence:\n *\n * - `icon` becomes V1's `logo_name` / `logo_color` and wins over `guid`, as `logo_name` does in\n * `SubHeader`.\n * - Otherwise `guid` resolves by prefix (`logoFromEntityGuid`). For an `MCH-` guid, a `CAT-`\n * `fallback_guid` becomes the merchant's `category_guid`: `MerchantLogo` draws that category as a\n * tile when the merchant image fails to load, and without it the tile is the Uncategorized icon.\n * Only a category fallback is applied, because a category tile is the only fallback\n * `MerchantLogo` has.\n *\n * `fallbackAlt` names the logo when the ref carries no `alt` (rows pass their `primary_text`).\n */\nexport const logoFromRef = (ref?: LogoRef, fallbackAlt?: string): Logo | undefined => {\n if (!ref) return undefined\n\n if (ref.icon) {\n return { logo_color: ref.color, logo_name: ref.icon }\n }\n\n const logo = logoFromEntityGuid(ref.guid, ref.alt ?? fallbackAlt)\n if (logo?.logo_name) {\n return ref.color ? { ...logo, logo_color: ref.color } : logo\n }\n\n if (logo?.merchant_guid && ref.fallback_guid?.startsWith('CAT-')) {\n return { ...logo, category_guid: ref.fallback_guid }\n }\n\n return logo\n}\n"],"mappings":"AAWA,IAAa,IAAA,CAAsB,GAAe,MAAmC;AACnF,MAAK,GAEL;AAAA,QAAI,EAAK,WAAW,MAAM,EACxB,QAAO;AAAA,MAAE,kBAAkB;AAAA,MAAM,kBAAkB;AAAA,IAAI;AAGzD,QAAI,EAAK,WAAW,MAAM,EACxB,QAAO;AAAA,MAAE,eAAe;AAAA,MAAM,eAAe;AAAA,IAAI;AAGnD,QAAI,EAAK,WAAW,MAAM,EACxB,QAAO;AAAA,MAAE,eAAe;AAAA,MAAM,eAAe;AAAA,IAAI;AAMnD,QAAI,EAAK,WAAW,MAAM,GAAG;AAC3B,YAAM,IAAO,EAAK,MAAM,CAAC;AAEzB,aAAO,gBAAgB,KAAK,CAAI,IAAI;AAAA,QAAE,WAAW;AAAA,QAAM,WAAW;AAAA,MAAK,IAAI;AAAA,IAC7E;AAAA;AAEF,GAgBa,IAAA,CAAe,GAAe,MAA2C;AACpF,MAAI,CAAC,EAAK;AAEV,MAAI,EAAI,KACN,QAAO;AAAA,IAAE,YAAY,EAAI;AAAA,IAAO,WAAW,EAAI;AAAA,EAAK;AAGtD,QAAM,IAAO,EAAmB,EAAI,MAAM,EAAI,OAAO,CAAW;AAChE,SAAI,GAAM,YACD,EAAI,QAAQ;AAAA,IAAE,GAAG;AAAA,IAAM,YAAY,EAAI;AAAA,EAAM,IAAI,IAGtD,GAAM,iBAAiB,EAAI,eAAe,WAAW,MAAM,IACtD;AAAA,IAAE,GAAG;AAAA,IAAM,eAAe,EAAI;AAAA,EAAc,IAG9C;AACT"}