mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-11 19:44:15 +00:00
added recovery ui
This commit is contained in:
parent
5b6d36744c
commit
be0c61a028
@ -9,452 +9,480 @@ import config from "@config"
|
|||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
const stepsOnError = {
|
const stepsOnError = {
|
||||||
username: "This username or email is not exist",
|
username: "This username or email is not exist",
|
||||||
password: "Password is incorrect",
|
password: "Password is incorrect",
|
||||||
}
|
}
|
||||||
|
|
||||||
const stepsValidations = {
|
const stepsValidations = {
|
||||||
username: async (state) => {
|
username: async (state) => {
|
||||||
const check = await AuthModel.usernameValidation(state.username).catch((err) => {
|
const check = await AuthModel.usernameValidation(state.username).catch(
|
||||||
return {
|
(err) => {
|
||||||
exists: false
|
return {
|
||||||
}
|
exists: false,
|
||||||
})
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
return check.exists
|
return check.exists
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const phasesToSteps = {
|
const phasesToSteps = {
|
||||||
0: "username",
|
0: "username",
|
||||||
1: "password",
|
1: "password",
|
||||||
}
|
}
|
||||||
|
|
||||||
class Login extends React.Component {
|
class Login extends React.Component {
|
||||||
static pageStatement = {
|
static pageStatement = {
|
||||||
bottomBarAllowed: false
|
bottomBarAllowed: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
loading: false,
|
loading: false,
|
||||||
loginInputs: {},
|
loginInputs: {},
|
||||||
error: null,
|
error: null,
|
||||||
phase: 0,
|
phase: 0,
|
||||||
|
|
||||||
mfa_required: null,
|
mfa_required: null,
|
||||||
activation: null,
|
activation: null,
|
||||||
forbidden: false,
|
forbidden: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
formRef = React.createRef()
|
formRef = React.createRef()
|
||||||
|
|
||||||
handleFinish = async () => {
|
handleFinish = async () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
mfa_required: false,
|
mfa_required: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
username: this.state.loginInputs.username,
|
username: this.state.loginInputs.username,
|
||||||
password: this.state.loginInputs.password,
|
password: this.state.loginInputs.password,
|
||||||
mfa_code: this.state.loginInputs.mfa_code,
|
mfa_code: this.state.loginInputs.mfa_code,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clearError()
|
this.clearError()
|
||||||
this.toggleLoading(true)
|
this.toggleLoading(true)
|
||||||
|
|
||||||
await AuthModel.login(payload, this.onDone).catch((error) => {
|
await AuthModel.login(payload, this.onDone).catch((error) => {
|
||||||
if (error.response.data) {
|
if (error.response.data) {
|
||||||
if (error.response.data.violation) {
|
if (error.response.data.violation) {
|
||||||
return this.setState({
|
return this.setState({
|
||||||
forbidden: error.response.data.violation
|
forbidden: error.response.data.violation,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error.response.data.activation_required) {
|
if (error.response.data.activation_required) {
|
||||||
return this.setState({
|
return this.setState({
|
||||||
activation: {
|
activation: {
|
||||||
required: true,
|
required: true,
|
||||||
user_id: error.response.data.user_id,
|
user_id: error.response.data.user_id,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.error(error, error.response)
|
console.error(error, error.response)
|
||||||
|
|
||||||
this.toggleLoading(false)
|
this.toggleLoading(false)
|
||||||
this.onError(error.response.data.error)
|
this.onError(error.response.data.error)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onDone = async ({ mfa_required } = {}) => {
|
onDone = async ({ mfa_required } = {}) => {
|
||||||
if (mfa_required) {
|
if (mfa_required) {
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
mfa_required: mfa_required,
|
mfa_required: mfa_required,
|
||||||
})
|
})
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof this.props.close === "function") {
|
if (typeof this.props.close === "function") {
|
||||||
await this.props.close({
|
await this.props.close({
|
||||||
unlock: true
|
unlock: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof this.props.onDone === "function") {
|
if (typeof this.props.onDone === "function") {
|
||||||
await this.props.onDone()
|
await this.props.onDone()
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickActivateAccount = async () => {
|
onClickActivateAccount = async () => {
|
||||||
const activationObj = this.state.activation
|
const activationObj = this.state.activation
|
||||||
|
|
||||||
if (!activationObj) {
|
if (!activationObj) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await AuthModel.activateAccount(
|
await AuthModel.activateAccount(
|
||||||
this.state.activation.user_id,
|
this.state.activation.user_id,
|
||||||
this.state.activation.code
|
this.state.activation.code,
|
||||||
)
|
)
|
||||||
|
|
||||||
this.handleFinish()
|
this.handleFinish()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.setState({
|
this.setState({
|
||||||
activation: {
|
activation: {
|
||||||
...this.state.activation,
|
...this.state.activation,
|
||||||
error: error
|
error: error,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickResendActivationCode = async () => {
|
onClickResendActivationCode = async () => {
|
||||||
const activationObj = this.state.activation
|
const activationObj = this.state.activation
|
||||||
|
|
||||||
if (!activationObj) {
|
if (!activationObj) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const rensendObj = await AuthModel.resendActivationCode(activationObj.user_id)
|
const rensendObj = await AuthModel.resendActivationCode(
|
||||||
.catch((error) => {
|
activationObj.user_id,
|
||||||
app.message.info(`Please try again later...`)
|
).catch((error) => {
|
||||||
return null
|
app.message.info(`Please try again later...`)
|
||||||
})
|
return null
|
||||||
|
})
|
||||||
if (rensendObj) {
|
|
||||||
this.setState({
|
if (rensendObj) {
|
||||||
activation: {
|
this.setState({
|
||||||
...this.state.activation,
|
activation: {
|
||||||
resended: rensendObj.date,
|
...this.state.activation,
|
||||||
},
|
resended: rensendObj.date,
|
||||||
})
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
onClickForgotPassword = () => {
|
|
||||||
if (this.props.locked) {
|
onClickForgotPassword = () => {
|
||||||
this.props.unlock()
|
if (this.props.locked) {
|
||||||
}
|
this.props.unlock()
|
||||||
|
}
|
||||||
if (typeof this.props.close === "function") {
|
|
||||||
this.props.close()
|
if (typeof this.props.close === "function") {
|
||||||
}
|
this.props.close()
|
||||||
|
}
|
||||||
app.location.push("/apr")
|
|
||||||
}
|
app.location.push("/auth?key=recover")
|
||||||
|
}
|
||||||
toggleLoading = (to) => {
|
|
||||||
if (typeof to === "undefined") {
|
toggleLoading = (to) => {
|
||||||
to = !this.state.loading
|
if (typeof to === "undefined") {
|
||||||
}
|
to = !this.state.loading
|
||||||
|
}
|
||||||
this.setState({
|
|
||||||
loading: to
|
this.setState({
|
||||||
})
|
loading: to,
|
||||||
}
|
})
|
||||||
|
}
|
||||||
clearError = () => {
|
|
||||||
this.setState({
|
clearError = () => {
|
||||||
error: null
|
this.setState({
|
||||||
})
|
error: null,
|
||||||
}
|
})
|
||||||
|
}
|
||||||
onError = (error) => {
|
|
||||||
this.setState({
|
onError = (error) => {
|
||||||
error: error
|
this.setState({
|
||||||
})
|
error: error,
|
||||||
}
|
})
|
||||||
|
}
|
||||||
onUpdateInput = (input, value) => {
|
|
||||||
if (input === "username") {
|
onUpdateInput = (input, value) => {
|
||||||
value = value.toLowerCase()
|
if (input === "username") {
|
||||||
value = value.trim()
|
value = value.toLowerCase()
|
||||||
}
|
value = value.trim()
|
||||||
|
}
|
||||||
// remove error from ref
|
|
||||||
this.formRef.current.setFields([
|
// remove error from ref
|
||||||
{
|
this.formRef.current.setFields([
|
||||||
name: input,
|
{
|
||||||
errors: []
|
name: input,
|
||||||
}
|
errors: [],
|
||||||
])
|
},
|
||||||
|
])
|
||||||
this.setState({
|
|
||||||
loginInputs: {
|
this.setState({
|
||||||
...this.state.loginInputs,
|
loginInputs: {
|
||||||
[input]: value
|
...this.state.loginInputs,
|
||||||
}
|
[input]: value,
|
||||||
})
|
},
|
||||||
}
|
})
|
||||||
|
}
|
||||||
nextStep = async () => {
|
|
||||||
const phase = phasesToSteps[this.state.phase]
|
nextStep = async () => {
|
||||||
|
const phase = phasesToSteps[this.state.phase]
|
||||||
if (typeof stepsValidations[phase] === "function") {
|
|
||||||
this.toggleLoading(true)
|
if (typeof stepsValidations[phase] === "function") {
|
||||||
|
this.toggleLoading(true)
|
||||||
const result = await stepsValidations[phase](this.state.loginInputs)
|
|
||||||
|
const result = await stepsValidations[phase](this.state.loginInputs)
|
||||||
this.toggleLoading(false)
|
|
||||||
|
this.toggleLoading(false)
|
||||||
if (!result) {
|
|
||||||
this.formRef.current.setFields([
|
if (!result) {
|
||||||
{
|
this.formRef.current.setFields([
|
||||||
name: phase,
|
{
|
||||||
errors: [stepsOnError[phase]]
|
name: phase,
|
||||||
},
|
errors: [stepsOnError[phase]],
|
||||||
])
|
},
|
||||||
|
])
|
||||||
return false
|
|
||||||
}
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const to = this.state.phase + 1
|
|
||||||
|
const to = this.state.phase + 1
|
||||||
if (!phasesToSteps[to]) {
|
|
||||||
return this.handleFinish()
|
if (!phasesToSteps[to]) {
|
||||||
}
|
return this.handleFinish()
|
||||||
|
}
|
||||||
this.setState({
|
|
||||||
phase: to
|
this.setState({
|
||||||
})
|
phase: to,
|
||||||
}
|
})
|
||||||
|
}
|
||||||
prevStep = () => {
|
|
||||||
const to = this.state.phase - 1
|
prevStep = () => {
|
||||||
|
const to = this.state.phase - 1
|
||||||
if (!phasesToSteps[to]) {
|
|
||||||
console.warn("No step found for phase", to)
|
if (!phasesToSteps[to]) {
|
||||||
|
console.warn("No step found for phase", to)
|
||||||
return
|
|
||||||
}
|
return
|
||||||
|
}
|
||||||
this.setState({
|
|
||||||
phase: to,
|
this.setState({
|
||||||
mfa_required: null,
|
phase: to,
|
||||||
})
|
mfa_required: null,
|
||||||
}
|
})
|
||||||
|
}
|
||||||
canNext = () => {
|
|
||||||
if (this.state.loading) {
|
canNext = () => {
|
||||||
return false
|
if (this.state.loading) {
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
const { phase } = this.state
|
|
||||||
|
const { phase } = this.state
|
||||||
const step = phasesToSteps[phase]
|
|
||||||
|
const step = phasesToSteps[phase]
|
||||||
return !!this.state.loginInputs[step]
|
|
||||||
}
|
return !!this.state.loginInputs[step]
|
||||||
|
}
|
||||||
render() {
|
|
||||||
if (this.state.forbidden) {
|
render() {
|
||||||
return <div className="login_wrapper">
|
if (this.state.forbidden) {
|
||||||
<div className="content">
|
return (
|
||||||
<h1>Access denied</h1>
|
<div className="login_wrapper">
|
||||||
<h3>Your account has been disabled due a violation to our terms of service</h3>
|
<div className="content">
|
||||||
|
<h1>Access denied</h1>
|
||||||
<p>Here is a detailed description of the violation</p>
|
<h3>
|
||||||
|
Your account has been disabled due a violation to
|
||||||
<div className="field-error">
|
our terms of service
|
||||||
{this.state.forbidden.reason}
|
</h3>
|
||||||
</div>
|
|
||||||
|
<p>Here is a detailed description of the violation</p>
|
||||||
<p>If you think this is an error, or you want to apeel this decision please contact our support</p>
|
|
||||||
</div>
|
<div className="field-error">
|
||||||
</div>
|
{this.state.forbidden.reason}
|
||||||
}
|
</div>
|
||||||
|
|
||||||
if (this.state.activation) {
|
<p>
|
||||||
return <div className="login_wrapper">
|
If you think this is an error, or you want to apeel
|
||||||
<div className="content">
|
this decision please contact our support
|
||||||
<h1>Activate your Account</h1>
|
</p>
|
||||||
<p>We have sent you an email with a code that you need to enter below in order to activate your account.</p>
|
</div>
|
||||||
|
</div>
|
||||||
<antd.Input.OTP
|
)
|
||||||
length={6}
|
}
|
||||||
onChange={(code) => this.setState({
|
|
||||||
activation: {
|
if (this.state.activation) {
|
||||||
...this.state.activation,
|
return (
|
||||||
code: code,
|
<div className="login_wrapper">
|
||||||
}
|
<div className="content">
|
||||||
})}
|
<h1>Activate your Account</h1>
|
||||||
/>
|
<p>
|
||||||
|
We have sent you an email with a code that you need
|
||||||
<div className="resend">
|
to enter below in order to activate your account.
|
||||||
{
|
</p>
|
||||||
this.state.activation.resended && <antd.Alert
|
|
||||||
message={`Mail resended`}
|
<antd.Input.OTP
|
||||||
/>
|
length={6}
|
||||||
}
|
onChange={(code) =>
|
||||||
<a
|
this.setState({
|
||||||
href="#"
|
activation: {
|
||||||
onClick={this.onClickResendActivationCode}
|
...this.state.activation,
|
||||||
>
|
code: code,
|
||||||
Didn't receive the email?
|
},
|
||||||
</a>
|
})
|
||||||
</div>
|
}
|
||||||
|
/>
|
||||||
{
|
|
||||||
this.state.activation.error && <div className="field-error">
|
<div className="resend">
|
||||||
{this.state.activation.error.response.data.error}
|
{this.state.activation.resended && (
|
||||||
</div>
|
<antd.Alert message={`Mail resended`} />
|
||||||
}
|
)}
|
||||||
|
<a
|
||||||
<antd.Button
|
href="#"
|
||||||
onClick={this.onClickActivateAccount}
|
onClick={this.onClickResendActivationCode}
|
||||||
>
|
>
|
||||||
Activate
|
Didn't receive the email?
|
||||||
</antd.Button>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
}
|
{this.state.activation.error && (
|
||||||
|
<div className="field-error">
|
||||||
return <div className="login_wrapper">
|
{
|
||||||
<div className="content">
|
this.state.activation.error.response.data
|
||||||
<div className="header">
|
.error
|
||||||
<h1>
|
}
|
||||||
Sign in
|
</div>
|
||||||
</h1>
|
)}
|
||||||
<h3>
|
|
||||||
To continue to {config.app.siteName}
|
<antd.Button onClick={this.onClickActivateAccount}>
|
||||||
</h3>
|
Activate
|
||||||
</div>
|
</antd.Button>
|
||||||
|
</div>
|
||||||
<antd.Form
|
</div>
|
||||||
name="login"
|
)
|
||||||
className="fields"
|
}
|
||||||
autoCorrect="off"
|
|
||||||
autoCapitalize="none"
|
return (
|
||||||
autoComplete="on"
|
<div className="login_wrapper">
|
||||||
onFinish={this.handleFinish}
|
<div className="content">
|
||||||
ref={this.formRef}
|
<div className="header">
|
||||||
>
|
<h1>Sign in</h1>
|
||||||
<antd.Form.Item
|
<h3>To continue to {config.app.siteName}</h3>
|
||||||
name="username"
|
</div>
|
||||||
className="field"
|
|
||||||
>
|
<antd.Form
|
||||||
<span><Icons.FiMail /> Username or Email</span>
|
name="login"
|
||||||
<antd.Input
|
className="fields"
|
||||||
placeholder="myusername / myemail@example.com"
|
autoCorrect="off"
|
||||||
onChange={(e) => this.onUpdateInput("username", e.target.value)}
|
autoCapitalize="none"
|
||||||
onPressEnter={this.nextStep}
|
autoComplete="on"
|
||||||
disabled={this.state.phase !== 0}
|
onFinish={this.handleFinish}
|
||||||
autoFocus
|
ref={this.formRef}
|
||||||
/>
|
>
|
||||||
</antd.Form.Item>
|
<antd.Form.Item name="username" className="field">
|
||||||
|
<span>
|
||||||
<antd.Form.Item
|
<Icons.FiMail /> Username or Email
|
||||||
name="password"
|
</span>
|
||||||
className={classnames(
|
<antd.Input
|
||||||
"field",
|
placeholder="myusername / myemail@example.com"
|
||||||
{
|
onChange={(e) =>
|
||||||
["hidden"]: this.state.phase !== 1,
|
this.onUpdateInput(
|
||||||
}
|
"username",
|
||||||
)}
|
e.target.value,
|
||||||
>
|
)
|
||||||
<span><Icons.FiLock /> Password</span>
|
}
|
||||||
<antd.Input.Password
|
onPressEnter={this.nextStep}
|
||||||
//placeholder="********"
|
disabled={this.state.phase !== 0}
|
||||||
onChange={(e) => this.onUpdateInput("password", e.target.value)}
|
autoFocus
|
||||||
onPressEnter={this.nextStep}
|
/>
|
||||||
/>
|
</antd.Form.Item>
|
||||||
</antd.Form.Item>
|
|
||||||
|
<antd.Form.Item
|
||||||
<antd.Form.Item
|
name="password"
|
||||||
name="mfa_code"
|
className={classnames("field", {
|
||||||
className={classnames(
|
["hidden"]: this.state.phase !== 1,
|
||||||
"field",
|
})}
|
||||||
{
|
>
|
||||||
["hidden"]: !this.state.mfa_required,
|
<span>
|
||||||
}
|
<Icons.FiLock /> Password
|
||||||
)}
|
</span>
|
||||||
>
|
<antd.Input.Password
|
||||||
<span><Icons.FiLock /> Verification Code</span>
|
//placeholder="********"
|
||||||
|
onChange={(e) =>
|
||||||
{
|
this.onUpdateInput(
|
||||||
this.state.mfa_required && <>
|
"password",
|
||||||
<p>We send a verification code to [{this.state.mfa_required.sended_to}]</p>
|
e.target.value,
|
||||||
|
)
|
||||||
<p>
|
}
|
||||||
Didn't receive the code? <a onClick={this.handleFinish}>Resend</a>
|
onPressEnter={this.nextStep}
|
||||||
</p>
|
/>
|
||||||
</>
|
</antd.Form.Item>
|
||||||
}
|
|
||||||
|
<antd.Form.Item
|
||||||
<antd.Input.OTP
|
name="mfa_code"
|
||||||
length={4}
|
className={classnames("field", {
|
||||||
formatter={(str) => str.toUpperCase()}
|
["hidden"]: !this.state.mfa_required,
|
||||||
onChange={(code) => this.onUpdateInput("mfa_code", code)}
|
})}
|
||||||
onPressEnter={this.nextStep}
|
>
|
||||||
/>
|
<span>
|
||||||
</antd.Form.Item>
|
<Icons.FiLock /> Verification Code
|
||||||
</antd.Form>
|
</span>
|
||||||
|
|
||||||
<div className="component-row">
|
{this.state.mfa_required && (
|
||||||
{
|
<>
|
||||||
this.state.phase > 0 && <antd.Button
|
<p>
|
||||||
onClick={this.prevStep}
|
We send a verification code to [
|
||||||
disabled={this.state.loading}
|
{this.state.mfa_required.sended_to}]
|
||||||
>
|
</p>
|
||||||
Back
|
|
||||||
</antd.Button>
|
<p>
|
||||||
}
|
Didn't receive the code?{" "}
|
||||||
<antd.Button
|
<a onClick={this.handleFinish}>
|
||||||
onClick={this.nextStep}
|
Resend
|
||||||
disabled={!this.canNext() || this.state.loading}
|
</a>
|
||||||
loading={this.state.loading}
|
</p>
|
||||||
>
|
</>
|
||||||
Continue
|
)}
|
||||||
</antd.Button>
|
|
||||||
</div>
|
<antd.Input.OTP
|
||||||
|
length={4}
|
||||||
{
|
formatter={(str) => str.toUpperCase()}
|
||||||
this.state.error && <div className="field-error">
|
onChange={(code) =>
|
||||||
{this.state.error}
|
this.onUpdateInput("mfa_code", code)
|
||||||
</div>
|
}
|
||||||
}
|
onPressEnter={this.nextStep}
|
||||||
|
/>
|
||||||
<div className="field" onClick={this.onClickForgotPassword}>
|
</antd.Form.Item>
|
||||||
<a>Forgot your password?</a>
|
</antd.Form>
|
||||||
</div>
|
|
||||||
</div>
|
<div className="component-row">
|
||||||
</div>
|
{this.state.phase > 0 && (
|
||||||
}
|
<antd.Button
|
||||||
|
onClick={this.prevStep}
|
||||||
|
disabled={this.state.loading}
|
||||||
|
>
|
||||||
|
Back
|
||||||
|
</antd.Button>
|
||||||
|
)}
|
||||||
|
<antd.Button
|
||||||
|
onClick={this.nextStep}
|
||||||
|
disabled={!this.canNext() || this.state.loading}
|
||||||
|
loading={this.state.loading}
|
||||||
|
>
|
||||||
|
Continue
|
||||||
|
</antd.Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{this.state.error && (
|
||||||
|
<div className="field-error">{this.state.error}</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="field" onClick={this.onClickForgotPassword}>
|
||||||
|
<a>Forgot your password?</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ForwardedLogin = (props) => {
|
const ForwardedLogin = (props) => {
|
||||||
return <Login {...props} />
|
return <Login {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ForwardedLogin
|
export default ForwardedLogin
|
149
packages/app/src/pages/auth/forms/recovery/index.jsx
Normal file
149
packages/app/src/pages/auth/forms/recovery/index.jsx
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { Input } from "antd"
|
||||||
|
|
||||||
|
import FormWithSteps from "@components/FormWithSteps"
|
||||||
|
import AuthModel from "@models/auth"
|
||||||
|
|
||||||
|
const Steps = [
|
||||||
|
{
|
||||||
|
id: "email_input",
|
||||||
|
render: ({ updateState, values }) => {
|
||||||
|
function onChangeInput(e) {
|
||||||
|
updateState("account", e.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>
|
||||||
|
First enter your account or email address to find your
|
||||||
|
associated account.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
placeholder="@username or email"
|
||||||
|
value={values.account}
|
||||||
|
onChange={onChangeInput}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
validate: (values) => {
|
||||||
|
return values.account && values.account.length > 3
|
||||||
|
},
|
||||||
|
onNext: async ({ values, updateState, setError }) => {
|
||||||
|
try {
|
||||||
|
const recoverSession = await AuthModel.recoverPassword(
|
||||||
|
values.account,
|
||||||
|
)
|
||||||
|
|
||||||
|
updateState("recoverSession", recoverSession)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error.response.data)
|
||||||
|
setError(error.response.data.error)
|
||||||
|
|
||||||
|
return {
|
||||||
|
cancel: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "new_password",
|
||||||
|
render: ({ updateState, values }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>Enter a new password for your account.</p>
|
||||||
|
|
||||||
|
<Input.Password
|
||||||
|
placeholder="New Password"
|
||||||
|
value={values.new_password}
|
||||||
|
onChange={(e) =>
|
||||||
|
updateState("new_password", e.target.value)
|
||||||
|
}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
validate: (values) => {
|
||||||
|
if (!values.new_password) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return values.new_password.length >= 8
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "otp_input",
|
||||||
|
render: ({ updateState, values }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>
|
||||||
|
We've sent you a code to your email [
|
||||||
|
{values.recoverSession.email}]
|
||||||
|
</p>
|
||||||
|
<p>Expires in {values.recoverSession.expires_in} minutes</p>
|
||||||
|
|
||||||
|
<Input.OTP
|
||||||
|
length={values.recoverSession.code_length}
|
||||||
|
onChange={(value) => updateState("otp", value)}
|
||||||
|
value={values.otp}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
validate: (values) => {
|
||||||
|
if (!values.otp) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return values.otp.length === values.recoverSession.code_length
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const OnFinish = async ({ values, setError }) => {
|
||||||
|
try {
|
||||||
|
const result = await AuthModel.changePassword({
|
||||||
|
newPassword: values.new_password,
|
||||||
|
code: values.otp,
|
||||||
|
verificationToken: values.recoverSession.verificationToken,
|
||||||
|
})
|
||||||
|
|
||||||
|
app.message.info("Password changed successfully")
|
||||||
|
app.navigation.goAuth()
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
setError(error.message)
|
||||||
|
|
||||||
|
return {
|
||||||
|
cancel: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Header = () => {
|
||||||
|
return (
|
||||||
|
<div className="steped-form-header">
|
||||||
|
<h1>Account Recovery</h1>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const RecoveryPage = (props) => {
|
||||||
|
return (
|
||||||
|
<FormWithSteps
|
||||||
|
header={Header}
|
||||||
|
steps={Steps}
|
||||||
|
onCancel={() => {
|
||||||
|
props.setActiveKey("selector")
|
||||||
|
}}
|
||||||
|
onFinish={OnFinish}
|
||||||
|
cancelable
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RecoveryPage
|
@ -13,202 +13,187 @@ import PasswordStep from "./steps/password"
|
|||||||
import EmailStep from "./steps/email"
|
import EmailStep from "./steps/email"
|
||||||
import TOSStep from "./steps/tos"
|
import TOSStep from "./steps/tos"
|
||||||
|
|
||||||
const steps = [
|
const steps = [UsernameStep, PasswordStep, EmailStep, TOSStep]
|
||||||
UsernameStep,
|
|
||||||
PasswordStep,
|
|
||||||
EmailStep,
|
|
||||||
TOSStep,
|
|
||||||
]
|
|
||||||
|
|
||||||
const RegisterForm = (props) => {
|
const RegisterForm = (props) => {
|
||||||
const [finishing, setFinishing] = React.useState(false)
|
const [finishing, setFinishing] = React.useState(false)
|
||||||
const [finishError, setFinishError] = React.useState(false)
|
const [finishError, setFinishError] = React.useState(false)
|
||||||
const [finishSuccess, setFinishSuccess] = React.useState(false)
|
const [finishSuccess, setFinishSuccess] = React.useState(false)
|
||||||
|
|
||||||
const [stepsValues, setStepsValues] = React.useState({})
|
const [stepsValues, setStepsValues] = React.useState({})
|
||||||
const [step, setStep] = React.useState(0)
|
const [step, setStep] = React.useState(0)
|
||||||
|
|
||||||
const currentStepData = steps[step - 1]
|
const currentStepData = steps[step - 1]
|
||||||
|
|
||||||
async function finish() {
|
async function finish() {
|
||||||
setFinishError(null)
|
setFinishError(null)
|
||||||
setFinishSuccess(false)
|
setFinishSuccess(false)
|
||||||
setFinishing(true)
|
setFinishing(true)
|
||||||
|
|
||||||
const result = await AuthModel.register({
|
const result = await AuthModel.register({
|
||||||
username: stepsValues.username,
|
username: stepsValues.username,
|
||||||
password: stepsValues.password,
|
password: stepsValues.password,
|
||||||
email: stepsValues.email,
|
email: stepsValues.email,
|
||||||
tos: stepsValues.tos,
|
tos: stepsValues.tos,
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
setFinishSuccess(false)
|
setFinishSuccess(false)
|
||||||
setFinishing(false)
|
setFinishing(false)
|
||||||
setFinishError(err)
|
setFinishError(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
setFinishing(false)
|
setFinishing(false)
|
||||||
setFinishSuccess(true)
|
setFinishSuccess(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextStep(to) {
|
function nextStep(to) {
|
||||||
setStep((prev) => {
|
setStep((prev) => {
|
||||||
if (!to) {
|
if (!to) {
|
||||||
to = prev + 1
|
to = prev + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to === steps.length + 1) {
|
if (to === steps.length + 1) {
|
||||||
finish()
|
finish()
|
||||||
return prev
|
return prev
|
||||||
}
|
}
|
||||||
|
|
||||||
return to
|
return to
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function prevStep() {
|
function prevStep() {
|
||||||
setStep((prev) => {
|
setStep((prev) => {
|
||||||
return prev - 1
|
return prev - 1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateStepValue = (value) => setStepsValues((prev) => {
|
const updateStepValue = (value) =>
|
||||||
return {
|
setStepsValues((prev) => {
|
||||||
...prev,
|
return {
|
||||||
[currentStepData.key]: value
|
...prev,
|
||||||
}
|
[currentStepData.key]: value,
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function canNextStep() {
|
function canNextStep() {
|
||||||
if (!currentStepData) {
|
if (!currentStepData) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentStepData.required) {
|
if (!currentStepData.required) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentStepValue = stepsValues[currentStepData.key]
|
const currentStepValue = stepsValues[currentStepData.key]
|
||||||
|
|
||||||
if (currentStepData.required) {
|
if (currentStepData.required) {
|
||||||
if (!currentStepValue) {
|
if (!currentStepValue) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div
|
return (
|
||||||
className={classnames(
|
<div
|
||||||
"register_form",
|
className={classnames("register_form", {
|
||||||
{
|
["welcome_step"]: step === 0 && !finishing,
|
||||||
["welcome_step"]: step === 0 && !finishing
|
})}
|
||||||
}
|
>
|
||||||
)}
|
<div className="register_form_header-text">
|
||||||
>
|
{!finishSuccess && !finishing && step === 0 && (
|
||||||
<div className="register_form_header-text">
|
<>
|
||||||
{
|
<h1>👋 Hi! Nice to meet you</h1>
|
||||||
!finishSuccess && !finishing && step === 0 && <>
|
<p>
|
||||||
<h1>👋 Hi! Nice to meet you</h1>
|
Tell us some basic information to get started
|
||||||
<p>Tell us some basic information to get started creating your account.</p>
|
creating your account.
|
||||||
</>
|
</p>
|
||||||
}
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{
|
{!finishSuccess && !finishing && step > 0 && (
|
||||||
!finishSuccess && !finishing && step > 0 && <>
|
<>
|
||||||
<h1>
|
<h1>
|
||||||
{
|
{currentStepData?.icon &&
|
||||||
currentStepData?.icon && createIconRender(currentStepData.icon)
|
createIconRender(currentStepData.icon)}
|
||||||
}
|
|
||||||
|
|
||||||
{currentStepData?.title}
|
{currentStepData?.title}
|
||||||
</h1>
|
</h1>
|
||||||
<p>
|
<p>
|
||||||
{
|
{typeof currentStepData?.description === "function"
|
||||||
typeof currentStepData?.description === "function" ?
|
? currentStepData?.description()
|
||||||
currentStepData?.description() : currentStepData.description
|
: currentStepData.description}
|
||||||
}
|
</p>
|
||||||
</p>
|
</>
|
||||||
</>
|
)}
|
||||||
}
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{
|
{!finishSuccess &&
|
||||||
!finishSuccess && !finishing && step > 0 && React.createElement(currentStepData.content, {
|
!finishing &&
|
||||||
onPressEnter: nextStep,
|
step > 0 &&
|
||||||
currentValue: stepsValues[currentStepData.key],
|
React.createElement(currentStepData.content, {
|
||||||
updateValue: updateStepValue,
|
onPressEnter: nextStep,
|
||||||
})
|
currentValue: stepsValues[currentStepData.key],
|
||||||
}
|
updateValue: updateStepValue,
|
||||||
|
})}
|
||||||
|
|
||||||
{
|
{finishing && (
|
||||||
finishing && <div className="register_form_creating">
|
<div className="register_form_creating">
|
||||||
<Icons.LoadingOutlined />
|
<Icons.LoadingOutlined />
|
||||||
<h1>
|
<h1>Creating your account</h1>
|
||||||
Creating your account
|
</div>
|
||||||
</h1>
|
)}
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{finishSuccess && (
|
||||||
finishSuccess && <div className="register_form_success">
|
<div className="register_form_success">
|
||||||
<Icons.CheckCircleOutlined />
|
<Icons.CheckCircleOutlined />
|
||||||
<h1>
|
<h1>Welcome abord!</h1>
|
||||||
Welcome abord!
|
<p>
|
||||||
</h1>
|
One last step, we need you to login with your new
|
||||||
<p>
|
account.
|
||||||
One last step, we need you to login with your new account.
|
</p>
|
||||||
</p>
|
|
||||||
|
|
||||||
<antd.Button
|
<antd.Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => props.changeStage(0)}
|
onClick={() => props.setActiveKey("selector")}
|
||||||
>
|
>
|
||||||
Go to login
|
Go to login
|
||||||
</antd.Button>
|
</antd.Button>
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
|
|
||||||
{
|
{finishError && (
|
||||||
finishError && <antd.Alert
|
<antd.Alert type="error" message={finishError.message} />
|
||||||
type="error"
|
)}
|
||||||
message={finishError.message}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{!finishSuccess && !finishing && (
|
||||||
!finishSuccess && !finishing && <div className="register_form_actions">
|
<div className="register_form_actions">
|
||||||
{
|
{step === 0 && (
|
||||||
step === 0 &&
|
<antd.Button
|
||||||
<antd.Button
|
onClick={() => props.setActiveKey("selector")}
|
||||||
onClick={() => props.changeStage(0)}
|
>
|
||||||
>
|
Cancel
|
||||||
Cancel
|
</antd.Button>
|
||||||
</antd.Button>
|
)}
|
||||||
}
|
{step > 0 && (
|
||||||
{
|
<antd.Button onClick={() => prevStep()}>
|
||||||
step > 0 &&
|
Back
|
||||||
<antd.Button
|
</antd.Button>
|
||||||
onClick={() => prevStep()}
|
)}
|
||||||
>
|
|
||||||
Back
|
|
||||||
</antd.Button>
|
|
||||||
}
|
|
||||||
|
|
||||||
<antd.Button
|
<antd.Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => nextStep()}
|
onClick={() => nextStep()}
|
||||||
disabled={!canNextStep()}
|
disabled={!canNextStep()}
|
||||||
>
|
>
|
||||||
{
|
{step === steps.length ? "Finish" : "Next"}
|
||||||
step === steps.length ? "Finish" : "Next"
|
</antd.Button>
|
||||||
}
|
</div>
|
||||||
</antd.Button>
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
)
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RegisterForm
|
export default RegisterForm
|
@ -4,62 +4,63 @@ import config from "@config"
|
|||||||
import { Icons } from "@components/Icons"
|
import { Icons } from "@components/Icons"
|
||||||
|
|
||||||
const MainSelector = (props) => {
|
const MainSelector = (props) => {
|
||||||
const {
|
return (
|
||||||
onClickLogin,
|
<>
|
||||||
onClickRegister,
|
<div className="content_header">
|
||||||
} = props
|
<img src={config.logo.alt} className="logo" />
|
||||||
|
</div>
|
||||||
|
|
||||||
return <>
|
<div className="actions">
|
||||||
<div className="content_header">
|
{app.userData && (
|
||||||
<img src={config.logo.alt} className="logo" />
|
<antd.Button
|
||||||
</div>
|
type="default"
|
||||||
|
size="large"
|
||||||
|
onClick={() => {
|
||||||
|
app.navigation.goMain()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<antd.Avatar
|
||||||
|
size={23}
|
||||||
|
shape="square"
|
||||||
|
src={app.userData.avatar}
|
||||||
|
/>{" "}
|
||||||
|
Continue as {app.userData.username}
|
||||||
|
</antd.Button>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="actions">
|
<antd.Button
|
||||||
{
|
onClick={() => app.controls.openLoginForm()}
|
||||||
app.userData && <antd.Button
|
icon={<Icons.FiLogIn />}
|
||||||
type="default"
|
type="primary"
|
||||||
size="large"
|
>
|
||||||
onClick={() => {
|
Continue with a Comty™ Account
|
||||||
app.navigation.goMain()
|
</antd.Button>
|
||||||
}}
|
|
||||||
>
|
|
||||||
<antd.Avatar size={23} shape="square" src={app.userData.avatar} /> Continue as {app.userData.username}
|
|
||||||
</antd.Button>
|
|
||||||
}
|
|
||||||
|
|
||||||
<antd.Button
|
<antd.Button
|
||||||
onClick={onClickLogin}
|
onClick={() => app.controls.openLoginForm()}
|
||||||
icon={<Icons.FiLogIn />}
|
icon={<Icons.FiLogIn />}
|
||||||
type="primary"
|
type="primary"
|
||||||
>
|
disabled
|
||||||
Continue with a Comty™ Account
|
>
|
||||||
</antd.Button>
|
Continue with a RageStudio© ID™
|
||||||
|
</antd.Button>
|
||||||
|
|
||||||
<antd.Button
|
<h4>Or create a new account</h4>
|
||||||
onClick={onClickLogin}
|
|
||||||
icon={<Icons.FiLogIn />}
|
|
||||||
type="primary"
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
Continue with a RageStudio© ID™
|
|
||||||
</antd.Button>
|
|
||||||
|
|
||||||
<h4>Or create a new account</h4>
|
<antd.Button
|
||||||
|
onClick={() => props.setActiveKey("register")}
|
||||||
|
icon={<Icons.FiUserPlus />}
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
|
Create a Comty™ Account
|
||||||
|
</antd.Button>
|
||||||
|
|
||||||
<antd.Button
|
<a onClick={() => props.setActiveKey("recovery")}>
|
||||||
onClick={onClickRegister}
|
I need help to recover my account
|
||||||
icon={<Icons.FiUserPlus />}
|
</a>
|
||||||
type="primary"
|
</div>
|
||||||
>
|
</>
|
||||||
Create a Comty™ Account
|
)
|
||||||
</antd.Button>
|
|
||||||
|
|
||||||
<p style={{ display: "inline" }}>
|
|
||||||
<Icons.FiInfo />
|
|
||||||
Registering a new account accepts the <a onClick={() => app.location.push("/terms")}>Terms and Conditions</a> and <a onClick={() => app.location.push("/privacy")}>Privacy policy</a> for the services provided by {config.author}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MainSelector
|
export default MainSelector
|
@ -1,80 +1,82 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
import useRandomFeaturedWallpaperUrl from "@hooks/useRandomFeaturedWallpaperUrl"
|
import useRandomFeaturedWallpaperUrl from "@hooks/useRandomFeaturedWallpaperUrl"
|
||||||
|
import useUrlQueryActiveKey from "@hooks/useUrlQueryActiveKey"
|
||||||
|
|
||||||
import RegisterForm from "./forms/register"
|
import RegisterForm from "./forms/register"
|
||||||
import MainSelector from "./forms/selector"
|
import MainSelector from "./forms/selector"
|
||||||
|
import RecoveryForm from "./forms/recovery"
|
||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
const GradientSVG = () => {
|
const GradientSVG = () => {
|
||||||
return <svg height="100%" width="100%">
|
return (
|
||||||
<defs>
|
<svg height="100%" width="100%">
|
||||||
<linearGradient id="0" x1="0" y1="0.5" x2="1" y2="0.5">
|
<defs>
|
||||||
<stop offset="0%" stop-color="rgba(225, 0, 209, 0.1)" />
|
<linearGradient id="0" x1="0" y1="0.5" x2="1" y2="0.5">
|
||||||
<stop offset="25%" stop-color="rgba(233, 0, 182, 0.08)" />
|
<stop offset="0%" stop-color="rgba(225, 0, 209, 0.1)" />
|
||||||
<stop offset="50%" stop-color="rgba(240, 0, 154, 0.05)" />
|
<stop offset="25%" stop-color="rgba(233, 0, 182, 0.08)" />
|
||||||
<stop offset="100%" stop-color="rgba(255, 0, 0, 0)" />
|
<stop offset="50%" stop-color="rgba(240, 0, 154, 0.05)" />
|
||||||
</linearGradient>
|
<stop offset="100%" stop-color="rgba(255, 0, 0, 0)" />
|
||||||
<radialGradient id="1" gradientTransform="translate(-0.81 -0.5) scale(2, 1.2)">
|
</linearGradient>
|
||||||
<stop offset="0%" stop-color="rgba(255, 96, 100, 0.2)" />
|
<radialGradient
|
||||||
<stop offset="20%" stop-color="rgba(255, 96, 100, 0.16)" />
|
id="1"
|
||||||
<stop offset="40%" stop-color="rgba(255, 96, 100, 0.12)" />
|
gradientTransform="translate(-0.81 -0.5) scale(2, 1.2)"
|
||||||
<stop offset="60%" stop-color="rgba(255, 96, 100, 0.08)" />
|
>
|
||||||
<stop offset="100%" stop-color="rgba(255, 96, 100, 0)" />
|
<stop offset="0%" stop-color="rgba(255, 96, 100, 0.2)" />
|
||||||
</radialGradient>
|
<stop offset="20%" stop-color="rgba(255, 96, 100, 0.16)" />
|
||||||
</defs>
|
<stop offset="40%" stop-color="rgba(255, 96, 100, 0.12)" />
|
||||||
<rect fill="url(#0)" height="100%" width="100%" />
|
<stop offset="60%" stop-color="rgba(255, 96, 100, 0.08)" />
|
||||||
<rect fill="url(#1)" height="100%" width="100%" />
|
<stop offset="100%" stop-color="rgba(255, 96, 100, 0)" />
|
||||||
</svg>
|
</radialGradient>
|
||||||
|
</defs>
|
||||||
|
<rect fill="url(#0)" height="100%" width="100%" />
|
||||||
|
<rect fill="url(#1)" height="100%" width="100%" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const stagesToComponents = {
|
const keyToComponents = {
|
||||||
0: MainSelector,
|
selector: MainSelector,
|
||||||
2: RegisterForm
|
register: RegisterForm,
|
||||||
|
recovery: RecoveryForm,
|
||||||
}
|
}
|
||||||
|
|
||||||
const AuthPage = (props) => {
|
const AuthPage = (props) => {
|
||||||
const [stage, setStage] = React.useState(0)
|
const [activeKey, setActiveKey] = useUrlQueryActiveKey({
|
||||||
const randomWallpaperURL = useRandomFeaturedWallpaperUrl()
|
defaultKey: "selector",
|
||||||
|
})
|
||||||
|
const randomWallpaperURL = useRandomFeaturedWallpaperUrl()
|
||||||
|
|
||||||
function changeStage(nextStage) {
|
return (
|
||||||
setStage(nextStage)
|
<div className="login-page">
|
||||||
}
|
<div className="background">
|
||||||
|
<GradientSVG />
|
||||||
|
</div>
|
||||||
|
|
||||||
const onClickLogin = () => {
|
<div className="wrapper">
|
||||||
app.controls.openLoginForm()
|
<div
|
||||||
}
|
className="wrapper_background"
|
||||||
|
style={{
|
||||||
|
backgroundImage: randomWallpaperURL
|
||||||
|
? `url(${randomWallpaperURL})`
|
||||||
|
: null,
|
||||||
|
animation: randomWallpaperURL ? "opacityIn 1s" : null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
const onClickRegister = () => {
|
<div className="content">
|
||||||
changeStage(2)
|
{React.createElement(
|
||||||
}
|
keyToComponents[activeKey] ??
|
||||||
|
keyToComponents["selector"],
|
||||||
return <div className="login-page">
|
{
|
||||||
<div className="background">
|
setActiveKey: setActiveKey,
|
||||||
<GradientSVG />
|
},
|
||||||
</div>
|
)}
|
||||||
|
</div>
|
||||||
<div className="wrapper">
|
</div>
|
||||||
<div
|
</div>
|
||||||
className="wrapper_background"
|
)
|
||||||
style={{
|
|
||||||
backgroundImage: randomWallpaperURL ? `url(${randomWallpaperURL})` : null,
|
|
||||||
animation: randomWallpaperURL ? "opacityIn 1s" : null
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="content">
|
|
||||||
{
|
|
||||||
React.createElement(stagesToComponents[stage] ?? stagesToComponents[0], {
|
|
||||||
onClickLogin,
|
|
||||||
onClickRegister,
|
|
||||||
changeStage,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AuthPage
|
export default AuthPage
|
@ -1,11 +0,0 @@
|
|||||||
import React from "react"
|
|
||||||
|
|
||||||
import "./index.less"
|
|
||||||
|
|
||||||
const AccountPasswordRecovery = () => {
|
|
||||||
return <div className="password_recover">
|
|
||||||
<h1>Account Password Recovery</h1>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AccountPasswordRecovery
|
|
@ -1,3 +0,0 @@
|
|||||||
.password_recover {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user