Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

JobForm.jsx 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. import propTypes from 'prop-types';
  2. import img from '../../assets/Group 305.png';
  3. import * as Yup from 'yup';
  4. import { Formik, Form, ErrorMessage } from 'formik';
  5. import { JobFormContext } from '../../context';
  6. import { useContext, useState, useRef, useEffect } from 'react';
  7. import * as emailjs from 'emailjs-com';
  8. import { motion } from 'framer-motion';
  9. import MyDropzone from './MyDropzone';
  10. import HashPositions from './HashPositions';
  11. import useDataApi from '../../hooks/useDataApi';
  12. import axios from 'axios';
  13. const api_url = 'http://localhost:1337';
  14. export default function JobForm(props) {
  15. const [sucMsg, setSucMsg] = useState(false);
  16. const cntCareersJobs = props.cntCareers;
  17. let defaultPositionSelection = props.defaultPositionSelection;
  18. //search context for prevous entry TODO
  19. const { jobForm, setJobForm } = useContext(JobFormContext);
  20. const [otherInputState, setOtherInputState] = useState(true);
  21. const [selectedPosition, setSelectedPosition] = useState('');
  22. const [errorMsg, setErrorMsg] = useState('');
  23. const fileInput = useRef();
  24. function changeFormHandler(event) {
  25. const { name, value } = event.target;
  26. setJobForm({
  27. ...jobForm,
  28. [name]: value,
  29. });
  30. }
  31. function dropzoneToFormData(files) {
  32. setJobForm({
  33. ...jobForm,
  34. file: files,
  35. });
  36. }
  37. function hashToFormData(selected, other) {
  38. setJobForm({
  39. ...jobForm,
  40. position: selected,
  41. other: other,
  42. });
  43. }
  44. useEffect(() => {
  45. if (jobForm.file !== '') {
  46. setErrorMsg('');
  47. }
  48. }, [jobForm.file]);
  49. const validationSchema = Yup.object({
  50. email: Yup.string().email('Invalid email format').required('Email is Required'),
  51. firstName: Yup.string().min(2, "First name too short")
  52. .max(50, "First name too long").required('First Name is Required'),
  53. lastName: Yup.string().min(2, "Last name too short")
  54. .max(50, "Last name too long").required('Last name is Required'),
  55. coverLetter: Yup.string().trim().min(2, "Cover Letter too short").required('Cover Letter is Required'),
  56. });
  57. return (
  58. <div className="mt-10 sm:mt-0 mx-auto">
  59. <div className="md:grid md:grid-cols-2 md:gap-6">
  60. <motion.div
  61. className="mt-5 md:mt-0 md:col-span-1"
  62. initial={{ x: -60, opacity: 0 }}
  63. animate={{ x: 0, opacity: 1 }}
  64. exit={{ x: -60, opacity: 0 }}
  65. transition={{ duration: 0.3, ease: 'easeOut' }}
  66. >
  67. <Formik
  68. initialValues={jobForm}
  69. validationSchema={validationSchema}
  70. onChange={changeFormHandler}
  71. onSubmit={values => {
  72. setSucMsg(false);
  73. //prep file
  74. const prepFile = async file => {
  75. if (file.size >= 2000000) {
  76. setErrorMsg('File too large!');
  77. return null;
  78. } else {
  79. const base64 = await convertBase64(file);
  80. return base64;
  81. }
  82. };
  83. //convert file
  84. const convertBase64 = file => {
  85. return new Promise((resolve, reject) => {
  86. const fileReader = new FileReader();
  87. fileReader.readAsDataURL(file);
  88. fileReader.onload = () => {
  89. resolve(fileReader.result);
  90. };
  91. fileReader.onerror = error => {
  92. reject(error);
  93. };
  94. });
  95. };
  96. let data = {};
  97. // &filters[SubmitDate][$gte]=${period}
  98. //const hookdata = useDataApi(`${api_url}/api/job-submissions?filters[Email][$eq]=${values.email}&filters[SubmitDate][$gte]=${period}`);
  99. const fetchData = async () => {
  100. axios.get(`${api_url}/api/job-submissions?filters[Email][$eq]=${values.email}`)
  101. .then((res) => {
  102. data = res.data.data[0];
  103. console.log(data);
  104. const submitDate = new Date(data.attributes.SubmitDate);
  105. const now = new Date();
  106. if ((now.getMonth() - submitDate.getMonth()) < 1)
  107. {
  108. setErrorMsg('You Already sent an email');
  109. return false
  110. }
  111. else {
  112. fetch(`${api_url}/api/job-submissions/${data.id}`, {
  113. method: "PUT",
  114. headers: {
  115. "Content-type": "application/json; charset=UTF-8",
  116. },
  117. body: JSON.stringify({
  118. data: {
  119. SubmitDate: now,
  120. }
  121. })
  122. }).then(r => r.json()).then(() => {
  123. setErrorMsg('');
  124. return true;
  125. }).catch(err => {
  126. return false
  127. });
  128. }
  129. });
  130. };
  131. console.log(fetchData());
  132. if (jobForm.file === '') {
  133. setErrorMsg('CV is Required');
  134. } else {
  135. if (fetchData()) {
  136. prepFile(jobForm.file).then(res => {
  137. const newtemplateParams = {
  138. Position: values.position,
  139. Other: values.other,
  140. Firstname: values.firstName,
  141. Lastname: values.lastName,
  142. Coverletter: values.coverLetter,
  143. Email: values.email,
  144. Link: values.link,
  145. File: res,
  146. };
  147. // emailjs
  148. // .send(
  149. // process.env.REACT_APP_SERVICE_ID,
  150. // process.env.REACT_APP_JOB_TEMPLATE_ID,
  151. // newtemplateParams,
  152. // process.env.REACT_APP_USER_ID,
  153. // )
  154. // .then(
  155. // result => {
  156. // console.log(result.text);
  157. // setSucMsg(true);
  158. // },
  159. // error => {
  160. // console.log(error.text);
  161. // },
  162. // );
  163. });
  164. }
  165. }
  166. }}
  167. >
  168. {props => (
  169. <Form onSubmit={props.handleSubmit}>
  170. <div className="sm:rounded-md">
  171. <div className="py-2 sm:py-6">
  172. <div className="">
  173. <div className="col-span-1 sm:col-span-1">
  174. <div className="py-1 hidden">
  175. <label
  176. htmlFor="first-name"
  177. className="block text-sm font-medium text-gray-700 dark:text-gray-400"
  178. >
  179. Position
  180. </label>
  181. <input
  182. type="text"
  183. name="position"
  184. id="position"
  185. onBlur={changeFormHandler}
  186. value={selectedPosition.substring(1)}
  187. onChange={props.handleChange}
  188. autoComplete="given-name"
  189. className="mt-1 disabled:bg-gray-100 disabled:border-gray-300 focus:ring-dg-primary-600 focus:border-dg-primary-900 block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200"
  190. />
  191. <div className="h-4">
  192. <ErrorMessage
  193. name="position"
  194. component="div"
  195. className="text-sm text-right text-red-600"
  196. />
  197. </div>
  198. </div>
  199. <HashPositions
  200. changeFormHandler={changeFormHandler}
  201. hashToFormData={hashToFormData}
  202. cntCareers={cntCareersJobs}
  203. otherInputState={otherInputState}
  204. setOtherInputState={setOtherInputState}
  205. defaultPositionSelection={defaultPositionSelection}
  206. setSelectedPosition={setSelectedPosition}
  207. />
  208. <div className="py-1">
  209. <label
  210. htmlFor="first-name"
  211. className="block text-sm font-medium text-gray-700 dark:text-gray-400"
  212. >
  213. Other
  214. </label>
  215. <input
  216. disabled={otherInputState ? 'disabled' : ''}
  217. type="text"
  218. name="other"
  219. id="other"
  220. value={props.values.other}
  221. onChange={props.handleChange}
  222. className="mt-1 disabled:bg-gray-100 disabled:border-gray-300 dark:disabled:bg-gray-400 dark:disabled:border-gray-600 focus:ring-dg-primary-600 focus:border-dg-primary-900 dark:bg-dg-primary-1500 dark:text-white block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200"
  223. />
  224. <div className="h-4">
  225. <ErrorMessage
  226. name="other"
  227. component="div"
  228. className="text-sm text-right text-red-600"
  229. />
  230. </div>
  231. </div>
  232. <div className="py-1">
  233. <label
  234. htmlFor="first-name"
  235. className="block text-sm font-medium text-gray-700 dark:text-gray-400"
  236. >
  237. First name
  238. </label>
  239. <input
  240. type="text"
  241. name="firstName"
  242. id="firstName"
  243. onBlur={changeFormHandler}
  244. value={props.values.firstName}
  245. onChange={props.handleChange}
  246. autoComplete="name"
  247. autofill="true"
  248. className="mt-1 focus:ring-dg-primary-600 focus:border-dg-primary-900 dark:bg-dg-primary-1500 dark:text-white block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200"
  249. />
  250. <div className="h-4">
  251. <ErrorMessage
  252. name="firstName"
  253. component="div"
  254. className="text-sm text-right text-red-600"
  255. />
  256. </div>
  257. </div>
  258. <div className="py-1">
  259. <label
  260. htmlFor="last-name"
  261. className="block text-sm font-medium text-gray-700 dark:text-gray-400"
  262. >
  263. Last name
  264. </label>
  265. <input
  266. onBlur={changeFormHandler}
  267. type="text"
  268. name="lastName"
  269. id="lastName"
  270. value={props.values.lastName}
  271. onChange={props.handleChange}
  272. autoComplete="family-name"
  273. autofill="true"
  274. className="mt-1 focus:ring-dg-primary-900 focus:border-dg-primary-900 dark:bg-dg-primary-1500 dark:text-white block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200"
  275. />
  276. <div className="h-4">
  277. <ErrorMessage
  278. name="lastName"
  279. component="div"
  280. className="text-sm text-right text-red-600"
  281. />
  282. </div>
  283. </div>
  284. <div className="py-1">
  285. <label
  286. htmlFor="email"
  287. className="block text-sm font-medium text-gray-700 dark:text-gray-400"
  288. >
  289. Email
  290. </label>
  291. <input
  292. onBlur={changeFormHandler}
  293. type="email"
  294. name="email"
  295. id="email"
  296. value={props.values.email}
  297. onChange={props.handleChange}
  298. autoComplete="email"
  299. autofill="true"
  300. className="mt-1 focus:ring-dg-primary-900 focus:border-dg-primary-900 dark:bg-dg-primary-1500 dark:text-white block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200"
  301. />
  302. <div className="h-4">
  303. <ErrorMessage
  304. name="email"
  305. component="div"
  306. className="text-sm text-right text-red-600"
  307. />
  308. </div>
  309. </div>
  310. {/* <div className="form-check py-2">
  311. <input
  312. className="form-check-input appearance-none h-6 w-6 border text-dg-primary-900 border-dg-primary-600 rounded-sm bg-white checked:dg-primary-900 checked:border-dg-primary-900 focus:outline-none transition duration-200 align-top bg-no-repeat bg-center bg-contain float-left cursor-pointer focus:ring-dg-primary-900"
  313. type="checkbox"
  314. value=""
  315. id="meeting"
  316. />
  317. <label
  318. className="ml-3 form-check-label inline-block text-gray-800"
  319. htmlFor="meeting"
  320. >
  321. Schedule a meeting right away
  322. </label>
  323. </div> */}
  324. <div className="py-1">
  325. <label
  326. htmlFor="coverLetter"
  327. className="block text-sm font-medium text-gray-700 dark:text-gray-400"
  328. >
  329. Cover Letter
  330. </label>
  331. <textarea
  332. onBlur={changeFormHandler}
  333. type="text"
  334. placeholder="Why would you like to join us?"
  335. className="resize-y min-h-12 h-32 rounded-md mt-1 text-base focus:ring-dg-primary-900 focus:border-dg-primary-900 dark:bg-dg-primary-1500 dark:text-white sm:text-sm border-dg-primary-600 block w-full shadow-sm transition duration-200"
  336. name="coverLetter"
  337. id="coverLetter"
  338. value={props.values.coverLetter}
  339. onChange={props.handleChange}
  340. ></textarea>
  341. <div className="h-4">
  342. <ErrorMessage
  343. name="coverLetter"
  344. component="div"
  345. className="text-sm text-right text-red-600"
  346. />
  347. </div>
  348. </div>
  349. <div className="py-1">
  350. <label
  351. htmlFor="link"
  352. className="block text-sm font-medium text-gray-700 dark:text-gray-400"
  353. >
  354. Website link or Portfolio (optional)
  355. </label>
  356. <input
  357. type="url"
  358. name="link"
  359. id="link"
  360. onBlur={changeFormHandler}
  361. value={props.values.link}
  362. onChange={props.handleChange}
  363. className="mt-1 focus:ring-dg-primary-600 focus:border-dg-primary-900 dark:bg-dg-primary-1500 dark:text-white block w-full shadow-sm sm:text-sm border-dg-primary-600 rounded-md transition duration-200"
  364. />
  365. <div className="h-4">
  366. <ErrorMessage
  367. name="link"
  368. component="div"
  369. className="text-sm text-right text-red-600"
  370. />
  371. </div>
  372. </div>
  373. <div className="py-1 dark:text-gray-500">
  374. <MyDropzone
  375. dropzoneToFormData={dropzoneToFormData}
  376. props={props}
  377. fileInput={fileInput}
  378. />
  379. <div className="h-4">
  380. <div className="text-sm text-right">{errorMsg}</div>
  381. </div>
  382. </div>
  383. <div className=" py-3 text-right">
  384. <button
  385. type="submit"
  386. className="btn btn_primary transition-all inline-flex justify-center py-4 px-14 border border-transparent shadow-md text-sm font-semibold rounded-xl text-white bg-dg-primary-600 hover:bg-dg-primary-900 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-dg-primary-600"
  387. >
  388. Submit
  389. </button>
  390. </div>
  391. {sucMsg && <div className={'text-sm text-right text-dg-primary-900'}>
  392. Submission Succesful! Thank you!
  393. </div> }
  394. </div>
  395. <div className="col-span-1 sm:col-span-1 lg:col-span-1"></div>
  396. </div>
  397. </div>
  398. </div>
  399. </Form>
  400. )}
  401. </Formik>
  402. </motion.div>
  403. <motion.div
  404. className="mt-5 md:mt-0 md:col-span-1 flex items-center"
  405. initial={{ x: 60, opacity: 0 }}
  406. animate={{ x: 0, opacity: 1 }}
  407. exit={{ x: 60, opacity: 0 }}
  408. transition={{ duration: 0.3, ease: 'easeOut' }}
  409. >
  410. <img src={img} />
  411. </motion.div>
  412. </div>
  413. </div>
  414. );
  415. }
  416. JobForm.propTypes = {
  417. defaultPositionSelection: propTypes.string,
  418. };