199 lines
6.9 KiB
TypeScript
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>
|
|
</>
|
|
);
|
|
}
|