@stokr/components-library 3.0.31 → 3.0.32

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 (57) hide show
  1. package/dist/analytics/index.js +2 -1
  2. package/dist/components/2FA/Connect2FA.js +11 -1
  3. package/dist/components/2FA/EnterCode.js +13 -2
  4. package/dist/components/2FA/InstallAuthApp.js +4 -0
  5. package/dist/components/2FA/ResetCode.js +2 -1
  6. package/dist/components/2FA/Sucess2FA.js +14 -2
  7. package/dist/components/2FA/disable-2fa-flow.js +15 -2
  8. package/dist/components/2FA/enable-2fa-flow.js +5 -0
  9. package/dist/components/2FA/main-flow.js +3 -0
  10. package/dist/components/ConfirmModal/ConfirmModal.js +21 -2
  11. package/dist/components/FAQ/FAQ.js +37 -23
  12. package/dist/components/ForgotPasswordModal/ForgotPasswordModal.js +24 -3
  13. package/dist/components/Input/InputPassword.js +27 -12
  14. package/dist/components/Input/OtpInput.js +21 -7
  15. package/dist/components/Input/Select.js +11 -2
  16. package/dist/components/Input/TableFilterDropdown.js +23 -7
  17. package/dist/components/LoginModal/LoginModal.js +7 -4
  18. package/dist/components/Modal/Modal.styles.js +10 -2
  19. package/dist/components/Modal/NewVentureModal/NewVentureModal.js +21 -6
  20. package/dist/components/Modal/PaymentModal.js +16 -16
  21. package/dist/components/RegisterConfirmModal/RegisterConfirmModal.js +1 -1
  22. package/dist/components/RegisterModal/RegisterModal.js +30 -5
  23. package/dist/components/ResetConfirmModal/ResetConfirmModal.js +1 -1
  24. package/dist/components/ResetPasswordModal/ResetPasswordModal.js +16 -4
  25. package/dist/components/StepController/StepControllerProgress.js +1 -0
  26. package/dist/components/Switch/Switch.js +5 -3
  27. package/dist/components/ToDoList/ToDoListTask.js +1 -0
  28. package/dist/components/VerifyEmailModal/VerifyEmailModal.js +14 -2
  29. package/dist/components/headerHo/HeaderHo.js +2 -0
  30. package/dist/components/icons/LinkIcon.js +2 -2
  31. package/dist/components/taxId/complete.js +23 -2
  32. package/dist/components/taxId/flow.js +11 -1
  33. package/dist/components/taxId/register-taxid.js +25 -4
  34. package/dist/runtime-config.js +1 -1
  35. package/dist/static/country-list.json +251 -251
  36. package/dist/static/fonts/Ionicons/ionicons.min.css +2810 -2810
  37. package/dist/static/fonts/Ionicons/ionicons.min.css.js +1 -1
  38. package/dist/static/fonts/icomoon/selection.json +910 -910
  39. package/dist/static/fonts/icomoon/style.css +139 -139
  40. package/dist/static/images/copy_icon.svg +4 -4
  41. package/dist/static/images/download_icon.svg +3 -3
  42. package/dist/static/images/numbers/number_eight.svg +3 -3
  43. package/dist/static/images/numbers/number_five.svg +4 -4
  44. package/dist/static/images/numbers/number_four.svg +3 -3
  45. package/dist/static/images/numbers/number_nine.svg +4 -4
  46. package/dist/static/images/numbers/number_one.svg +4 -4
  47. package/dist/static/images/numbers/number_seven.svg +4 -4
  48. package/dist/static/images/numbers/number_six.svg +4 -4
  49. package/dist/static/images/numbers/number_three.svg +3 -3
  50. package/dist/static/images/numbers/number_two.svg +4 -4
  51. package/dist/static/images/numbers/number_zero.svg +3 -3
  52. package/dist/static/images/plus-icon.svg +4 -4
  53. package/dist/static/images/search-icon.svg +3 -3
  54. package/dist/static/images/transfer-icon.svg +10 -10
  55. package/dist/static/images/warning-filled.svg +3 -3
  56. package/dist/utils/formatCurrencyValue.js +4 -2
  57. package/package.json +1 -1
@@ -95,7 +95,8 @@ function initAnalytics({
95
95
  rage_click: true,
96
96
  scroll,
97
97
  submit: true,
98
- capture_text_content: false
98
+ capture_text_content: false,
99
+ capture_extra_attrs: ["data-cy"]
99
100
  },
100
101
  record_sessions_percent: 100,
101
102
  record_heatmap_data: true,
@@ -44,7 +44,17 @@ const Connect2FA = (props) => {
44
44
  }
45
45
  )
46
46
  ] }),
47
- /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingTop: true, center: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(Button, { minWidth: "150px", onClick: changeStep, fluid: true, children: "Continue" }) })
47
+ /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingTop: true, center: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(
48
+ Button,
49
+ {
50
+ minWidth: "150px",
51
+ id: "enable-2fa-connect-continue-btn",
52
+ "data-cy": "enable-2fa-connect-continue",
53
+ onClick: changeStep,
54
+ fluid: true,
55
+ children: "Continue"
56
+ }
57
+ ) })
48
58
  ] }) })
49
59
  ] }) });
50
60
  };
@@ -19,7 +19,7 @@ const EnterCode = (props) => {
19
19
  /* @__PURE__ */ jsx("h3", { children: "Enter 2FA code" }),
20
20
  /* @__PURE__ */ jsx("p", { children: "Enter the log in 2FA code from your authenticator app" })
21
21
  ] }) }),
22
- /* @__PURE__ */ jsx(ModalInner, { modalBot: true, children: onModalSwitch && /* @__PURE__ */ jsx(ModalLinkWrap, { children: /* @__PURE__ */ jsx(ModalLink, { type: "button", as: "button", onClick: onModalSwitch, children: "Lost your device?" }) }) })
22
+ /* @__PURE__ */ jsx(ModalInner, { modalBot: true, children: onModalSwitch && /* @__PURE__ */ jsx(ModalLinkWrap, { children: /* @__PURE__ */ jsx(ModalLink, { type: "button", as: "button", "data-cy": "2fa-enter-code-lost-device", onClick: onModalSwitch, children: "Lost your device?" }) }) })
23
23
  ] }),
24
24
  /* @__PURE__ */ jsx(Column, { part: 8, children: /* @__PURE__ */ jsx(ModalInner, { children: /* @__PURE__ */ jsx(
25
25
  Formik,
@@ -38,6 +38,7 @@ const EnterCode = (props) => {
38
38
  id: "otp-input",
39
39
  name: "otpInput",
40
40
  numInputs: 6,
41
+ dataCyPrefix: "2fa-enter-code-otp",
41
42
  value: values.otpInput,
42
43
  onChange: (e) => {
43
44
  setFieldValue("otpInput", e);
@@ -48,7 +49,17 @@ const EnterCode = (props) => {
48
49
  ),
49
50
  /* @__PURE__ */ jsx(FormError, { show: errors.otpInput && touched.otpInput, children: errors.otpInput })
50
51
  ] }) }),
51
- /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingBottom: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(Button, { type: "submit", id: "2fa-enter-code-btn", fluid: true, disabled: submitDisabled, children: "Continue" }) }),
52
+ /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingBottom: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(
53
+ Button,
54
+ {
55
+ type: "submit",
56
+ id: "2fa-enter-code-btn",
57
+ "data-cy": "2fa-enter-code-submit",
58
+ fluid: true,
59
+ disabled: submitDisabled,
60
+ children: "Continue"
61
+ }
62
+ ) }),
52
63
  /* @__PURE__ */ jsx(ComponentWrapper, { paddingVeticalHalf: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(FormError, { show: popupError?.popup === "enter2fa", children: popupError.message }) })
53
64
  ] });
54
65
  }
@@ -22,6 +22,8 @@ const InstallAuthApp = (props) => {
22
22
  Button,
23
23
  {
24
24
  minWidth: "150px",
25
+ id: "enable-2fa-download-app-btn",
26
+ "data-cy": "enable-2fa-download-auth-app",
25
27
  fluid: true,
26
28
  onClick: () => {
27
29
  window.open("https://onelink.to/ev63j9", "_blank");
@@ -50,6 +52,8 @@ const InstallAuthApp = (props) => {
50
52
  Button,
51
53
  {
52
54
  minWidth: "150px",
55
+ id: "enable-2fa-install-app-continue-btn",
56
+ "data-cy": "enable-2fa-install-app-continue",
53
57
  onClick: changeStep,
54
58
  fluid: true,
55
59
  children: "Continue"
@@ -12,7 +12,7 @@ const ResetCode = (props) => {
12
12
  /* @__PURE__ */ jsx("h3", { children: "Lost your device?" }),
13
13
  /* @__PURE__ */ jsx("p", { children: "No problem! We are here to help you..." })
14
14
  ] }) }),
15
- /* @__PURE__ */ jsx(ModalInner, { modalBot: true, children: /* @__PURE__ */ jsx(ModalLinkWrap, { children: /* @__PURE__ */ jsx(ModalLink, { type: "button", as: "button", onClick: onModalSwitch, children: "Enter 2FA code" }) }) })
15
+ /* @__PURE__ */ jsx(ModalInner, { modalBot: true, children: /* @__PURE__ */ jsx(ModalLinkWrap, { children: /* @__PURE__ */ jsx(ModalLink, { type: "button", as: "button", "data-cy": "2fa-reset-code-back-to-enter-code", onClick: onModalSwitch, children: "Enter 2FA code" }) }) })
16
16
  ] }),
17
17
  /* @__PURE__ */ jsx(Column, { part: 8, children: /* @__PURE__ */ jsx(ModalInner, { children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(
18
18
  "a",
@@ -20,6 +20,7 @@ const ResetCode = (props) => {
20
20
  href: "https://stokr.zendesk.com/hc/en-us/requests/new",
21
21
  target: "_blank",
22
22
  rel: "noreferrer",
23
+ "data-cy": "2fa-reset-code-contact-support",
23
24
  style: { textDecoration: "underline" },
24
25
  children: "Contact us to reset your 2FA."
25
26
  }
@@ -12,7 +12,11 @@ const Sucess2FA = ({
12
12
  titleText = "Success!",
13
13
  subTitleLeft = "",
14
14
  textRight = "",
15
- buttonText = "Continue"
15
+ buttonText = "Continue",
16
+ /** DOM id for the primary action button — override per screen (verify email, enable/disable 2FA, etc.) */
17
+ continueButtonId = "success-flow-continue-btn",
18
+ /** Playwright / analytics-friendly selector for the primary button */
19
+ continueButtonDataCy = "success-flow-continue"
16
20
  }) => {
17
21
  return /* @__PURE__ */ jsx(ModalWrapper, { children: /* @__PURE__ */ jsxs(Row, { children: [
18
22
  /* @__PURE__ */ jsxs(Column, { part: 8, children: [
@@ -30,7 +34,9 @@ const Sucess2FA = ({
30
34
  /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(
31
35
  Button,
32
36
  {
37
+ id: continueButtonId,
33
38
  minWidth: "240px",
39
+ "data-cy": continueButtonDataCy,
34
40
  onClick: () => {
35
41
  onClick();
36
42
  },
@@ -42,7 +48,13 @@ const Sucess2FA = ({
42
48
  ] }) });
43
49
  };
44
50
  Sucess2FA.propTypes = {
45
- onClick: PropTypes.func.isRequired
51
+ onClick: PropTypes.func.isRequired,
52
+ titleText: PropTypes.string,
53
+ subTitleLeft: PropTypes.string,
54
+ textRight: PropTypes.string,
55
+ buttonText: PropTypes.string,
56
+ continueButtonId: PropTypes.string,
57
+ continueButtonDataCy: PropTypes.string
46
58
  };
47
59
  var stdin_default = Sucess2FA;
48
60
  export {
@@ -60,6 +60,8 @@ const Disable2FA = ({ showFlow, setShowFlow, onSuccess, onRequiresRecentLoginErr
60
60
  children: /* @__PURE__ */ jsx(ModalInner, { noPadding: true, children: isModalOpen.sucess ? /* @__PURE__ */ jsx(
61
61
  stdin_default$1,
62
62
  {
63
+ continueButtonId: "disable-2fa-success-continue-btn",
64
+ continueButtonDataCy: "disable-2fa-success-continue",
63
65
  onClick: () => {
64
66
  setShowFlow(false);
65
67
  onSuccess?.();
@@ -77,8 +79,19 @@ const Disable2FA = ({ showFlow, setShowFlow, onSuccess, onRequiresRecentLoginErr
77
79
  ] }),
78
80
  /* @__PURE__ */ jsx(Column, { part: 8, children: /* @__PURE__ */ jsxs(ModalInner, { children: [
79
81
  /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingVertical: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("p", { children: "Do you want to remove your log in 2FA authentication?" }) }) }),
80
- /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(Button, { secondary: true, style: { marginRight: 20 }, onClick: () => setShowFlow(false), fluid: true, children: "NO" }) }),
81
- /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingHorizontal: true, noPaddingTop: true, children: /* @__PURE__ */ jsx(Button, { onClick: handleDisableClick, fluid: true, children: "Yes" }) })
82
+ /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(
83
+ Button,
84
+ {
85
+ secondary: true,
86
+ style: { marginRight: 20 },
87
+ id: "disable-2fa-confirm-no-btn",
88
+ "data-cy": "disable-2fa-confirm-no",
89
+ onClick: () => setShowFlow(false),
90
+ fluid: true,
91
+ children: "NO"
92
+ }
93
+ ) }),
94
+ /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingHorizontal: true, noPaddingTop: true, children: /* @__PURE__ */ jsx(Button, { id: "disable-2fa-confirm-yes-btn", "data-cy": "disable-2fa-confirm-yes", onClick: handleDisableClick, fluid: true, children: "Yes" }) })
82
95
  ] }) })
83
96
  ] }) }) })
84
97
  }
@@ -64,6 +64,8 @@ const Enable2FAFlow = ({ showFlow, setShowFlow, onSuccess, totpData, onRequiresR
64
64
  return /* @__PURE__ */ jsx(Modal, { isOpen: showFlow, onClose: () => setShowFlow(false), children: /* @__PURE__ */ jsx(ModalInner, { noPadding: true, children: showSuccess ? /* @__PURE__ */ jsx(
65
65
  stdin_default$1,
66
66
  {
67
+ continueButtonId: "enable-2fa-success-continue-btn",
68
+ continueButtonDataCy: "enable-2fa-success-continue",
67
69
  onClick: () => {
68
70
  if (onSuccess) onSuccess();
69
71
  setshowSuccess(false);
@@ -88,18 +90,21 @@ const Enable2FAFlow = ({ showFlow, setShowFlow, onSuccess, totpData, onRequiresR
88
90
  stepsProgressList: [
89
91
  {
90
92
  id: "app",
93
+ dataCy: "enable-2fa-progress-app",
91
94
  handleClick: () => {
92
95
  stepController.changeStep("app", 0);
93
96
  }
94
97
  },
95
98
  {
96
99
  id: "connect",
100
+ dataCy: "enable-2fa-progress-connect",
97
101
  handleClick: () => {
98
102
  stepController.changeStep("connect", 1);
99
103
  }
100
104
  },
101
105
  {
102
106
  id: "enter-code",
107
+ dataCy: "enable-2fa-progress-enter-code",
103
108
  handleClick: () => stepController.changeStep("enter-code", 2)
104
109
  }
105
110
  ],
@@ -129,6 +129,7 @@ const Main2FAFlow = ({
129
129
  children: /* @__PURE__ */ jsx(
130
130
  stdin_default$1,
131
131
  {
132
+ dataCy: "2fa-settings-toggle",
132
133
  value1: "disabled",
133
134
  value2: "enabled",
134
135
  value1Color: colors.orangishRed,
@@ -194,6 +195,8 @@ const Main2FAFlow = ({
194
195
  isFlowopen.requiresRecentLogin && /* @__PURE__ */ jsx(Modal, { isOpen: isFlowopen.requiresRecentLogin, onClose: () => handleFlowClose("requiresRecentLogin"), children: /* @__PURE__ */ jsx(ModalInner, { noPadding: true, children: /* @__PURE__ */ jsx(
195
196
  stdin_default$4,
196
197
  {
198
+ continueButtonId: "2fa-requires-recent-login-btn",
199
+ continueButtonDataCy: "2fa-requires-recent-login-submit",
197
200
  onClick: () => {
198
201
  onLoginAgainClick?.();
199
202
  },
@@ -89,8 +89,27 @@ const ConfirmModalComponent = ({
89
89
  onConfirm: handleConfirm,
90
90
  onCancel: handleCancel
91
91
  }) }) : /* @__PURE__ */ jsxs(ComponentWrapper, { noPaddingHorizontal: true, flex: true, style: { gap: 16 }, children: [
92
- showCancel && /* @__PURE__ */ jsx(Button, { outlineBlack: true, minWidth: "120px", onClick: handleCancel, ...cancelButtonProps, children: cancelText }),
93
- /* @__PURE__ */ jsx(Button, { minWidth: "120px", onClick: () => handleConfirm(true), ...buttonProps, children: confirmText })
92
+ showCancel && /* @__PURE__ */ jsx(
93
+ Button,
94
+ {
95
+ outlineBlack: true,
96
+ minWidth: "120px",
97
+ onClick: handleCancel,
98
+ ...cancelButtonProps,
99
+ "data-cy": cancelButtonProps["data-cy"] ?? "confirm-modal-cancel",
100
+ children: cancelText
101
+ }
102
+ ),
103
+ /* @__PURE__ */ jsx(
104
+ Button,
105
+ {
106
+ minWidth: "120px",
107
+ onClick: () => handleConfirm(true),
108
+ ...buttonProps,
109
+ "data-cy": buttonProps["data-cy"] ?? "confirm-modal-confirm",
110
+ children: confirmText
111
+ }
112
+ )
94
113
  ] })
95
114
  ] }) }),
96
115
  showRedBar && /* @__PURE__ */ jsx(RedBar, { barColor, style: barStyle })
@@ -4,8 +4,13 @@ import { Text } from "../Text/Text.styles.js";
4
4
  import { useState } from "react";
5
5
  import scrollToElement from "scroll-to-element";
6
6
  import { FaqItems, FaqItem, FaqTitle, FaqDropdownIcon, FaqContent, FaqText } from "./FAQ.styles.js";
7
+ function slugFromTitle(title) {
8
+ if (title == null) return "";
9
+ const raw = typeof title === "string" ? title : "";
10
+ return raw.toLowerCase().trim().slice(0, 48).replace(/\s+/g, "-").replace(/[^a-z0-9_-]/g, "");
11
+ }
7
12
  const FAQ = (props) => {
8
- const { items, noScroll, scrollRef, modalViewMore, withTextStyling } = props;
13
+ const { items, noScroll, scrollRef, modalViewMore, withTextStyling, dataCyPrefix = "faq" } = props;
9
14
  const [activeIndex, setActiveIndex] = useState(null);
10
15
  const onTitleClick = (e, index) => {
11
16
  e.persist();
@@ -30,27 +35,34 @@ const FAQ = (props) => {
30
35
  fontWeight: "300",
31
36
  lineHeight: "16px"
32
37
  };
33
- return /* @__PURE__ */ jsx(FaqItems, { children: items.map((item, index) => (
34
- // eslint-disable-next-line @eslint-react/no-array-index-key
35
- /* @__PURE__ */ jsxs(FaqItem, { children: [
36
- /* @__PURE__ */ jsxs(
37
- FaqTitle,
38
- {
39
- isActive: activeIndex === index,
40
- onClick: (e) => onTitleClick(e, index),
41
- modalViewMore,
42
- children: [
43
- item.title,
44
- /* @__PURE__ */ jsx(FaqDropdownIcon, {})
45
- ]
46
- }
47
- ),
48
- /* @__PURE__ */ jsx(FaqContent, { isOpened: activeIndex === index, children: !Array.isArray(item.content) ? /* @__PURE__ */ jsx(FaqText, { children: item.content }) : /* @__PURE__ */ jsxs(Fragment, { children: [
49
- /* @__PURE__ */ jsx("br", {}),
50
- /* @__PURE__ */ jsx(Text, { style: withTextStyling ? textStyling : {}, children: /* @__PURE__ */ jsx("ul", { children: item.content.map((answer) => /* @__PURE__ */ jsx("li", { children: answer }, answer)) }) })
51
- ] }) })
52
- ] }, index)
53
- )) });
38
+ return /* @__PURE__ */ jsx(FaqItems, { "data-cy": `${dataCyPrefix}-accordion`, children: items.map((item, index) => {
39
+ const titleSlug = slugFromTitle(item.title);
40
+ const itemCy = titleSlug ? `${dataCyPrefix}-item-${titleSlug}` : `${dataCyPrefix}-item-${index}`;
41
+ return (
42
+ // eslint-disable-next-line @eslint-react/no-array-index-key -- FAQ order is content-defined
43
+ /* @__PURE__ */ jsxs(FaqItem, { "data-cy": `${itemCy}-wrap`, children: [
44
+ /* @__PURE__ */ jsxs(
45
+ FaqTitle,
46
+ {
47
+ type: "button",
48
+ "data-cy": `${itemCy}-toggle`,
49
+ "aria-expanded": activeIndex === index,
50
+ isActive: activeIndex === index,
51
+ onClick: (e) => onTitleClick(e, index),
52
+ modalViewMore,
53
+ children: [
54
+ item.title,
55
+ /* @__PURE__ */ jsx(FaqDropdownIcon, {})
56
+ ]
57
+ }
58
+ ),
59
+ /* @__PURE__ */ jsx(FaqContent, { "data-cy": `${itemCy}-panel`, isOpened: activeIndex === index, children: !Array.isArray(item.content) ? /* @__PURE__ */ jsx(FaqText, { children: item.content }) : /* @__PURE__ */ jsxs(Fragment, { children: [
60
+ /* @__PURE__ */ jsx("br", {}),
61
+ /* @__PURE__ */ jsx(Text, { style: withTextStyling ? textStyling : {}, children: /* @__PURE__ */ jsx("ul", { children: item.content.map((answer) => /* @__PURE__ */ jsx("li", { children: answer }, answer)) }) })
62
+ ] }) })
63
+ ] }, index)
64
+ );
65
+ }) });
54
66
  };
55
67
  FAQ.propTypes = {
56
68
  items: PropTypes.arrayOf(
@@ -58,7 +70,9 @@ FAQ.propTypes = {
58
70
  title: PropTypes.node.isRequired,
59
71
  content: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.node]).isRequired
60
72
  })
61
- ).isRequired
73
+ ).isRequired,
74
+ /** Prefix for data-cy: `{prefix}-accordion`, `{prefix}-item-{slug}-toggle`, etc. */
75
+ dataCyPrefix: PropTypes.string
62
76
  };
63
77
  var stdin_default = FAQ;
64
78
  export {
@@ -43,7 +43,17 @@ class ForgotPasswordModal extends PureComponent {
43
43
  ] }) }),
44
44
  /* @__PURE__ */ jsx(ModalInner, { modalBot: true, children: /* @__PURE__ */ jsxs(ModalLinkWrap, { children: [
45
45
  footerTextContent,
46
- /* @__PURE__ */ jsx(ModalLink, { type: "button", to: "#", as: "button", onClick: onModalSwitch, children: "Log in" })
46
+ /* @__PURE__ */ jsx(
47
+ ModalLink,
48
+ {
49
+ type: "button",
50
+ to: "#",
51
+ as: "button",
52
+ "data-cy": "forgot-password-modal-switch-to-login",
53
+ onClick: onModalSwitch,
54
+ children: "Log in"
55
+ }
56
+ )
47
57
  ] }) })
48
58
  ] }),
49
59
  /* @__PURE__ */ jsx(Column, { part: 8, children: /* @__PURE__ */ jsx(ModalInner, { children: popupSuccess.popup !== "forgot" ? /* @__PURE__ */ jsx(
@@ -69,12 +79,23 @@ class ForgotPasswordModal extends PureComponent {
69
79
  error: !!errors.email,
70
80
  touched: !!touched.email,
71
81
  onChange: handleChange,
72
- onBlur: handleBlur
82
+ onBlur: handleBlur,
83
+ "data-cy": "forgot-password-modal-email-input"
73
84
  }
74
85
  ),
75
86
  /* @__PURE__ */ jsx(FormError, { show: errors.email && touched.email, children: errors.email })
76
87
  ] }) }),
77
- /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingBottom: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(Button, { type: "submit", id: "forgot-password-submit-btn", fluid: true, disabled: submitDisabled, children: isActionLoading === "forgot" ? "Sending Reset Link" : "Send Reset Link" }) }),
88
+ /* @__PURE__ */ jsx(ComponentWrapper, { noPaddingBottom: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(
89
+ Button,
90
+ {
91
+ type: "submit",
92
+ id: "forgot-password-submit-btn",
93
+ "data-cy": "forgot-password-modal-submit",
94
+ fluid: true,
95
+ disabled: submitDisabled,
96
+ children: isActionLoading === "forgot" ? "Sending Reset Link" : "Send Reset Link"
97
+ }
98
+ ) }),
78
99
  /* @__PURE__ */ jsx(ComponentWrapper, { paddingVeticalHalf: true, noPaddingHorizontal: true, children: /* @__PURE__ */ jsx(FormError, { show: popupError.popup === "forgot", children: popupError.message }) })
79
100
  ] });
80
101
  }
@@ -22,7 +22,12 @@ const InputPassword = (props) => {
22
22
  touched = false,
23
23
  info = "",
24
24
  showStrength = false,
25
- autoComplete = "current-password"
25
+ autoComplete = "current-password",
26
+ onChange,
27
+ onBlur,
28
+ onFocus,
29
+ toggleDataCy,
30
+ ...domRest
26
31
  } = props;
27
32
  const [isPasswordVisible, setIsPasswordVisible] = useState(false);
28
33
  const [isCapslockOn, setIsCapslockOn] = useState(false);
@@ -37,16 +42,16 @@ const InputPassword = (props) => {
37
42
  const handleCapslock = (e) => {
38
43
  setIsCapslockOn(e.getModifierState("CapsLock"));
39
44
  };
40
- const onFocus = (e, field) => {
41
- props.onFocus?.(e, field);
45
+ const handleFocus = (e, field) => {
46
+ onFocus?.(e, field);
42
47
  setHasFocus(true);
43
48
  };
44
- const onBlur = (e, field) => {
45
- if (props.onBlur) props.onBlur(e, field);
49
+ const handleBlur = (e, field) => {
50
+ onBlur?.(e, field);
46
51
  setHasFocus(false);
47
52
  };
48
- const onChange = (e, field) => {
49
- props.onChange?.(e, field);
53
+ const handleChange = (e, field) => {
54
+ onChange?.(e, field);
50
55
  };
51
56
  const passwordStrengthFunction = () => {
52
57
  if (value.length === 0) {
@@ -67,19 +72,28 @@ const InputPassword = (props) => {
67
72
  /* @__PURE__ */ jsx(InputWrap, { error: error && touched, children: /* @__PURE__ */ jsx(
68
73
  "input",
69
74
  {
75
+ ...domRest,
70
76
  type: isPasswordVisible ? "text" : "password",
71
77
  id,
72
78
  name,
73
79
  value,
74
80
  autoComplete,
75
- onChange,
76
- onBlur,
77
- onFocus,
81
+ onChange: handleChange,
82
+ onBlur: handleBlur,
83
+ onFocus: handleFocus,
78
84
  onKeyUp: handleCapslock,
79
85
  onKeyDown: handleCapslock
80
86
  }
81
87
  ) }),
82
- /* @__PURE__ */ jsx(ShowPassword, { onClick: togglePasswordVisibility, children: isPasswordVisible ? /* @__PURE__ */ jsx("i", { className: "ion ion-md-eye-off" }) : /* @__PURE__ */ jsx("i", { className: "ion ion-md-eye" }) }),
88
+ /* @__PURE__ */ jsx(
89
+ ShowPassword,
90
+ {
91
+ type: "button",
92
+ onClick: togglePasswordVisibility,
93
+ "data-cy": toggleDataCy ?? `${id}-password-visibility-toggle`,
94
+ children: isPasswordVisible ? /* @__PURE__ */ jsx("i", { className: "ion ion-md-eye-off" }) : /* @__PURE__ */ jsx("i", { className: "ion ion-md-eye" })
95
+ }
96
+ ),
83
97
  /* @__PURE__ */ jsxs(BottomWrap, { children: [
84
98
  showStrength ? /* @__PURE__ */ jsxs(PasswordStrengthWrap, { children: [
85
99
  /* @__PURE__ */ jsxs(PasswordStrengthIndicators, { passwordStrength, children: [
@@ -112,7 +126,8 @@ InputPassword.propTypes = {
112
126
  onFocus: PropTypes.func,
113
127
  info: PropTypes.string,
114
128
  showStrength: PropTypes.bool,
115
- autoComplete: PropTypes.string
129
+ autoComplete: PropTypes.string,
130
+ toggleDataCy: PropTypes.string
116
131
  };
117
132
  var stdin_default = InputPassword;
118
133
  export {
@@ -23,7 +23,18 @@ const Separator = styled.span`
23
23
  `}
24
24
  `;
25
25
  const OtpInput = (props) => {
26
- const { value, numInputs = 4, RenderSeparator = Separator, inputType = "text", shouldAutoFocus = true, label } = props;
26
+ const {
27
+ value,
28
+ numInputs = 4,
29
+ RenderSeparator = Separator,
30
+ inputType = "text",
31
+ shouldAutoFocus = true,
32
+ label,
33
+ /** Per-digit selectors: `{prefix}-digit-0`, … */
34
+ dataCyPrefix,
35
+ onChange,
36
+ ...otpProps
37
+ } = props;
27
38
  const [labelUp, setLabelUp] = useState(false);
28
39
  const [hasFocus, setHasFocus] = useState(false);
29
40
  const checkLabel = (focus) => {
@@ -40,10 +51,9 @@ const OtpInput = (props) => {
40
51
  if (value && !labelUp) setLabelUp(true);
41
52
  }, [value, labelUp]);
42
53
  const handleChange = (e, field) => {
43
- const { onChange } = props;
44
54
  onChange?.(e, field);
45
55
  };
46
- return /* @__PURE__ */ jsxs(Wrapper, { children: [
56
+ return /* @__PURE__ */ jsxs(Wrapper, { ...dataCyPrefix ? { "data-cy": `${dataCyPrefix}-wrapper` } : {}, children: [
47
57
  label && /* @__PURE__ */ jsx(Label, { isUp: true, style: { lineHeight: "inherit", top: "-5px" }, children: label }),
48
58
  /* @__PURE__ */ jsx(InputWrap, { children: /* @__PURE__ */ jsx(
49
59
  Input,
@@ -55,10 +65,14 @@ const OtpInput = (props) => {
55
65
  shouldAutoFocus,
56
66
  inputStyle,
57
67
  renderSeparator: /* @__PURE__ */ jsx(RenderSeparator, {}),
58
- renderInput: (_props) => {
59
- return /* @__PURE__ */ jsx("input", { ..._props });
60
- },
61
- ...props
68
+ renderInput: (inputProps, index) => /* @__PURE__ */ jsx(
69
+ "input",
70
+ {
71
+ ...inputProps,
72
+ ...dataCyPrefix ? { "data-cy": `${dataCyPrefix}-digit-${index}` } : {}
73
+ }
74
+ ),
75
+ ...otpProps
62
76
  }
63
77
  ) })
64
78
  ] });
@@ -22,6 +22,11 @@ const SelectMenuListWithScroll = (props) => {
22
22
  SelectMenuListWithScroll.propTypes = {
23
23
  children: PropTypes.node.isRequired
24
24
  };
25
+ function createControlWithDataCy(dataCy) {
26
+ return function ControlWithDataCy(ctlProps) {
27
+ return /* @__PURE__ */ jsx(components.Control, { ...ctlProps, innerProps: { ...ctlProps.innerProps, "data-cy": dataCy } });
28
+ };
29
+ }
25
30
  const Select = (props) => {
26
31
  const {
27
32
  id,
@@ -36,6 +41,7 @@ const Select = (props) => {
36
41
  menuHeight,
37
42
  creatable = false,
38
43
  formatCreateLabel = null,
44
+ dataCy,
39
45
  ...otherProps
40
46
  } = props;
41
47
  const [labelUp, setLabelUp] = useState(!!value);
@@ -87,7 +93,8 @@ const Select = (props) => {
87
93
  const selectComponents = {
88
94
  DropdownIndicator,
89
95
  IndicatorSeparator: null,
90
- MenuList: SelectMenuListWithScroll
96
+ MenuList: SelectMenuListWithScroll,
97
+ ...dataCy ? { Control: createControlWithDataCy(dataCy) } : {}
91
98
  };
92
99
  const currentValue = creatable ? options?.find((option) => option.value === value) || (value ? { value, label: value } : null) : options?.find((option) => option.value === value);
93
100
  return /* @__PURE__ */ jsxs(Wrapper, { children: [
@@ -136,7 +143,9 @@ Select.propTypes = {
136
143
  formatCreateLabel: PropTypes.func,
137
144
  onChange: PropTypes.func,
138
145
  onBlur: PropTypes.func,
139
- onFocus: PropTypes.func
146
+ onFocus: PropTypes.func,
147
+ /** Playwright / autocapture: selector on the react-select control */
148
+ dataCy: PropTypes.string
140
149
  };
141
150
  export {
142
151
  Select,
@@ -80,6 +80,10 @@ const ClearAllOption = styled.div`
80
80
  background-color: ${colors.grey};
81
81
  }
82
82
  `;
83
+ function slugForDataCy(text) {
84
+ if (text == null || text === "") return "";
85
+ return String(text).toLowerCase().trim().replace(/\s+/g, "-").replace(/[^a-z0-9_-]/g, "");
86
+ }
83
87
  const TableFilterDropdown = ({
84
88
  label,
85
89
  options,
@@ -93,8 +97,10 @@ const TableFilterDropdown = ({
93
97
  menuTop = 8,
94
98
  showClearAll = false,
95
99
  clearAllText = "Clear all",
100
+ dataCy,
96
101
  ...props
97
102
  }) => {
103
+ const triggerDataCy = dataCy ?? (label ? `table-filter-${slugForDataCy(label)}` : "table-filter-dropdown");
98
104
  const [isOpen, setIsOpen] = useState(false);
99
105
  const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
100
106
  const containerRef = useRef(null);
@@ -191,19 +197,27 @@ const TableFilterDropdown = ({
191
197
  children: [
192
198
  /* @__PURE__ */ jsx(OptionsList, { children: options.map((option) => {
193
199
  const isSelected = value.includes(option.value);
194
- return /* @__PURE__ */ jsxs(CheckboxWrapperDiv, { onClick: (e) => handleOptionClick(option.value, e), children: [
195
- /* @__PURE__ */ jsx(CheckboxDiv, { isSelected, children: /* @__PURE__ */ jsx(SvgCheckIcon, {}) }),
196
- /* @__PURE__ */ jsx(OptionLabel, { children: option.label })
197
- ] }, option.value);
200
+ return /* @__PURE__ */ jsxs(
201
+ CheckboxWrapperDiv,
202
+ {
203
+ "data-cy": `${triggerDataCy}-option-${slugForDataCy(option.value)}`,
204
+ onClick: (e) => handleOptionClick(option.value, e),
205
+ children: [
206
+ /* @__PURE__ */ jsx(CheckboxDiv, { isSelected, children: /* @__PURE__ */ jsx(SvgCheckIcon, {}) }),
207
+ /* @__PURE__ */ jsx(OptionLabel, { children: option.label })
208
+ ]
209
+ },
210
+ option.value
211
+ );
198
212
  }) }),
199
- showClearAll && hasActiveFilters && /* @__PURE__ */ jsx(ClearAllOption, { onClick: handleClearAll, children: clearAllText })
213
+ showClearAll && hasActiveFilters && /* @__PURE__ */ jsx(ClearAllOption, { "data-cy": `${triggerDataCy}-clear-all`, onClick: handleClearAll, children: clearAllText })
200
214
  ]
201
215
  }
202
216
  );
203
217
  return createPortal(menu, document.body);
204
218
  };
205
219
  return /* @__PURE__ */ jsxs(DropdownContainer, { ref: containerRef, ...props, children: [
206
- /* @__PURE__ */ jsxs(TriggerContainer, { ref: triggerRef, onClick: handleTriggerClick, "data-clickable": "true", children: [
220
+ /* @__PURE__ */ jsxs(TriggerContainer, { ref: triggerRef, onClick: handleTriggerClick, "data-cy": triggerDataCy, "data-clickable": "true", children: [
207
221
  label && /* @__PURE__ */ jsx("span", { children: label }),
208
222
  /* @__PURE__ */ jsxs(IconWrapper, { children: [
209
223
  /* @__PURE__ */ jsx(IconComponent, {}),
@@ -240,7 +254,9 @@ TableFilterDropdown.propTypes = {
240
254
  /** Show "Clear all" option at the bottom of the list */
241
255
  showClearAll: PropTypes.bool,
242
256
  /** Custom text for the "Clear all" option */
243
- clearAllText: PropTypes.string
257
+ clearAllText: PropTypes.string,
258
+ /** Override default `table-filter-{label}` data-cy on trigger */
259
+ dataCy: PropTypes.string
244
260
  };
245
261
  export {
246
262
  TableFilterDropdown