Refactor SignupModal

This commit is contained in:
Justin Edmund 2022-02-01 00:20:04 -08:00
parent 47c51b97f7
commit 305f0e1f88

View file

@ -1,6 +1,8 @@
import React from 'react' import React, { useContext, useState } from 'react'
import { withCookies, Cookies } from 'react-cookie' import { withCookies, Cookies } from 'react-cookie'
import { createPortal } from 'react-dom' import { createPortal } from 'react-dom'
import AppContext from '~context/AppContext'
import api from '~utils/api' import api from '~utils/api'
import Button from '~components/Button' import Button from '~components/Button'
@ -10,18 +12,11 @@ import Overlay from '~components/Overlay'
import './index.scss' import './index.scss'
// import New from '../../../assets/new'
interface Props { interface Props {
cookies: Cookies cookies: Cookies
close: () => void close: () => void
} }
interface State {
formValid: boolean
errors: ErrorMap
}
interface ErrorMap { interface ErrorMap {
[index: string]: string [index: string]: string
username: string username: string
@ -32,117 +27,111 @@ interface ErrorMap {
const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
class SignupModal extends React.Component<Props, State> { const SignupModal = (props: Props) => {
usernameInput: React.RefObject<HTMLInputElement> const { setAuthenticated } = useContext(AppContext)
emailInput: React.RefObject<HTMLInputElement>
passwordInput: React.RefObject<HTMLInputElement>
passwordConfirmationInput: React.RefObject<HTMLInputElement>
form: React.RefObject<HTMLInputElement>[]
constructor(props: Props) { const [formValid, setFormValid] = useState(false)
super(props) const [errors, setErrors] = useState<ErrorMap>({
this.state = { username: '',
formValid: false, email: '',
errors: { password: '',
username: '', passwordConfirmation: ''
email: '', })
password: '',
passwordConfirmation: '' const usernameInput = React.createRef<HTMLInputElement>()
} const emailInput = React.createRef<HTMLInputElement>()
} const passwordInput = React.createRef<HTMLInputElement>()
const passwordConfirmationInput = React.createRef<HTMLInputElement>()
this.usernameInput = React.createRef() const form = [usernameInput, emailInput, passwordInput, passwordConfirmationInput]
this.emailInput = React.createRef()
this.passwordInput = React.createRef()
this.passwordConfirmationInput = React.createRef()
this.form = [this.usernameInput, this.emailInput, this.passwordInput, this.passwordConfirmationInput]
}
check = (event: React.ChangeEvent<HTMLInputElement>) => { function check(event: React.ChangeEvent<HTMLInputElement>) {
const name = event.target.name const name = event.target.name
const value = event.target.value const value = event.target.value
if (value.length > 0 && this.state.errors[name].length == 0) { if (value.length > 0 && errors[name].length == 0) {
const errors = this.state.errors const newErrors = errors
api.check(name, value) api.check(name, value)
.then((response) => { .then((response) => {
if (!response.data.available) { if (!response.data.available) {
errors[name] = `This ${name} is already in use` newErrors[name] = `This ${name} is already in use`
} }
this.setState({ errors: errors }) setErrors(newErrors)
}, (error) => { }, (error) => {
console.log(error) console.log(error)
}) })
} }
} }
process = (event: React.FormEvent) => { function process(event: React.FormEvent) {
event.preventDefault() event.preventDefault()
const body = { const body = {
user: { user: {
username: this.usernameInput.current?.value, username: usernameInput.current?.value,
email: this.emailInput.current?.value, email: emailInput.current?.value,
password: this.passwordInput.current?.value, password: passwordInput.current?.value,
password_confirmation: this.passwordConfirmationInput.current?.value password_confirmation: passwordConfirmationInput.current?.value
} }
} }
if (this.state.formValid) { if (formValid) {
api.endpoints.users.create(body) api.endpoints.users.create(body)
.then((response) => { .then((response) => {
const cookies = this.props.cookies const cookies = props.cookies
cookies.set('user', response.data.user, { path: '/'}) cookies.set('user', response.data.user, { path: '/'})
this.props.close()
setAuthenticated(true)
props.close()
}, (error) => { }, (error) => {
console.log(error) console.log(error)
}) })
} }
} }
validateForm = () => { function validateForm() {
let valid = true let valid = true
Object.values(this.form).forEach( Object.values(form).forEach(
(input) => input.current?.value.length == 0 && (valid = false) (input) => input.current?.value.length == 0 && (valid = false)
) )
Object.values(this.state.errors).forEach( Object.values(errors).forEach(
(error) => error.length > 0 && (valid = false) (error) => error.length > 0 && (valid = false)
) )
return valid return valid
} }
handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
event.preventDefault() event.preventDefault()
const { name, value } = event.target const { name, value } = event.target
const errors = this.state.errors let newErrors = errors
switch(name) { switch(name) {
case 'username': case 'username':
errors.username = value.length < 3 newErrors.username = value.length < 3
? 'Username must be at least 3 characters' ? 'Username must be at least 3 characters'
: '' : ''
break break
case 'email': case 'email':
errors.email = emailRegex.test(value) newErrors.email = emailRegex.test(value)
? '' ? ''
: 'That email address is not valid' : 'That email address is not valid'
break break
case 'password': case 'password':
errors.password = value.length < 8 newErrors.password = value.length < 8
? 'Password must be at least 8 characters' ? 'Password must be at least 8 characters'
: '' : ''
break break
case 'confirm_password': case 'confirm_password':
errors.passwordConfirmation = this.passwordInput.current?.value === this.passwordConfirmationInput.current?.value newErrors.passwordConfirmation = passwordInput.current?.value === passwordConfirmationInput.current?.value
? '' ? ''
: 'Your passwords don\'t match' : 'Your passwords don\'t match'
break break
@ -151,67 +140,64 @@ class SignupModal extends React.Component<Props, State> {
break break
} }
this.setState({ errors: errors }) setErrors(newErrors)
this.setState({ formValid: this.validateForm() }) setFormValid(validateForm())
} }
render() { return (
const errors = this.state.errors createPortal(
return ( <div>
createPortal( <Modal
<div> title="Sign up"
<Modal styleName="SignupForm"
title="Sign up" close={ () => {} }
styleName="SignupForm" >
close={ () => {} } <form className="form" onSubmit={process}>
> <div id="fields">
<form className="form" onSubmit={this.process}> <Fieldset
<div id="fields"> fieldName="username"
<Fieldset placeholder="Username"
fieldName="username" onBlur={check}
placeholder="Username" onChange={handleChange}
onBlur={this.check} error={errors.username}
onChange={this.handleChange} ref={usernameInput}
error={errors.username} />
ref={this.usernameInput}
/>
<Fieldset <Fieldset
fieldName="email" fieldName="email"
placeholder="Email address" placeholder="Email address"
onBlur={this.check} onBlur={check}
onChange={this.handleChange} onChange={handleChange}
error={errors.email} error={errors.email}
ref={this.emailInput} ref={emailInput}
/> />
<Fieldset <Fieldset
fieldName="password" fieldName="password"
placeholder="Password" placeholder="Password"
onChange={this.handleChange} onChange={handleChange}
error={errors.password} error={errors.password}
ref={this.passwordInput} ref={passwordInput}
/> />
<Fieldset <Fieldset
fieldName="confirm_password" fieldName="confirm_password"
placeholder="Password (again)" placeholder="Password (again)"
onChange={this.handleChange} onChange={handleChange}
error={errors.passwordConfirmation} error={errors.passwordConfirmation}
ref={this.passwordConfirmationInput} ref={passwordConfirmationInput}
/> />
</div> </div>
<div id="ModalBottom"> <div id="ModalBottom">
<Button color="blue" disabled={!this.state.formValid}>Sign up</Button> <Button color="blue" disabled={!formValid}>Sign up</Button>
</div> </div>
</form> </form>
</Modal> </Modal>
<Overlay onClick={this.props.close} /> <Overlay onClick={props.close} />
</div>, </div>,
document.body document.body
)
) )
} )
} }