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.

233 lines
12 KiB

  1. import { useEffect, FormEventHandler, useState } from 'react';
  2. import { Head, Link, useForm } from '@inertiajs/react';
  3. import GuestLayout from '@/Layouts/GuestLayout';
  4. import ProjectBanner from '@/Components/ProjectBanner';
  5. import FormGroup from '@/Components/FormGroup';
  6. import InputError from '@/Components/InputError';
  7. import InputLabel from '@/Components/InputLabel';
  8. import TextInput from '@/Components/TextInput';
  9. import PrimaryButton from '@/Components/PrimaryButton';
  10. import { Grid, User, Mail, AtSign, Lock, Eye, EyeOff, LogIn, Unlock, CheckCircle, XOctagon } from 'react-feather';
  11. import axios from 'axios';
  12. import Modal from '@/Components/Modal';
  13. import ModalButton from '@/Components/ModalButton';
  14. export default function Register() {
  15. const { data, setData, post, processing, errors, reset } = useForm({
  16. emp_id: '',
  17. name: '',
  18. email: '',
  19. username: '',
  20. password: '',
  21. password_confirmation: '',
  22. role_id: ''
  23. });
  24. useEffect(() => {
  25. return () => {
  26. reset('password', 'password_confirmation');
  27. };
  28. }, []);
  29. const [showPassword, setShowPassword] = useState(false);
  30. const toggleShowPassword = () => {
  31. setShowPassword((prevShowPassword) => !prevShowPassword);
  32. };
  33. const [status, setStatus] = useState('');
  34. const [feedback, setFeedback] = useState('');
  35. const [isSuccessModalOpen, setIsSuccessModalOpen] = useState(false);
  36. const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
  37. const handleCloseSuccessModal = () => {
  38. setIsSuccessModalOpen(false);
  39. window.location.href = '/login';
  40. };
  41. const submit: FormEventHandler = async (e) => {
  42. e.preventDefault();
  43. try {
  44. const response = await axios.post(route('register'), data);
  45. setStatus('Success')
  46. setFeedback(response.data.message);
  47. setIsSuccessModalOpen(true);
  48. } catch (error) {
  49. setStatus('Error')
  50. if (axios.isAxiosError(error)) {
  51. setFeedback(error.response?.data.message || 'An error occurred');
  52. } else {
  53. setFeedback('An unexpected error occurred');
  54. }
  55. setIsErrorModalOpen(true);
  56. }
  57. };
  58. return (
  59. <GuestLayout>
  60. <Head title="Register" />
  61. <div id="Register" className="hero min-h-screen bg-secondary-main">
  62. <div className="hero-content flex-row-reverse">
  63. <ProjectBanner />
  64. <div className="card w-104 shrink-0 bg-primary-background">
  65. <div className="card-body justify-center items-center">
  66. <img src="assets/images/img-signup.png" alt="An image that represents a sign up form from StorySet" width="250" height="250" />
  67. <form id="SignUpForm" onSubmit={ submit }>
  68. <FormGroup>
  69. <InputLabel htmlFor='emp_id'>
  70. <Grid className='stroke-neutral-10' />
  71. </InputLabel>
  72. <TextInput
  73. id='emp_id'
  74. name='emp_id'
  75. value={data.emp_id}
  76. autoComplete='off'
  77. placeholder='Employee ID'
  78. required
  79. onChange={(e) => setData('emp_id', e.target.value)}
  80. />
  81. <InputError message={errors.emp_id} className="mt-2" />
  82. <select name="role_id" id="role_id" value={data.role_id} onChange={(e) => setData('role_id', e.target.value)}
  83. className='px-2 py-0 flex-grow w-full h-[30px] ml-1 bg-primary-background border border-primary-hover focus:outline-none focus:bg-neutral-10 focus:border focus:border-primary-hover'>
  84. <option value="" selected disabled>Select your role</option>
  85. <option value="1">Admin</option>
  86. <option value="2">Team Leader</option>
  87. <option value="3">Team Member</option>
  88. </select>
  89. </FormGroup>
  90. <FormGroup>
  91. <InputLabel htmlFor='name'>
  92. <User className='stroke-neutral-10' />
  93. </InputLabel>
  94. <TextInput
  95. id='name'
  96. name='name'
  97. value={data.name}
  98. autoComplete='off'
  99. placeholder='Full Name'
  100. required
  101. onChange={(e) => setData('name', e.target.value)}
  102. />
  103. <InputError message={errors.name} className="mt-2" />
  104. </FormGroup>
  105. <FormGroup>
  106. <InputLabel htmlFor='email'>
  107. <Mail className='stroke-neutral-10' />
  108. </InputLabel>
  109. <TextInput
  110. type='email'
  111. id='email'
  112. name='email'
  113. value={data.email}
  114. autoComplete='off'
  115. placeholder='Email Address'
  116. required
  117. onChange={(e) => setData('email', e.target.value)}
  118. />
  119. <InputError message={errors.email} className="mt-2" />
  120. </FormGroup>
  121. <FormGroup>
  122. <InputLabel htmlFor='username'>
  123. <AtSign className='stroke-neutral-10' />
  124. </InputLabel>
  125. <TextInput
  126. id='username'
  127. name='username'
  128. value={data.username}
  129. autoComplete='off'
  130. placeholder='Username'
  131. required
  132. onChange={(e) => setData('username', e.target.value)}
  133. />
  134. <InputError message={errors.username} className="mt-2" />
  135. </FormGroup>
  136. <FormGroup>
  137. <InputLabel htmlFor='password'>
  138. <Lock className='stroke-neutral-10' />
  139. </InputLabel>
  140. <TextInput
  141. type={showPassword ? "text" : "password"}
  142. id='password'
  143. name='password'
  144. value={data.password}
  145. autoComplete='off'
  146. placeholder='Password'
  147. required
  148. onChange={(e) => setData('password', e.target.value)}
  149. className='border-r-0'
  150. />
  151. <label htmlFor="showPassword" className="swap items-center border border-primary-hover border-l-0">
  152. <input type="checkbox" name="showPassword" id="showPassword" onChange={toggleShowPassword} checked={showPassword} className='hidden' />
  153. <Eye className='stroke-secondary-main swap-off px-1' />
  154. <EyeOff className='stroke-secondary-main swap-on px-1' />
  155. </label>
  156. <InputError message={errors.password} className="mt-2" />
  157. </FormGroup>
  158. <FormGroup>
  159. <InputLabel htmlFor='password_confirmation'>
  160. <Unlock className='stroke-neutral-10' />
  161. </InputLabel>
  162. <TextInput
  163. type={"password"}
  164. id='password_confirmation'
  165. name='password_confirmation'
  166. value={data.password_confirmation}
  167. autoComplete='off'
  168. placeholder='Confirm Password'
  169. required
  170. onChange={(e) => setData('password_confirmation', e.target.value)}
  171. />
  172. </FormGroup>
  173. <div className="flex items-center justify-end mt-4">
  174. <Link
  175. href={route('login')}
  176. className="btn btn-link text-secondary-main"
  177. >
  178. Already registered? Login instead.
  179. </Link>
  180. <PrimaryButton type='submit' disabled={processing}>
  181. Sign Up
  182. <LogIn className='stroke-neutral-10' />
  183. </PrimaryButton>
  184. </div>
  185. </form>
  186. </div>
  187. </div>
  188. </div>
  189. <Modal show={isSuccessModalOpen} onClose={() => setIsSuccessModalOpen(false)} maxWidth="lg" styling='success'>
  190. <div className="p-4 flex flex-col items-center">
  191. <CheckCircle className='stroke-success-main' size={80} />
  192. <h2 className="text-xl font-bold mt-2">{ status }</h2>
  193. <p className="mt-4">{ feedback }</p>
  194. <ModalButton onClick={handleCloseSuccessModal} className="bg-success-main text-white hover:bg-success-hover active:bg-success-pressed">
  195. Login Now
  196. </ModalButton>
  197. </div>
  198. </Modal>
  199. <Modal show={isErrorModalOpen} onClose={() => setIsErrorModalOpen(false)} maxWidth="lg" styling='error'>
  200. <div className="p-4 flex flex-col items-center">
  201. <XOctagon className='stroke-error-main' size={80} />
  202. <h2 className="text-xl font-bold mt-2">{ status }</h2>
  203. <p className="mt-4">{ feedback }</p>
  204. <ModalButton onClick={() => setIsErrorModalOpen(false)} className="bg-error-main text-white hover:bg-error-hover active:bg-error-pressed">
  205. Close
  206. </ModalButton>
  207. </div>
  208. </Modal>
  209. </div>
  210. </GuestLayout>
  211. );
  212. }