So basicall I wanted to create a registration process where you give your userName, email (but it can not exist in a database), password and then confirmed password. Project is in nextJS with pages router and typescript.
import React, { useState } from 'react'
import styles from './styles.module.css'
import { Header } from '@/components'
import Head from 'next/head'
import { hash } from '@/scripts/hashing'
import axios from 'axios'
import { getTokens } from '@/scripts/tokens'
import { store } from '@/redux/store'
import Link from 'next/link'
import { useDispatch } from 'react-redux'
import { setAccessToken, setRefreshToken } from '@/redux/constants/jwtTokensReducer'
const Register = () => {
const [name, setName] = React.useState('')
const [email, setEmail] = useState('')
const [emailExists, setEmailExists] = useState(false)
const [password, setPassword] = useState('')
const [repeatedPassword, setRepeatedPassword] = useState('')
const [passwordsMatch, setPasswordsMatch] = useState(true)
const dispatch = useDispatch()
const checkEmailExists =async () => {
if(email) {
await getTokens(dispatch)
console.log(store.getState().jwtTokens.accessToken)
await axios.get(`${process.env.API_URL}/api/email=${email}`, {
headers: {
token: store.getState().jwtTokens.accessToken,
}
}).then(res => {
if(res.data !== null) {
setEmailExists(true)
} else {
setEmailExists(false)
}
})
} else {
setEmailExists(false)
}
}
const checkPasswordsMatch =async () => {
// this function compares passwords and works as expected
}
const register =async (e:any) => {
e.preventDefault()
checkEmailExists()
checkPasswordsMatch()
console.log(emailExists)
if(!emailExists && passwordsMatch) {
const hashedPass = await hash(password)
console.log('Hashed Password:', hashedPass)
const restaurant = {
name: name,
email: email,
email_confirmed: false,
password: hashedPass,
created: `${new Date().getDay()}.${new Date().getMonth()}.${new Date().getFullYear()}`,
cuisineType: cuisineType,
address: address,
phoneNumber: phoneNumber,
priceRange: priceRange,
}
console.log('aaa')
await getTokens(dispatch)
// const accessToken = await axios.post(`${process.env.API_URL}/api/web/jwt-action`, {
// accessToken: store.getState().jwtTokens.accessToken,
// refreshToken: store.getState().jwtTokens.refreshToken,
// })
console.log(store.getState().jwtTokens.accessToken)
console.log('bbb')
axios.post(`${process.env.API_URL}/api/restaurants/register`, {
restaurant: restaurant
}, { headers: { token: store.getState().jwtTokens.accessToken,}}).then(() => console.log('registered'))
}
}
return (
<>
<Head>
<title>Registration</title>
</Head>
<div className={`${styles.main}`}>
<Header />
<div className={`${styles.Registration}`}>
<p className={`${styles.RegistrationTitle}`}>Register</p>
<form className={`${styles.RegistrationForm}`} onSubmit={register}}>
<div className={`${styles.RegistrationReg_LogBox}`}>
<Link href={`/login`} className={`${styles.RegistrationLogBox}`}>Login</Link>
<Link href={`/registration`} className={`${styles.RegistrationRegBox}`}>Register</Link>
</div>
<div>
<input className={`${styles.RegistrationInput}`}
type='text' onChange={e => setName(e.target.value)} placeholder='Restaurant name*' required/>
</div>
<div>
<input className={`${styles.RegistrationInput}
${emailExists && styles.RegistrationWarn}`}
type='email' onChange={e => setEmail(e.target.value)} placeholder='email*'
onFocus={() => setEmailExists(false)} onBlur={checkEmailExists} required/>
{emailExists && <p className={`${styles.RegistrationErrorText}`}>Email is already used</p>}
</div>
<div>
<input className={`${styles.RegistrationInput} ${!passwordsMatch && styles.RegistrationWarn}`}
type='password' autoComplete='new-password' onChange={e => setPassword(e.target.value)} placeholder='password*' onBlur={checkPasswordsMatch} onFocus={() => setPasswordsMatch(true)} required minLength={8}/>
<p className={`${styles.RegistrationInfoText}`}>Passwords needs to be at least 8 char long</p>
</div>
<div>
<input className={`${styles.RegistrationInput} ${!passwordsMatch && styles.RegistrationWarn}`}
type='password' autoComplete='new-password' onChange={e => setRepeatedPassword(e.target.value)} placeholder='confirm password*' onBlur={checkPasswordsMatch} onFocus={() => setPasswordsMatch(true)} required minLength={8}/>
{!passwordsMatch && <p className={`${styles.RegistrationErrorText}`}>Passwords needs to match</p>}
</div>
<button type='submit' className={`${styles.RegistrationSubmitButton}`}>Register</button>
<p className={`${styles.RegistrationFormNoAccount}`}>Already have an account? <span className={`${styles.RegistrationFormHighlightedText}`}>
<Link href={`/login`}>Login now</Link></span></p>
</form>
</div>
</div>
</>
)
}
export default Register
there is also a function getTokens()
import axios from 'axios'
import { setAccessToken, setRefreshToken } from '@/redux/constants/jwtTokensReducer'
import { store } from '@/redux/store'
import { hash } from '@/scripts/hashing'
import { encrypt } from './encryption'
import { Dispatch } from 'redux'
export const getTokens = async (dispatch: Dispatch) => {
axios.post(`${process.env.API_URL}/api/web/jwt-action`, {
accessToken: store.getState().jwtTokens.accessToken,
refreshToken: store.getState().jwtTokens.refreshToken,
})
.then(data => {
if(data.data.accessToken) {
dispatch({type: setAccessToken, payload: data.data.accessToken})
}
if(data.data.refreshToken) {
dispatch({type: setRefreshToken, payload: data.data.refreshToken})
}
})
}
The problem I would like to solve is that tokens are valid for 15m which means if user was on the page for longer period than that and then submitted the form it wouldn’t register him to the app, so I would like to call getTokens() inside register() and execute it before sending post request to /registration. I’ve tried things like async await but it didn’t helped.
If you help me with that, could you look later on this question where there are 2 more related to this registration?
2
Answers
You need
useSelector
to retrieve the updated values afterdispatch
. Try doing it this waygetTokens
is declaredasync
but it doesn’t wait for anything to resolve prior to returning. I suspect that the rest of theregister
callback is running/completing prior to the access/refresh tokens being updated in state.It’s also a bit of an anti-pattern to mix
async/await
with Promise chains, select one or the other.async/await
Promise chain