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.
189 lines
8.6 KiB
189 lines
8.6 KiB
import { FormEventHandler, Fragment, PropsWithChildren, useEffect, useState } from 'react';
|
|
import { Dialog, Transition } from '@headlessui/react';
|
|
import { FileText, Box, Info, XCircle, ArrowRightCircle, CheckCircle, XOctagon } from 'react-feather';
|
|
import { useForm } from '@inertiajs/react';
|
|
import FormGroup from '@/Components/FormGroup';
|
|
import InputLabel from '@/Components/InputLabel';
|
|
import TextInput from '@/Components/TextInput';
|
|
import InputError from '@/Components/InputError';
|
|
import ErrorButton from '@/Components/ErrorButton';
|
|
import PrimaryButton from '@/Components/PrimaryButton';
|
|
import axios from 'axios';
|
|
import Modal from '@/Components/Modal';
|
|
import ModalButton from '@/Components/ModalButton';
|
|
|
|
export default function AddCategoryModal({
|
|
show = false,
|
|
maxWidth = '2xl',
|
|
closeable = true,
|
|
onClose = () => {},
|
|
onCategoryAdded = () => {},
|
|
className = '',
|
|
}: PropsWithChildren<{
|
|
show: boolean;
|
|
maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
closeable?: boolean;
|
|
onClose: CallableFunction;
|
|
onCategoryAdded: CallableFunction;
|
|
className?: string;
|
|
}>) {
|
|
const close = () => {
|
|
if (closeable) {
|
|
onClose();
|
|
}
|
|
};
|
|
|
|
const maxWidthClass = {
|
|
sm: 'sm:max-w-sm',
|
|
md: 'sm:max-w-md',
|
|
lg: 'sm:max-w-lg',
|
|
xl: 'sm:max-w-xl',
|
|
'2xl': 'sm:max-w-2xl',
|
|
}[maxWidth];
|
|
|
|
const { data, setData, errors, reset } = useForm({
|
|
subjectTitle: '',
|
|
description:'',
|
|
});
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
reset('subjectTitle');
|
|
reset('description');
|
|
};
|
|
}, []);
|
|
|
|
const [status, setStatus] = useState('');
|
|
const [feedback, setFeedback] = useState('');
|
|
const [isSuccessModalOpen, setIsSuccessModalOpen] = useState(false);
|
|
const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
|
|
|
|
const handleCloseSuccessModal = () => {
|
|
setIsSuccessModalOpen(false);
|
|
onCategoryAdded();
|
|
close();
|
|
}
|
|
|
|
const submit: FormEventHandler = async (e) => {
|
|
e.preventDefault();
|
|
|
|
try {
|
|
const response = await axios.post(route('category.add'), data);
|
|
setStatus('Success')
|
|
setFeedback(response.data.message);
|
|
setIsSuccessModalOpen(true);
|
|
} catch (error) {
|
|
setStatus('Error')
|
|
if (axios.isAxiosError(error)) {
|
|
setFeedback(error.response?.data.message || 'An error occurred');
|
|
} else {
|
|
setFeedback('An unexpected error occurred');
|
|
}
|
|
setIsErrorModalOpen(true);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Transition show={show} as={Fragment} leave="duration-200">
|
|
<Dialog
|
|
as="div"
|
|
id="modal"
|
|
className="fixed inset-0 flex overflow-y-auto px-4 py-6 sm:px-0 items-center z-50 transform transition-all"
|
|
onClose={close}
|
|
>
|
|
<Transition.Child
|
|
as={Fragment}
|
|
enter="ease-out duration-300"
|
|
enterFrom="opacity-0"
|
|
enterTo="opacity-100"
|
|
leave="ease-in duration-200"
|
|
leaveFrom="opacity-100"
|
|
leaveTo="opacity-0"
|
|
>
|
|
<div className="absolute inset-0 bg-neutral-0 opacity-50" />
|
|
</Transition.Child>
|
|
|
|
<Transition.Child
|
|
as={Fragment}
|
|
enter="ease-out duration-300"
|
|
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
|
leave="ease-in duration-200"
|
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
>
|
|
<Dialog.Panel
|
|
className={`mb-6 bg-white border-4 rounded-lg overflow-hidden shadow-xl items-center transform transition-all sm:w-full sm:mx-auto bg-neutral-white ${maxWidthClass} ${className}`}
|
|
>
|
|
<div className="p-4 flex flex-col">
|
|
<h1 className="font-bold text-xl text-primary-main flex items-center my-2"><FileText className="stroke-primary-main mr-2" />Add New Category</h1>
|
|
<div className="divider"></div>
|
|
|
|
<form id="AddCategoryForm">
|
|
<div>
|
|
<FormGroup>
|
|
<InputLabel htmlFor="subjectTitle"><Box className='stroke-neutral-10' /></InputLabel>
|
|
<label htmlFor="subjectTitle" className="mx-2 font-semibold">Subject Category Title:</label>
|
|
|
|
</FormGroup>
|
|
<TextInput
|
|
id='subjectTitle'
|
|
name='subjectTitle'
|
|
value={data.subjectTitle}
|
|
autoComplete='off'
|
|
required
|
|
onChange={(e) => setData('subjectTitle', e.target.value)}
|
|
/>
|
|
<InputError message={errors.subjectTitle} className="mt-2" />
|
|
</div>
|
|
|
|
<div>
|
|
<FormGroup>
|
|
<InputLabel htmlFor="category"><Info className='stroke-neutral-10' /></InputLabel>
|
|
<label htmlFor="category" className="mx-2 font-semibold">Description:</label>
|
|
</FormGroup>
|
|
<textarea className="px-2 flex-grow w-full bg-primary-background border border-primary-hover focus:outline-none focus:bg-neutral-10 focus:border-2 focus:border-primary-hover"
|
|
onChange={(e) => setData('description', e.target.value)}>
|
|
</textarea>
|
|
</div>
|
|
|
|
<div className='flex items-center justify-center mt-3 w-full'>
|
|
<ErrorButton type="button" className='w-1/2' onClick={close}>
|
|
<XCircle className='stroke-neutral-10' />
|
|
Cancel
|
|
</ErrorButton>
|
|
<PrimaryButton type="button" onClick={submit} className='w-1/2'>
|
|
<ArrowRightCircle className='stroke-neutral-10' />
|
|
Save
|
|
</PrimaryButton>
|
|
</div>
|
|
</form>
|
|
</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">{ status }</h2>
|
|
<p className="mt-4">{ feedback }</p>
|
|
<ModalButton onClick={handleCloseSuccessModal} className="bg-success-main text-white hover:bg-success-hover active:bg-success-pressed">
|
|
Close
|
|
</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">{ status }</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>
|
|
</Dialog.Panel>
|
|
</Transition.Child>
|
|
</Dialog>
|
|
</Transition>
|
|
);
|
|
}
|