UNPKG

@particle-network/auth-core-modal

Version:

Auth Core provides MPC (Multi-Party Computation)-based threshold signatures.

430 lines (423 loc) 26.8 kB
"use client"; import { defaultCountriesData, getCurrentCountry } from "./chunk-HMCOJQRK.js"; import { encryptValue, getAccountList } from "./chunk-FBPWVRLF.js"; import { header_default } from "./chunk-AG2VTU64.js"; import { useMessage_default } from "./chunk-6S7UKOH5.js"; import "./chunk-I2KPE54W.js"; import { power_footer_default } from "./chunk-7BQ5GPLQ.js"; import { EmailRegExp, useAuthCoreModal, useCustomNavigate, useParticleAuth, useUserInfo } from "./chunk-LKAVNLWK.js"; import "./chunk-LQ53OFQ3.js"; // src/pages/loginAccountBind/index.tsx import { AuthType, checkHasBoundLoginPhoneOrEmail } from "@particle-network/auth-core"; import { useRequest, useThrottleFn } from "ahooks"; import { Button, Form as Form2, Input as Input2, Modal } from "antd"; import { parsePhoneNumber as parsePhoneNumber2 } from "libphonenumber-js/max"; import React2, { useEffect as useEffect2, useMemo as useMemo2, useState as useState2 } from "react"; import { useTranslation as useTranslation2 } from "react-i18next"; // src/components/phoneInputItem/index.tsx import { DownOutlined } from "@ant-design/icons"; import { useClickAway } from "ahooks"; import { Form, Input, InputNumber } from "antd"; import getUnicodeFlagIcon from "country-flag-icons/unicode"; import { isValidPhoneNumber, parsePhoneNumber } from "libphonenumber-js/max"; import React, { useEffect, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; // src/components/phoneInputItem/index.less var phoneInputItem_default = ".phone-input-item-container {\n position: relative;\n display: block;\n width: 100%;\n height: auto;\n overflow: initial;\n}\n.phone-input-item-container .ant-input-affix-wrapper,\n.phone-input-item-container .ant-input-number-group-wrapper {\n width: 100%;\n padding: 0;\n border: 1px solid var(--input-border-color) !important;\n border-radius: var(--primary-btn-border-radius);\n line-height: 47px;\n background: var(--input-background-color) !important;\n box-shadow: none !important;\n}\n.phone-input-item-container .ant-input-affix-wrapper .ant-input-number-group-addon,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input-number-group-addon {\n position: initial;\n border: none;\n background-color: var(--input-background-color);\n border-end-start-radius: var(--primary-btn-border-radius);\n border-start-start-radius: var(--primary-btn-border-radius);\n}\n.phone-input-item-container .ant-input-affix-wrapper .ant-input-number-status-error:not(.ant-input-number-disabled, .ant-input-number-borderless).ant-input-number,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input-number-status-error:not(.ant-input-number-disabled, .ant-input-number-borderless).ant-input-number,\n.phone-input-item-container .ant-input-affix-wrapper .ant-input-number-status-error:not(\n .ant-input-number-disabled,\n .ant-input-number-borderless\n ).ant-input-number:hover,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input-number-status-error:not(\n .ant-input-number-disabled,\n .ant-input-number-borderless\n ).ant-input-number:hover {\n border: none;\n background: none;\n}\n.phone-input-item-container .ant-input-affix-wrapper .ant-input-number,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input-number {\n border: none;\n background: none;\n}\n.phone-input-item-container .ant-input-affix-wrapper .ant-input-number-focused,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input-number-focused {\n box-shadow: none !important;\n}\n.phone-input-item-container .ant-input-affix-wrapper .ant-input-number-disabled,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input-number-disabled {\n background: none;\n}\n.phone-input-item-container .ant-input-affix-wrapper .ant-input,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input,\n.phone-input-item-container .ant-input-affix-wrapper .ant-input-number-input,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input-number-input {\n height: 47px;\n border: none !important;\n border-radius: 0;\n line-height: 47px;\n color: var(--text-color);\n}\n.phone-input-item-container .ant-input-affix-wrapper .ant-input:hover,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input:hover,\n.phone-input-item-container .ant-input-affix-wrapper .ant-input-number-input:hover,\n.phone-input-item-container .ant-input-number-group-wrapper .ant-input-number-input:hover {\n border: none !important;\n}\n.phone-input-item-container .ant-input-affix-wrapper[data-focus='true'],\n.phone-input-item-container .ant-input-number-group-wrapper[data-focus='true'] {\n border: 1px solid var(--accent-color) !important;\n}\n.phone-input-item-container .ant-input[disabled] {\n width: 100%;\n height: 47px;\n border: 1px solid var(--input-border-color);\n border-radius: var(--primary-btn-border-radius);\n color: var(--text-color);\n background-color: var(--input-background-color);\n}\n.phone-input-item-container .country-box {\n position: initial;\n cursor: pointer;\n}\n.phone-input-item-container .country-box .prefix-wrap {\n display: flex;\n color: var(--text-color);\n gap: 4px;\n}\n.phone-input-item-container .country-box .account-select-country-list {\n position: absolute;\n z-index: 2;\n top: 54px;\n left: 0%;\n width: 100%;\n height: 350px;\n border-radius: var(--card-border-radius) !important;\n overflow: hidden auto;\n background-color: var(--input-background-color);\n}\n.phone-input-item-container .country-box .account-select-country-list::-webkit-scrollbar {\n display: none;\n width: 0;\n}\n.phone-input-item-container .country-box .account-select-country-list .search-input-wrap .ant-input:focus {\n border: none !important;\n box-shadow: none !important;\n}\n.phone-input-item-container .country-box .account-select-country-list .search-input-wrap.account-select-country-item {\n padding-right: 13px;\n}\n.phone-input-item-container .country-box .account-select-country-list .search-input-wrap.account-select-country-item:hover {\n background: var(--input-background-color);\n}\n.phone-input-item-container .country-box .account-select-country-list .search-input-wrap.account-select-country-item:hover.search-input-wrap {\n background: none;\n}\n.phone-input-item-container .country-box .account-select-country-list .search-input-wrap .ant-input-clear-icon {\n color: var(--text-color);\n}\n.phone-input-item-container .country-box .account-select-country-list .search-input-wrap .ant-input-affix-wrapper {\n border-color: var(--keyword-border-color) !important;\n}\n.phone-input-item-container .country-box .account-select-country-list .search-input-wrap .ant-input-suffix {\n position: relative;\n right: 10px;\n}\n.phone-input-item-container .country-box .account-select-country-list .search-input-wrap .search-input {\n width: 100%;\n height: 32px;\n border-radius: var(--primary-btn-border-radius);\n overflow: hidden;\n color: var(--text-color);\n background-color: var(--input-background-color);\n}\n.phone-input-item-container .country-box .account-select-country-list .search-input-wrap .search-input .ant-input {\n width: 100%;\n height: auto;\n padding-top: 4px;\n padding-bottom: 4px;\n line-height: initial;\n}\n.phone-input-item-container .country-box .account-select-country-list .no-data {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 160px;\n color: var(--text-color);\n}\n.phone-input-item-container .country-box .account-select-country-list .account-select-country-item {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n box-sizing: border-box;\n height: 47px;\n padding: 5px 0 5px 13px;\n margin: 0;\n border-bottom: 1px solid var(--keyword-border-color);\n font-size: 14px;\n color: var(--text-color);\n cursor: pointer;\n}\n.phone-input-item-container .country-box .account-select-country-list .account-select-country-item:hover {\n background-color: var(--keyword-border-color);\n}\n.phone-input-item-container .country-box .account-select-country-list .account-select-country-item div {\n display: flex;\n max-width: 80%;\n margin-right: 13px;\n}\n.phone-input-item-container .country-box input[type='number']::-webkit-inner-spin-button,\n.phone-input-item-container .country-box input[type='number']::-webkit-outer-spin-button {\n appearance: none;\n margin: 0;\n}\n.phone-input-item-container .country-box.phone {\n display: flex;\n align-items: center;\n}\n.phone-input-item-container .country-box .account-select-opt {\n display: flex;\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n width: 40px;\n height: 100%;\n padding-right: 4px;\n padding-left: 4px;\n cursor: pointer;\n}\n.phone-input-item-container .country-box .account-select-opt .account-select-icon {\n display: flex;\n justify-content: center;\n align-items: center;\n overflow: hidden;\n font-size: 15px;\n}\n.phone-input-item-container .country-box .account-select-opt .down-more {\n margin-left: 6px;\n font-size: 10px;\n}\n.phone-input-item-container .country-box span {\n flex-shrink: 0;\n margin: 0;\n font-size: 15px;\n}\n.phone-input-item-container .country-box .country-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.phone-input-item-container .country-box input {\n flex-shrink: 1;\n box-sizing: border-box;\n width: 100%;\n height: 45px;\n padding: 0 15px;\n border: none;\n outline: none;\n font-weight: 400;\n font-size: 15px;\n line-height: 45px;\n color: var(--text-color);\n background-color: transparent;\n}\n"; // src/components/phoneInputItem/index.tsx var PhoneInputItem = (props) => { const form = props.form; const phoneValue = Form.useWatch(props.name, form); const [countryData, setCountryData] = useState(["United States", "us", "1"]); const { t } = useTranslation(); const [visbSelectCountry, setVisbSelectCountry] = useState(false); const clickRef = useRef(); const forItemRef = useRef(); const [searchValue, setSearchValue] = useState(""); const searchInputRef = useRef(); const countriesList = useMemo(() => { return defaultCountriesData.filter((item) => { return item.join("+").toLowerCase().includes(searchValue.toLowerCase()); }); }, [searchValue]); useClickAway(() => { setVisbSelectCountry(false); }, clickRef); useEffect(() => { if (visbSelectCountry) { setSearchValue(""); } }, [visbSelectCountry]); useEffect(() => { if (phoneValue == null ? void 0 : phoneValue.includes("*")) { return; } const countryCode = `+${countryData[2]}`; const value = (phoneValue || "").replace(/^\+\d+/, "").trim(); form.setFieldsValue({ [props.name]: `${countryCode} ${value}` }); if (value) { form.validateFields(["_phone"]); } }, [countryData, phoneValue]); useEffect(() => { var _a; try { if ((_a = phoneValue == null ? void 0 : phoneValue.includes) == null ? void 0 : _a.call(phoneValue, "*")) { form.setFieldsValue({ _phone: phoneValue }); } else if (phoneValue) { if (isValidPhoneNumber(phoneValue)) { const phoneNumber = parsePhoneNumber(phoneValue); const value = phoneNumber.nationalNumber; form.setFieldsValue({ _phone: value }); const countryCode = phoneNumber.countryCallingCode.toString(); const regionCode = phoneNumber.country; if (countryCode && regionCode) { const items = defaultCountriesData.filter( (item) => item[2].toString() === countryCode && item[1].toLowerCase() === regionCode.toLowerCase() ); if (items && items.length > 0) { setCountryData(items[items.length - 1]); } } } } else { const currentCountry = getCurrentCountry(); if (currentCountry) { setCountryData(currentCountry); } } } catch (error) { } }, [phoneValue]); return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("style", null, phoneInputItem_default), /* @__PURE__ */ React.createElement("div", { className: "phone-input-item-container" }, /* @__PURE__ */ React.createElement( Form.Item, { className: !props.disabled || props.disabled && props.previewMode !== "input" ? "hidden" : "", extra: props.extra, name: props.name }, /* @__PURE__ */ React.createElement(Input, { disabled: props.disabled }) ), /* @__PURE__ */ React.createElement( Form.Item, { name: "_phone", className: props.disabled && props.previewMode == "input" ? "hidden" : "", extra: props.extra, rules: [ { required: true, validator: (rule, value) => { try { if (!value) { return Promise.reject(t("login.input_phone_holder")); } else { try { value = `+${countryData[2]} ${value}`; if (!isValidPhoneNumber(value)) { return Promise.reject(t("login.phone_format_error")); } } catch (error) { return Promise.reject(t("login.phone_format_error")); } } } catch (error) { return Promise.reject(t("login.phone_format_error")); } return Promise.resolve(); } } ] }, /* @__PURE__ */ React.createElement( InputNumber, { placeholder: t("account.mobile"), disabled: props.disabled, controls: false, onChange: (value) => { form.setFieldsValue({ [props.name]: `+${countryData[2]} ${value}` }); }, onFocus: () => { var _a; (_a = document.querySelector(".ant-input-number-group-wrapper")) == null ? void 0 : _a.setAttribute("data-focus", "true"); }, onBlur: () => { var _a; (_a = document.querySelector(".ant-input-number-group-wrapper")) == null ? void 0 : _a.setAttribute("data-focus", "false"); }, addonBefore: /* @__PURE__ */ React.createElement("div", { className: "country-box phone", ref: forItemRef }, /* @__PURE__ */ React.createElement( "div", { className: "prefix-wrap", onClick: () => { if (!props.disabled) { setVisbSelectCountry(!visbSelectCountry); setTimeout(() => { var _a; (_a = searchInputRef.current) == null ? void 0 : _a.focus(); }); } }, ref: clickRef }, /* @__PURE__ */ React.createElement("div", { className: "account-select-opt" }, /* @__PURE__ */ React.createElement("div", { className: "account-select-icon" }, getUnicodeFlagIcon(`${countryData[1]}`)), /* @__PURE__ */ React.createElement(DownOutlined, { className: "down-more" })), /* @__PURE__ */ React.createElement("span", null, "+", countryData[2]) ), visbSelectCountry && /* @__PURE__ */ React.createElement("div", { className: "account-select-country-list " }, /* @__PURE__ */ React.createElement( "div", { className: "account-select-country-item search-input-wrap", onClick: (e) => { e.stopPropagation(); } }, /* @__PURE__ */ React.createElement( Input, { ref: searchInputRef, className: "search-input", type: "text", placeholder: t("login.search_country_holder"), allowClear: true, onChange: (e) => { var _a; const value = ((_a = e == null ? void 0 : e.target) == null ? void 0 : _a.value) || ""; setSearchValue(value); } } ) ), countriesList && !!countriesList.length ? /* @__PURE__ */ React.createElement("div", { className: "p-country-list" }, countriesList.map((item, index) => /* @__PURE__ */ React.createElement( "div", { key: `${item[0]}-${item[1]}-${item[2]}`, className: "account-select-country-item", onClick: () => { setCountryData(item); setVisbSelectCountry(false); } }, /* @__PURE__ */ React.createElement("div", { className: "country-box" }, /* @__PURE__ */ React.createElement("div", { className: "country-flag" }, getUnicodeFlagIcon(`${item[1]}`)), /* @__PURE__ */ React.createElement("span", { className: "country-name" }, item[0])), /* @__PURE__ */ React.createElement("div", { className: "country-code" }, "+" + item[2]) ))) : /* @__PURE__ */ React.createElement("div", { className: "no-data" }, "No data"))) } ) ))); }; var phoneInputItem_default2 = PhoneInputItem; // src/pages/loginAccountBind/index.less var loginAccountBind_default = ".login-account-bind {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 100%;\n overflow-y: auto;\n}\n.login-account-bind .ant-input-status-error:not(.ant-input-disabled, .ant-input-borderless).ant-input {\n background-color: var(--input-background-color);\n}\n.login-account-bind .ant-spin-spinning {\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: 100%;\n padding-bottom: 20vh;\n}\n.login-account-bind .account-title {\n font-weight: 500;\n font-size: 18px;\n}\n.login-account-bind .account-bind-form {\n width: 100%;\n padding: 0 18px;\n margin-top: 34px;\n}\n.login-account-bind .account-bind-form .account-input {\n width: 100%;\n height: 47px;\n border: 1px solid var(--input-border-color);\n border-radius: var(--primary-btn-border-radius);\n color: var(--text-color);\n background-color: var(--input-background-color);\n}\n.login-account-bind .account-bind-form .link-account-hint {\n align-self: flex-start;\n padding-top: 6px;\n font-size: 12px;\n color: var(--secondary-text-color);\n}\n.login-account-bind .account-bind-form .link-btn {\n margin-top: 15px;\n margin-bottom: 30px;\n}\n.login-account-bind .account-bind-form .unlink-btn {\n margin-top: 15px;\n margin-bottom: 30px;\n color: #fff;\n background: #ea4335;\n}\n.login-account-bind .footer-box {\n position: absolute;\n bottom: 10px;\n margin: 0;\n}\n@media screen and (max-height: 350px) {\n .login-account-bind .footer-box {\n position: unset;\n bottom: 0;\n margin-bottom: 10px;\n }\n}\n"; // src/pages/loginAccountBind/index.tsx var LoginAccountBind = (props) => { const state = props; const authType = (state == null ? void 0 : state.authType) || ""; const verifyToken = (state == null ? void 0 : state.verifyToken) || ""; const { t } = useTranslation2(); const [form] = Form2.useForm(); const navigate = useCustomNavigate(); const message = useMessage_default(); const { userInfo } = useUserInfo(); const { showSelectSecurityAccount } = useParticleAuth(); const [submitLoading, setSubmitLoading] = useState2(false); const { runAsync: loginBindingsCheckRequest } = useRequest(checkHasBoundLoginPhoneOrEmail, { manual: true }); const { authCoreModal } = useAuthCoreModal(); const accountList = useMemo2(() => { return getAccountList({ userInfo, t }); }, [userInfo]); const accountInfo = useMemo2(() => { var _a; const data = ((_a = accountList == null ? void 0 : accountList.find) == null ? void 0 : _a.call(accountList, (item) => item.type === authType)) || {}; return data; }, [accountList, authType]); const canLink = useMemo2(() => { return !accountInfo.value && !accountInfo.id; }, [accountInfo]); const canUnlink = useMemo2(() => { return !accountInfo.isOriginal && !canLink; }, [accountInfo]); const bindLoginAccount = () => { form.validateFields().then((values) => { var _a, _b, _c, _d, _e, _f, _g; const targetInputValue = ((_d = (_c = (_b = (_a = form.getFieldsValue()) == null ? void 0 : _a.inputValue) == null ? void 0 : _b.replace(/\s/g, "")) == null ? void 0 : _c.trim) == null ? void 0 : _d.call(_c)) || ""; setSubmitLoading(true); if (authType === "phone" && ((_e = userInfo == null ? void 0 : userInfo.security_account) == null ? void 0 : _e.phone) === targetInputValue) { Modal.error({ title: t("new.duplicate_phonel_bindings"), wrapClassName: "auth-core-modal-error", getContainer: () => { return authCoreModal.rootBody; } }); setSubmitLoading(false); return; } else if (authType === "email" && ((_g = (_f = userInfo == null ? void 0 : userInfo.security_account) == null ? void 0 : _f.email) == null ? void 0 : _g.toLowerCase()) === (targetInputValue == null ? void 0 : targetInputValue.toLowerCase())) { Modal.error({ title: t("new.duplicate_email_bindings"), wrapClassName: "auth-core-modal-error", getContainer: () => { return authCoreModal.rootBody; } }); setSubmitLoading(false); return; } const params = {}; if (authType === AuthType.phone) { params.phone = targetInputValue; } else { params.email = targetInputValue; } loginBindingsCheckRequest(params).then((res) => { navigate("/account/verify", { state: { account: targetInputValue, authType, verifyToken, pageType: "bind_login_account" /* BindLoginAccount */ } }); setSubmitLoading(false); }).catch((error) => { setSubmitLoading(false); if (error.error_code === 20109) { Modal.error({ title: authType === AuthType.phone ? t("error.server_phone_20109") : t("error.server_email_20109"), wrapClassName: "auth-core-modal-error", getContainer: () => { return authCoreModal.rootBody; } }); } else { message.error(error.message); } }); }); }; const { run: toAccountVerify } = useThrottleFn( (params) => { navigate("/account/verify", { state: { account: params.account, authType, unbindAccount: form.getFieldValue("inputValue"), pageType: "unbind_login_account" /* UnbindLoginAccount */ } }); }, { wait: 3e3 } ); const unbindLoginAccount = () => { var _a, _b, _c, _d; if (((_a = userInfo == null ? void 0 : userInfo.security_account) == null ? void 0 : _a.email) && ((_b = userInfo == null ? void 0 : userInfo.security_account) == null ? void 0 : _b.phone)) { showSelectSecurityAccount(true, { authType, unbindAccount: form.getFieldValue("inputValue"), pageType: "unbind_login_account" /* UnbindLoginAccount */ }); } else { toAccountVerify({ account: ((_c = userInfo == null ? void 0 : userInfo.security_account) == null ? void 0 : _c.email) || ((_d = userInfo == null ? void 0 : userInfo.security_account) == null ? void 0 : _d.phone) }); } }; useEffect2(() => { if ((accountInfo == null ? void 0 : accountInfo.value) || (accountInfo == null ? void 0 : accountInfo.id)) { if (authType === AuthType.phone) { const phoneNumber = parsePhoneNumber2(accountInfo == null ? void 0 : accountInfo.value.replace(/\s/g, "")); const countryCode = phoneNumber.countryCallingCode; const nationalNumber = phoneNumber.nationalNumber; form.setFieldsValue({ inputValue: encryptValue(`+${countryCode} ${nationalNumber}`) }); } else { form.setFieldsValue({ inputValue: encryptValue((accountInfo == null ? void 0 : accountInfo.value) || (accountInfo == null ? void 0 : accountInfo.id) || "") }); } } }, [accountInfo == null ? void 0 : accountInfo.value, accountInfo == null ? void 0 : accountInfo.id, authType]); return /* @__PURE__ */ React2.createElement("div", { className: "login-account-bind " }, /* @__PURE__ */ React2.createElement("style", null, loginAccountBind_default), /* @__PURE__ */ React2.createElement(header_default, { displayBackBtn: true }, accountInfo.name), /* @__PURE__ */ React2.createElement(Form2, { className: "account-bind-form", layout: "vertical", form, onFinish: bindLoginAccount }, authType === AuthType.phone ? /* @__PURE__ */ React2.createElement( phoneInputItem_default2, { name: "inputValue", form, disabled: !canLink, previewMode: "input", extra: /* @__PURE__ */ React2.createElement("div", { className: "link-account-hint" }, t("new.link_account_hint").format(accountInfo.name)) } ) : /* @__PURE__ */ React2.createElement( Form2.Item, { name: "inputValue", validateTrigger: "onBlur", extra: /* @__PURE__ */ React2.createElement("div", { className: "link-account-hint" }, t("new.link_account_hint").format(accountInfo.name)), rules: [ { required: true, validator: async (rule, value) => { if (!value) { return Promise.reject(t("account.input_vaild_email")); } else if (!EmailRegExp.test(value)) { return Promise.reject(t("login.email_format_error")); } return Promise.resolve(); } } ] }, /* @__PURE__ */ React2.createElement( Input2, { className: "account-input", placeholder: accountInfo.name, disabled: !canLink, onChange: (e) => form.setFields([ { name: "email", value: e.target.value, errors: [] } ]) } ) ), /* @__PURE__ */ React2.createElement(Form2.Item, null, canLink ? /* @__PURE__ */ React2.createElement( Button, { className: "primary-antd-btn link-btn", loading: submitLoading, htmlType: "submit" }, t("account.link") ) : /* @__PURE__ */ React2.createElement(React2.Fragment, null))), /* @__PURE__ */ React2.createElement(power_footer_default, null)); }; var loginAccountBind_default2 = LoginAccountBind; export { loginAccountBind_default2 as default }; //# sourceMappingURL=loginAccountBind-RTTVHPHA.js.map