@stokr/components-library 3.0.46 → 3.0.48
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/dist/components/2FA/login-with-otp-flow.js +14 -0
- package/dist/components/2FA/main-flow.js +28 -3
- package/dist/components/Modal/NewVentureModal/NewVentureModal.js +9 -17
- package/dist/components/headerHo/HeaderHo.js +10 -0
- package/dist/hooks/useNewVentureForm.js +9 -4
- package/dist/index.js +3 -0
- package/dist/utils/show-account-locked-modal.js +20 -0
- package/package.json +1 -1
|
@@ -10,6 +10,7 @@ import stdin_default$3 from "./ResetCode.js";
|
|
|
10
10
|
import { authenticationApi } from "../../api/authenticationApi.js";
|
|
11
11
|
import { useNavigate } from "react-router-dom";
|
|
12
12
|
import { getConfig, getPlatformURL } from "../../runtime-config.js";
|
|
13
|
+
import { isAccountLockedError, showAccountLockedModal } from "../../utils/show-account-locked-modal.js";
|
|
13
14
|
import { navigateToHref } from "../../routing/navigate-app.js";
|
|
14
15
|
const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false }) => {
|
|
15
16
|
const navigate = useNavigate();
|
|
@@ -95,6 +96,19 @@ const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false }) => {
|
|
|
95
96
|
clearPopupError();
|
|
96
97
|
return;
|
|
97
98
|
}
|
|
99
|
+
if (isAccountLockedError(error)) {
|
|
100
|
+
clearPopupError();
|
|
101
|
+
setIsModalOpen((prev) => ({
|
|
102
|
+
...prev,
|
|
103
|
+
login: false
|
|
104
|
+
}));
|
|
105
|
+
await showAccountLockedModal();
|
|
106
|
+
setIsModalOpen((prev) => ({
|
|
107
|
+
...prev,
|
|
108
|
+
login: true
|
|
109
|
+
}));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
98
112
|
if (errorMessage) {
|
|
99
113
|
handleSetPopupError("login", errorMessage);
|
|
100
114
|
} else {
|
|
@@ -13,11 +13,14 @@ import { InfoIcon } from "../InfoIcon/InfoIcon.js";
|
|
|
13
13
|
import { Modal } from "../Modal/Modal.js";
|
|
14
14
|
import stdin_default$4 from "./Sucess2FA.js";
|
|
15
15
|
import { ModalInner } from "../Modal/Modal.styles.js";
|
|
16
|
+
import { showProgress } from "../Modal/SuccessModal/SuccessModal.js";
|
|
17
|
+
const SUPPORT_URL = "https://support.stokr.io/";
|
|
16
18
|
const Main2FAFlow = ({
|
|
17
19
|
onRequiresRecentLoginError,
|
|
18
20
|
open2faflow,
|
|
19
21
|
onLoginAgainClick,
|
|
20
22
|
openDisable2faflow,
|
|
23
|
+
allowDisable2FA = false,
|
|
21
24
|
title = "SET UP YOUR LOG IN TWO FACTOR AUTHENTICATION",
|
|
22
25
|
subtitle = "Protect your account with an additional layer of security to log in",
|
|
23
26
|
showSwitch = true,
|
|
@@ -27,7 +30,7 @@ const Main2FAFlow = ({
|
|
|
27
30
|
const { user, checkMfaEnrollment, userMfaEnrollment, generateTotpSecret } = useContext(AuthContext);
|
|
28
31
|
const [isFlowopen, setIsFlowOpen] = useState({
|
|
29
32
|
enable2fa: open2faflow || false,
|
|
30
|
-
disable2fa: openDisable2faflow || false,
|
|
33
|
+
disable2fa: allowDisable2FA && (openDisable2faflow || false),
|
|
31
34
|
requiresRecentLogin: false
|
|
32
35
|
});
|
|
33
36
|
const [is2FAEnabled, setis2FAEnabled] = useState(false);
|
|
@@ -81,6 +84,16 @@ const Main2FAFlow = ({
|
|
|
81
84
|
[nextFlowId]: true
|
|
82
85
|
}));
|
|
83
86
|
};
|
|
87
|
+
const showDisable2faBlockedModal = () => showProgress({
|
|
88
|
+
title: "TWO-FACTOR AUTHENTICATION REQUIRED",
|
|
89
|
+
subtitle: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
90
|
+
"Under our security policy, two-factor authentication is required on all accounts and cannot be turned off. To reset your method, contact our",
|
|
91
|
+
" ",
|
|
92
|
+
/* @__PURE__ */ jsx("a", { href: SUPPORT_URL, target: "_blank", rel: "noreferrer", children: "support team" }),
|
|
93
|
+
"."
|
|
94
|
+
] }),
|
|
95
|
+
maxWidth: "820px"
|
|
96
|
+
});
|
|
84
97
|
const handleFlowClose = (flowId, completed = false) => {
|
|
85
98
|
setIsFlowOpen((prev) => ({ ...prev, [flowId]: false }));
|
|
86
99
|
if (onFlowClose) onFlowClose({ flow: flowId, completed });
|
|
@@ -99,7 +112,14 @@ const Main2FAFlow = ({
|
|
|
99
112
|
};
|
|
100
113
|
const flowActions = {
|
|
101
114
|
openEnable2FA: () => switchOpenFlow("disable2fa", "enable2fa"),
|
|
102
|
-
openDisable2FA: () =>
|
|
115
|
+
openDisable2FA: () => {
|
|
116
|
+
if (!is2FAEnabled) return;
|
|
117
|
+
if (!allowDisable2FA) {
|
|
118
|
+
void showDisable2faBlockedModal();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
switchOpenFlow("enable2fa", "disable2fa");
|
|
122
|
+
},
|
|
103
123
|
closeFlows: () => {
|
|
104
124
|
const wasOpen = Object.keys(isFlowopen).find((key) => isFlowopen[key]);
|
|
105
125
|
setIsFlowOpen({
|
|
@@ -148,6 +168,10 @@ const Main2FAFlow = ({
|
|
|
148
168
|
} else if (value === "enabled") {
|
|
149
169
|
switchOpenFlow("disable2fa", "enable2fa");
|
|
150
170
|
} else if (value === "disabled") {
|
|
171
|
+
if (!allowDisable2FA) {
|
|
172
|
+
void showDisable2faBlockedModal();
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
151
175
|
switchOpenFlow("enable2fa", "disable2fa");
|
|
152
176
|
}
|
|
153
177
|
}
|
|
@@ -177,7 +201,7 @@ const Main2FAFlow = ({
|
|
|
177
201
|
onSuccess: onEnable2FASuccess
|
|
178
202
|
}
|
|
179
203
|
),
|
|
180
|
-
isFlowopen.disable2fa && /* @__PURE__ */ jsx(
|
|
204
|
+
allowDisable2FA && isFlowopen.disable2fa && /* @__PURE__ */ jsx(
|
|
181
205
|
stdin_default$3,
|
|
182
206
|
{
|
|
183
207
|
showFlow: isFlowopen.disable2fa,
|
|
@@ -210,6 +234,7 @@ const Main2FAFlow = ({
|
|
|
210
234
|
};
|
|
211
235
|
Main2FAFlow.propTypes = {
|
|
212
236
|
onRequiresRecentLoginError: PropTypes.func,
|
|
237
|
+
allowDisable2FA: PropTypes.bool,
|
|
213
238
|
/** Called when any flow/modal is closed. Receives the flowId: 'enable2fa' | 'disable2fa' | 'requiresRecentLogin' */
|
|
214
239
|
onFlowClose: PropTypes.func
|
|
215
240
|
};
|
|
@@ -29,6 +29,7 @@ const defaultProject = {
|
|
|
29
29
|
const NewVentureModal = (props) => {
|
|
30
30
|
const navigate = useNavigate();
|
|
31
31
|
const { user } = useContext(AuthContext);
|
|
32
|
+
const isLoggedIn = !!user?._id;
|
|
32
33
|
const {
|
|
33
34
|
title = "Register Your Interest",
|
|
34
35
|
description = "Register your interest and learn more about this investment opportunity.",
|
|
@@ -66,7 +67,10 @@ const NewVentureModal = (props) => {
|
|
|
66
67
|
salesChannel,
|
|
67
68
|
customSuccessMessage
|
|
68
69
|
});
|
|
69
|
-
const validationSchema = Yup.object().shape({
|
|
70
|
+
const validationSchema = isLoggedIn ? Yup.object().shape({
|
|
71
|
+
email: Yup.string().nullable(),
|
|
72
|
+
name: Yup.string().nullable()
|
|
73
|
+
}) : Yup.object().shape({
|
|
70
74
|
email: Yup.string().matches(emailRegex, "Oops, that's not a valid address").required("Oops, this can't be blank"),
|
|
71
75
|
name: Yup.string().required("Oops, this can't be blank")
|
|
72
76
|
});
|
|
@@ -112,6 +116,7 @@ const NewVentureModal = (props) => {
|
|
|
112
116
|
] }) : /* @__PURE__ */ jsx(
|
|
113
117
|
Formik,
|
|
114
118
|
{
|
|
119
|
+
enableReinitialize: true,
|
|
115
120
|
initialValues: {
|
|
116
121
|
email: email || "",
|
|
117
122
|
name: name || "",
|
|
@@ -133,20 +138,6 @@ const NewVentureModal = (props) => {
|
|
|
133
138
|
};
|
|
134
139
|
const oneOfCheckbox = values.mailingList && !mailingListDisabled || values.privateInvestorList && !privateInvestorListDisabled;
|
|
135
140
|
const optionalCheckBoxForm = optionalCheckBox ? values.optionalCheckBoxChecked : true;
|
|
136
|
-
if (email && !values.email) {
|
|
137
|
-
setFieldValue("email", email);
|
|
138
|
-
setFieldTouched("email");
|
|
139
|
-
}
|
|
140
|
-
if (name && !values.name) {
|
|
141
|
-
setFieldValue("name", name);
|
|
142
|
-
setFieldTouched("name");
|
|
143
|
-
}
|
|
144
|
-
if (mailingList && !values.mailingList) {
|
|
145
|
-
setFieldValue("mailingList", mailingList);
|
|
146
|
-
}
|
|
147
|
-
if (privateInvestorList && !values.privateInvestorList) {
|
|
148
|
-
setFieldValue("privateInvestorList", privateInvestorList);
|
|
149
|
-
}
|
|
150
141
|
const handleCheckboxChange = (e) => {
|
|
151
142
|
handleChange(e);
|
|
152
143
|
if (e.target.checked) {
|
|
@@ -155,10 +146,11 @@ const NewVentureModal = (props) => {
|
|
|
155
146
|
updateCheckedCheckboxes(checkedCheckboxes.filter((item) => item !== e.target.id));
|
|
156
147
|
}
|
|
157
148
|
};
|
|
158
|
-
|
|
149
|
+
const requiresIdentityFields = !isLoggedIn;
|
|
150
|
+
const submitDisabled = requiresIdentityFields && (!values.email || !!errors.email || !values.name || !!errors.name) || isSubmitting || !oneOfCheckbox || !optionalCheckBoxForm;
|
|
159
151
|
return /* @__PURE__ */ jsxs(stdin_default, { children: [
|
|
160
152
|
/* @__PURE__ */ jsx(ComponentWrapper, { noPadding: true, children: /* @__PURE__ */ jsxs(FormField, { children: [
|
|
161
|
-
!
|
|
153
|
+
!isLoggedIn && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
162
154
|
/* @__PURE__ */ jsx(
|
|
163
155
|
Input,
|
|
164
156
|
{
|
|
@@ -23,6 +23,7 @@ import { auth } from "../../firebase-config.js";
|
|
|
23
23
|
import { getConfig } from "../../runtime-config.js";
|
|
24
24
|
import { getBackofficeAppUrl } from "../../utils/app-urls-analytics-backoffice.js";
|
|
25
25
|
import { track } from "../../analytics/index.js";
|
|
26
|
+
import { isAccountLockedError, showAccountLockedModal } from "../../utils/show-account-locked-modal.js";
|
|
26
27
|
import { navigateToHref } from "../../routing/navigate-app.js";
|
|
27
28
|
const Outer = styled.div.withConfig({
|
|
28
29
|
shouldForwardProp: (props) => !["fixed"].includes(props)
|
|
@@ -320,6 +321,15 @@ const _HeaderHoClass = class _HeaderHoClass extends Component {
|
|
|
320
321
|
this.setIsActionLoading(void 0);
|
|
321
322
|
return;
|
|
322
323
|
}
|
|
324
|
+
if (isAccountLockedError(error)) {
|
|
325
|
+
this.setOpenModalStatus("login", false);
|
|
326
|
+
setIsLoginModalOpen?.(false);
|
|
327
|
+
this.clearPopupError();
|
|
328
|
+
this.setIsActionLoading(void 0);
|
|
329
|
+
await showAccountLockedModal();
|
|
330
|
+
this.setOpenModalStatus("login", true);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
323
333
|
if (errorMessage) {
|
|
324
334
|
this.setPopupError("login", errorMessage);
|
|
325
335
|
} else {
|
|
@@ -75,6 +75,11 @@ const updateUserSubscription = (user, project, updates) => {
|
|
|
75
75
|
}
|
|
76
76
|
return { ...user, ...updates };
|
|
77
77
|
};
|
|
78
|
+
const resolveUserDisplayName = (user) => {
|
|
79
|
+
if (!user) return "";
|
|
80
|
+
const fullNameFromParts = `${user.firstName || ""} ${user.lastName || ""}`.trim();
|
|
81
|
+
return user.username || user.name || user.fullName || fullNameFromParts || "";
|
|
82
|
+
};
|
|
78
83
|
const useNewVentureForm = ({ project, user, salesChannel, customSuccessMessage }) => {
|
|
79
84
|
const [formValues, setFormValues] = useState(initialState);
|
|
80
85
|
const { setUser, checkPrivateInvestorAll, checkIfUserSubscribedAll } = useContext(AuthContext);
|
|
@@ -86,9 +91,9 @@ const useNewVentureForm = ({ project, user, salesChannel, customSuccessMessage }
|
|
|
86
91
|
setFormValues((prev) => ({ ...prev, isSubmitting: true }));
|
|
87
92
|
try {
|
|
88
93
|
const dataToSend = {
|
|
89
|
-
email: values.email,
|
|
94
|
+
email: values.email || user?.email || "",
|
|
90
95
|
projectId: project._id,
|
|
91
|
-
name: values.name,
|
|
96
|
+
name: values.name || resolveUserDisplayName(user),
|
|
92
97
|
checkedCheckboxes: formValues.checkedCheckboxes,
|
|
93
98
|
salesChannel: salesChannel ? salesChannel : window.location.pathname.includes("featured-assets") ? "featuredAssets" : "investor"
|
|
94
99
|
};
|
|
@@ -192,8 +197,8 @@ const useNewVentureForm = ({ project, user, salesChannel, customSuccessMessage }
|
|
|
192
197
|
});
|
|
193
198
|
}
|
|
194
199
|
if (user?._id) {
|
|
195
|
-
formValuesCopy.email = user.email;
|
|
196
|
-
formValuesCopy.name = user
|
|
200
|
+
formValuesCopy.email = user.email || "";
|
|
201
|
+
formValuesCopy.name = resolveUserDisplayName(user);
|
|
197
202
|
const projectSubscription = getProjectSubscription(user, project);
|
|
198
203
|
if (projectSubscription.isPrivateInvestor) {
|
|
199
204
|
formValuesCopy.privateInvestorListText = "You are already registered on the whitelist.";
|
package/dist/index.js
CHANGED
|
@@ -135,6 +135,7 @@ import { isUSInvestor, usCountries } from "./utils/isUSInvestor.js";
|
|
|
135
135
|
import { km_ify } from "./utils/km_ify.js";
|
|
136
136
|
import { momentUtils } from "./utils/moment.js";
|
|
137
137
|
import { openFile, saveAs } from "./utils/saveAs.js";
|
|
138
|
+
import { isAccountLockedError, showAccountLockedModal } from "./utils/show-account-locked-modal.js";
|
|
138
139
|
import { ScrollToTop, scrollToElement, useScrollActions } from "./utils/scrollUtils.js";
|
|
139
140
|
import { useTimer } from "./hooks/useTimer.js";
|
|
140
141
|
import { useTransactionPolling } from "./hooks/useTransactionPolling.js";
|
|
@@ -625,6 +626,7 @@ export {
|
|
|
625
626
|
iconsMap,
|
|
626
627
|
identify,
|
|
627
628
|
initAnalytics,
|
|
629
|
+
isAccountLockedError,
|
|
628
630
|
isAlreadyOnOnboardingFlow,
|
|
629
631
|
isExternalUrl,
|
|
630
632
|
isUSInvestor,
|
|
@@ -647,6 +649,7 @@ export {
|
|
|
647
649
|
scrollToElement,
|
|
648
650
|
default6 as semanticUiStyle,
|
|
649
651
|
setUserProperties,
|
|
652
|
+
showAccountLockedModal,
|
|
650
653
|
showProgress,
|
|
651
654
|
showSuccess,
|
|
652
655
|
sizes,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { showProgress } from "../components/Modal/SuccessModal/SuccessModal.js";
|
|
4
|
+
const SUPPORT_URL = "https://support.stokr.io/";
|
|
5
|
+
const ACCOUNT_LOCKED_CODE = "auth/user-disabled";
|
|
6
|
+
const isAccountLockedError = (error) => error?.code === ACCOUNT_LOCKED_CODE;
|
|
7
|
+
const showAccountLockedModal = () => showProgress({
|
|
8
|
+
title: "TOO MANY ATTEMPTS",
|
|
9
|
+
subtitle: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10
|
+
"For your security, your account has been temporarily locked after multiple failed sign-in attempts. To restore access, contact our",
|
|
11
|
+
" ",
|
|
12
|
+
/* @__PURE__ */ jsx("a", { href: SUPPORT_URL, target: "_blank", rel: "noreferrer", children: "support team" }),
|
|
13
|
+
"."
|
|
14
|
+
] }),
|
|
15
|
+
maxWidth: "820px"
|
|
16
|
+
});
|
|
17
|
+
export {
|
|
18
|
+
isAccountLockedError,
|
|
19
|
+
showAccountLockedModal
|
|
20
|
+
};
|