You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
8.6 KiB
173 lines
8.6 KiB
import { useEffect, FormEventHandler, useState } from 'react';
|
|
import Checkbox from '@/Components/Checkbox';
|
|
import GuestLayout from '@/Layouts/GuestLayout';
|
|
import InputError from '@/Components/InputError';
|
|
import InputLabel from '@/Components/InputLabel';
|
|
import PrimaryButton from '@/Components/PrimaryButton';
|
|
import TextInput from '@/Components/TextInput';
|
|
import { Head, Link, useForm } from '@inertiajs/react';
|
|
import { AtSign, Lock, Eye, EyeOff, LogIn, CheckCircle, XOctagon } from 'react-feather';
|
|
import FormGroup from '@/Components/FormGroup';
|
|
import ProjectBanner from '@/Components/ProjectBanner';
|
|
import Modal from '@/Components/Modal';
|
|
import axios from 'axios';
|
|
import ModalButton from '@/Components/ModalButton';
|
|
|
|
export default function Login({ status, canResetPassword }: { status?: string, canResetPassword: boolean }) {
|
|
const { data, setData, post, processing, errors, reset } = useForm({
|
|
username: '',
|
|
password: '',
|
|
remember: false,
|
|
});
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
reset('password');
|
|
};
|
|
}, []);
|
|
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const toggleShowPassword = () => {
|
|
setShowPassword((prevShowPassword) => !prevShowPassword);
|
|
};
|
|
|
|
const [statusTitle, setStatusTitle] = useState('');
|
|
const [feedback, setFeedback] = useState('');
|
|
const [isSuccessModalOpen, setIsSuccessModalOpen] = useState(false);
|
|
const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
|
|
|
|
const handleCloseSuccessModal = () => {
|
|
setIsSuccessModalOpen(false);
|
|
window.location.href = '/login';
|
|
};
|
|
|
|
const submit: FormEventHandler = async (e) => {
|
|
e.preventDefault();
|
|
|
|
try {
|
|
const response = await axios.post(route('login'), data);
|
|
setStatusTitle('Success')
|
|
setFeedback(response.data.message);
|
|
setIsSuccessModalOpen(true);
|
|
} catch (error) {
|
|
setStatusTitle('Error')
|
|
if (axios.isAxiosError(error)) {
|
|
setFeedback(error.response?.data.message || 'An error occurred');
|
|
} else {
|
|
setFeedback('An unexpected error occurred');
|
|
}
|
|
setIsErrorModalOpen(true);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<GuestLayout>
|
|
<Head title="Log in" />
|
|
|
|
{status && <div className="mb-4 font-medium text-sm text-green-600">{status}</div>}
|
|
|
|
<div id="Login" className="hero min-h-screen bg-secondary-main">
|
|
<div className="hero-content flex-row">
|
|
<ProjectBanner />
|
|
|
|
<div className="card w-104 shrink-0 bg-primary-background">
|
|
<div className="card-body justify-center items-center">
|
|
<img src="assets/images/img-login.png" alt="An image that represents a login form from StorySet" width="250" height="250" />
|
|
|
|
<form id="SignInForm" onSubmit={ submit }>
|
|
<FormGroup>
|
|
<InputLabel htmlFor='username'>
|
|
<AtSign className='stroke-neutral-10' />
|
|
</InputLabel>
|
|
<TextInput
|
|
id='username'
|
|
name='username'
|
|
value={data.username}
|
|
autoComplete='off'
|
|
placeholder='Username'
|
|
required
|
|
onChange={(e) => setData('username', e.target.value)}
|
|
/>
|
|
<InputError message={errors.username} className="mt-2" />
|
|
</FormGroup>
|
|
|
|
<FormGroup>
|
|
<InputLabel htmlFor='password'>
|
|
<Lock className='stroke-neutral-10' />
|
|
</InputLabel>
|
|
<TextInput
|
|
type={showPassword ? "text" : "password"}
|
|
id='password'
|
|
name='password'
|
|
value={data.password}
|
|
autoComplete='off'
|
|
placeholder='Password'
|
|
required
|
|
onChange={(e) => setData('password', e.target.value)}
|
|
className='border-r-0'
|
|
/>
|
|
<label htmlFor="showPassword" className="swap items-center border border-primary-hover border-l-0">
|
|
<input type="checkbox" name="showPassword" id="showPassword" onChange={toggleShowPassword} checked={showPassword} className='hidden' />
|
|
<Eye className='swap-off px-1 stroke-secondary-main' />
|
|
<EyeOff className='swap-on px-1 stroke-secondary-main' />
|
|
</label>
|
|
<InputError message={errors.password} className="mt-2" />
|
|
</FormGroup>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<label className="flex items-center">
|
|
<Checkbox
|
|
name="remember"
|
|
checked={data.remember}
|
|
onChange={(e) => setData('remember', e.target.checked)}
|
|
/>
|
|
<span className="ml-1 text-secondary-main">Remember me</span>
|
|
</label>
|
|
|
|
{canResetPassword && (
|
|
<Link
|
|
href={route('password.request')}
|
|
className="btn btn-link text-secondary-main m-0 p-0"
|
|
>
|
|
Forgot password...
|
|
</Link>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex items-center justify-end mt-4">
|
|
<p className="invisible">No account yet? Register instead.</p>
|
|
<PrimaryButton type='submit' disabled={processing}>
|
|
Log In
|
|
<LogIn className='stroke-neutral-10' />
|
|
</PrimaryButton>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Modal show={isSuccessModalOpen} onClose={() => setIsSuccessModalOpen(false)} maxWidth="lg" styling='success'>
|
|
<div className="p-4 flex flex-col items-center">
|
|
<CheckCircle className='stroke-success-main' size={80} />
|
|
<h2 className="text-xl font-bold mt-2">{ statusTitle }</h2>
|
|
<p className="mt-4">{ feedback }</p>
|
|
<ModalButton onClick={handleCloseSuccessModal} className="bg-success-main text-white hover:bg-success-hover active:bg-success-pressed">
|
|
Go to Dashboard
|
|
</ModalButton>
|
|
</div>
|
|
</Modal>
|
|
|
|
<Modal show={isErrorModalOpen} onClose={() => setIsErrorModalOpen(false)} maxWidth="lg" styling='error'>
|
|
<div className="p-4 flex flex-col items-center">
|
|
<XOctagon className='stroke-error-main' size={80} />
|
|
<h2 className="text-xl font-bold mt-2">{ statusTitle }</h2>
|
|
<p className="mt-4">{ feedback }</p>
|
|
<ModalButton onClick={() => setIsErrorModalOpen(false)} className="bg-error-main text-white hover:bg-error-hover active:bg-error-pressed">
|
|
Close
|
|
</ModalButton>
|
|
</div>
|
|
</Modal>
|
|
</div>
|
|
</GuestLayout>
|
|
);
|
|
}
|