// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import React from "react"; import {Button, Form, Input, Result} from "antd"; import * as Setting from "../Setting"; import * as AuthBackend from "./AuthBackend"; import * as ProviderButton from "./ProviderButton"; import i18next from "i18next"; import * as Util from "./Util"; import {authConfig} from "./Auth"; import * as ApplicationBackend from "../backend/ApplicationBackend"; import * as AgreementModal from "../common/modal/AgreementModal"; import {SendCodeInput} from "../common/SendCodeInput"; import RegionSelect from "../common/select/RegionSelect"; import CustomGithubCorner from "../common/CustomGithubCorner"; import LanguageSelect from "../common/select/LanguageSelect"; import {withRouter} from "react-router-dom"; import {CountryCodeSelect} from "../common/select/CountryCodeSelect"; import * as PasswordChecker from "../common/PasswordChecker"; const formItemLayout = { labelCol: { xs: { span: 24, }, sm: { span: 8, }, }, wrapperCol: { xs: { span: 24, }, sm: { span: 16, }, }, }; export const tailFormItemLayout = { wrapperCol: { xs: { span: 24, offset: 0, }, sm: { span: 16, offset: 8, }, }, }; class SignupPage extends React.Component { constructor(props) { super(props); this.state = { classes: props, applicationName: (props.applicationName ?? props.match?.params?.applicationName) ?? null, email: "", phone: "", countryCode: "", emailCode: "", phoneCode: "", validEmail: false, validPhone: false, region: "", isTermsOfUseVisible: false, termsOfUseContent: "", }; this.form = React.createRef(); } componentDidMount() { const oAuthParams = Util.getOAuthGetParameters(); if (oAuthParams !== null) { const signinUrl = window.location.href.replace("/signup/oauth/authorize", "/login/oauth/authorize"); sessionStorage.setItem("signinUrl", signinUrl); } if (this.getApplicationObj() === undefined) { if (this.state.applicationName !== null) { this.getApplication(this.state.applicationName); } else if (oAuthParams !== null) { this.getApplicationLogin(oAuthParams); } else { Setting.showMessage("error", `Unknown application name: ${this.state.applicationName}`); this.onUpdateApplication(null); } } } getApplication(applicationName) { if (applicationName === undefined) { return; } ApplicationBackend.getApplication("admin", applicationName) .then((res) => { if (res.status === "error") { Setting.showMessage("error", res.msg); return; } this.onUpdateApplication(res.data); }); } getApplicationLogin(oAuthParams) { AuthBackend.getApplicationLogin(oAuthParams) .then((res) => { if (res.status === "ok") { const application = res.data; this.onUpdateApplication(application); } else { this.onUpdateApplication(null); this.setState({ msg: res.msg, }); } }); } getResultPath(application, signupParams) { if (signupParams?.plan && signupParams?.pricing) { // the prompt page needs the user to be signed in, so for paid-user sign up, just go to buy-plan page return `/buy-plan/${application.organization}/${signupParams?.pricing}?user=${signupParams.username}&plan=${signupParams.plan}`; } if (authConfig.appName === application.name) { return "/result"; } else { if (Setting.hasPromptPage(application)) { return `/prompt/${application.name}`; } else { return `/result/${application.name}`; } } } getApplicationObj() { return this.props.application; } onUpdateAccount(account) { this.props.onUpdateAccount(account); } onUpdateApplication(application) { this.props.onUpdateApplication(application); } parseOffset(offset) { if (offset === 2 || offset === 4 || Setting.inIframe() || Setting.isMobile()) { return "0 auto"; } if (offset === 1) { return "0 10%"; } if (offset === 3) { return "0 60%"; } } onFinish(values) { const application = this.getApplicationObj(); const params = new URLSearchParams(window.location.search); values.plan = params.get("plan"); values.pricing = params.get("pricing"); AuthBackend.signup(values) .then((res) => { if (res.status === "ok") { // the user's id will be returned by `signup()`, if user signup by phone, the `username` in `values` is undefined. values.username = res.data.split("/")[1]; if (Setting.hasPromptPage(application) && (!values.plan || !values.pricing)) { AuthBackend.getAccount("") .then((res) => { let account = null; if (res.status === "ok") { account = res.data; account.organization = res.data2; this.onUpdateAccount(account); Setting.goToLinkSoft(this, this.getResultPath(application, values)); } else { Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`); } }); } else { Setting.goToLinkSoft(this, this.getResultPath(application, values)); } } else { Setting.showMessage("error", i18next.t(`signup:${res.msg}`)); } }); } onFinishFailed(values, errorFields, outOfDate) { this.form.current.scrollToField(errorFields[0].name); } isProviderVisible(providerItem) { return Setting.isProviderVisibleForSignUp(providerItem); } renderFormItem(application, signupItem) { if (!signupItem.visible) { return null; } const required = signupItem.required; if (signupItem.name === "Username") { return ( ); } else if (signupItem.name === "Display name") { if (signupItem.rule === "First, last" && Setting.getLanguage() !== "zh") { return ( ); } return ( ); } else if (signupItem.name === "Affiliation") { return ( ); } else if (signupItem.name === "ID card") { return ( ); } else if (signupItem.name === "Country/Region") { return ( {this.setState({region: value});}} /> ); } else if (signupItem.name === "Email") { return ( { if (this.state.email !== "" && !Setting.isValidEmail(this.state.email)) { this.setState({validEmail: false}); return Promise.reject(i18next.t("signup:The input is not valid Email!")); } this.setState({validEmail: true}); return Promise.resolve(); }, }, ]} > this.setState({email: e.target.value})} /> { signupItem.rule !== "No verification" && } ); } else if (signupItem.name === "Phone") { return ( ({ validator: (_, value) => { if (!required && !value) { return Promise.resolve(); } if (value && !Setting.isValidPhone(value, getFieldValue("countryCode"))) { this.setState({validPhone: false}); return Promise.reject(i18next.t("signup:The input is not valid Phone!")); } this.setState({validPhone: true}); return Promise.resolve(); }, }), ]} > this.setState({phone: e.target.value})} /> { signupItem.rule !== "No verification" && } ); } else if (signupItem.name === "Password") { return ( { const errorMsg = PasswordChecker.checkPasswordComplexity(value, application.organizationObj.passwordOptions); if (errorMsg === "") { return Promise.resolve(); } else { return Promise.reject(errorMsg); } }, }, ]} hasFeedback > ); } else if (signupItem.name === "Confirm password") { return ( ({ validator(rule, value) { if (!value || getFieldValue("password") === value) { return Promise.resolve(); } return Promise.reject(i18next.t("signup:Your confirmed password is inconsistent with the password!")); }, }), ]} > ); } else if (signupItem.name === "Invitation code") { return ( ); } else if (signupItem.name === "Agreement") { return AgreementModal.renderAgreementFormItem(application, required, tailFormItemLayout, this); } } renderForm(application) { if (!application.enableSignUp) { return ( Setting.redirectToLoginPage(application, this.props.history)}> { i18next.t("login:Sign In") } , ]} > ); } return (
this.onFinish(values)} onFinishFailed={(errorInfo) => this.onFinishFailed(errorInfo.values, errorInfo.errorFields, errorInfo.outOfDate)} initialValues={{ application: application.name, organization: application.organization, countryCode: application.organizationObj.countryCodes?.[0], }} size="large" layout={Setting.isMobile() ? "vertical" : "horizontal"} style={{width: Setting.isMobile() ? "300px" : "400px"}} > { application.signupItems?.map(signupItem => this.renderFormItem(application, signupItem)) }   {i18next.t("signup:Have account?")}  { const linkInStorage = sessionStorage.getItem("signinUrl"); if (linkInStorage !== null && linkInStorage !== "") { Setting.goToLink(linkInStorage); } else { Setting.redirectToLoginPage(application, this.props.history); } }}> {i18next.t("signup:sign in now")} { application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => { return ProviderButton.renderProviderLogo(providerItem.provider, application, 30, 5, "small", this.props.location); }) }
); } render() { const application = this.getApplicationObj(); if (application === undefined || application === null) { return null; } if (application.signupHtml !== "") { return (
); } return (
{Setting.inIframe() || Setting.isMobile() ? null :
} {Setting.inIframe() || !Setting.isMobile() ? null :
}
{ Setting.renderHelmet(application) } { Setting.renderLogo(application) } { this.renderForm(application) }
); } } export default withRouter(SignupPage);