@mx-cartographer/experiences 9.4.19-alpha.al3 → 9.4.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -7
- package/dist/common/components/dialog/Dialog.d.ts +1 -1
- package/dist/common/components/dialog/Dialog.es.js.map +1 -1
- package/dist/core/types/AppData.d.ts +0 -2
- package/dist/core/types/localization/InsightsFeedCopy.d.ts +6 -0
- package/dist/insights-v2/beatActions.d.ts +5 -19
- package/dist/insights-v2/beatActions.es.js.map +1 -1
- package/dist/insights-v2/components/BaseLayout.d.ts +8 -3
- package/dist/insights-v2/components/BaseLayout.es.js +105 -80
- package/dist/insights-v2/components/BaseLayout.es.js.map +1 -1
- package/dist/insights-v2/components/DismissInsightDialog.d.ts +1 -8
- package/dist/insights-v2/components/DismissInsightDialog.es.js.map +1 -1
- package/dist/insights-v2/components/FeedbackBar.d.ts +1 -12
- package/dist/insights-v2/components/FeedbackBar.es.js.map +1 -1
- package/dist/insights-v2/components/FeedbackDialog.d.ts +7 -25
- package/dist/insights-v2/components/FeedbackDialog.es.js +54 -42
- package/dist/insights-v2/components/FeedbackDialog.es.js.map +1 -1
- package/dist/insights-v2/components/HiddenConfirmationCard.d.ts +1 -11
- package/dist/insights-v2/components/HiddenConfirmationCard.es.js.map +1 -1
- package/dist/insights-v2/components/InsightOptionsMenu.d.ts +1 -6
- package/dist/insights-v2/components/InsightOptionsMenu.es.js.map +1 -1
- package/dist/insights-v2/components/ObsolesceBanner.d.ts +26 -0
- package/dist/insights-v2/components/ObsolesceBanner.es.js +119 -0
- package/dist/insights-v2/components/ObsolesceBanner.es.js.map +1 -0
- package/dist/insights-v2/hooks/useBeatFeedbackFlow.d.ts +8 -15
- package/dist/insights-v2/hooks/useBeatFeedbackFlow.es.js +35 -25
- package/dist/insights-v2/hooks/useBeatFeedbackFlow.es.js.map +1 -1
- package/dist/insights-v2/index.d.ts +2 -1
- package/dist/insights-v2/index.es.js +32 -30
- package/package.json +1 -9
- package/dist/rum/RumRedaction.d.ts +0 -3
- package/dist/rum/RumRedaction.es.js +0 -8
- package/dist/rum/RumRedaction.es.js.map +0 -1
- package/dist/rum/beforeSend.d.ts +0 -40
- package/dist/rum/beforeSend.es.js +0 -16
- package/dist/rum/beforeSend.es.js.map +0 -1
- package/dist/rum/errorBuffer.d.ts +0 -9
- package/dist/rum/errorBuffer.es.js +0 -27
- package/dist/rum/errorBuffer.es.js.map +0 -1
- package/dist/rum/index.d.ts +0 -3
- package/dist/rum/index.es.js +0 -11
|
@@ -1,37 +1,19 @@
|
|
|
1
|
+
export type FeedbackDialogCloseReason = 'closeButton' | 'backdropClick' | 'escapeKeyDown';
|
|
1
2
|
export interface FeedbackDialogProps {
|
|
2
|
-
/** Dialog title. */
|
|
3
3
|
title: string;
|
|
4
|
-
/** Available feedback reasons. The last option reveals the detail field. */
|
|
5
4
|
options: string[];
|
|
6
|
-
/** Max characters for the detail text field (enforced on the input). */
|
|
7
5
|
characterLimit?: number;
|
|
8
|
-
/** Localized helper text shown under the detail field (e.g. "250 Character Limit"). */
|
|
9
6
|
characterLimitLabel?: string;
|
|
10
|
-
/** Whether the dialog is open. */
|
|
11
7
|
isOpen: boolean;
|
|
12
|
-
/** Invoked on primary action (Submit); parent owns analytics + dispatch. */
|
|
13
8
|
onSubmit: (option: string, detail?: string) => void;
|
|
14
|
-
/**
|
|
15
|
-
onClose: () => void;
|
|
16
|
-
|
|
9
|
+
/** Called on every close; `reason` is set for user-initiated closes (X/backdrop/escape), undefined on submit/back. */
|
|
10
|
+
onClose: (reason?: FeedbackDialogCloseReason) => void;
|
|
11
|
+
onBackClick?: () => void;
|
|
12
|
+
onTextInputFocus?: () => void;
|
|
17
13
|
secondaryText: string;
|
|
18
|
-
/** Button text for primary (Submit) action. */
|
|
19
14
|
primaryText: string;
|
|
20
|
-
/** ARIA label for close button. */
|
|
21
15
|
closeAriaLabel: string;
|
|
22
16
|
}
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
* Presentational — the parent owns all copy, option definitions, and callback logic.
|
|
26
|
-
*
|
|
27
|
-
* This component can be used by any feature that needs to ask users for feedback.
|
|
28
|
-
* Examples: rating an insight, dismissing a notification, rating a recommendation.
|
|
29
|
-
*
|
|
30
|
-
* The dialog is a single-select radio list of reasons; selecting the last option
|
|
31
|
-
* ("Other") reveals a multiline text field. Submit is disabled until a valid
|
|
32
|
-
* answer exists.
|
|
33
|
-
*
|
|
34
|
-
* Figma: 287:20484 (options only) / 287:20566 (with text field).
|
|
35
|
-
*/
|
|
36
|
-
declare const FeedbackDialog: ({ isOpen, onClose, onSubmit, title, options, characterLimit, characterLimitLabel, secondaryText, primaryText, closeAriaLabel, }: FeedbackDialogProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
17
|
+
/** 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;
|
|
37
19
|
export default FeedbackDialog;
|
|
@@ -1,34 +1,45 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { useState as
|
|
3
|
-
import
|
|
4
|
-
import { Text as
|
|
5
|
-
import { jsx as
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
var
|
|
12
|
-
const [t, m] =
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
|
|
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: c, 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 s = t === r[r.length - 1], R = !t || s && !a.trim(), f = () => {
|
|
17
|
+
m(""), d("");
|
|
18
|
+
}, D = (e) => {
|
|
19
|
+
if (e === "backdropClick" || e === "escapeKeyDown") return e;
|
|
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?.());
|
|
16
28
|
};
|
|
17
|
-
return /* @__PURE__ */
|
|
29
|
+
return /* @__PURE__ */ g(P, {
|
|
18
30
|
copy: {
|
|
19
|
-
title:
|
|
20
|
-
close_aria:
|
|
21
|
-
},
|
|
22
|
-
disablePrimaryButton: C,
|
|
23
|
-
isOpen: p,
|
|
24
|
-
onClose: () => {
|
|
25
|
-
u(), g();
|
|
31
|
+
title: c,
|
|
32
|
+
close_aria: y
|
|
26
33
|
},
|
|
34
|
+
disablePrimaryButton: R,
|
|
35
|
+
isOpen: l,
|
|
36
|
+
onClose: M,
|
|
27
37
|
onPrimaryAction: () => {
|
|
28
|
-
|
|
38
|
+
n.current = !0, x(t, s ? a.trim() : void 0), f();
|
|
29
39
|
},
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
onSecondaryAction: T,
|
|
41
|
+
primaryText: S,
|
|
42
|
+
secondaryText: C,
|
|
32
43
|
sx: {
|
|
33
44
|
"& .MuiDialogContent-root": { py: 0 },
|
|
34
45
|
"& .MuiDialog-paperScrollPaper": { bgcolor: "background.paper" },
|
|
@@ -47,46 +58,47 @@ var P = 250, W = ({ isOpen: p, onClose: g, onSubmit: b, title: i, options: r, ch
|
|
|
47
58
|
}
|
|
48
59
|
}
|
|
49
60
|
},
|
|
50
|
-
children: [/* @__PURE__ */
|
|
51
|
-
"aria-label":
|
|
61
|
+
children: [/* @__PURE__ */ o(G, { children: /* @__PURE__ */ o(H, {
|
|
62
|
+
"aria-label": c,
|
|
52
63
|
name: "feedback-radio-group",
|
|
53
|
-
onChange: (
|
|
64
|
+
onChange: (e) => m(e.target.value),
|
|
54
65
|
value: t,
|
|
55
|
-
children: r.map((
|
|
56
|
-
control: /* @__PURE__ */
|
|
57
|
-
label:
|
|
66
|
+
children: r.map((e) => /* @__PURE__ */ o(z, {
|
|
67
|
+
control: /* @__PURE__ */ o(L, { sx: { "& .MuiSvgIcon-root": { fontSize: 22 } } }),
|
|
68
|
+
label: e,
|
|
58
69
|
sx: { "& .MuiFormControlLabel-label": {
|
|
59
70
|
color: "text.primary",
|
|
60
71
|
fontSize: 15
|
|
61
72
|
} },
|
|
62
|
-
value:
|
|
63
|
-
},
|
|
64
|
-
}) }),
|
|
73
|
+
value: e
|
|
74
|
+
}, e))
|
|
75
|
+
}) }), s && /* @__PURE__ */ g(_, {
|
|
65
76
|
sx: {
|
|
66
77
|
gap: 3,
|
|
67
78
|
mt: 4
|
|
68
79
|
},
|
|
69
|
-
children: [/* @__PURE__ */
|
|
80
|
+
children: [/* @__PURE__ */ o(E, {
|
|
70
81
|
autoFocus: !0,
|
|
71
82
|
maxRows: 4,
|
|
72
83
|
minRows: 4,
|
|
73
84
|
multiline: !0,
|
|
74
|
-
onChange: (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
onChange: (e) => d(e.target.value),
|
|
86
|
+
onFocus: A,
|
|
87
|
+
slotProps: { htmlInput: { maxLength: v } },
|
|
88
|
+
value: a
|
|
89
|
+
}), u && /* @__PURE__ */ o(j, {
|
|
78
90
|
sx: {
|
|
79
91
|
color: "text.secondary",
|
|
80
92
|
fontWeight: 400
|
|
81
93
|
},
|
|
82
94
|
variant: "subtitle2",
|
|
83
|
-
children:
|
|
95
|
+
children: u
|
|
84
96
|
})]
|
|
85
97
|
})]
|
|
86
98
|
});
|
|
87
99
|
};
|
|
88
100
|
export {
|
|
89
|
-
|
|
101
|
+
O as default
|
|
90
102
|
};
|
|
91
103
|
|
|
92
104
|
//# sourceMappingURL=FeedbackDialog.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FeedbackDialog.es.js","names":[],"sources":["../../../src/insights-v2/components/FeedbackDialog.tsx"],"sourcesContent":["import { 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
|
|
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': { outline: '2px solid', outlineColor: 'primary.main' },\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={<Radio sx={{ '& .MuiSvgIcon-root': { fontSize: 22 } }} />}\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":";;;;;;;;;;AAaA,IAAM,IAAkB,KAqBlB,IAAA,CAAkB,EACtB,QAAA,GACA,SAAA,GACA,UAAA,GACA,OAAA,GACA,SAAA,GACA,gBAAA,IAAiB,GACjB,qBAAA,GACA,eAAA,GACA,aAAA,GACA,gBAAA,GACA,aAAA,GACA,kBAAA,EAAA,MACyB;AACzB,QAAM,CAAC,GAAU,CAAA,IAAe,EAAS,EAAE,GACrC,CAAC,GAAQ,CAAA,IAAa,EAAS,EAAE,GACjC,IAAkB,EAAO,EAAK,GAC9B,IAAqB,EAAO,EAAK;AASvC,MAPA,EAAA,MAAgB;AACd,IAAI,MACF,EAAgB,UAAU,IAC1B,EAAmB,UAAU;AAAA,EAEjC,GAAG,CAAC,CAAM,CAAC,GAEP,EAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,IAAU,MAAa,EAAQ,EAAQ,SAAS,CAAA,GAChD,IAAmB,CAAC,KAAa,KAAW,CAAC,EAAO,KAAK,GAEzD,IAAA,MAAc;AAClB,IAAA,EAAY,EAAE,GACd,EAAU,EAAE;AAAA,EACd,GAEM,IAAA,CAAsB,MAA2D;AACrF,QAAI,MAAW,mBAAmB,MAAW,gBAAiB,QAAO;AACrE,QAAI,CAAC,EAAmB,QAAS,QAAO;AAAA,EAE1C,GAEM,IAAA,CAAe,GAAkB,MAAoB;AACzD,UAAM,IAAc,EAAmB,CAAM;AAC7C,IAAA,EAAM,GACN,EAAQ,CAAW;AAAA,EACrB,GAEM,IAAA,MAAmB;AACvB,IAAA,EAAmB,UAAU,IAC7B,IAAc;AAAA,EAChB,GAEM,IAAA,MAAwB;AAC5B,IAAK,EAAgB,YACnB,EAAgB,UAAU,IAC1B,IAAmB;AAAA,EAEvB;AAQA,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,MAAM;AAAA,MAAE,OAAA;AAAA,MAAO,YAAY;AAAA,IAAe;AAAA,IAC1C,sBAAsB;AAAA,IACd,QAAA;AAAA,IACR,SAAS;AAAA,IACT,iBAZE,MAAqB;AACzB,MAAA,EAAmB,UAAU,IAC7B,EAAS,GAAU,IAAU,EAAO,KAAK,IAAI,MAAS,GACtD,EAAM;AAAA,IACR;AAAA,IASI,mBAAmB;AAAA,IACN,aAAA;AAAA,IACE,eAAA;AAAA,IACf,IAAI;AAAA,MACF,4BAA4B,EAAE,IAAI,EAAE;AAAA,MACpC,iCAAiC,EAAE,SAAS,mBAAmB;AAAA,MAC/D,sBAAsB;AAAA,QACpB,SAAS;AAAA,QACT,mBAAmB;AAAA,UAAE,SAAS;AAAA,UAAa,cAAc;AAAA,QAAe;AAAA,MAC1E;AAAA,MACA,yBAAyB;AAAA,QACvB,QAAQ;AAAA,QACR,WAAW;AAAA,UAAE,SAAS;AAAA,UAAe,QAAQ;AAAA,QAAO;AAAA,MACtD;AAAA,IACF;AAAA,IApBF,UAAA,CAsBE,gBAAA,EAAC,GAAD,EAAA,UACE,gBAAA,EAAC,GAAD;AAAA,MACE,cAAY;AAAA,MACZ,MAAK;AAAA,MACL,UAAA,CAAW,MAAM,EAAY,EAAE,OAAO,KAAK;AAAA,MAC3C,OAAO;AAAA,MAEN,UAAA,EAAQ,IAAA,CAAK,MACZ,gBAAA,EAAC,GAAD;AAAA,QACE,SAAS,gBAAA,EAAC,GAAD,EAAO,IAAI,EAAE,sBAAsB,EAAE,UAAU,GAAG,EAAE,EAAI,CAAA;AAAA,QAEjE,OAAO;AAAA,QACP,IAAI,EACF,gCAAgC;AAAA,UAC9B,OAAO;AAAA,UACP,UAAU;AAAA,QACZ,EACF;AAAA,QACA,OAAO;AAAA,MACR,GATM,CASN,CACF;AAAA,IACS,CAAA,EACD,CAAA,GAEZ,KACC,gBAAA,EAAC,GAAD;AAAA,MAAO,IAAI;AAAA,QAAE,KAAK;AAAA,QAAG,IAAI;AAAA,MAAE;AAAA,MAA3B,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,QACE,WAAA;AAAA,QACA,SAAS;AAAA,QACT,SAAS;AAAA,QACT,WAAW;AAAA,QACX,UAAA,CAAW,MAAM,EAAU,EAAE,OAAO,KAAK;AAAA,QACzC,SAAS;AAAA,QACT,WAAW,EAAE,WAAW,EAAE,WAAW,EAAe,EAAE;AAAA,QACtD,OAAO;AAAA,MACR,CAAA,GACA,KACC,gBAAA,EAAC,GAAD;AAAA,QAAM,IAAI;AAAA,UAAE,OAAO;AAAA,UAAkB,YAAY;AAAA,QAAI;AAAA,QAAG,SAAQ;AAAA,QAC7D,UAAA;AAAA,MACG,CAAA,CAEH;AAAA,IAEH,CAAA,CAAA;AAAA;AAEZ"}
|
|
@@ -3,17 +3,7 @@ export interface HiddenConfirmationCardProps {
|
|
|
3
3
|
onUndo: () => void;
|
|
4
4
|
onLeaveFeedback: () => void;
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
7
|
-
* Inline card that replaces a beat once it has been hidden, prompting the user
|
|
8
|
-
* to undo or leave feedback. Presentational — the host owns visibility and
|
|
9
|
-
* wires the callbacks. Copy comes from `insights_feed.hidden_confirmation`.
|
|
10
|
-
*
|
|
11
|
-
* The close IconButton is absolutely positioned in the top-right corner (top: 4
|
|
12
|
-
* + a 40px button centers its icon on the title line), and the action row is
|
|
13
|
-
* indented under the text column.
|
|
14
|
-
*
|
|
15
|
-
* Figma: 287:20383 — "Template | Hidden Card".
|
|
16
|
-
*/
|
|
6
|
+
/** Inline confirmation card shown after hiding an insight. */
|
|
17
7
|
export declare const HiddenConfirmationCard: (({ onClose, onUndo, onLeaveFeedback }: HiddenConfirmationCardProps) => import("react/jsx-runtime").JSX.Element | null) & {
|
|
18
8
|
displayName: string;
|
|
19
9
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HiddenConfirmationCard.es.js","names":[],"sources":["../../../src/insights-v2/components/HiddenConfirmationCard.tsx"],"sourcesContent":["import Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport IconButton from '@mui/material/IconButton'\nimport Stack from '@mui/material/Stack'\n\nimport { observer } from 'mobx-react-lite'\n\nimport { Close, VisibilityOff } from '@mxenabled/mx-icons'\nimport { P, Text } from '@mxenabled/mxui'\n\nimport { useGlobalCopyStore } from '../../common'\n\nexport interface HiddenConfirmationCardProps {\n onClose: () => void\n onUndo: () => void\n onLeaveFeedback: () => void\n}\n\n
|
|
1
|
+
{"version":3,"file":"HiddenConfirmationCard.es.js","names":[],"sources":["../../../src/insights-v2/components/HiddenConfirmationCard.tsx"],"sourcesContent":["import Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport IconButton from '@mui/material/IconButton'\nimport Stack from '@mui/material/Stack'\n\nimport { observer } from 'mobx-react-lite'\n\nimport { Close, VisibilityOff } from '@mxenabled/mx-icons'\nimport { P, Text } from '@mxenabled/mxui'\n\nimport { useGlobalCopyStore } from '../../common'\n\nexport interface HiddenConfirmationCardProps {\n onClose: () => void\n onUndo: () => void\n onLeaveFeedback: () => void\n}\n\n/** Inline confirmation card shown after hiding an insight. */\nexport const HiddenConfirmationCard = observer(\n ({ onClose, onUndo, onLeaveFeedback }: HiddenConfirmationCardProps) => {\n const copy = useGlobalCopyStore().insights_feed?.hidden_confirmation\n\n if (!copy) return null\n\n return (\n <Card\n elevation={1}\n sx={{\n position: 'relative',\n bgcolor: 'action.disabledBackground',\n borderRadius: 2,\n pt: 16,\n px: 16,\n pb: 8,\n }}\n >\n <IconButton\n aria-label={copy.close_aria}\n onClick={onClose}\n sx={{ minHeight: 40, minWidth: 40, position: 'absolute', right: 4, top: 4 }}\n >\n <Close size={20} sx={{ color: 'text.secondary' }} />\n </IconButton>\n\n <Stack sx={{ gap: 6 }}>\n <Stack sx={{ flexDirection: 'row', gap: 12 }}>\n <Box\n sx={{\n flexShrink: 0,\n width: 32,\n height: 32,\n borderRadius: 1,\n bgcolor: 'grey.300',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <VisibilityOff size={20} sx={{ color: 'text.secondary' }} />\n </Box>\n\n <Stack sx={{ gap: 6 }}>\n <P aria-live=\"assertive\" bold sx={{ lineHeight: '16px' }} variant=\"body1\">\n {copy.title}\n </P>\n\n <P\n sx={{ color: 'text.primary', fontSize: 13, lineHeight: '20px' }}\n variant=\"subtitle2\"\n >\n {copy.description}\n </P>\n </Stack>\n </Stack>\n\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n gap: 4,\n height: 28,\n pb: 6,\n pl: 36,\n }}\n >\n <Button onClick={onUndo} size=\"small\" sx={{ minWidth: 0, px: 8 }} variant=\"text\">\n <Text bold variant=\"body2\">\n {copy.undo}\n </Text>\n </Button>\n <Button\n onClick={onLeaveFeedback}\n size=\"small\"\n sx={{ minWidth: 0, px: 8 }}\n variant=\"text\"\n >\n <Text bold sx={{ color: 'text.secondary' }} variant=\"body2\">\n {copy.leave_feedback}\n </Text>\n </Button>\n </Stack>\n </Stack>\n </Card>\n )\n },\n)\n\nexport default HiddenConfirmationCard\n"],"mappings":"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"}
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The insight card's "…" overflow menu. This repo owns the item set — order,
|
|
3
|
-
* icons, and labels (from `insights_feed.overflow_menu` copy) — while the host
|
|
4
|
-
* supplies the action handler via `beatActions.onMenuAction` (read from
|
|
5
|
-
* context). Renders nothing without a handler or before copy resolves.
|
|
6
|
-
*/
|
|
1
|
+
/** Overflow menu for insight cards. */
|
|
7
2
|
export declare const InsightOptionsMenu: (() => import("react/jsx-runtime").JSX.Element | null) & {
|
|
8
3
|
displayName: string;
|
|
9
4
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InsightOptionsMenu.es.js","names":[],"sources":["../../../src/insights-v2/components/InsightOptionsMenu.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\n\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport { useGlobalCopyStore } from '../../common'\n\nimport { useBeatActions } from '../beatActions'\n\nimport { OverflowMenu, type OverflowMenuItem } from './OverflowMenu'\n\n
|
|
1
|
+
{"version":3,"file":"InsightOptionsMenu.es.js","names":[],"sources":["../../../src/insights-v2/components/InsightOptionsMenu.tsx"],"sourcesContent":["import { observer } from 'mobx-react-lite'\n\nimport { Icon } from '@mxenabled/mx-icons'\n\nimport { useGlobalCopyStore } from '../../common'\n\nimport { useBeatActions } from '../beatActions'\n\nimport { OverflowMenu, type OverflowMenuItem } from './OverflowMenu'\n\n/** Overflow menu for insight cards. */\nexport const InsightOptionsMenu = observer(() => {\n const { onMenuAction } = useBeatActions()\n const copy = useGlobalCopyStore().insights_feed?.overflow_menu\n\n if (!onMenuAction || !copy) return null\n\n const { onAction, onOpen, disabled } = onMenuAction\n\n const items: OverflowMenuItem[] = [\n {\n key: 'helpful',\n icon: <Icon name=\"thumb_up\" size={24} sx={{ color: 'text.primary' }} />,\n label: copy.helpful,\n onSelect: () => onAction('helpful'),\n },\n {\n key: 'not_helpful',\n icon: <Icon name=\"thumb_down\" size={24} sx={{ color: 'text.primary' }} />,\n label: copy.not_helpful,\n onSelect: () => onAction('not_helpful'),\n },\n {\n key: 'hide',\n icon: <Icon name=\"visibility_off\" size={24} sx={{ color: 'text.primary' }} />,\n label: copy.hide,\n onSelect: () => onAction('hide'),\n },\n ]\n\n return (\n <OverflowMenu ariaLabel={copy.aria_label} disabled={disabled} items={items} onOpen={onOpen} />\n )\n})\n\nexport default InsightOptionsMenu\n"],"mappings":";;;;;;AAWA,IAAa,IAAqB,EAAA,MAAe;AAC/C,QAAM,EAAE,cAAA,EAAA,IAAiB,EAAe,GAClC,IAAO,EAAmB,EAAE,eAAe;AAEjD,MAAI,CAAC,KAAgB,CAAC,EAAM,QAAO;AAEnC,QAAM,EAAE,UAAA,GAAU,QAAA,GAAQ,UAAA,EAAA,IAAa,GAEjC,IAA4B;AAAA,IAChC;AAAA,MACE,KAAK;AAAA,MACL,MAAM,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAK;AAAA,QAAW,MAAM;AAAA,QAAI,IAAI,EAAE,OAAO,eAAe;AAAA,MAAI,CAAA;AAAA,MACtE,OAAO,EAAK;AAAA,MACZ,UAAA,MAAgB,EAAS,SAAS;AAAA,IACpC;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAK;AAAA,QAAa,MAAM;AAAA,QAAI,IAAI,EAAE,OAAO,eAAe;AAAA,MAAI,CAAA;AAAA,MACxE,OAAO,EAAK;AAAA,MACZ,UAAA,MAAgB,EAAS,aAAa;AAAA,IACxC;AAAA,IACA;AAAA,MACE,KAAK;AAAA,MACL,MAAM,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAK;AAAA,QAAiB,MAAM;AAAA,QAAI,IAAI,EAAE,OAAO,eAAe;AAAA,MAAI,CAAA;AAAA,MAC5E,OAAO,EAAK;AAAA,MACZ,UAAA,MAAgB,EAAS,MAAM;AAAA,IACjC;AAAA,EACF;AAEA,SACE,gBAAA,EAAC,GAAD;AAAA,IAAc,WAAW,EAAK;AAAA,IAAsB,UAAA;AAAA,IAAiB,OAAA;AAAA,IAAe,QAAA;AAAA,EAAS,CAAA;AAEjG,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export type ObsolesceBannerState = 'refresh_available' | 'refreshing' | 'updated' | 'not_refreshable' | 'hidden';
|
|
3
|
+
export interface ObsolesceBannerCopy {
|
|
4
|
+
new_information_available: string;
|
|
5
|
+
updating: string;
|
|
6
|
+
update: string;
|
|
7
|
+
insight_updated: string;
|
|
8
|
+
insight_no_longer_applicable: string;
|
|
9
|
+
dismiss: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ObsolesceBannerProps {
|
|
12
|
+
state: ObsolesceBannerState;
|
|
13
|
+
onRefresh: () => void;
|
|
14
|
+
onDismiss: () => void;
|
|
15
|
+
copy: ObsolesceBannerCopy;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Presentational obsolescence banner. State transitions are announced to
|
|
19
|
+
* screen readers by the host via a global aria-live region (Pulse's
|
|
20
|
+
* useObsoleteManager dispatches updateAriaLive on each transition, matching
|
|
21
|
+
* the legacy ObsoleteManager). A component-level aria-live is intentionally
|
|
22
|
+
* omitted: it would double-announce in Pulse and, because the banner unmounts
|
|
23
|
+
* via <Collapse unmountOnExit>, would be a less reliable live region than a
|
|
24
|
+
* persistent global one.
|
|
25
|
+
*/
|
|
26
|
+
export declare const ObsolesceBanner: React.FC<ObsolesceBannerProps>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { useRef as C } from "react";
|
|
2
|
+
import { Text as l } from "@mxenabled/mxui";
|
|
3
|
+
import { Cancel as k, CheckCircle as v, Sync as _ } from "@mxenabled/mx-icons";
|
|
4
|
+
import { jsx as t, jsxs as c } from "react/jsx-runtime";
|
|
5
|
+
import { useTheme as B } from "@mui/material/styles";
|
|
6
|
+
import { Box as d, Button as u, Collapse as R, Stack as I } from "@mui/material";
|
|
7
|
+
var S = 50, p = {
|
|
8
|
+
fontSize: 11,
|
|
9
|
+
minWidth: "auto",
|
|
10
|
+
padding: "4px 8px",
|
|
11
|
+
textTransform: "none",
|
|
12
|
+
"&:hover": {
|
|
13
|
+
backgroundColor: "transparent",
|
|
14
|
+
textDecoration: "underline"
|
|
15
|
+
}
|
|
16
|
+
}, H = ({ state: o, onRefresh: f, onDismiss: g, copy: r }) => {
|
|
17
|
+
const e = B(), m = o === "refresh_available", i = o === "refreshing", b = o === "updated", x = o === "not_refreshable", h = o !== "hidden", a = m || i ? {
|
|
18
|
+
backgroundColor: e.palette.success?.lighter,
|
|
19
|
+
iconColor: e.palette.success?.dark,
|
|
20
|
+
textColor: e.palette.success?.dark,
|
|
21
|
+
icon: /* @__PURE__ */ t(_, { sx: { ...i && {
|
|
22
|
+
animation: "spin 1.6s linear infinite",
|
|
23
|
+
"@keyframes spin": {
|
|
24
|
+
"0%": { transform: "rotate(0deg)" },
|
|
25
|
+
"100%": { transform: "rotate(360deg)" }
|
|
26
|
+
}
|
|
27
|
+
} } }),
|
|
28
|
+
message: i ? r.updating : r.new_information_available,
|
|
29
|
+
button: /* @__PURE__ */ t(u, {
|
|
30
|
+
onClick: f,
|
|
31
|
+
disabled: i,
|
|
32
|
+
variant: "text",
|
|
33
|
+
size: "small",
|
|
34
|
+
"aria-label": r.update,
|
|
35
|
+
sx: {
|
|
36
|
+
...p,
|
|
37
|
+
color: i ? e.palette.text?.secondary : e.palette.success?.dark
|
|
38
|
+
},
|
|
39
|
+
children: /* @__PURE__ */ t(l, {
|
|
40
|
+
bold: !0,
|
|
41
|
+
variant: "body2",
|
|
42
|
+
children: r.update
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
} : b ? {
|
|
46
|
+
backgroundColor: e.palette.success?.lighter,
|
|
47
|
+
iconColor: e.palette.success?.dark,
|
|
48
|
+
textColor: e.palette.success?.dark,
|
|
49
|
+
icon: /* @__PURE__ */ t(v, {}),
|
|
50
|
+
message: r.insight_updated,
|
|
51
|
+
button: null
|
|
52
|
+
} : x ? {
|
|
53
|
+
backgroundColor: e.palette.neutral?.light,
|
|
54
|
+
iconColor: e.palette.neutral?.dark,
|
|
55
|
+
textColor: e.palette.neutral?.dark,
|
|
56
|
+
icon: /* @__PURE__ */ t(k, { filled: !0 }),
|
|
57
|
+
message: r.insight_no_longer_applicable,
|
|
58
|
+
button: /* @__PURE__ */ t(u, {
|
|
59
|
+
onClick: g,
|
|
60
|
+
variant: "text",
|
|
61
|
+
size: "small",
|
|
62
|
+
"aria-label": r.dismiss,
|
|
63
|
+
sx: {
|
|
64
|
+
...p,
|
|
65
|
+
color: e.palette.neutral?.dark
|
|
66
|
+
},
|
|
67
|
+
children: /* @__PURE__ */ t(l, {
|
|
68
|
+
bold: !0,
|
|
69
|
+
variant: "body2",
|
|
70
|
+
children: r.dismiss
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
} : null, s = C(a);
|
|
74
|
+
a && (s.current = a);
|
|
75
|
+
const n = a ?? s.current;
|
|
76
|
+
return n ? /* @__PURE__ */ t(R, {
|
|
77
|
+
in: h,
|
|
78
|
+
unmountOnExit: !0,
|
|
79
|
+
children: /* @__PURE__ */ c(d, {
|
|
80
|
+
sx: {
|
|
81
|
+
alignItems: "center",
|
|
82
|
+
backgroundColor: n.backgroundColor,
|
|
83
|
+
borderRadius: "8px",
|
|
84
|
+
display: "flex",
|
|
85
|
+
height: S,
|
|
86
|
+
justifyContent: "space-between",
|
|
87
|
+
pb: 14,
|
|
88
|
+
position: "relative",
|
|
89
|
+
pt: 8,
|
|
90
|
+
px: 12,
|
|
91
|
+
top: 10
|
|
92
|
+
},
|
|
93
|
+
children: [/* @__PURE__ */ c(I, {
|
|
94
|
+
sx: {
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
flexDirection: "row",
|
|
97
|
+
gap: 4
|
|
98
|
+
},
|
|
99
|
+
children: [/* @__PURE__ */ t(d, {
|
|
100
|
+
sx: {
|
|
101
|
+
color: n.iconColor,
|
|
102
|
+
display: "flex",
|
|
103
|
+
alignItems: "center"
|
|
104
|
+
},
|
|
105
|
+
children: n.icon
|
|
106
|
+
}), /* @__PURE__ */ t(l, {
|
|
107
|
+
variant: "subtitle2",
|
|
108
|
+
sx: { color: n.textColor },
|
|
109
|
+
children: n.message
|
|
110
|
+
})]
|
|
111
|
+
}), n.button]
|
|
112
|
+
})
|
|
113
|
+
}) : null;
|
|
114
|
+
};
|
|
115
|
+
export {
|
|
116
|
+
H as ObsolesceBanner
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
//# sourceMappingURL=ObsolesceBanner.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ObsolesceBanner.es.js","names":[],"sources":["../../../src/insights-v2/components/ObsolesceBanner.tsx"],"sourcesContent":["import React, { useRef } from 'react'\nimport { Box, Button, Collapse, Stack } from '@mui/material'\nimport { useTheme } from '@mui/material/styles'\nimport { Cancel, CheckCircle, Sync } from '@mxenabled/mx-icons'\nimport { Text } from '@mxenabled/mxui'\n\nexport type ObsolesceBannerState =\n | 'refresh_available'\n | 'refreshing'\n | 'updated'\n | 'not_refreshable'\n | 'hidden'\n\nexport interface ObsolesceBannerCopy {\n new_information_available: string\n updating: string\n update: string\n insight_updated: string\n insight_no_longer_applicable: string\n dismiss: string\n}\n\nexport interface ObsolesceBannerProps {\n state: ObsolesceBannerState\n onRefresh: () => void\n onDismiss: () => void\n copy: ObsolesceBannerCopy\n}\n\nconst BANNER_HEIGHT = 50\n\nconst bannerButtonSx = {\n fontSize: 11,\n minWidth: 'auto',\n padding: '4px 8px',\n textTransform: 'none',\n '&:hover': {\n backgroundColor: 'transparent',\n textDecoration: 'underline',\n },\n} as const\n\n/**\n * Presentational obsolescence banner. State transitions are announced to\n * screen readers by the host via a global aria-live region (Pulse's\n * useObsoleteManager dispatches updateAriaLive on each transition, matching\n * the legacy ObsoleteManager). A component-level aria-live is intentionally\n * omitted: it would double-announce in Pulse and, because the banner unmounts\n * via <Collapse unmountOnExit>, would be a less reliable live region than a\n * persistent global one.\n */\nexport const ObsolesceBanner: React.FC<ObsolesceBannerProps> = ({\n state,\n onRefresh,\n onDismiss,\n copy,\n}) => {\n const theme = useTheme()\n\n const isRefreshAvailable = state === 'refresh_available'\n const isRefreshing = state === 'refreshing'\n const isUpdated = state === 'updated'\n const isNotRefreshable = state === 'not_refreshable'\n const isVisible = state !== 'hidden'\n\n const getBannerConfig = () => {\n if (isRefreshAvailable || isRefreshing) {\n return {\n backgroundColor: theme.palette.success?.lighter,\n iconColor: theme.palette.success?.dark,\n textColor: theme.palette.success?.dark,\n icon: (\n <Sync\n sx={{\n ...(isRefreshing && {\n animation: 'spin 1.6s linear infinite',\n '@keyframes spin': {\n '0%': { transform: 'rotate(0deg)' },\n '100%': { transform: 'rotate(360deg)' },\n },\n }),\n }}\n />\n ),\n message: isRefreshing ? copy.updating : copy.new_information_available,\n button: (\n <Button\n onClick={onRefresh}\n disabled={isRefreshing}\n variant=\"text\"\n size=\"small\"\n aria-label={copy.update}\n sx={{\n ...bannerButtonSx,\n color: isRefreshing ? theme.palette.text?.secondary : theme.palette.success?.dark,\n }}\n >\n <Text bold={true} variant=\"body2\">\n {copy.update}\n </Text>\n </Button>\n ),\n }\n }\n\n if (isUpdated) {\n return {\n backgroundColor: theme.palette.success?.lighter,\n iconColor: theme.palette.success?.dark,\n textColor: theme.palette.success?.dark,\n icon: <CheckCircle />,\n message: copy.insight_updated,\n button: null,\n }\n }\n\n if (isNotRefreshable) {\n return {\n backgroundColor: theme.palette.neutral?.light,\n iconColor: theme.palette.neutral?.dark,\n textColor: theme.palette.neutral?.dark,\n icon: <Cancel filled={true} />,\n message: copy.insight_no_longer_applicable,\n button: (\n <Button\n onClick={onDismiss}\n variant=\"text\"\n size=\"small\"\n aria-label={copy.dismiss}\n sx={{\n ...bannerButtonSx,\n color: theme.palette.neutral?.dark,\n }}\n >\n <Text bold={true} variant=\"body2\">\n {copy.dismiss}\n </Text>\n </Button>\n ),\n }\n }\n\n return null\n }\n\n const config = getBannerConfig()\n\n // Keep the last visible config so the banner can animate out on 'hidden'\n // instead of unmounting instantly (Collapse needs content while in={false}).\n const lastConfig = useRef(config)\n if (config) lastConfig.current = config\n const renderedConfig = config ?? lastConfig.current\n\n if (!renderedConfig) {\n return null\n }\n\n return (\n <Collapse in={isVisible} unmountOnExit>\n <Box\n sx={{\n alignItems: 'center',\n backgroundColor: renderedConfig.backgroundColor,\n borderRadius: '8px',\n display: 'flex',\n height: BANNER_HEIGHT,\n justifyContent: 'space-between',\n pb: 14,\n position: 'relative',\n pt: 8,\n px: 12,\n top: 10,\n }}\n >\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', gap: 4 }}>\n <Box\n sx={{\n color: renderedConfig.iconColor,\n display: 'flex',\n alignItems: 'center',\n }}\n >\n {renderedConfig.icon}\n </Box>\n <Text\n variant=\"subtitle2\"\n sx={{\n color: renderedConfig.textColor,\n }}\n >\n {renderedConfig.message}\n </Text>\n </Stack>\n {renderedConfig.button}\n </Box>\n </Collapse>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
import { Beat } from '../../core';
|
|
2
2
|
import { BeatActions, InsightRating } from '../beatActions';
|
|
3
3
|
import { DismissType } from '../components/DismissInsightDialog';
|
|
4
|
-
|
|
4
|
+
import { FeedbackDialogCloseReason } from '../components/FeedbackDialog';
|
|
5
5
|
export type FeedbackVariant = InsightRating | 'hide';
|
|
6
|
-
/**
|
|
7
|
-
* What the card slot shows:
|
|
8
|
-
* - `visible` the original beat card
|
|
9
|
-
* - `confirming` the hidden-confirmation card (grace period after a hide)
|
|
10
|
-
* - `dismissed` nothing (beat stays hidden; the host removes it on refresh)
|
|
11
|
-
*/
|
|
12
6
|
export type CardState = 'visible' | 'confirming' | 'dismissed';
|
|
13
7
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* card, and the shared feedback survey dialog.
|
|
17
|
-
*
|
|
18
|
-
* Experiences owns this UI; the host only receives callbacks (rate / dismiss /
|
|
19
|
-
* undo / submit-feedback) via `beatActions`. Keeping the machine here leaves
|
|
20
|
-
* BaseLayout as pure layout.
|
|
8
|
+
* Manages feedback and dismiss UI state for a beat card.
|
|
9
|
+
* Handles feedback bar, dismiss dialog, confirmation card, and survey dialogs.
|
|
21
10
|
*/
|
|
22
11
|
export declare const useBeatFeedbackFlow: (beat: Beat, beatActions: BeatActions) => {
|
|
23
12
|
cardState: CardState;
|
|
@@ -35,10 +24,14 @@ export declare const useBeatFeedbackFlow: (beat: Beat, beatActions: BeatActions)
|
|
|
35
24
|
wrappedActions: BeatActions;
|
|
36
25
|
openRatingSurvey: () => void;
|
|
37
26
|
openHideSurvey: () => void;
|
|
38
|
-
closeSurvey: () => void;
|
|
27
|
+
closeSurvey: (reason?: FeedbackDialogCloseReason) => void;
|
|
39
28
|
submitSurvey: (option: string, detail?: string) => void;
|
|
40
29
|
confirmDismiss: (type: DismissType) => void;
|
|
41
30
|
undoDismiss: () => void;
|
|
42
31
|
collapseConfirmation: () => void;
|
|
43
32
|
closeDismissDialog: () => void;
|
|
33
|
+
feedbackDialogCallbacks: {
|
|
34
|
+
onBackClick: (() => void) | undefined;
|
|
35
|
+
onTextInputFocus: (() => void) | undefined;
|
|
36
|
+
};
|
|
44
37
|
};
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { useGlobalCopyStore as
|
|
2
|
-
import { useMemo as
|
|
3
|
-
var
|
|
4
|
-
const
|
|
5
|
-
|
|
1
|
+
import { useGlobalCopyStore as b } from "../../common/context/hooks.es.js";
|
|
2
|
+
import { useEffect as g, useMemo as p, useState as u } from "react";
|
|
3
|
+
var w = (n, o) => {
|
|
4
|
+
const d = b(), [r, l] = u(null), [i, t] = u(null), [h, a] = u(!1), [f, c] = u(!1);
|
|
5
|
+
g(() => {
|
|
6
|
+
n.is_dismissed || c(!1);
|
|
7
|
+
}, [n.is_dismissed]);
|
|
8
|
+
const k = p(() => n.is_dismissed && f ? "dismissed" : n.is_dismissed ? "confirming" : "visible", [n.is_dismissed, f]), v = (() => {
|
|
9
|
+
const e = d.insights_feed?.feedback, s = d.insights_feed?.hide_feedback, m = {
|
|
6
10
|
characterLimitLabel: (i === "hide" ? s : e)?.character_limit,
|
|
7
11
|
closeAriaLabel: (i === "hide" ? s : e)?.close_aria ?? "Close",
|
|
8
12
|
submitText: (i === "hide" ? s : e)?.submit ?? "Submit",
|
|
@@ -13,61 +17,67 @@ var x = (r, o) => {
|
|
|
13
17
|
options: Object.values(s.options),
|
|
14
18
|
...m
|
|
15
19
|
};
|
|
16
|
-
const
|
|
20
|
+
const _ = Object.values(i === "not_helpful" ? e?.not_helpful_options ?? {} : e?.helpful_options ?? {});
|
|
17
21
|
return {
|
|
18
22
|
title: e?.tell_us_more_title ?? "Tell us more",
|
|
19
|
-
options:
|
|
23
|
+
options: _,
|
|
20
24
|
...m
|
|
21
25
|
};
|
|
22
|
-
})(),
|
|
26
|
+
})(), S = p(() => {
|
|
23
27
|
const e = o.onMenuAction;
|
|
24
28
|
return e ? {
|
|
25
29
|
...o,
|
|
26
30
|
onMenuAction: {
|
|
27
31
|
...e,
|
|
28
32
|
onAction: (s) => {
|
|
29
|
-
s === "helpful" || s === "not_helpful" ?
|
|
33
|
+
s === "helpful" || s === "not_helpful" ? l(s) : s === "hide" && a(!0), e.onAction(s);
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
36
|
} : o;
|
|
33
37
|
}, [o]);
|
|
34
38
|
return {
|
|
35
|
-
cardState:
|
|
36
|
-
isDismissOpen:
|
|
39
|
+
cardState: k,
|
|
40
|
+
isDismissOpen: h,
|
|
37
41
|
isSurveyOpen: i !== null,
|
|
38
|
-
isFeedbackBarShown:
|
|
39
|
-
survey:
|
|
40
|
-
wrappedActions:
|
|
42
|
+
isFeedbackBarShown: r !== null,
|
|
43
|
+
survey: v,
|
|
44
|
+
wrappedActions: S,
|
|
41
45
|
openRatingSurvey: () => {
|
|
42
|
-
|
|
46
|
+
r && t(r);
|
|
43
47
|
},
|
|
44
48
|
openHideSurvey: () => t("hide"),
|
|
45
|
-
closeSurvey: () => {
|
|
46
|
-
i !== "hide" &&
|
|
49
|
+
closeSurvey: (e) => {
|
|
50
|
+
e && o.onFeedbackDialogClose?.(e), i !== "hide" && l(null), t(null);
|
|
47
51
|
},
|
|
48
52
|
submitSurvey: (e, s) => {
|
|
49
53
|
i && (o.onSubmitFeedback?.({
|
|
50
|
-
beatGuid:
|
|
54
|
+
beatGuid: n.guid,
|
|
51
55
|
source: i,
|
|
52
56
|
option: e,
|
|
53
57
|
detail: s
|
|
54
|
-
}), t(null), i === "hide" ?
|
|
58
|
+
}), t(null), i === "hide" ? c(!0) : l(null));
|
|
55
59
|
},
|
|
56
60
|
confirmDismiss: (e) => {
|
|
57
61
|
o.onDismissInsight?.({
|
|
58
|
-
beatGuid:
|
|
62
|
+
beatGuid: n.guid,
|
|
59
63
|
type: e
|
|
60
|
-
})
|
|
64
|
+
});
|
|
61
65
|
},
|
|
62
66
|
undoDismiss: () => {
|
|
63
|
-
o.onUndoDismiss?.({ beatGuid:
|
|
67
|
+
o.onUndoDismiss?.({ beatGuid: n.guid }), l(null);
|
|
64
68
|
},
|
|
65
|
-
collapseConfirmation: () =>
|
|
66
|
-
|
|
69
|
+
collapseConfirmation: () => {
|
|
70
|
+
c(!0);
|
|
71
|
+
},
|
|
72
|
+
closeDismissDialog: () => a(!1),
|
|
73
|
+
feedbackDialogCallbacks: {
|
|
74
|
+
onBackClick: o.onFeedbackDialogBack,
|
|
75
|
+
onTextInputFocus: o.onFeedbackTextFocus
|
|
76
|
+
}
|
|
67
77
|
};
|
|
68
78
|
};
|
|
69
79
|
export {
|
|
70
|
-
|
|
80
|
+
w as useBeatFeedbackFlow
|
|
71
81
|
};
|
|
72
82
|
|
|
73
83
|
//# sourceMappingURL=useBeatFeedbackFlow.es.js.map
|