@mx-cartographer/experiences 9.6.0 → 9.6.2

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 (73) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/common/components/ConnectDrawer.es.js +17 -44
  3. package/dist/common/components/ConnectDrawer.es.js.map +1 -1
  4. package/dist/common/components/ConnectWidgetPanel.d.ts +8 -0
  5. package/dist/common/components/ConnectWidgetPanel.es.js +44 -0
  6. package/dist/common/components/ConnectWidgetPanel.es.js.map +1 -0
  7. package/dist/common/components/dialog/Dialog.d.ts +2 -0
  8. package/dist/common/components/dialog/Dialog.es.js +30 -30
  9. package/dist/common/components/dialog/Dialog.es.js.map +1 -1
  10. package/dist/common/components/index.d.ts +1 -0
  11. package/dist/common/index.es.js +67 -65
  12. package/dist/core/types/InsightsInstanceSlotData.d.ts +0 -1
  13. package/dist/core/types/InsightsInstanceSlotData.es.js.map +1 -1
  14. package/dist/core/types/localization/InsightsFeedCopy.d.ts +87 -0
  15. package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js +19 -19
  16. package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js.map +1 -1
  17. package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.d.ts +21 -0
  18. package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.es.js +16 -0
  19. package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.es.js.map +1 -0
  20. package/dist/insights-v2/actionBlocks/ConnectionDetailActionBlock.d.ts +12 -0
  21. package/dist/insights-v2/actionBlocks/ConnectionDetailActionBlock.es.js +25 -0
  22. package/dist/insights-v2/actionBlocks/ConnectionDetailActionBlock.es.js.map +1 -0
  23. package/dist/insights-v2/actionBlocks/FeedbackModalActionBlock.d.ts +17 -0
  24. package/dist/insights-v2/actionBlocks/FeedbackModalActionBlock.es.js +39 -0
  25. package/dist/insights-v2/actionBlocks/FeedbackModalActionBlock.es.js.map +1 -0
  26. package/dist/insights-v2/actionBlocks/SurveyModalActionBlock.d.ts +16 -0
  27. package/dist/insights-v2/actionBlocks/SurveyModalActionBlock.es.js +47 -0
  28. package/dist/insights-v2/actionBlocks/SurveyModalActionBlock.es.js.map +1 -0
  29. package/dist/insights-v2/beatActions.d.ts +2 -2
  30. package/dist/insights-v2/beatActions.es.js.map +1 -1
  31. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.d.ts +2 -4
  32. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.es.js +24 -33
  33. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/AccountSwitchBlock.es.js.map +1 -1
  34. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.d.ts +36 -0
  35. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.es.js +40 -0
  36. package/dist/insights-v2/blocks/ComponentBlocks/AccountSwitchBlock/layout.es.js.map +1 -0
  37. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.d.ts +8 -18
  38. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js +43 -42
  39. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js.map +1 -1
  40. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/index.d.ts +2 -1
  41. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.d.ts +30 -0
  42. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js +29 -0
  43. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js.map +1 -0
  44. package/dist/insights-v2/blocks/resolveVariantConfig.d.ts +10 -0
  45. package/dist/insights-v2/blocks/resolveVariantConfig.es.js +6 -0
  46. package/dist/insights-v2/blocks/resolveVariantConfig.es.js.map +1 -0
  47. package/dist/insights-v2/components/BaseLayout.es.js +14 -14
  48. package/dist/insights-v2/components/ConnectionDetailDrillDown.d.ts +32 -0
  49. package/dist/insights-v2/components/ConnectionDetailDrillDown.es.js +148 -0
  50. package/dist/insights-v2/components/ConnectionDetailDrillDown.es.js.map +1 -0
  51. package/dist/insights-v2/components/FeedbackDialog.d.ts +3 -1
  52. package/dist/insights-v2/components/FeedbackDialog.es.js +80 -72
  53. package/dist/insights-v2/components/FeedbackDialog.es.js.map +1 -1
  54. package/dist/insights-v2/components/FeedbackModal.d.ts +60 -0
  55. package/dist/insights-v2/components/FeedbackModal.es.js +61 -0
  56. package/dist/insights-v2/components/FeedbackModal.es.js.map +1 -0
  57. package/dist/insights-v2/components/SurveyModal.d.ts +65 -0
  58. package/dist/insights-v2/components/SurveyModal.es.js +138 -0
  59. package/dist/insights-v2/components/SurveyModal.es.js.map +1 -0
  60. package/dist/insights-v2/components/celebrationGradients.d.ts +19 -7
  61. package/dist/insights-v2/components/celebrationGradients.es.js +7 -4
  62. package/dist/insights-v2/components/celebrationGradients.es.js.map +1 -1
  63. package/dist/insights-v2/components/shared/StatusSnackbar.d.ts +28 -0
  64. package/dist/insights-v2/components/shared/StatusSnackbar.es.js +19 -0
  65. package/dist/insights-v2/components/shared/StatusSnackbar.es.js.map +1 -0
  66. package/dist/insights-v2/index.d.ts +4 -0
  67. package/dist/insights-v2/index.es.js +78 -69
  68. package/dist/insights-v2/mappings/actionBlocksKey.d.ts +4 -0
  69. package/dist/insights-v2/mappings/actionBlocksKey.es.js +4 -0
  70. package/dist/insights-v2/mappings/actionBlocksKey.es.js.map +1 -1
  71. package/dist/insights-v2/mappings/blocks.es.js +79 -56
  72. package/dist/insights-v2/mappings/blocks.es.js.map +1 -1
  73. package/package.json +1 -1
@@ -3,6 +3,8 @@ export interface FeedbackDialogProps {
3
3
  title: string;
4
4
  options: string[];
5
5
  characterLimit?: number;
6
+ /** Optional paragraph rendered between the title and the options (Figma feedback survey). */
7
+ description?: string;
6
8
  characterLimitLabel?: string;
7
9
  isOpen: boolean;
8
10
  onSubmit: (option: string, detail?: string) => void;
@@ -15,5 +17,5 @@ export interface FeedbackDialogProps {
15
17
  closeAriaLabel: string;
16
18
  }
17
19
  /** Generic feedback survey dialog. Last option shows detail text field. */
18
- declare const FeedbackDialog: ({ isOpen, onClose, onSubmit, title, options, characterLimit, characterLimitLabel, secondaryText, primaryText, closeAriaLabel, onBackClick, onTextInputFocus, }: FeedbackDialogProps) => import("react/jsx-runtime").JSX.Element | null;
20
+ declare const FeedbackDialog: ({ isOpen, onClose, onSubmit, title, options, characterLimit, description, characterLimitLabel, secondaryText, primaryText, closeAriaLabel, onBackClick, onTextInputFocus, }: FeedbackDialogProps) => import("react/jsx-runtime").JSX.Element | null;
19
21
  export default FeedbackDialog;
@@ -1,45 +1,45 @@
1
- import P from "../../common/components/dialog/Dialog.es.js";
2
- import { useEffect as w, useRef as p, useState as b } from "react";
3
- import _ from "@mui/material/Stack";
4
- import { Text as j } from "@mxenabled/mxui";
5
- import { jsx as o, jsxs as g } from "react/jsx-runtime";
6
- import z from "@mui/material/FormControlLabel";
7
- import E from "@mui/material/TextField";
8
- import L from "@mui/material/Radio";
9
- import G from "@mui/material/FormControl";
10
- import H from "@mui/material/RadioGroup";
11
- var K = 250, O = ({ isOpen: l, onClose: h, onSubmit: x, title: s, options: r, characterLimit: v = K, characterLimitLabel: u, secondaryText: C, primaryText: S, closeAriaLabel: y, onBackClick: k, onTextInputFocus: F }) => {
12
- const [t, m] = b(""), [a, d] = b(""), i = p(!1), n = p(!1);
13
- if (w(() => {
14
- l && (i.current = !1, n.current = !1);
15
- }, [l]), r.length === 0) return null;
16
- const c = t === r[r.length - 1], R = !t || c && !a.trim(), f = () => {
17
- m(""), d("");
18
- }, D = (e) => {
1
+ import _ from "../../common/components/dialog/Dialog.es.js";
2
+ import { useEffect as j, useRef as b, useState as h } from "react";
3
+ import z from "@mui/material/Stack";
4
+ import { Text as g } from "@mxenabled/mxui";
5
+ import { jsx as o, jsxs as x } from "react/jsx-runtime";
6
+ import E from "@mui/material/FormControlLabel";
7
+ import L from "@mui/material/TextField";
8
+ import G from "@mui/material/Radio";
9
+ import H from "@mui/material/FormControl";
10
+ import K from "@mui/material/RadioGroup";
11
+ var W = 250, ee = ({ isOpen: a, onClose: v, onSubmit: C, title: s, options: r, characterLimit: y = W, description: u, characterLimitLabel: m, secondaryText: S, primaryText: k, closeAriaLabel: F, onBackClick: R, onTextInputFocus: D }) => {
12
+ const [t, d] = h(""), [l, f] = h(""), i = b(!1), n = b(!1);
13
+ if (j(() => {
14
+ a && (i.current = !1, n.current = !1);
15
+ }, [a]), r.length === 0) return null;
16
+ const c = t === r[r.length - 1], M = !t || c && !l.trim(), p = () => {
17
+ d(""), f("");
18
+ }, T = (e) => {
19
19
  if (e === "backdropClick" || e === "escapeKeyDown") return e;
20
20
  if (!n.current) return "closeButton";
21
- }, M = (e, B) => {
22
- const I = D(B);
23
- f(), h(I);
24
- }, T = () => {
25
- n.current = !0, k?.();
26
- }, A = () => {
27
- i.current || (i.current = !0, F?.());
21
+ }, A = (e, P) => {
22
+ const w = T(P);
23
+ p(), v(w);
24
+ }, B = () => {
25
+ n.current = !0, R?.();
26
+ }, I = () => {
27
+ i.current || (i.current = !0, D?.());
28
28
  };
29
- return /* @__PURE__ */ g(P, {
29
+ return /* @__PURE__ */ x(_, {
30
30
  copy: {
31
31
  title: s,
32
- close_aria: y
32
+ close_aria: F
33
33
  },
34
- disablePrimaryButton: R,
35
- isOpen: l,
36
- onClose: M,
34
+ disablePrimaryButton: M,
35
+ isOpen: a,
36
+ onClose: A,
37
37
  onPrimaryAction: () => {
38
- n.current = !0, x(t, c ? a.trim() : void 0), f();
38
+ n.current = !0, C(t, c ? l.trim() : void 0), p();
39
39
  },
40
- onSecondaryAction: T,
41
- primaryText: S,
42
- secondaryText: C,
40
+ onSecondaryAction: B,
41
+ primaryText: k,
42
+ secondaryText: S,
43
43
  sx: {
44
44
  "& .MuiDialogContent-root": { py: 0 },
45
45
  "& .MuiDialog-paperScrollPaper": { bgcolor: "background.paper" },
@@ -58,50 +58,58 @@ var K = 250, O = ({ isOpen: l, onClose: h, onSubmit: x, title: s, options: r, ch
58
58
  }
59
59
  }
60
60
  },
61
- children: [/* @__PURE__ */ o(G, { children: /* @__PURE__ */ o(H, {
62
- "aria-label": s,
63
- name: "feedback-radio-group",
64
- onChange: (e) => m(e.target.value),
65
- value: t,
66
- children: r.map((e) => /* @__PURE__ */ o(z, {
67
- control: /* @__PURE__ */ o(L, { sx: { "& .MuiSvgIcon-root": {
68
- fontSize: 22,
69
- color: "action.active"
70
- } } }),
71
- label: e,
72
- sx: { "& .MuiFormControlLabel-label": {
73
- color: "text.primary",
74
- fontSize: 15
75
- } },
76
- value: e
77
- }, e))
78
- }) }), c && /* @__PURE__ */ g(_, {
79
- sx: {
80
- gap: 3,
81
- mt: 4
82
- },
83
- children: [/* @__PURE__ */ o(E, {
84
- autoFocus: !0,
85
- maxRows: 4,
86
- minRows: 4,
87
- multiline: !0,
61
+ children: [
62
+ u && /* @__PURE__ */ o(g, {
63
+ sx: { mb: 8 },
64
+ variant: "body1",
65
+ children: u
66
+ }),
67
+ /* @__PURE__ */ o(H, { children: /* @__PURE__ */ o(K, {
68
+ "aria-label": s,
69
+ name: "feedback-radio-group",
88
70
  onChange: (e) => d(e.target.value),
89
- onFocus: A,
90
- slotProps: { htmlInput: { maxLength: v } },
91
- value: a
92
- }), u && /* @__PURE__ */ o(j, {
71
+ value: t,
72
+ children: r.map((e) => /* @__PURE__ */ o(E, {
73
+ control: /* @__PURE__ */ o(G, { sx: { "& .MuiSvgIcon-root": {
74
+ fontSize: 22,
75
+ color: "action.active"
76
+ } } }),
77
+ label: e,
78
+ sx: { "& .MuiFormControlLabel-label": {
79
+ color: "text.primary",
80
+ fontSize: 15
81
+ } },
82
+ value: e
83
+ }, e))
84
+ }) }),
85
+ c && /* @__PURE__ */ x(z, {
93
86
  sx: {
94
- color: "text.secondary",
95
- fontWeight: 400
87
+ gap: 3,
88
+ mt: 4
96
89
  },
97
- variant: "subtitle2",
98
- children: u
99
- })]
100
- })]
90
+ children: [/* @__PURE__ */ o(L, {
91
+ autoFocus: !0,
92
+ maxRows: 4,
93
+ minRows: 4,
94
+ multiline: !0,
95
+ onChange: (e) => f(e.target.value),
96
+ onFocus: I,
97
+ slotProps: { htmlInput: { maxLength: y } },
98
+ value: l
99
+ }), m && /* @__PURE__ */ o(g, {
100
+ sx: {
101
+ color: "text.secondary",
102
+ fontWeight: 400
103
+ },
104
+ variant: "subtitle2",
105
+ children: m
106
+ })]
107
+ })
108
+ ]
101
109
  });
102
110
  };
103
111
  export {
104
- O as default
112
+ ee as default
105
113
  };
106
114
 
107
115
  //# sourceMappingURL=FeedbackDialog.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackDialog.es.js","names":[],"sources":["../../../src/insights-v2/components/FeedbackDialog.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport FormControl from '@mui/material/FormControl'\nimport FormControlLabel from '@mui/material/FormControlLabel'\nimport Radio from '@mui/material/Radio'\nimport RadioGroup from '@mui/material/RadioGroup'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\n\nimport { Text } from '@mxenabled/mxui'\n\nimport { Dialog } from '../../common'\n\nconst CHARACTER_LIMIT = 250\n\nexport type FeedbackDialogCloseReason = 'closeButton' | 'backdropClick' | 'escapeKeyDown'\n\nexport interface FeedbackDialogProps {\n title: string\n options: string[]\n characterLimit?: number\n characterLimitLabel?: string\n isOpen: boolean\n onSubmit: (option: string, detail?: string) => void\n /** Called on every close; `reason` is set for user-initiated closes (X/backdrop/escape), undefined on submit/back. */\n onClose: (reason?: FeedbackDialogCloseReason) => void\n onBackClick?: () => void\n onTextInputFocus?: () => void\n secondaryText: string\n primaryText: string\n closeAriaLabel: string\n}\n\n/** Generic feedback survey dialog. Last option shows detail text field. */\nconst FeedbackDialog = ({\n isOpen,\n onClose,\n onSubmit,\n title,\n options,\n characterLimit = CHARACTER_LIMIT,\n characterLimitLabel,\n secondaryText,\n primaryText,\n closeAriaLabel,\n onBackClick,\n onTextInputFocus,\n}: FeedbackDialogProps) => {\n const [selected, setSelected] = useState('')\n const [detail, setDetail] = useState('')\n const hasTrackedFocus = useRef(false)\n const skipCloseAnalytics = useRef(false)\n\n useEffect(() => {\n if (isOpen) {\n hasTrackedFocus.current = false\n skipCloseAnalytics.current = false\n }\n }, [isOpen])\n\n if (options.length === 0) return null\n\n const isOther = selected === options[options.length - 1]\n const isSubmitDisabled = !selected || (isOther && !detail.trim())\n\n const reset = () => {\n setSelected('')\n setDetail('')\n }\n\n const resolveCloseReason = (reason?: string): FeedbackDialogCloseReason | undefined => {\n if (reason === 'backdropClick' || reason === 'escapeKeyDown') return reason\n if (!skipCloseAnalytics.current) return 'closeButton'\n return undefined\n }\n\n const handleClose = (_event?: unknown, reason?: string) => {\n const closeReason = resolveCloseReason(reason)\n reset()\n onClose(closeReason)\n }\n\n const handleBack = () => {\n skipCloseAnalytics.current = true\n onBackClick?.()\n }\n\n const handleTextFocus = () => {\n if (!hasTrackedFocus.current) {\n hasTrackedFocus.current = true\n onTextInputFocus?.()\n }\n }\n\n const handleSubmit = () => {\n skipCloseAnalytics.current = true\n onSubmit(selected, isOther ? detail.trim() : undefined)\n reset()\n }\n\n return (\n <Dialog\n copy={{ title, close_aria: closeAriaLabel }}\n disablePrimaryButton={isSubmitDisabled}\n isOpen={isOpen}\n onClose={handleClose}\n onPrimaryAction={handleSubmit}\n onSecondaryAction={handleBack}\n primaryText={primaryText}\n secondaryText={secondaryText}\n sx={{\n '& .MuiDialogContent-root': { py: 0 },\n '& .MuiDialog-paperScrollPaper': { bgcolor: 'background.paper' },\n '& .MuiDialog-paper': {\n outline: 'none',\n '&:focus-visible': {\n outline: '2px solid',\n outlineColor: 'primary.main',\n },\n },\n '& .MuiButton-outlined': {\n border: 'none',\n '&:hover': { bgcolor: 'transparent', border: 'none' },\n },\n }}\n >\n <FormControl>\n <RadioGroup\n aria-label={title}\n name=\"feedback-radio-group\"\n onChange={(e) => setSelected(e.target.value)}\n value={selected}\n >\n {options.map((option) => (\n <FormControlLabel\n control={\n <Radio\n sx={{\n '& .MuiSvgIcon-root': {\n fontSize: 22,\n color: 'action.active',\n },\n }}\n />\n }\n key={option}\n label={option}\n sx={{\n '& .MuiFormControlLabel-label': {\n color: 'text.primary',\n fontSize: 15,\n },\n }}\n value={option}\n />\n ))}\n </RadioGroup>\n </FormControl>\n\n {isOther && (\n <Stack sx={{ gap: 3, mt: 4 }}>\n <TextField\n autoFocus\n maxRows={4}\n minRows={4}\n multiline={true}\n onChange={(e) => setDetail(e.target.value)}\n onFocus={handleTextFocus}\n slotProps={{ htmlInput: { maxLength: characterLimit } }}\n value={detail}\n />\n {characterLimitLabel && (\n <Text sx={{ color: 'text.secondary', fontWeight: 400 }} variant=\"subtitle2\">\n {characterLimitLabel}\n </Text>\n )}\n </Stack>\n )}\n </Dialog>\n )\n}\n\nexport default FeedbackDialog\n"],"mappings":"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"}
1
+ {"version":3,"file":"FeedbackDialog.es.js","names":[],"sources":["../../../src/insights-v2/components/FeedbackDialog.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport FormControl from '@mui/material/FormControl'\nimport FormControlLabel from '@mui/material/FormControlLabel'\nimport Radio from '@mui/material/Radio'\nimport RadioGroup from '@mui/material/RadioGroup'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\n\nimport { Text } from '@mxenabled/mxui'\n\nimport { Dialog } from '../../common'\n\nconst CHARACTER_LIMIT = 250\n\nexport type FeedbackDialogCloseReason = 'closeButton' | 'backdropClick' | 'escapeKeyDown'\n\nexport interface FeedbackDialogProps {\n title: string\n options: string[]\n characterLimit?: number\n /** Optional paragraph rendered between the title and the options (Figma feedback survey). */\n description?: string\n characterLimitLabel?: string\n isOpen: boolean\n onSubmit: (option: string, detail?: string) => void\n /** Called on every close; `reason` is set for user-initiated closes (X/backdrop/escape), undefined on submit/back. */\n onClose: (reason?: FeedbackDialogCloseReason) => void\n onBackClick?: () => void\n onTextInputFocus?: () => void\n secondaryText: string\n primaryText: string\n closeAriaLabel: string\n}\n\n/** Generic feedback survey dialog. Last option shows detail text field. */\nconst FeedbackDialog = ({\n isOpen,\n onClose,\n onSubmit,\n title,\n options,\n characterLimit = CHARACTER_LIMIT,\n description,\n characterLimitLabel,\n secondaryText,\n primaryText,\n closeAriaLabel,\n onBackClick,\n onTextInputFocus,\n}: FeedbackDialogProps) => {\n const [selected, setSelected] = useState('')\n const [detail, setDetail] = useState('')\n const hasTrackedFocus = useRef(false)\n const skipCloseAnalytics = useRef(false)\n\n useEffect(() => {\n if (isOpen) {\n hasTrackedFocus.current = false\n skipCloseAnalytics.current = false\n }\n }, [isOpen])\n\n if (options.length === 0) return null\n\n const isOther = selected === options[options.length - 1]\n const isSubmitDisabled = !selected || (isOther && !detail.trim())\n\n const reset = () => {\n setSelected('')\n setDetail('')\n }\n\n const resolveCloseReason = (reason?: string): FeedbackDialogCloseReason | undefined => {\n if (reason === 'backdropClick' || reason === 'escapeKeyDown') return reason\n if (!skipCloseAnalytics.current) return 'closeButton'\n return undefined\n }\n\n const handleClose = (_event?: unknown, reason?: string) => {\n const closeReason = resolveCloseReason(reason)\n reset()\n onClose(closeReason)\n }\n\n const handleBack = () => {\n skipCloseAnalytics.current = true\n onBackClick?.()\n }\n\n const handleTextFocus = () => {\n if (!hasTrackedFocus.current) {\n hasTrackedFocus.current = true\n onTextInputFocus?.()\n }\n }\n\n const handleSubmit = () => {\n skipCloseAnalytics.current = true\n onSubmit(selected, isOther ? detail.trim() : undefined)\n reset()\n }\n\n return (\n <Dialog\n copy={{ title, close_aria: closeAriaLabel }}\n disablePrimaryButton={isSubmitDisabled}\n isOpen={isOpen}\n onClose={handleClose}\n onPrimaryAction={handleSubmit}\n onSecondaryAction={handleBack}\n primaryText={primaryText}\n secondaryText={secondaryText}\n sx={{\n '& .MuiDialogContent-root': { py: 0 },\n '& .MuiDialog-paperScrollPaper': { bgcolor: 'background.paper' },\n '& .MuiDialog-paper': {\n outline: 'none',\n '&:focus-visible': {\n outline: '2px solid',\n outlineColor: 'primary.main',\n },\n },\n '& .MuiButton-outlined': {\n border: 'none',\n '&:hover': { bgcolor: 'transparent', border: 'none' },\n },\n }}\n >\n {description && (\n <Text sx={{ mb: 8 }} variant=\"body1\">\n {description}\n </Text>\n )}\n <FormControl>\n <RadioGroup\n aria-label={title}\n name=\"feedback-radio-group\"\n onChange={(e) => setSelected(e.target.value)}\n value={selected}\n >\n {options.map((option) => (\n <FormControlLabel\n control={\n <Radio\n sx={{\n '& .MuiSvgIcon-root': {\n fontSize: 22,\n color: 'action.active',\n },\n }}\n />\n }\n key={option}\n label={option}\n sx={{\n '& .MuiFormControlLabel-label': {\n color: 'text.primary',\n fontSize: 15,\n },\n }}\n value={option}\n />\n ))}\n </RadioGroup>\n </FormControl>\n\n {isOther && (\n <Stack sx={{ gap: 3, mt: 4 }}>\n <TextField\n autoFocus\n maxRows={4}\n minRows={4}\n multiline={true}\n onChange={(e) => setDetail(e.target.value)}\n onFocus={handleTextFocus}\n slotProps={{ htmlInput: { maxLength: characterLimit } }}\n value={detail}\n />\n {characterLimitLabel && (\n <Text sx={{ color: 'text.secondary', fontWeight: 400 }} variant=\"subtitle2\">\n {characterLimitLabel}\n </Text>\n )}\n </Stack>\n )}\n </Dialog>\n )\n}\n\nexport default FeedbackDialog\n"],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { FeedbackDialogCloseReason } from './FeedbackDialog';
2
+ /** Localized strings the modal renders — resolved by the caller (see FeedbackModalActionBlock). */
3
+ export interface FeedbackModalContent {
4
+ /** Dialog title, e.g. "Can you tell us why?". */
5
+ title: string;
6
+ /** Optional paragraph under the title, e.g. "We'd love to hear why…". */
7
+ description?: string;
8
+ /** Survey reasons; the last option reveals the free-text detail field. */
9
+ options: string[];
10
+ /** Primary (Submit) button label. */
11
+ submitText: string;
12
+ /** Secondary (No thanks) button label. */
13
+ cancelText: string;
14
+ /** ARIA label for the dialog close button. */
15
+ closeAriaLabel: string;
16
+ /** Helper text under the detail field, e.g. "250 character limit". */
17
+ characterLimitLabel?: string;
18
+ /** Success snackbar message, e.g. "Your feedback has been submitted.". */
19
+ successMessage: string;
20
+ /** Error snackbar message, e.g. "Your feedback could not be submitted.". */
21
+ errorMessage: string;
22
+ /** Error snackbar action label, e.g. "Try Again". */
23
+ tryAgainText: string;
24
+ /** ARIA label for the snackbar close button. */
25
+ toastCloseAriaLabel: string;
26
+ }
27
+ interface FeedbackModalProps {
28
+ isOpen: boolean;
29
+ copy: FeedbackModalContent;
30
+ /**
31
+ * Fired when the survey is submitted. May return a promise: a rejection
32
+ * switches to the error snackbar (Figma `1941:167637`), whose Try Again
33
+ * action re-submits the same selection. Sync/resolved submissions show the
34
+ * success snackbar.
35
+ */
36
+ onSubmit: (option: string, detail?: string) => void | Promise<void>;
37
+ /**
38
+ * Fired when the whole flow ends: the dialog is dismissed without submitting
39
+ * (reason set), or either snackbar is closed / auto-hides (no reason).
40
+ */
41
+ onClose: (reason?: FeedbackDialogCloseReason) => void;
42
+ /**
43
+ * When provided, the secondary button acts as "Back" — it fires this instead
44
+ * of ending the flow via `onClose` (e.g. SurveyModal returning to its survey
45
+ * step). When absent, the secondary ("No thanks") ends the flow as before.
46
+ */
47
+ onBack?: () => void;
48
+ }
49
+ /**
50
+ * The CTA feedback drilldown (Figma `1941:192803`): a "Can you tell us why?"
51
+ * survey dialog followed by a success snackbar (Figma `1941:167636`) — or an
52
+ * error snackbar with a Try Again action (Figma `1941:167637`) when the
53
+ * submission fails.
54
+ *
55
+ * Purely presentational — copy arrives resolved via `FeedbackModalContent`;
56
+ * the `feedback_modal_block` action block wires it to the copy store, the beat
57
+ * actions, and the action-drawer session.
58
+ */
59
+ declare const FeedbackModal: ({ copy, isOpen, onBack, onClose, onSubmit }: FeedbackModalProps) => import("react/jsx-runtime").JSX.Element;
60
+ export default FeedbackModal;
@@ -0,0 +1,61 @@
1
+ import g from "./shared/StatusSnackbar.es.js";
2
+ import k from "./FeedbackDialog.es.js";
3
+ import { useEffect as L, useRef as u, useState as T } from "react";
4
+ import { Fragment as A, jsx as b, jsxs as S } from "react/jsx-runtime";
5
+ var D = ({ copy: e, isOpen: a, onBack: l, onClose: m, onSubmit: d }) => {
6
+ const [t, i] = T("survey"), n = u(!1), s = u(null);
7
+ L(() => {
8
+ a && (i("survey"), n.current = !1, s.current = null);
9
+ }, [a]);
10
+ const f = async (r, c) => {
11
+ n.current = !0, s.current = {
12
+ option: r,
13
+ detail: c
14
+ };
15
+ try {
16
+ await d(r, c), i("success");
17
+ } catch {
18
+ i("error");
19
+ }
20
+ }, h = () => {
21
+ s.current && f(s.current.option, s.current.detail);
22
+ }, o = u(!1), v = l ? () => {
23
+ o.current = !0, l();
24
+ } : void 0, x = (r) => {
25
+ if (!n.current) {
26
+ if (o.current) {
27
+ o.current = !1;
28
+ return;
29
+ }
30
+ m(r);
31
+ }
32
+ };
33
+ return /* @__PURE__ */ S(A, { children: [/* @__PURE__ */ b(k, {
34
+ characterLimitLabel: e.characterLimitLabel,
35
+ closeAriaLabel: e.closeAriaLabel,
36
+ description: e.description,
37
+ isOpen: a && t === "survey" && !n.current,
38
+ onBackClick: v,
39
+ onClose: x,
40
+ onSubmit: (r, c) => {
41
+ f(r, c);
42
+ },
43
+ options: e.options,
44
+ primaryText: e.submitText,
45
+ secondaryText: e.cancelText,
46
+ title: e.title
47
+ }), /* @__PURE__ */ b(g, {
48
+ actionText: t === "error" ? e.tryAgainText : void 0,
49
+ closeAriaLabel: e.toastCloseAriaLabel,
50
+ message: t === "error" ? e.errorMessage : e.successMessage,
51
+ onActionClick: h,
52
+ onClose: () => m(),
53
+ open: a && t !== "survey",
54
+ severity: t === "error" ? "error" : "success"
55
+ })] });
56
+ };
57
+ export {
58
+ D as default
59
+ };
60
+
61
+ //# sourceMappingURL=FeedbackModal.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeedbackModal.es.js","names":[],"sources":["../../../src/insights-v2/components/FeedbackModal.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport StatusSnackbar from './shared/StatusSnackbar'\n\nimport FeedbackDialog, { type FeedbackDialogCloseReason } from './FeedbackDialog'\n\n/** Localized strings the modal renders — resolved by the caller (see FeedbackModalActionBlock). */\nexport interface FeedbackModalContent {\n /** Dialog title, e.g. \"Can you tell us why?\". */\n title: string\n /** Optional paragraph under the title, e.g. \"We'd love to hear why…\". */\n description?: string\n /** Survey reasons; the last option reveals the free-text detail field. */\n options: string[]\n /** Primary (Submit) button label. */\n submitText: string\n /** Secondary (No thanks) button label. */\n cancelText: string\n /** ARIA label for the dialog close button. */\n closeAriaLabel: string\n /** Helper text under the detail field, e.g. \"250 character limit\". */\n characterLimitLabel?: string\n /** Success snackbar message, e.g. \"Your feedback has been submitted.\". */\n successMessage: string\n /** Error snackbar message, e.g. \"Your feedback could not be submitted.\". */\n errorMessage: string\n /** Error snackbar action label, e.g. \"Try Again\". */\n tryAgainText: string\n /** ARIA label for the snackbar close button. */\n toastCloseAriaLabel: string\n}\n\ninterface FeedbackModalProps {\n isOpen: boolean\n copy: FeedbackModalContent\n /**\n * Fired when the survey is submitted. May return a promise: a rejection\n * switches to the error snackbar (Figma `1941:167637`), whose Try Again\n * action re-submits the same selection. Sync/resolved submissions show the\n * success snackbar.\n */\n onSubmit: (option: string, detail?: string) => void | Promise<void>\n /**\n * Fired when the whole flow ends: the dialog is dismissed without submitting\n * (reason set), or either snackbar is closed / auto-hides (no reason).\n */\n onClose: (reason?: FeedbackDialogCloseReason) => void\n /**\n * When provided, the secondary button acts as \"Back\" — it fires this instead\n * of ending the flow via `onClose` (e.g. SurveyModal returning to its survey\n * step). When absent, the secondary (\"No thanks\") ends the flow as before.\n */\n onBack?: () => void\n}\n\ntype Phase = 'survey' | 'success' | 'error'\n\n/**\n * The CTA feedback drilldown (Figma `1941:192803`): a \"Can you tell us why?\"\n * survey dialog followed by a success snackbar (Figma `1941:167636`) — or an\n * error snackbar with a Try Again action (Figma `1941:167637`) when the\n * submission fails.\n *\n * Purely presentational — copy arrives resolved via `FeedbackModalContent`;\n * the `feedback_modal_block` action block wires it to the copy store, the beat\n * actions, and the action-drawer session.\n */\nconst FeedbackModal = ({ copy, isOpen, onBack, onClose, onSubmit }: FeedbackModalProps) => {\n const [phase, setPhase] = useState<Phase>('survey')\n // Ref, not state: the shared Dialog fires `onClose()` synchronously right\n // after `onPrimaryAction()`, before the state update lands. Without the ref\n // that close would end the whole flow and the snackbar could never show.\n const hasSubmitted = useRef(false)\n // Kept for the error snackbar's Try Again, which re-submits the selection.\n const lastSubmission = useRef<{ option: string; detail?: string } | null>(null)\n\n // A new flow session starts from the survey, not a stale snackbar.\n useEffect(() => {\n if (isOpen) {\n setPhase('survey')\n hasSubmitted.current = false\n lastSubmission.current = null\n }\n }, [isOpen])\n\n const submit = async (option: string, detail?: string) => {\n hasSubmitted.current = true\n lastSubmission.current = { option, detail }\n try {\n await onSubmit(option, detail)\n setPhase('success')\n } catch {\n setPhase('error')\n }\n }\n\n const retry = () => {\n if (lastSubmission.current) {\n void submit(lastSubmission.current.option, lastSubmission.current.detail)\n }\n }\n\n // Ref for the same reason as hasSubmitted: the back-click's trailing Dialog\n // close fires synchronously, before any state lands.\n const backTaken = useRef(false)\n\n const handleBack = onBack\n ? () => {\n backTaken.current = true\n onBack()\n }\n : undefined\n\n // Only user-initiated closes (X / backdrop / escape / No thanks) end the\n // flow — the post-submit close hands over to the snackbar, and a back-click's\n // trailing close belongs to the caller's back navigation.\n const handleDialogClose = (reason?: FeedbackDialogCloseReason) => {\n if (hasSubmitted.current) return\n if (backTaken.current) {\n backTaken.current = false\n return\n }\n onClose(reason)\n }\n\n return (\n <>\n <FeedbackDialog\n characterLimitLabel={copy.characterLimitLabel}\n closeAriaLabel={copy.closeAriaLabel}\n description={copy.description}\n isOpen={isOpen && phase === 'survey' && !hasSubmitted.current}\n onBackClick={handleBack}\n onClose={handleDialogClose}\n onSubmit={(option, detail) => void submit(option, detail)}\n options={copy.options}\n primaryText={copy.submitText}\n secondaryText={copy.cancelText}\n title={copy.title}\n />\n <StatusSnackbar\n actionText={phase === 'error' ? copy.tryAgainText : undefined}\n closeAriaLabel={copy.toastCloseAriaLabel}\n message={phase === 'error' ? copy.errorMessage : copy.successMessage}\n onActionClick={retry}\n onClose={() => onClose()}\n open={isOpen && phase !== 'survey'}\n severity={phase === 'error' ? 'error' : 'success'}\n />\n </>\n )\n}\n\nexport default FeedbackModal\n"],"mappings":";;;;AAmEA,IAAM,IAAA,CAAiB,EAAE,MAAA,GAAM,QAAA,GAAQ,QAAA,GAAQ,SAAA,GAAS,UAAA,EAAA,MAAmC;AACzF,QAAM,CAAC,GAAO,CAAA,IAAY,EAAgB,QAAQ,GAI5C,IAAe,EAAO,EAAK,GAE3B,IAAiB,EAAmD,IAAI;AAG9E,EAAA,EAAA,MAAgB;AACd,IAAI,MACF,EAAS,QAAQ,GACjB,EAAa,UAAU,IACvB,EAAe,UAAU;AAAA,EAE7B,GAAG,CAAC,CAAM,CAAC;AAEX,QAAM,IAAS,OAAO,GAAgB,MAAoB;AACxD,IAAA,EAAa,UAAU,IACvB,EAAe,UAAU;AAAA,MAAE,QAAA;AAAA,MAAQ,QAAA;AAAA,IAAO;AAC1C,QAAI;AACF,YAAM,EAAS,GAAQ,CAAM,GAC7B,EAAS,SAAS;AAAA,IACpB,QAAQ;AACN,MAAA,EAAS,OAAO;AAAA,IAClB;AAAA,EACF,GAEM,IAAA,MAAc;AAClB,IAAI,EAAe,WACjB,EAAY,EAAe,QAAQ,QAAQ,EAAe,QAAQ,MAAM;AAAA,EAE5E,GAIM,IAAY,EAAO,EAAK,GAExB,IAAa,IAAA,MACT;AACJ,IAAA,EAAU,UAAU,IACpB,EAAO;AAAA,EACT,IACA,QAKE,IAAA,CAAqB,MAAuC;AAChE,QAAI,CAAA,EAAa,SACjB;AAAA,UAAI,EAAU,SAAS;AACrB,QAAA,EAAU,UAAU;AACpB;AAAA,MACF;AACA,MAAA,EAAQ,CAAM;AAAA;AAAA,EAChB;AAEA,SACE,gBAAA,EAAA,GAAA,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,IACE,qBAAqB,EAAK;AAAA,IAC1B,gBAAgB,EAAK;AAAA,IACrB,aAAa,EAAK;AAAA,IAClB,QAAQ,KAAU,MAAU,YAAY,CAAC,EAAa;AAAA,IACtD,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAA,CAAW,GAAQ,MAAA;AAAW,MAAK,EAAO,GAAQ,CAAM;AAAA;AAAA,IACxD,SAAS,EAAK;AAAA,IACd,aAAa,EAAK;AAAA,IAClB,eAAe,EAAK;AAAA,IACpB,OAAO,EAAK;AAAA,EACb,CAAA,GACD,gBAAA,EAAC,GAAD;AAAA,IACE,YAAY,MAAU,UAAU,EAAK,eAAe;AAAA,IACpD,gBAAgB,EAAK;AAAA,IACrB,SAAS,MAAU,UAAU,EAAK,eAAe,EAAK;AAAA,IACtD,eAAe;AAAA,IACf,SAAA,MAAe,EAAQ;AAAA,IACvB,MAAM,KAAU,MAAU;AAAA,IAC1B,UAAU,MAAU,UAAU,UAAU;AAAA,EACzC,CAAA,CACD,EAAA,CAAA;AAEN"}
@@ -0,0 +1,65 @@
1
+ /** One survey row (Figma `<UtilityRow>`). Rows act immediately on click. */
2
+ export interface SurveyModalOption {
3
+ /** Overline above the row label, e.g. "Yes," / "No,". */
4
+ overline: string;
5
+ /** Row label, e.g. "This looks correct." */
6
+ label: string;
7
+ /**
8
+ * Row behavior + glyph: `positive` (green check_circle) submits the label
9
+ * right away; `negative` (red cancel) opens the reasons dialog.
10
+ */
11
+ tone: 'positive' | 'negative';
12
+ }
13
+ /** Localized strings the modal renders — resolved by the caller (see SurveyModalActionBlock). */
14
+ export interface SurveyModalContent {
15
+ /** Survey dialog title, e.g. "Does this look right?". */
16
+ title: string;
17
+ options: SurveyModalOption[];
18
+ /** Reasons dialog primary (Submit) button label. */
19
+ submitText: string;
20
+ /** ARIA label for the dialog close buttons. */
21
+ closeAriaLabel: string;
22
+ /** Reasons dialog title (negative path), e.g. "This looks wrong". */
23
+ reasonsTitle: string;
24
+ /** Reasons dialog options; the last one reveals the detail text field. */
25
+ reasonOptions: string[];
26
+ /** Reasons dialog secondary (Back) label. */
27
+ backText: string;
28
+ /** Helper text under the reasons detail field. */
29
+ characterLimitLabel?: string;
30
+ /** Success snackbar message (Figma 1941:212643). */
31
+ successMessage: string;
32
+ /** Error snackbar message (Figma 1941:212644). */
33
+ errorMessage: string;
34
+ /** Error snackbar retry label, e.g. "Try Again". */
35
+ tryAgainText: string;
36
+ /** ARIA label for the snackbar close button. */
37
+ toastCloseAriaLabel: string;
38
+ }
39
+ interface SurveyModalProps {
40
+ isOpen: boolean;
41
+ copy: SurveyModalContent;
42
+ /**
43
+ * Fired when an answer is submitted — the positive row's label, or a
44
+ * reasons-dialog selection (with optional detail). May return a promise: a
45
+ * rejection switches to the error snackbar, whose Try Again re-submits.
46
+ */
47
+ onSubmit: (option: string, detail?: string) => void | Promise<void>;
48
+ /** Fired when the whole flow ends (dialogs dismissed or a snackbar closed). */
49
+ onClose: () => void;
50
+ }
51
+ /**
52
+ * The confirmation survey drilldown (Figma `1941:212640`, Upcoming
53
+ * Subscriptions "Does this look right?"):
54
+ *
55
+ * - the POSITIVE row submits immediately and shows the success snackbar
56
+ * (`1941:212643`) — or the error snackbar with Try Again (`1941:212644`);
57
+ * - the NEGATIVE row opens the reasons dialog (`1941:212642`, a FeedbackDialog:
58
+ * radios + Back/Submit), whose submission feeds the same snackbars.
59
+ *
60
+ * Purely presentational — copy arrives resolved via `SurveyModalContent`; the
61
+ * `survey_modal_block` action block wires it to the copy store, the beat
62
+ * actions, and the action-drawer session.
63
+ */
64
+ declare const SurveyModal: ({ copy, isOpen, onClose, onSubmit }: SurveyModalProps) => import("react/jsx-runtime").JSX.Element;
65
+ export default SurveyModal;
@@ -0,0 +1,138 @@
1
+ import T from "../../common/components/dialog/Dialog.es.js";
2
+ import C from "./shared/StatusSnackbar.es.js";
3
+ import L from "./FeedbackModal.es.js";
4
+ import { useEffect as k, useRef as d, useState as M } from "react";
5
+ import m from "@mui/material/Stack";
6
+ import { Text as h } from "@mxenabled/mxui";
7
+ import { Icon as b } from "@mxenabled/mx-icons";
8
+ import { Fragment as p, jsx as t, jsxs as l } from "react/jsx-runtime";
9
+ import y from "@mui/material/Divider";
10
+ import S from "@mui/material/ButtonBase";
11
+ var w = {
12
+ positive: {
13
+ color: "success.main",
14
+ name: "check_circle"
15
+ },
16
+ negative: {
17
+ color: "error.main",
18
+ name: "cancel"
19
+ }
20
+ }, W = ({ copy: e, isOpen: a, onClose: c, onSubmit: f }) => {
21
+ const [s, o] = M("survey"), u = d(!1), n = d(null);
22
+ k(() => {
23
+ a && (o("survey"), u.current = !1, n.current = null);
24
+ }, [a]);
25
+ const x = async (r, i) => {
26
+ u.current = !0, n.current = {
27
+ option: r,
28
+ detail: i
29
+ };
30
+ try {
31
+ await f(r, i), o("success");
32
+ } catch {
33
+ o("error");
34
+ }
35
+ }, g = () => {
36
+ n.current && x(n.current.option, n.current.detail);
37
+ }, v = (r) => {
38
+ r.tone === "positive" ? x(r.label) : o("reasons");
39
+ }, A = () => {
40
+ u.current || c();
41
+ };
42
+ return /* @__PURE__ */ l(p, { children: [
43
+ /* @__PURE__ */ t(T, {
44
+ copy: {
45
+ title: e.title,
46
+ close_aria: e.closeAriaLabel
47
+ },
48
+ isOpen: a && s === "survey",
49
+ onClose: A,
50
+ showActions: !1,
51
+ sx: {
52
+ "& .MuiDialogContent-root": { py: 0 },
53
+ "& .MuiButton-outlined": {
54
+ border: "none",
55
+ "&:hover": {
56
+ bgcolor: "transparent",
57
+ border: "none"
58
+ }
59
+ }
60
+ },
61
+ children: /* @__PURE__ */ t(m, { children: e.options.map((r) => {
62
+ const i = w[r.tone];
63
+ return /* @__PURE__ */ l(m, { children: [/* @__PURE__ */ t(y, {}), /* @__PURE__ */ l(S, {
64
+ onClick: () => v(r),
65
+ sx: {
66
+ alignItems: "center",
67
+ display: "flex",
68
+ gap: 12,
69
+ justifyContent: "flex-start",
70
+ px: 4,
71
+ py: 14,
72
+ textAlign: "left",
73
+ width: "100%"
74
+ },
75
+ children: [
76
+ /* @__PURE__ */ t(b, {
77
+ name: i.name,
78
+ size: 24,
79
+ sx: { color: i.color }
80
+ }),
81
+ /* @__PURE__ */ l(m, {
82
+ sx: {
83
+ flex: 1,
84
+ minWidth: 0
85
+ },
86
+ children: [/* @__PURE__ */ t(h, {
87
+ color: "text.primary",
88
+ variant: "caption",
89
+ children: r.overline
90
+ }), /* @__PURE__ */ t(h, {
91
+ sx: { fontWeight: 600 },
92
+ variant: "body1",
93
+ children: r.label
94
+ })]
95
+ }),
96
+ /* @__PURE__ */ t(b, {
97
+ name: "chevron_right",
98
+ size: 20,
99
+ sx: { color: "text.primary" }
100
+ })
101
+ ]
102
+ })] }, r.label);
103
+ }) })
104
+ }),
105
+ /* @__PURE__ */ t(L, {
106
+ copy: {
107
+ title: e.reasonsTitle,
108
+ options: e.reasonOptions,
109
+ submitText: e.submitText,
110
+ cancelText: e.backText,
111
+ closeAriaLabel: e.closeAriaLabel,
112
+ characterLimitLabel: e.characterLimitLabel,
113
+ successMessage: e.successMessage,
114
+ errorMessage: e.errorMessage,
115
+ tryAgainText: e.tryAgainText,
116
+ toastCloseAriaLabel: e.toastCloseAriaLabel
117
+ },
118
+ isOpen: a && s === "reasons",
119
+ onBack: () => o("survey"),
120
+ onClose: () => c(),
121
+ onSubmit: f
122
+ }),
123
+ /* @__PURE__ */ t(C, {
124
+ actionText: s === "error" ? e.tryAgainText : void 0,
125
+ closeAriaLabel: e.toastCloseAriaLabel,
126
+ message: s === "error" ? e.errorMessage : e.successMessage,
127
+ onActionClick: g,
128
+ onClose: () => c(),
129
+ open: a && (s === "success" || s === "error"),
130
+ severity: s === "error" ? "error" : "success"
131
+ })
132
+ ] });
133
+ };
134
+ export {
135
+ W as default
136
+ };
137
+
138
+ //# sourceMappingURL=SurveyModal.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SurveyModal.es.js","names":[],"sources":["../../../src/insights-v2/components/SurveyModal.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport ButtonBase from '@mui/material/ButtonBase'\nimport Divider from '@mui/material/Divider'\nimport Stack from '@mui/material/Stack'\n\nimport { Icon } from '@mxenabled/mx-icons'\nimport { Text } from '@mxenabled/mxui'\n\nimport { Dialog } from '../../common'\n\nimport FeedbackModal from './FeedbackModal'\nimport StatusSnackbar from './shared/StatusSnackbar'\n\n/** One survey row (Figma `<UtilityRow>`). Rows act immediately on click. */\nexport interface SurveyModalOption {\n /** Overline above the row label, e.g. \"Yes,\" / \"No,\". */\n overline: string\n /** Row label, e.g. \"This looks correct.\" */\n label: string\n /**\n * Row behavior + glyph: `positive` (green check_circle) submits the label\n * right away; `negative` (red cancel) opens the reasons dialog.\n */\n tone: 'positive' | 'negative'\n}\n\n/** Localized strings the modal renders — resolved by the caller (see SurveyModalActionBlock). */\nexport interface SurveyModalContent {\n /** Survey dialog title, e.g. \"Does this look right?\". */\n title: string\n options: SurveyModalOption[]\n /** Reasons dialog primary (Submit) button label. */\n submitText: string\n /** ARIA label for the dialog close buttons. */\n closeAriaLabel: string\n /** Reasons dialog title (negative path), e.g. \"This looks wrong\". */\n reasonsTitle: string\n /** Reasons dialog options; the last one reveals the detail text field. */\n reasonOptions: string[]\n /** Reasons dialog secondary (Back) label. */\n backText: string\n /** Helper text under the reasons detail field. */\n characterLimitLabel?: string\n /** Success snackbar message (Figma 1941:212643). */\n successMessage: string\n /** Error snackbar message (Figma 1941:212644). */\n errorMessage: string\n /** Error snackbar retry label, e.g. \"Try Again\". */\n tryAgainText: string\n /** ARIA label for the snackbar close button. */\n toastCloseAriaLabel: string\n}\n\ninterface SurveyModalProps {\n isOpen: boolean\n copy: SurveyModalContent\n /**\n * Fired when an answer is submitted — the positive row's label, or a\n * reasons-dialog selection (with optional detail). May return a promise: a\n * rejection switches to the error snackbar, whose Try Again re-submits.\n */\n onSubmit: (option: string, detail?: string) => void | Promise<void>\n /** Fired when the whole flow ends (dialogs dismissed or a snackbar closed). */\n onClose: () => void\n}\n\ntype Phase = 'survey' | 'reasons' | 'success' | 'error'\n\nconst TONE_ICON: Record<SurveyModalOption['tone'], { color: string; name: string }> = {\n positive: { color: 'success.main', name: 'check_circle' },\n negative: { color: 'error.main', name: 'cancel' },\n}\n\n/**\n * The confirmation survey drilldown (Figma `1941:212640`, Upcoming\n * Subscriptions \"Does this look right?\"):\n *\n * - the POSITIVE row submits immediately and shows the success snackbar\n * (`1941:212643`) — or the error snackbar with Try Again (`1941:212644`);\n * - the NEGATIVE row opens the reasons dialog (`1941:212642`, a FeedbackDialog:\n * radios + Back/Submit), whose submission feeds the same snackbars.\n *\n * Purely presentational — copy arrives resolved via `SurveyModalContent`; the\n * `survey_modal_block` action block wires it to the copy store, the beat\n * actions, and the action-drawer session.\n */\nconst SurveyModal = ({ copy, isOpen, onClose, onSubmit }: SurveyModalProps) => {\n const [phase, setPhase] = useState<Phase>('survey')\n // Guards the survey Dialog's trailing `onClose` after a row acted — the row\n // click hands over to the snackbar / reasons dialog, not a flow end.\n const actionTaken = useRef(false)\n // Kept for the error snackbar's Try Again, which re-submits the selection.\n const lastSubmission = useRef<{ option: string; detail?: string } | null>(null)\n\n // A fresh session starts from the survey.\n useEffect(() => {\n if (isOpen) {\n setPhase('survey')\n actionTaken.current = false\n lastSubmission.current = null\n }\n }, [isOpen])\n\n const submit = async (option: string, detail?: string) => {\n actionTaken.current = true\n lastSubmission.current = { option, detail }\n try {\n await onSubmit(option, detail)\n setPhase('success')\n } catch {\n setPhase('error')\n }\n }\n\n const retry = () => {\n if (lastSubmission.current) {\n void submit(lastSubmission.current.option, lastSubmission.current.detail)\n }\n }\n\n const handleRowClick = (option: SurveyModalOption) => {\n if (option.tone === 'positive') {\n void submit(option.label)\n } else {\n setPhase('reasons')\n }\n }\n\n const handleSurveyClose = () => {\n if (actionTaken.current) return\n onClose()\n }\n\n return (\n <>\n <Dialog\n copy={{ title: copy.title, close_aria: copy.closeAriaLabel }}\n isOpen={isOpen && phase === 'survey'}\n onClose={handleSurveyClose}\n // Figma 1941:212640: the DialogActions row is hidden — the utility\n // rows are the only actions; the flow closes via X or a row.\n showActions={false}\n sx={{\n '& .MuiDialogContent-root': { py: 0 },\n '& .MuiButton-outlined': {\n border: 'none',\n '&:hover': { bgcolor: 'transparent', border: 'none' },\n },\n }}\n >\n <Stack>\n {copy.options.map((option) => {\n const icon = TONE_ICON[option.tone]\n\n return (\n <Stack key={option.label}>\n <Divider />\n <ButtonBase\n onClick={() => handleRowClick(option)}\n sx={{\n alignItems: 'center',\n display: 'flex',\n gap: 12,\n justifyContent: 'flex-start',\n px: 4,\n py: 14,\n textAlign: 'left',\n width: '100%',\n }}\n >\n <Icon name={icon.name} size={24} sx={{ color: icon.color }} />\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Text color=\"text.primary\" variant=\"caption\">\n {option.overline}\n </Text>\n <Text sx={{ fontWeight: 600 }} variant=\"body1\">\n {option.label}\n </Text>\n </Stack>\n <Icon name=\"chevron_right\" size={20} sx={{ color: 'text.primary' }} />\n </ButtonBase>\n </Stack>\n )\n })}\n </Stack>\n </Dialog>\n\n {/* Negative path: the whole FeedbackModal — reasons dialog + its own\n success/error snackbars with Try Again. Back returns to the survey;\n its onClose fires only when the sub-flow truly ends. */}\n <FeedbackModal\n copy={{\n title: copy.reasonsTitle,\n options: copy.reasonOptions,\n submitText: copy.submitText,\n cancelText: copy.backText,\n closeAriaLabel: copy.closeAriaLabel,\n characterLimitLabel: copy.characterLimitLabel,\n successMessage: copy.successMessage,\n errorMessage: copy.errorMessage,\n tryAgainText: copy.tryAgainText,\n toastCloseAriaLabel: copy.toastCloseAriaLabel,\n }}\n isOpen={isOpen && phase === 'reasons'}\n onBack={() => setPhase('survey')}\n onClose={() => onClose()}\n onSubmit={onSubmit}\n />\n\n <StatusSnackbar\n actionText={phase === 'error' ? copy.tryAgainText : undefined}\n closeAriaLabel={copy.toastCloseAriaLabel}\n message={phase === 'error' ? copy.errorMessage : copy.successMessage}\n onActionClick={retry}\n onClose={() => onClose()}\n open={isOpen && (phase === 'success' || phase === 'error')}\n severity={phase === 'error' ? 'error' : 'success'}\n />\n </>\n )\n}\n\nexport default SurveyModal\n"],"mappings":"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"}
@@ -1,12 +1,13 @@
1
+ import { Theme } from '@mui/material/styles';
1
2
  /**
2
- * Decorative celebration washes used behind confetti-backed "complete"/milestone states.
3
- * Shared so both the block layer (`AccountBlock`) and the presentational
4
- * components/stories reference one source instead of re-declaring the string.
3
+ * Decorative slot washes shared by the block layouts and the presentational components, so
4
+ * one source holds each gradient. The 20%–25% washes layer over `background.paper` via
5
+ * `backgroundImage`; `DISCOVERED_ACCOUNTS_GRADIENT` is opaque and stands alone.
5
6
  *
6
- * - WARM_LIME_ACCENT_GRADIENT: 20%-opacity warm→lime wash; layer over `background.paper`
7
- * for a tinted background. Used for merchant categorization and deposit celebration states.
8
- * - CELEBRATION_GRADIENT: 20%-opacity warm→pink wash; layer over `background.paper`.
9
- * - DISCOVERED_ACCOUNTS_GRADIENT: Fully opaque (100% opacity); use as the sole background.
7
+ * - WARM_LIME_ACCENT_GRADIENT: merchant categorization and deposit celebration states.
8
+ * - CELEBRATION_GRADIENT / ACCOUNT_CONNECTED_GRADIENT: balance milestones, account connected.
9
+ * - WARNING_WASH_GRADIENT: a flagged charge (Unexpected Subscription Payment).
10
+ * - getPrimaryWashGradient(theme): pending connect / detected subscription, from the palette.
10
11
  */
11
12
  /**
12
13
  * Warm → lime accent wash at 20% opacity. Used as a tinted background behind
@@ -23,3 +24,14 @@ export declare const DISCOVERED_ACCOUNTS_GRADIENT = "linear-gradient(200.73deg,
23
24
  * `background` shorthand — a 20% gradient over transparency renders wrong.
24
25
  */
25
26
  export declare const ACCOUNT_CONNECTED_GRADIENT = "linear-gradient(257deg, rgba(255, 224, 153, 0.2) 1.86%, rgba(255, 129, 230, 0.2) 101.54%)";
27
+ /**
28
+ * Orange → red-orange wash at 25% opacity behind a flagged charge (Unexpected Subscription
29
+ * Payment). Figma "Warning Gradient 1": a bespoke two-stop blend with no palette token, so it
30
+ * stays a literal like the other washes here rather than being derived from `palette.warning`.
31
+ */
32
+ export declare const WARNING_WASH_GRADIENT = "linear-gradient(201deg, rgba(255, 170, 0, 0.25) 1.86%, rgba(255, 68, 0, 0.25) 101.54%)";
33
+ /**
34
+ * Blue slot wash behind a pending connect / detected-subscription row: `primary.light` →
35
+ * `primary.main` at 75% over paper, built from the live palette so it follows the theme.
36
+ */
37
+ export declare const getPrimaryWashGradient: ({ palette }: Theme) => string;