Skip to content
Snippets Groups Projects
Commit d3e2f71f authored by Embruch, Gerd's avatar Embruch, Gerd
Browse files

fixed registration and verification

parent 30875051
No related branches found
No related tags found
No related merge requests found
......@@ -26,22 +26,11 @@ function AuthState({ children }) {
// ### LOGIN
async function login(credentials) {
let result = {};
try {
result = await api.post(
'/users/login',
const result = await api.post(
'/auth/login',
credentials,
{ withCredentials: true }
);
} catch (error) {
result = await api.post(
'/users/adminlogin',
credentials,
{ withCredentials: true }
);
// try to match output with normal user
result.data.record = { ...result.data.admin, isAdmin: true };
}
// set current user to login and merge accessToken into currentUser
dispatchCurrentUser({ type: USER_ACTIONS.SET, payload: { ...result.data.record } });
setAccessToken(result.data.token);
......@@ -59,6 +48,11 @@ function AuthState({ children }) {
return result;
}
// ### REQUEST RESEND VERIFICATION TOKEN
function requestVerificationToken(email) {
return api.post('/auth/verification', { email });
}
// ### REQUEST PASSWORD RESET
function requestPasswordReset(email) {
return api.post('/users/requestpasswordreset', { email });
......@@ -76,6 +70,7 @@ function AuthState({ children }) {
login,
currentUser,
logout,
requestVerificationToken,
requestPasswordReset,
requestEmailReset,
USER_ACTIONS,
......
import { zodResolver } from '@hookform/resolvers/zod';
import React, { useRef, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { FormProvider, useForm, useFormContext } from 'react-hook-form';
import { Link } from 'react-router-dom';
import { z } from 'zod';
import Input from '../../components/form/Input';
import Submit from '../../components/form/Submit';
import { useAuth } from '../../contexts/Auth/AuthState';
import { mergeBackendValidation, setFlashMsg } from '../../utils/ErrorHandling';
import Heading from '../../components/font/Heading';
function ForgotPassword() {
// #################################
// VALIDATION SCHEMA
// #################################
const schema = z.object({
email: z.string().email(),
});
// #################################
// HOOKS
// #################################
const methods = useForm({
resolver: zodResolver(schema),
mode: 'onSubmit'
});
// #################################
// FUNCTIONS
// #################################
// ### IMPORT FUNCTION FROM AuthContext
const { requestVerificationToken } = useAuth();
// ### HANDLE SUBMITTING FORM
async function handleSendForm(inputs) {
try {
// send data to function
const result = await requestVerificationToken(inputs.email);
// set flash message
setFlashMsg(result.data?.message);
} catch (error) {
// catch the error
mergeBackendValidation(error.response.status, error.response.data, methods.setError);
}
}
// #################################
// OUTPUT
// #################################
return (
<>
{/* render page title */}
<Helmet><title>[{import.meta.env.VITE_APP_NAME}] Password forgot</title></Helmet>
<Heading level="1">resend verification token</Heading>
<FormProvider {...methods} >
<form onSubmit={methods.handleSubmit(handleSendForm)}>
<Input name='email' type='mail' title='E-Mail' className='h-16' required={true} />
<Submit value='request' />
</form>
</FormProvider>
<div className="my-4 flex justify-between">
<Link to="/signup/insertToken">Back to Verification</Link>
</div>
</>
);
}
export default React.memo(ForgotPassword);
\ No newline at end of file
......@@ -25,10 +25,10 @@ function Signup() {
password: z.string().refine((val) => val && validator.isStrongPassword(val), {
message: 'This value must be min 6 characters long and contain uppercase, lowercase, number, specialchar.',
}),
passwordConfirm: z.string(),
}).refine((data) => data.password === data.passwordConfirm, {
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
message: "Passwords don't match",
path: ["passwordConfirm"],
path: ["confirmPassword"],
});
// #################################
// HOOKS
......@@ -49,7 +49,7 @@ function Signup() {
username: '',
email: '',
password: '',
passwordConfirm: ''
confirmPassword: ''
}
});
......@@ -61,9 +61,9 @@ function Signup() {
async function handleSendForm(record) {
try {
// send data to API
const result = await api.post(`/users/signup`, record);
const result = await api.post(`/users`, record);
// if successfull redirect to login page
redirect(`/login`);
redirect(`/signup/insertToken`);
// FIX: flash message not dislayed
setFlashMsg(result.data?.message);
......@@ -88,13 +88,14 @@ function Signup() {
<Input name='username' type='text' title='username' className='h-16' />
<Input name='email' type='mail' title='E-Mail' className='h-16' />
<Input name='password' type='password' title='password' className='h-16' />
<Input name='passwordConfirm' type='password' title='confirm password' className='h-16' />
<Input name='confirmPassword' type='password' title='confirm password' className='h-16' />
<Submit value='Signup' />
</form>
</FormProvider>
<div className="mt-4">
<div className="mt-4 flex justify-between">
<Link to="/login">Back to Login</Link>
<Link to="/signup/insertToken">verify Account</Link>
</div>
</>
);
......
......@@ -49,7 +49,7 @@ function Verify() {
// TRY UPDATE
try {
// send data
const result = await api.post(`/users/confirmverification`, inputs);
const result = await api.patch(`/auth/verification`, inputs);
redirect('/login');
// set flash message
setFlashMsg(result.data?.message);
......@@ -77,6 +77,7 @@ function Verify() {
<div className="my-4 flex justify-between">
<Link to="/login">Back to Login</Link>
<Link to="/signup/resend_token">Resend Token</Link>
</div>
</>
);
......
......@@ -58,6 +58,7 @@ export const sitemap = [{
{
path: '/signup', children: [
{ index: true, element: loadComponent('User/Signup') },
{ path: 'resend_token', element: loadComponent('User/ResendVerificationToken') },
{ path: ':token', element: loadComponent('User/Verify') }
]
},
......
......@@ -29,21 +29,40 @@ api.interceptors.request.use(
// ### RESPONSE INTERCEPTOR
// refreshes accessToken if needed
api.interceptors.response.use(
async (res) => {
switch (res.config.url) {
case '/users/refreshjwt':
case '/users/logout':
case '/users/login':
(res) => {
return res;
default:
const refresh = await api.get(
'/users/refreshjwt',
},
async (err) => {
// console.log(err);
// save original request config
const originalConfig = err.config;
// if access denied and not a retry already
// BUG: Infinit loop because _retry isn't set at runtime
// console.log(originalConfig);
// console.log(JSON.stringify(originalConfig));
if (originalConfig && err?.response?.status === 403 && originalConfig._retry !== true) {
// patch config to remember it's a retry
originalConfig._retry = true;
console.log('trying to refresh the accessToken and rerun the request');
// console.log('retry', err.code, originalConfig._retry);
// refresh access token
try {
const result = await api.get(
'/auth',
{},
{ withCredentials: true }
);
localStorage.setItem("accessToken", JSON.stringify(refresh.data.token));
return res;
// TODO: don't store accessToken in localStorage, keep in memory only
localStorage.setItem("accessToken", JSON.stringify(result.data.accessToken));
// run retry
return api(originalConfig);
} catch (error) {
return Promise.reject(error);
}
}
return Promise.reject(err);
}
);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment