improve login component

This commit is contained in:
srgooglo 2022-10-25 11:52:32 +00:00
parent ee0c7c4a2d
commit 255e6968c0
2 changed files with 261 additions and 105 deletions

View File

@ -7,85 +7,85 @@ import config from "config"
import "./index.less" import "./index.less"
const formInstance = [ const LoginSteps = {
{ "username": (props) => {
id: "username", const handleUpdate = (e) => {
element: { props.onUpdate(e.target.value)
component: "Input",
icon: "User",
placeholder: "Username",
props: {
autoCorrect: "off",
autoCapitalize: "none",
className: "login-form-username",
},
},
item: {
hasFeedback: true,
rules: [
{
required: true,
message: 'Please input your Username!',
},
],
} }
return <div className="field">
<span><Icons.Mail /> Username or Email</span>
<div className="component">
<antd.Input
name="username"
defaultValue={props.defaultValue}
placeholder="myusername / myemail@example.com"
onChange={handleUpdate}
onPressEnter={props.next}
autoCorrect="off"
autoCapitalize="none"
autoComplete="on"
autoFocus
/>
</div>
</div>
}, },
{ "password": (props) => {
id: "password", const handleUpdate = (e) => {
element: { props.onUpdate(e.target.value)
component: "Input",
icon: "Lock",
placeholder: "Password",
props: {
type: "password"
} }
},
item: { return <div className="field">
hasFeedback: true, <span><Icons.Lock /> Password</span>
rules: [
{ <div className="component">
required: true, <antd.Input.Password
message: 'Please input your Password!', name="password"
}, defaultValue={props.defaultValue}
], onChange={handleUpdate}
onPressEnter={props.next}
autoCorrect="off"
autoCapitalize="none"
autoComplete="on"
autoFocus
/>
</div>
</div>
} }
}, }
{
id: "login_btn", const phasesToSteps = {
withValidation: true, 0: "username",
element: { 1: "password",
component: "Button", }
props: {
icon: "User",
children: "Login",
type: "primary",
htmlType: "submit"
}
}
},
]
export default class Login extends React.Component { export default class Login extends React.Component {
static pageStatement = { static pageStatement = {
bottomBarAllowed: false bottomBarAllowed: false
} }
handleFinish = async (values, ctx) => { state = {
ctx.toogleValidation(true) loading: false,
loginInputs: {},
const payload = { error: null,
username: values.username, phase: 0,
password: values.password,
allowRegenerate: values.allowRegenerate,
} }
handleFinish = async () => {
const payload = {
username: this.state.loginInputs.username,
password: this.state.loginInputs.password,
}
this.clearError()
this.toogleLoading(true)
this.props.sessionController.login(payload, (error, response) => { this.props.sessionController.login(payload, (error, response) => {
ctx.toogleValidation(false) this.toogleLoading(false)
ctx.clearErrors()
if (error) { if (error) {
ctx.shake("all") return this.onError(error)
return ctx.error("result", error)
} else { } else {
if (response.status === 200) { if (response.status === 200) {
this.onDone() this.onDone()
@ -104,31 +104,129 @@ export default class Login extends React.Component {
} }
} }
toogleLoading = (to) => {
if (typeof to === "undefined") {
to = !this.state.loading
}
this.setState({
loading: to
})
}
clearError = () => {
this.setState({
error: null
})
}
onError = (error) => {
this.setState({
error: error
})
}
onUpdateInput = (input, value) => {
this.setState({
loginInputs: {
...this.state.loginInputs,
[input]: value
}
})
}
renderCurrentInput = () => {
const { phase } = this.state
const step = phasesToSteps[phase]
return React.createElement(LoginSteps[step], {
onUpdate: (...props) => this.onUpdateInput(step, ...props),
next: this.nextStep,
defaultValue: this.state.loginInputs[step],
})
}
nextStep = () => {
const to = this.state.phase + 1
if (!phasesToSteps[to]) {
return this.handleFinish()
}
this.setState({
phase: to
})
}
prevStep = () => {
const to = this.state.phase - 1
if (!phasesToSteps[to]) {
console.warn("No step found for phase", to)
return
}
this.setState({
phase: to
})
}
canNext = () => {
if (this.state.loading) {
return false
}
const { phase } = this.state
const step = phasesToSteps[phase]
return !!this.state.loginInputs[step]
}
render() { render() {
return <div className="login"> return <div className="login_wrapper">
<div className="header"> <div className="content">
<div className="logo"> <h1>
<img src={config.logo?.full} /> Sign in
</div> </h1>
</div> <h3>
{this.props.session && <div className="session_available"> To continue to {config.app.siteName}
<h3><Icons.AlertCircle /> You already have a valid session.</h3> </h3>
<div className="session_card">
@{this.props.session.username} <div className="fields">
</div> {this.renderCurrentInput()}
<antd.Button
type="primary" <div className="field">
onClick={() => window.app.setLocation(config.app?.mainPath ?? "/home")} > <div className="component-row">
Go to home {
this.state.phase > 0 && <antd.Button
onClick={this.prevStep}
disabled={this.state.loading}
>
Back
</antd.Button> </antd.Button>
</div>} }
<FormGenerator <antd.Button
name="normal_login" onClick={this.nextStep}
renderLoadingIcon disabled={!this.canNext() || this.state.loading}
className="login-form" loading={this.state.loading}
items={formInstance} >
onFinish={this.handleFinish} Continue
/> </antd.Button>
</div>
</div>
<div className="field-error">
{this.state.error}
</div>
<div className="field">
<a>You need a account?</a>
</div>
</div>
</div>
</div> </div>
} }
} }

View File

@ -1,16 +1,22 @@
.login { .login_wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
> div { width: 100%;
margin-bottom: 20px;
}
.header { .header {
display: flex;
flex-direction: column;
width: 100%;
.logo { .logo {
width: 15vw; max-width: 200px;
margin-bottom: 40px;
img { img {
width: 100%; width: 100%;
@ -18,21 +24,73 @@
} }
} }
} }
}
.login-form { h1 {
font-family: "Space Grotesk", sans-serif;
margin: 0;
}
h3 {
font-size: 0.8rem;
}
.content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
justify-content: center;
}
.login-form-username { width: 80%;
font-size: 20px!important;
input { max-width: 600px;
padding: 20px!important;
font-size: 20px!important; margin: auto;
padding: 40px 0;
border-radius: 12px;
.fields {
display: flex;
flex-direction: column;
margin-top: 20px;
.field {
display: flex;
flex-direction: column;
margin-bottom: 20px;
.component {
margin-top: 5px;
}
.component-row {
display: inline-flex;
flex-direction: row;
justify-content: space-between;
}
}
.field-error {
color: red;
font-size: 0.8rem;
}
}
}
.ant-input {
padding: 5px;
border-radius: 8px;
}
.ant-input-affix-wrapper {
border-radius: 8px;
.ant-input {
border-radius: 0;
}
} }
} }