| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- import propTypes from 'prop-types';
-
- import img from '../../assets/Group 305.png';
- import * as Yup from 'yup';
- import { Formik, Form, ErrorMessage } from 'formik';
- import { JobFormContext } from '../../context';
- import { useContext, useState, useRef, useEffect } from 'react';
- import * as emailjs from 'emailjs-com';
- import { motion } from 'framer-motion';
- import ReactGA from 'react-ga4';
- import MyDropzone from './MyDropzone';
- import HashPositions from './HashPositions';
- import ReCAPTCHA from 'react-google-recaptcha';
- import axios from 'axios';
- import { UIContext } from '../../context/UIContextProvider';
-
- const api_url = process.env.REACT_APP_API_URL;
-
- export default function JobForm(props) {
- const [btnText, setBtnText] = useState('');
- const [sucMsg, setSucMsg] = useState(false);
- const captchaRef = useRef(null);
- const [msgText, setMsgText] = useState('');
- const cntCareersJobs = props.cntCareers;
- let defaultPositionSelection = props.defaultPositionSelection;
-
- //search context for prevous entry TODO
- const { jobForm, setJobForm } = useContext(UIContext);
-
- const [otherInputState, setOtherInputState] = useState(true);
- const [selectedPosition, setSelectedPosition] = useState(jobForm.position);
- //console.log(selectedPosition);
- const [errorMsg, setErrorMsg] = useState('');
- const [errorMsgPosition, setErrorMsgPosition] = useState('');
- const fileInput = useRef();
-
- function changeFormHandler(event) {
- const { name, value } = event.target;
- setJobForm(prevState => ({
- ...prevState,
- [name]: value,
- }));
- }
-
- function dropzoneToFormData(files) {
- setJobForm(prevState => ({
- ...prevState,
- file: files,
- }));
- }
-
- function hashToFormData(selected, other) {
- setJobForm(prevState => ({
- ...prevState,
- position: selected,
- other: other,
- }));
- }
-
- useEffect(() => {
- setJobForm(prevState => ({
- ...prevState,
- position: selectedPosition,
- }));
- },[selectedPosition])
-
- useEffect(() => {
- setBtnText(props.cta);
- }, [props.cta]);
-
- useEffect(() => {
- if (jobForm.file !== '') {
- setErrorMsg('');
- }
- }, [jobForm.file]);
-
- const validationSchema = Yup.object({
- email: Yup.string().email('Invalid email format').required('Email is Required'),
- firstName: Yup.string()
- .min(2, 'First name too short')
- .max(50, 'First name too long')
- .required('First Name is Required'),
- lastName: Yup.string()
- .min(2, 'Last name too short')
- .max(50, 'Last name too long')
- .required('Last name is Required'),
- coverLetter: Yup.string()
- .trim()
- .min(2, 'Cover Letter too short')
- .required('Cover Letter is Required'),
- other: Yup.string(),
- });
-
- return (
- <div className="mt-10 sm:mt-0 mx-auto">
- <div className="md:grid md:grid-cols-2 md:gap-6">
- <motion.div
- className="mt-5 md:mt-0 md:col-span-1"
- initial={{ x: -60, opacity: 0 }}
- animate={{ x: 0, opacity: 1 }}
- exit={{ x: -60, opacity: 0 }}
- transition={{ duration: 0.3, ease: 'easeOut' }}
- >
- <Formik
- initialValues={jobForm}
- validationSchema={validationSchema}
- onChange={changeFormHandler}
- onSubmit={async values => {
- const prepFile = async file => {
- if (file.size >= 2000000) {
- setErrorMsg('File too large!');
- return null;
- } else {
- const base64 = await convertBase64(file);
- return base64;
- }
- };
- const convertBase64 = file => {
- return new Promise((resolve, reject) => {
- const fileReader = new FileReader();
-
- fileReader.readAsDataURL(file);
- fileReader.onload = () => {
- resolve(fileReader.result);
- };
-
- fileReader.onerror = error => {
- reject(error);
- };
- });
- };
- if (
- selectedPosition === '' ||
- (otherInputState === false && values.other === '')
- )
- setErrorMsgPosition('Position is Required');
- else {
- setSelectedPosition(jobForm.position);
- setErrorMsgPosition('');
- if (jobForm.file === '') {
- setErrorMsg('CV is Required');
- } else {
- setErrorMsg('');
- if (jobForm.file.size >= 2000000) {
- setErrorMsg('File too large!');
- } else {
- const file = {
- filename: 'CV.pdf',
- data: jobForm.file,
- };
-
- const token = captchaRef.current.getValue();
- captchaRef.current.reset();
- if (token.length === 0) {
- setSucMsg(true);
- setMsgText('Please fill reCAPTCHA and try again. Thank you!');
- } else {
- await axios
- .post(`${process.env.REACT_APP_CAPTCHA_API}/verify-token`, {
- token,
- })
- .then(res => {
- setSucMsg(true);
- if (res.data.data.success) {
- setMsgText('Submission Succesful! Thank you!');
-
- values.position = jobForm.position;
-
- // props.mg.messages.create('dilig.net', {
- // from: `${values.firstName} ${values.lastName} <${values.email}>`,
- // to: ['hr@dilig.net'],
- // subject: 'Applying for a position',
- // text: `Email: ${values.email}, Position:${selectedPosition} ${values.other}, Cover letter: ${values.coverLetter}, Link: ${values.link} `,
- // html: `<p>Email: ${values.email}</p><p>Position: ${selectedPosition} ${values.other}</p><p>Cover letter: ${values.coverLetter}</p><p>Link (optional): ${values.link}</p>`,
- // attachment: file,
- // });
- console.log(jobForm);
- } else
- setMsgText('Please fill reCAPTCHA and try again. Thank you!');
- })
- .catch(error => {
- console.log(error);
- });
- }
- }
- }
- }
- ReactGA.event('contact', {
- category: 'Contact',
- action: 'Job application',
- });
- }}
- >
- {props => (
- <Form onSubmit={props.handleSubmit}>
- <div className="sm:rounded-md">
- <div className="py-2 sm:py-6">
- <div className="">
- <div className="col-span-1 sm:col-span-1">
- <div className="hidden py-1">
- <label
- htmlFor="first-name"
- className="block text-sm font-medium text-gray-700 dark:text-gray-400"
- >
- Position
- </label>
- <input
- type="text"
- name="position"
- id="position"
- onBlur={changeFormHandler}
- value={selectedPosition}
- onChange={props.handleChange}
- autoComplete="given-name"
- 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"
- />
- <div className="h-4">
- <ErrorMessage
- name="position"
- component="div"
- className="text-sm text-right text-red-600"
- />
- </div>
- </div>
- {/* <RadioBoxesGroup/> */}
- <HashPositions
- changeFormHandler={changeFormHandler}
- cntCareers={cntCareersJobs}
- otherInputState={otherInputState}
- hashToFormData={hashToFormData}
- setOtherInputState={setOtherInputState}
- defaultPositionSelection={defaultPositionSelection}
- selectedPosition={selectedPosition}
- setSelectedPosition={setSelectedPosition}
- />
- <div className="py-1">
- <label
- htmlFor="first-name"
- className="block text-sm font-medium text-gray-700 dark:text-gray-400"
- >
- Other
- </label>
- <input
- disabled={otherInputState ? 'disabled' : ''}
- type="text"
- name="other"
- id="other"
- value={props.values.other}
- onChange={props.handleChange}
- 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"
- />
- </div>
- {errorMsgPosition != '' ? (
- <div className="h-4">
- <div className="text-sm text-right text-red-600">
- {errorMsgPosition}
- </div>
- </div>
- ) : null}
- <div className="py-1">
- <label
- htmlFor="first-name"
- className="block text-sm font-medium text-gray-700 dark:text-gray-400"
- >
- First name
- </label>
- <input
- type="text"
- name="firstName"
- id="firstName"
- onBlur={changeFormHandler}
- value={props.values.firstName}
- onChange={props.handleChange}
- autoComplete="name"
- autofill="true"
- 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"
- />
- <div className="h-4">
- <ErrorMessage
- name="firstName"
- component="div"
- className="text-sm text-right text-red-600"
- />
- </div>
- </div>
- <div className="py-1">
- <label
- htmlFor="last-name"
- className="block text-sm font-medium text-gray-700 dark:text-gray-400"
- >
- Last name
- </label>
- <input
- onBlur={changeFormHandler}
- type="text"
- name="lastName"
- id="lastName"
- value={props.values.lastName}
- onChange={props.handleChange}
- autoComplete="family-name"
- autofill="true"
- 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"
- />
- <div className="h-4">
- <ErrorMessage
- name="lastName"
- component="div"
- className="text-sm text-right text-red-600"
- />
- </div>
- </div>
- <div className="py-1">
- <label
- htmlFor="email"
- className="block text-sm font-medium text-gray-700 dark:text-gray-400"
- >
- Email
- </label>
- <input
- onBlur={changeFormHandler}
- type="email"
- name="email"
- id="email"
- value={props.values.email}
- onChange={props.handleChange}
- autoComplete="email"
- autofill="true"
- 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"
- />
- <div className="h-4">
- <ErrorMessage
- name="email"
- component="div"
- className="text-sm text-right text-red-600"
- />
- </div>
- </div>
- {/* <div className="form-check py-2">
- <input
- 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"
- type="checkbox"
- value=""
- id="meeting"
- />
- <label
- className="ml-3 form-check-label inline-block text-gray-800"
- htmlFor="meeting"
- >
- Schedule a meeting right away
- </label>
- </div> */}
-
- <div className="py-1">
- <label
- htmlFor="coverLetter"
- className="block text-sm font-medium text-gray-700 dark:text-gray-400"
- >
- Cover Letter
- </label>
- <textarea
- onBlur={changeFormHandler}
- type="text"
- placeholder="Why would you like to join us?"
- 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"
- name="coverLetter"
- id="coverLetter"
- value={props.values.coverLetter}
- onChange={props.handleChange}
- ></textarea>
- <div className="h-4">
- <ErrorMessage
- name="coverLetter"
- component="div"
- className="text-sm text-right text-red-600"
- />
- </div>
- </div>
-
- <div className="py-1">
- <label
- htmlFor="link"
- className="block text-sm font-medium text-gray-700 dark:text-gray-400"
- >
- Website link or Portfolio (optional)
- </label>
- <input
- type="url"
- name="link"
- id="link"
- onBlur={changeFormHandler}
- value={props.values.link}
- onChange={props.handleChange}
- 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"
- />
- <div className="h-4">
- <ErrorMessage
- name="link"
- component="div"
- className="text-sm text-right text-red-600"
- />
- </div>
- </div>
-
- <div className="py-1 dark:text-gray-500">
- <MyDropzone
- dropzoneToFormData={dropzoneToFormData}
- props={props}
- fileInput={fileInput}
- />
- <div className="h-4">
- <div className="text-sm text-right">{errorMsg}</div>
- </div>
- </div>
- <div className="items-center justify-end flex">
- <ReCAPTCHA
- sitekey={process.env.REACT_APP_SITE_KEY}
- ref={captchaRef}
- />
- </div>
- <div className=" py-3 text-right">
- <button
- type="submit"
- 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"
- >
- {btnText}
- </button>
- </div>
- {sucMsg && (
- <div className={'text-sm text-right text-dg-primary-900'}>
- {msgText}
- </div>
- )}
- </div>
-
- <div className="col-span-1 sm:col-span-1 lg:col-span-1 mt-8">
- Or contact us directly via email{' '}
- <a
- className="text-semibodld text-dg-primary-600"
- href="mailto:hr@dilig.net"
- >
- hr@dilig.net
- </a>
- </div>
- </div>
- </div>
- </div>
- </Form>
- )}
- </Formik>
- </motion.div>
- <motion.div
- className="mt-5 md:mt-0 md:col-span-1 flex items-center"
- initial={{ x: 60, opacity: 0 }}
- animate={{ x: 0, opacity: 1 }}
- exit={{ x: 60, opacity: 0 }}
- transition={{ duration: 0.3, ease: 'easeOut' }}
- >
- <img
- src={api_url + props.img.data.attributes.url}
- alt={props.img.data.attributes.alternativeText}
- />
- </motion.div>
- </div>
- </div>
- );
- }
-
- JobForm.propTypes = {
- defaultPositionSelection: propTypes.string,
- };
|