Files
relay/client/src/pages/Signup.tsx

199 lines
6.9 KiB
TypeScript

import icon from '../../assets/turtle.webp';
import { useForm, SubmitHandler } from 'react-hook-form';
import { Link, useNavigate } from 'react-router-dom';
import { useContext, useState } from 'react';
import LoadingWheel from '../components/chat/LoadingWheel.tsx';
import { axiosClient } from '@/utils/axiosClient.ts';
import { AuthContext } from '@/utils/AuthProvider.tsx';
type Inputs = {
username: string;
password: string;
sPassword: string;
};
export default function Signup() {
const { setUser, setAuthorized } = useContext(AuthContext);
const {
register,
handleSubmit,
formState: { errors },
} = useForm<Inputs>({
mode: 'onChange',
});
const navigate = useNavigate();
const [match, setMatch] = useState(true);
const [message, setMessage] = useState('');
const [isLoading, setIsLoading] = useState<boolean>(false);
const onSubmit: SubmitHandler<Inputs> = (data) => {
if (data.password !== data.sPassword) {
setMatch(true);
setTimeout(() => {
setMatch(false);
}, 100);
return;
}
setIsLoading(true);
setMatch(true);
axiosClient
.post(`/api/auth/signup`, data, {
withCredentials: true,
})
.then((res) => {
setUser({ username: res.data.username, id: res.data.user_id });
setAuthorized(true);
setIsLoading(false);
navigate('/chat');
console.log('Signed up');
})
.catch((err) => {
if (err.response) {
setMessage('');
setTimeout(() => {
setIsLoading(false);
setMessage(err.response.data.message);
}, 100);
}
console.error(err);
});
};
return (
<>
<div className="bg-[#121212] flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8 h-screen">
<div className="sm:mx-auto sm:w-full sm:max-w-sm">
<img alt="chat" src={icon} className="mx-auto h-10 w-auto" />
<h2 className="text-white mt-10 text-center text-2xl font-bold leading-9 tracking-tight">
Create an account
</h2>
</div>
<div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
<form onSubmit={handleSubmit(onSubmit)} className="space-y-5">
<div>
<label
htmlFor="username"
className="text-white text-sm leading-6"
>
Username
</label>
<div>
<input
{...register('username', {
maxLength: 20,
minLength: 4,
pattern: /^[A-Za-z0-9_]+$/i,
})}
id="username"
name="username"
type="username"
required
autoFocus
autoComplete="username"
className="pl-2 block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
<div>
{errors?.username?.type === 'maxLength' && (
<p className="text-red-400 text-sm">
First name cannot exceed 20 characters
</p>
)}
{errors?.username?.type === 'minLength' && (
<p className="text-red-400 text-sm">
Username must be between 4 and 20 characters
</p>
)}
{errors?.username?.type === 'pattern' && (
<p className="text-red-400 text-sm">
Username can only contain letters, numbers and underscores
</p>
)}
</div>
</div>
</div>
<div>
<div className="flex items-center justify-between">
<label
htmlFor="password"
className="text-white text-sm leading-6"
>
Password
</label>
</div>
<div>
<input
{...register('password', {
maxLength: 128,
minLength: 8,
})}
id="password"
name="password"
type="password"
required
className="pl-2 block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
{errors?.password?.type === 'maxLength' && (
<p className="text-red-400 text-sm">
Password cannot exceed 128 characters
</p>
)}
{errors?.password?.type === 'minLength' && (
<p className="text-red-400 text-sm">
Password must be at least 8 characters long
</p>
)}
</div>
</div>
<div>
<div className="flex items-center justify-between">
<label
htmlFor="password"
className="text-white text-sm leading-6"
>
Repeat password
</label>
</div>
<div>
<input
{...register('sPassword')}
id="sPassword"
name="sPassword"
type="password"
required
className="pl-2 block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
{!match && (
<p className="text-red-400 text-sm">Passwords don't match</p>
)}
<div>
<button
disabled={isLoading}
type="submit"
className="text-black w-full justify-center rounded-md bg-green-600 px-3 py-1.5 text-sm font-semibold leading-6 shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
{isLoading ? <LoadingWheel /> : 'Sign up'}
</button>
</div>
<div className="text-red-400 text-sm">{message}</div>
</form>
<p className="text-white mt-10 text-center text-sm">
Already have account?{' '}
<Link
to="/login"
className="text-green-400 leading-6 hover:text-green-600"
>
Log in
</Link>
</p>
</div>
</div>
</>
);
}