mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-16 01:32:02 +10:00
- implement work experience
- implement education - show dynamic names in layout
This commit is contained in:
@ -5,6 +5,7 @@ import { isFunction } from "lodash";
|
||||
import React, { forwardRef, useImperativeHandle } from "react";
|
||||
import { MdClose } from "react-icons/md";
|
||||
import Button from "../components/shared/Button";
|
||||
import { handleKeyDown } from "../utils";
|
||||
import styles from "./BaseModal.module.css";
|
||||
|
||||
const BaseModal = forwardRef(
|
||||
@ -33,7 +34,12 @@ const BaseModal = forwardRef(
|
||||
<div className={styles.modal}>
|
||||
<div className={styles.title}>
|
||||
<h2>{title}</h2>
|
||||
<MdClose size="18" onClick={handleClose} />
|
||||
<MdClose
|
||||
size="18"
|
||||
tabIndex="0"
|
||||
onClick={handleClose}
|
||||
onKeyDown={(e) => handleKeyDown(e, handleClose)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.body}>{children}</div>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { useFormikContext } from "formik";
|
||||
import { isEmpty, isFunction } from "lodash";
|
||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
@ -12,7 +13,6 @@ const DataModal = ({
|
||||
path,
|
||||
event,
|
||||
title,
|
||||
formik,
|
||||
onEdit,
|
||||
onCreate,
|
||||
children,
|
||||
@ -25,6 +25,7 @@ const DataModal = ({
|
||||
|
||||
const { emitter } = useContext(ModalContext);
|
||||
const { dispatch } = useContext(ResumeContext);
|
||||
const { values, setValues, resetForm, validateForm } = useFormikContext();
|
||||
|
||||
useEffect(() => {
|
||||
const unbind = emitter.on(event, (data) => {
|
||||
@ -36,12 +37,12 @@ const DataModal = ({
|
||||
}, [emitter, event]);
|
||||
|
||||
useEffect(() => {
|
||||
data && formik.setValues(data) && setEditMode(true);
|
||||
data && setValues(data) && setEditMode(true);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [data]);
|
||||
|
||||
const onSubmit = async (newData) => {
|
||||
if (isEmpty(await formik.validateForm(newData))) {
|
||||
if (isEmpty(await validateForm(newData))) {
|
||||
if (isEditMode) {
|
||||
if (data !== newData) {
|
||||
isFunction(onEdit)
|
||||
@ -79,15 +80,11 @@ const DataModal = ({
|
||||
: title.create;
|
||||
|
||||
const submitAction = (
|
||||
<Button
|
||||
type="submit"
|
||||
title={getTitle}
|
||||
onClick={() => onSubmit(formik.values)}
|
||||
/>
|
||||
<Button type="submit" title={getTitle} onClick={() => onSubmit(values)} />
|
||||
);
|
||||
|
||||
const onDestroy = () => {
|
||||
formik.resetForm();
|
||||
resetForm();
|
||||
setEditMode(false);
|
||||
setData(null);
|
||||
};
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import React, { Fragment } from "react";
|
||||
import AuthModal from "./AuthModal";
|
||||
import ResumeModal from "./ResumeModal";
|
||||
import EducationModal from "./sections/EducationModal";
|
||||
import SocialModal from "./sections/SocialModal";
|
||||
import WorkModal from "./sections/WorkModal";
|
||||
|
||||
const ModalRegistrar = () => {
|
||||
return (
|
||||
@ -9,6 +11,8 @@ const ModalRegistrar = () => {
|
||||
<AuthModal />
|
||||
<ResumeModal />
|
||||
<SocialModal />
|
||||
<WorkModal />
|
||||
<EducationModal />
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { useFormik } from "formik";
|
||||
import { Formik } from "formik";
|
||||
import { get } from "lodash";
|
||||
import React, { useContext } from "react";
|
||||
import * as Yup from "yup";
|
||||
import Input from "../components/shared/Input";
|
||||
@ -20,44 +21,45 @@ const ResumeModal = () => {
|
||||
const { events } = useContext(ModalContext);
|
||||
const { createResume, updateResume } = useContext(DatabaseContext);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues,
|
||||
validationSchema,
|
||||
});
|
||||
|
||||
const getFieldProps = (name) => ({
|
||||
const getFieldProps = (formik, name) => ({
|
||||
touched: get(formik, `touched.${name}`, false),
|
||||
error: get(formik, `errors.${name}`, ""),
|
||||
...formik.getFieldProps(name),
|
||||
error: formik.errors[name],
|
||||
});
|
||||
|
||||
return (
|
||||
<DataModal
|
||||
name="Resume"
|
||||
formik={formik}
|
||||
title={{
|
||||
create: "Create Resume",
|
||||
edit: "Edit Resume",
|
||||
}}
|
||||
onEdit={updateResume}
|
||||
onCreate={createResume}
|
||||
event={events.CREATE_RESUME_MODAL}
|
||||
<Formik
|
||||
validateOnBlur
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
>
|
||||
<Input
|
||||
type="text"
|
||||
name="name"
|
||||
label="Name"
|
||||
className="mb-8"
|
||||
placeholder="Full Stack Web Developer"
|
||||
{...getFieldProps("name")}
|
||||
/>
|
||||
{(formik) => (
|
||||
<DataModal
|
||||
name="Resume"
|
||||
title={{
|
||||
create: "Create Resume",
|
||||
edit: "Edit Resume",
|
||||
}}
|
||||
onEdit={updateResume}
|
||||
onCreate={createResume}
|
||||
event={events.CREATE_RESUME_MODAL}
|
||||
>
|
||||
<Input
|
||||
label="Name"
|
||||
className="mb-8"
|
||||
placeholder="Full Stack Web Developer"
|
||||
{...getFieldProps(formik, "name")}
|
||||
/>
|
||||
|
||||
<p>
|
||||
You are going to be creating a new resume from scratch, but first, let's
|
||||
give it a name. This can be the name of the role you want to apply for,
|
||||
or if you're making a resume for a friend, you could call it Alex's
|
||||
Resume.
|
||||
</p>
|
||||
</DataModal>
|
||||
<p>
|
||||
You are going to be creating a new resume from scratch, but first,
|
||||
let's give it a name. This can be the name of the role you want to
|
||||
apply for, or if you're making a resume for a friend, you could call
|
||||
it Alex's Resume.
|
||||
</p>
|
||||
</DataModal>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
154
src/modals/sections/EducationModal.js
Normal file
154
src/modals/sections/EducationModal.js
Normal file
@ -0,0 +1,154 @@
|
||||
import { Field, FieldArray, Formik } from "formik";
|
||||
import { get } from "lodash";
|
||||
import React, { useContext } from "react";
|
||||
import { MdAdd } from "react-icons/md";
|
||||
import * as Yup from "yup";
|
||||
import Input from "../../components/shared/Input";
|
||||
import ModalContext from "../../contexts/ModalContext";
|
||||
import { handleKeyDown } from "../../utils";
|
||||
import DataModal from "../DataModal";
|
||||
|
||||
const initialValues = {
|
||||
institution: "",
|
||||
field: "",
|
||||
degree: "",
|
||||
gpa: "",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
courses: [],
|
||||
__temp: "",
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
institution: Yup.string().required("This is a required field."),
|
||||
field: Yup.string().required("This is a required field."),
|
||||
degree: Yup.string(),
|
||||
gpa: Yup.string(),
|
||||
startDate: Yup.date().required("This is a required field."),
|
||||
endDate: Yup.date().when(
|
||||
"startDate",
|
||||
(startDate, schema) =>
|
||||
startDate &&
|
||||
schema.min(startDate, "End Date must be later than Start Date")
|
||||
),
|
||||
courses: Yup.array().of(Yup.string().required("This is a required field.")),
|
||||
__temp: Yup.string().ensure(),
|
||||
});
|
||||
|
||||
const EducationModal = () => {
|
||||
const { events } = useContext(ModalContext);
|
||||
|
||||
const getFieldProps = (formik, name) => ({
|
||||
touched: get(formik, `touched.${name}`, false),
|
||||
error: get(formik, `errors.${name}`, ""),
|
||||
...formik.getFieldProps(name),
|
||||
});
|
||||
|
||||
return (
|
||||
<Formik
|
||||
validateOnBlur
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
>
|
||||
{(formik) => (
|
||||
<DataModal
|
||||
path="education.items"
|
||||
name="Education"
|
||||
event={events.EDUCATION_MODAL}
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<Input
|
||||
label="Institution"
|
||||
className="col-span-2"
|
||||
placeholder="Dayananda Sagar College of Engineering"
|
||||
{...getFieldProps(formik, "institution")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Field of Study"
|
||||
className="col-span-2"
|
||||
placeholder="Computer Science & Engineering"
|
||||
{...getFieldProps(formik, "field")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Degree Type"
|
||||
placeholder="Bachelor's Degree"
|
||||
{...getFieldProps(formik, "degree")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="GPA"
|
||||
placeholder="8.8"
|
||||
{...getFieldProps(formik, "gpa")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="date"
|
||||
label="Start Date"
|
||||
placeholder="6th August 208"
|
||||
{...getFieldProps(formik, "startDate")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="date"
|
||||
label="End Date"
|
||||
placeholder="6th August 208"
|
||||
{...getFieldProps(formik, "endDate")}
|
||||
/>
|
||||
|
||||
<FieldArray
|
||||
name="courses"
|
||||
render={(arrayHelpers) => {
|
||||
const handleClickAdd = () => {
|
||||
formik.values.__temp &&
|
||||
arrayHelpers.push(formik.values.__temp);
|
||||
formik.setFieldValue("__temp", "");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="col-span-2">
|
||||
<label>
|
||||
<span>Courses</span>
|
||||
|
||||
{formik.values.courses &&
|
||||
formik.values.courses.map((x, i) => (
|
||||
<Field key={i} name={`courses.${i}`}>
|
||||
{({ field, meta }) => (
|
||||
<Input
|
||||
className="my-1"
|
||||
showDeleteItemButton
|
||||
onDeleteItem={() => arrayHelpers.remove(i)}
|
||||
{...field}
|
||||
{...meta}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
))}
|
||||
|
||||
<div className="flex items-center">
|
||||
<Input
|
||||
placeholder="Algorithms & Data Structures"
|
||||
{...getFieldProps(formik, "__temp")}
|
||||
/>
|
||||
<MdAdd
|
||||
size="18px"
|
||||
tabIndex="0"
|
||||
className="mx-4 cursor-pointer opacity-50 hover:opacity-75"
|
||||
onKeyDown={(e) => handleKeyDown(e, handleClickAdd)}
|
||||
onClick={handleClickAdd}
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</DataModal>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
export default EducationModal;
|
||||
@ -1,4 +1,5 @@
|
||||
import { useFormik } from "formik";
|
||||
import { Formik } from "formik";
|
||||
import { get } from "lodash";
|
||||
import React, { useContext } from "react";
|
||||
import * as Yup from "yup";
|
||||
import Input from "../../components/shared/Input";
|
||||
@ -25,52 +26,47 @@ const validationSchema = Yup.object().shape({
|
||||
const SocialModal = () => {
|
||||
const { events } = useContext(ModalContext);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues,
|
||||
validationSchema,
|
||||
validateOnBlur: true,
|
||||
});
|
||||
|
||||
const getFieldProps = (name) => ({
|
||||
const getFieldProps = (formik, name) => ({
|
||||
touched: get(formik, `touched.${name}`, false),
|
||||
error: get(formik, `errors.${name}`, ""),
|
||||
...formik.getFieldProps(name),
|
||||
touched: formik.touched[name],
|
||||
error: formik.errors[name],
|
||||
});
|
||||
|
||||
return (
|
||||
<DataModal
|
||||
formik={formik}
|
||||
path="social.items"
|
||||
name="Social Network"
|
||||
event={events.SOCIAL_MODAL}
|
||||
<Formik
|
||||
validateOnBlur
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<Input
|
||||
type="text"
|
||||
name="network"
|
||||
label="Network"
|
||||
placeholder="Twitter"
|
||||
{...getFieldProps("network")}
|
||||
/>
|
||||
{(formik) => (
|
||||
<DataModal
|
||||
path="social.items"
|
||||
name="Social Network"
|
||||
event={events.SOCIAL_MODAL}
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<Input
|
||||
label="Network"
|
||||
placeholder="Twitter"
|
||||
{...getFieldProps(formik, "network")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="text"
|
||||
name="username"
|
||||
label="Username"
|
||||
placeholder="KingOKings"
|
||||
{...getFieldProps("username")}
|
||||
/>
|
||||
<Input
|
||||
label="Username"
|
||||
placeholder="KingOKings"
|
||||
{...getFieldProps(formik, "username")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="text"
|
||||
name="url"
|
||||
label="URL"
|
||||
className="col-span-2"
|
||||
placeholder="https://twitter.com/KingOKings"
|
||||
{...getFieldProps("url")}
|
||||
/>
|
||||
</div>
|
||||
</DataModal>
|
||||
<Input
|
||||
label="URL"
|
||||
className="col-span-2"
|
||||
placeholder="https://twitter.com/KingOKings"
|
||||
{...getFieldProps(formik, "url")}
|
||||
/>
|
||||
</div>
|
||||
</DataModal>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
156
src/modals/sections/WorkModal.js
Normal file
156
src/modals/sections/WorkModal.js
Normal file
@ -0,0 +1,156 @@
|
||||
import { Field, FieldArray, Formik } from "formik";
|
||||
import { get } from "lodash";
|
||||
import React, { useContext } from "react";
|
||||
import { MdAdd } from "react-icons/md";
|
||||
import * as Yup from "yup";
|
||||
import Input from "../../components/shared/Input";
|
||||
import ModalContext from "../../contexts/ModalContext";
|
||||
import { handleKeyDown } from "../../utils";
|
||||
import DataModal from "../DataModal";
|
||||
|
||||
const initialValues = {
|
||||
company: "",
|
||||
position: "",
|
||||
website: "https://",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
summary: "",
|
||||
highlights: [],
|
||||
__temp: "",
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
company: Yup.string().required("This is a required field."),
|
||||
position: Yup.string().required("This is a required field."),
|
||||
website: Yup.string().url("Must be a valid URL"),
|
||||
startDate: Yup.date().required("This is a required field."),
|
||||
endDate: Yup.date().when(
|
||||
"startDate",
|
||||
(startDate, schema) =>
|
||||
startDate &&
|
||||
schema.min(startDate, "End Date must be later than Start Date")
|
||||
),
|
||||
summary: Yup.string().min(10, "Please enter at least 10 characters."),
|
||||
highlights: Yup.array().of(
|
||||
Yup.string().required("This is a required field.")
|
||||
),
|
||||
__temp: Yup.string().ensure(),
|
||||
});
|
||||
|
||||
const WorkModal = () => {
|
||||
const { events } = useContext(ModalContext);
|
||||
|
||||
const getFieldProps = (formik, name) => ({
|
||||
touched: get(formik, `touched.${name}`, false),
|
||||
error: get(formik, `errors.${name}`, ""),
|
||||
...formik.getFieldProps(name),
|
||||
});
|
||||
|
||||
return (
|
||||
<Formik
|
||||
validateOnBlur
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
>
|
||||
{(formik) => (
|
||||
<DataModal
|
||||
path="work.items"
|
||||
name="Work Experience"
|
||||
event={events.WORK_MODAL}
|
||||
>
|
||||
<div className="grid grid-cols-2 gap-8">
|
||||
<Input
|
||||
label="Company"
|
||||
className="col-span-2"
|
||||
placeholder="Postdot Technologies Pvt. Ltd."
|
||||
{...getFieldProps(formik, "company")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Position"
|
||||
placeholder="Full Stack Web Developer"
|
||||
{...getFieldProps(formik, "position")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Website"
|
||||
placeholder="https://example.com/"
|
||||
{...getFieldProps(formik, "website")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="date"
|
||||
label="Start Date"
|
||||
placeholder="6th August 208"
|
||||
{...getFieldProps(formik, "startDate")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="date"
|
||||
label="End Date"
|
||||
placeholder="6th August 208"
|
||||
{...getFieldProps(formik, "endDate")}
|
||||
/>
|
||||
|
||||
<Input
|
||||
type="textarea"
|
||||
label="Summary"
|
||||
className="col-span-2"
|
||||
{...getFieldProps(formik, "summary")}
|
||||
/>
|
||||
|
||||
<FieldArray
|
||||
name="highlights"
|
||||
render={(arrayHelpers) => {
|
||||
const handleClickAdd = () => {
|
||||
formik.values.__temp &&
|
||||
arrayHelpers.push(formik.values.__temp);
|
||||
formik.setFieldValue("__temp", "");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="col-span-2">
|
||||
<label>
|
||||
<span>Highlights</span>
|
||||
|
||||
{formik.values.highlights &&
|
||||
formik.values.highlights.map((x, i) => (
|
||||
<Field key={i} name={`highlights.${i}`}>
|
||||
{({ field, meta }) => (
|
||||
<Input
|
||||
className="my-1"
|
||||
showDeleteItemButton
|
||||
onDeleteItem={() => arrayHelpers.remove(i)}
|
||||
{...field}
|
||||
{...meta}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
))}
|
||||
|
||||
<div className="flex items-center">
|
||||
<Input
|
||||
placeholder="Worked passionately in customer service in a high volume restaurant."
|
||||
{...getFieldProps(formik, "__temp")}
|
||||
/>
|
||||
<MdAdd
|
||||
size="18px"
|
||||
tabIndex="0"
|
||||
className="mx-4 cursor-pointer opacity-50 hover:opacity-75"
|
||||
onKeyDown={(e) => handleKeyDown(e, handleClickAdd)}
|
||||
onClick={handleClickAdd}
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</DataModal>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkModal;
|
||||
Reference in New Issue
Block a user