mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-15 01:01:43 +10:00
- implement certifications section
This commit is contained in:
@ -6,6 +6,7 @@ import ModalContext from "../../../contexts/ModalContext";
|
|||||||
import Button from "../../shared/Button";
|
import Button from "../../shared/Button";
|
||||||
import EmptyList from "./EmptyList";
|
import EmptyList from "./EmptyList";
|
||||||
import styles from "./List.module.css";
|
import styles from "./List.module.css";
|
||||||
|
import ListItem from "./ListItem";
|
||||||
|
|
||||||
const List = ({
|
const List = ({
|
||||||
path,
|
path,
|
||||||
@ -17,7 +18,6 @@ const List = ({
|
|||||||
text,
|
text,
|
||||||
textPath,
|
textPath,
|
||||||
event,
|
event,
|
||||||
listItemComponent: ListItemComponent,
|
|
||||||
}) => {
|
}) => {
|
||||||
const { emitter } = useContext(ModalContext);
|
const { emitter } = useContext(ModalContext);
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ const List = ({
|
|||||||
<EmptyList />
|
<EmptyList />
|
||||||
) : (
|
) : (
|
||||||
items.map((x, i) => (
|
items.map((x, i) => (
|
||||||
<ListItemComponent
|
<ListItem
|
||||||
key={x.id}
|
key={x.id}
|
||||||
data={x}
|
data={x}
|
||||||
path={path}
|
path={path}
|
||||||
|
|||||||
@ -2,10 +2,10 @@ import { Menu, MenuItem } from "@material-ui/core";
|
|||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
import { IoIosArrowDown, IoIosArrowUp } from "react-icons/io";
|
import { IoIosArrowDown, IoIosArrowUp } from "react-icons/io";
|
||||||
import { MdMoreVert } from "react-icons/md";
|
import { MdMoreVert } from "react-icons/md";
|
||||||
import ResumeContext from "../../../../contexts/ResumeContext";
|
import ResumeContext from "../../../contexts/ResumeContext";
|
||||||
import styles from "./TripleFieldListItem.module.css";
|
import styles from "./ListItem.module.css";
|
||||||
|
|
||||||
const TripleFieldListItem = ({
|
const ListItem = ({
|
||||||
title,
|
title,
|
||||||
subtitle,
|
subtitle,
|
||||||
text,
|
text,
|
||||||
@ -67,9 +67,14 @@ const TripleFieldListItem = ({
|
|||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className="grid">
|
<div className="grid">
|
||||||
<span className="font-medium truncate">{title}</span>
|
<span className="font-medium truncate">{title}</span>
|
||||||
<span className="mt-1 text-sm opacity-75 truncate">{subtitle}</span>
|
|
||||||
|
|
||||||
<span className="w-4/5 mt-5 text-sm opacity-75 truncate">{text}</span>
|
{subtitle && (
|
||||||
|
<span className="mt-1 text-sm opacity-75 truncate">{subtitle}</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{text && (
|
||||||
|
<span className="w-4/5 mt-5 text-sm opacity-75 truncate">{text}</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.menu}>
|
<div className={styles.menu}>
|
||||||
@ -103,4 +108,4 @@ const TripleFieldListItem = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TripleFieldListItem;
|
export default ListItem;
|
||||||
@ -1,103 +0,0 @@
|
|||||||
import { Menu, MenuItem } from "@material-ui/core";
|
|
||||||
import React, { useContext, useState } from "react";
|
|
||||||
import { IoIosArrowDown, IoIosArrowUp } from "react-icons/io";
|
|
||||||
import { MdMoreVert } from "react-icons/md";
|
|
||||||
import ResumeContext from "../../../../contexts/ResumeContext";
|
|
||||||
import styles from "./DoubleFieldListItem.module.css";
|
|
||||||
|
|
||||||
const DoubleFieldListItem = ({
|
|
||||||
title,
|
|
||||||
subtitle,
|
|
||||||
path,
|
|
||||||
data,
|
|
||||||
isFirst,
|
|
||||||
isLast,
|
|
||||||
onEdit,
|
|
||||||
}) => {
|
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
|
||||||
const { dispatch } = useContext(ResumeContext);
|
|
||||||
|
|
||||||
const handleClick = (event) => setAnchorEl(event.currentTarget);
|
|
||||||
|
|
||||||
const handleClose = () => setAnchorEl(null);
|
|
||||||
|
|
||||||
const handleEdit = () => {
|
|
||||||
onEdit();
|
|
||||||
handleClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMoveUp = () => {
|
|
||||||
dispatch({
|
|
||||||
type: "on_move_item_up",
|
|
||||||
payload: {
|
|
||||||
path,
|
|
||||||
value: data,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
handleClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMoveDown = () => {
|
|
||||||
dispatch({
|
|
||||||
type: "on_move_item_down",
|
|
||||||
payload: {
|
|
||||||
path,
|
|
||||||
value: data,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
handleClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDelete = () => {
|
|
||||||
dispatch({
|
|
||||||
type: "on_delete_item",
|
|
||||||
payload: {
|
|
||||||
path,
|
|
||||||
value: data,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
handleClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.container}>
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<span className="font-medium truncate">{title}</span>
|
|
||||||
<span className="mt-1 text-sm opacity-75 truncate">{subtitle}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.menu}>
|
|
||||||
<MdMoreVert
|
|
||||||
size="18px"
|
|
||||||
aria-haspopup="true"
|
|
||||||
onClick={handleClick}
|
|
||||||
className="cursor-pointer"
|
|
||||||
/>
|
|
||||||
<Menu
|
|
||||||
keepMounted
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
onClose={handleClose}
|
|
||||||
open={Boolean(anchorEl)}
|
|
||||||
>
|
|
||||||
<div className="flex items-center space-around">
|
|
||||||
<MenuItem disabled={isFirst} onClick={handleMoveUp}>
|
|
||||||
<IoIosArrowUp size="18px" />
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem disabled={isLast} onClick={handleMoveDown}>
|
|
||||||
<IoIosArrowDown size="18px" />
|
|
||||||
</MenuItem>
|
|
||||||
</div>
|
|
||||||
<MenuItem onClick={handleEdit}>Edit</MenuItem>
|
|
||||||
<MenuItem onClick={handleDelete}>
|
|
||||||
<span className="text-red-600 font-medium">Delete</span>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DoubleFieldListItem;
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
.container {
|
|
||||||
@apply flex items-center justify-between border-t border-secondary px-6 py-5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container:first-child {
|
|
||||||
@apply border-t-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu {
|
|
||||||
@apply opacity-0;
|
|
||||||
@apply transition-opacity duration-200 ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container:hover .menu {
|
|
||||||
@apply opacity-100;
|
|
||||||
@apply transition-opacity duration-200 ease-in-out;
|
|
||||||
}
|
|
||||||
@ -2,7 +2,6 @@ import { get } from "lodash";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Heading from "../../shared/Heading";
|
import Heading from "../../shared/Heading";
|
||||||
import List from "../lists/List";
|
import List from "../lists/List";
|
||||||
import TripleFieldListItem from "../lists/triple/TripleFieldListItem";
|
|
||||||
|
|
||||||
const Awards = ({ id, name, event, state }) => {
|
const Awards = ({ id, name, event, state }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -19,7 +18,6 @@ const Awards = ({ id, name, event, state }) => {
|
|||||||
titlePath="title"
|
titlePath="title"
|
||||||
subtitlePath="awarder"
|
subtitlePath="awarder"
|
||||||
textPath="summary"
|
textPath="summary"
|
||||||
listItemComponent={TripleFieldListItem}
|
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
26
src/components/builder/sections/Certifications.js
Normal file
26
src/components/builder/sections/Certifications.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { get } from "lodash";
|
||||||
|
import React from "react";
|
||||||
|
import Heading from "../../shared/Heading";
|
||||||
|
import List from "../lists/List";
|
||||||
|
|
||||||
|
const Certifications = ({ id, name, event, state }) => {
|
||||||
|
const path = `${id}.items`;
|
||||||
|
const items = get(state, path, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<Heading>{name}</Heading>
|
||||||
|
|
||||||
|
<List
|
||||||
|
path={path}
|
||||||
|
items={items}
|
||||||
|
event={event}
|
||||||
|
titlePath="title"
|
||||||
|
subtitlePath="issuer"
|
||||||
|
textPath="summary"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Certifications;
|
||||||
@ -2,7 +2,6 @@ import { get } from "lodash";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Heading from "../../shared/Heading";
|
import Heading from "../../shared/Heading";
|
||||||
import List from "../lists/List";
|
import List from "../lists/List";
|
||||||
import TripleFieldListItem from "../lists/triple/TripleFieldListItem";
|
|
||||||
|
|
||||||
const Education = ({ id, name, event, state }) => {
|
const Education = ({ id, name, event, state }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -18,7 +17,6 @@ const Education = ({ id, name, event, state }) => {
|
|||||||
event={event}
|
event={event}
|
||||||
titlePath="institution"
|
titlePath="institution"
|
||||||
textPath="field"
|
textPath="field"
|
||||||
listItemComponent={TripleFieldListItem}
|
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { get } from "lodash";
|
import { get } from "lodash";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Heading from "../../shared/Heading";
|
import Heading from "../../shared/Heading";
|
||||||
import DoubleFieldListItem from "../lists/double/DoubleFieldListItem";
|
|
||||||
import List from "../lists/List";
|
import List from "../lists/List";
|
||||||
|
|
||||||
const Social = ({ id, name, event, state }) => {
|
const Social = ({ id, name, event, state }) => {
|
||||||
@ -18,7 +17,6 @@ const Social = ({ id, name, event, state }) => {
|
|||||||
event={event}
|
event={event}
|
||||||
titlePath="network"
|
titlePath="network"
|
||||||
subtitlePath="username"
|
subtitlePath="username"
|
||||||
listItemComponent={DoubleFieldListItem}
|
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { get } from "lodash";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Heading from "../../shared/Heading";
|
import Heading from "../../shared/Heading";
|
||||||
import List from "../lists/List";
|
import List from "../lists/List";
|
||||||
import TripleFieldListItem from "../lists/triple/TripleFieldListItem";
|
|
||||||
|
|
||||||
const Work = ({ id, name, event, state }) => {
|
const Work = ({ id, name, event, state }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -18,7 +17,6 @@ const Work = ({ id, name, event, state }) => {
|
|||||||
event={event}
|
event={event}
|
||||||
titlePath="company"
|
titlePath="company"
|
||||||
textPath="summary"
|
textPath="summary"
|
||||||
listItemComponent={TripleFieldListItem}
|
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -5,6 +5,7 @@ const ModalEvents = {
|
|||||||
WORK_MODAL: "work_modal",
|
WORK_MODAL: "work_modal",
|
||||||
EDUCATION_MODAL: "education_modal",
|
EDUCATION_MODAL: "education_modal",
|
||||||
AWARD_MODAL: "award_modal",
|
AWARD_MODAL: "award_modal",
|
||||||
|
CERTIFICATION_MODAL: "certification_modal",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ModalEvents;
|
export default ModalEvents;
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { AiOutlineTwitter } from "react-icons/ai";
|
import { AiFillSafetyCertificate, AiOutlineTwitter } from "react-icons/ai";
|
||||||
import { FaAward } from "react-icons/fa";
|
import { FaAward } from "react-icons/fa";
|
||||||
import { IoMdBriefcase, IoMdDocument } from "react-icons/io";
|
import { IoMdBriefcase, IoMdDocument } from "react-icons/io";
|
||||||
import { MdPerson, MdSchool } from "react-icons/md";
|
import { MdPerson, MdSchool } from "react-icons/md";
|
||||||
import Awards from "../components/builder/sections/Awards";
|
import Awards from "../components/builder/sections/Awards";
|
||||||
|
import Certifications from "../components/builder/sections/Certifications";
|
||||||
import Education from "../components/builder/sections/Education";
|
import Education from "../components/builder/sections/Education";
|
||||||
import Objective from "../components/builder/sections/Objective";
|
import Objective from "../components/builder/sections/Objective";
|
||||||
import Profile from "../components/builder/sections/Profile";
|
import Profile from "../components/builder/sections/Profile";
|
||||||
@ -51,4 +52,11 @@ export default [
|
|||||||
component: Awards,
|
component: Awards,
|
||||||
event: ModalEvents.AWARD_MODAL,
|
event: ModalEvents.AWARD_MODAL,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "certifications",
|
||||||
|
name: "Certifications",
|
||||||
|
icon: AiFillSafetyCertificate,
|
||||||
|
component: Certifications,
|
||||||
|
event: ModalEvents.CERTIFICATION_MODAL,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import React, { Fragment } from "react";
|
|||||||
import AuthModal from "./AuthModal";
|
import AuthModal from "./AuthModal";
|
||||||
import ResumeModal from "./ResumeModal";
|
import ResumeModal from "./ResumeModal";
|
||||||
import AwardModal from "./sections/AwardModal";
|
import AwardModal from "./sections/AwardModal";
|
||||||
|
import CertificateModal from "./sections/CertificateModal";
|
||||||
import EducationModal from "./sections/EducationModal";
|
import EducationModal from "./sections/EducationModal";
|
||||||
import SocialModal from "./sections/SocialModal";
|
import SocialModal from "./sections/SocialModal";
|
||||||
import WorkModal from "./sections/WorkModal";
|
import WorkModal from "./sections/WorkModal";
|
||||||
@ -15,6 +16,7 @@ const ModalRegistrar = () => {
|
|||||||
<WorkModal />
|
<WorkModal />
|
||||||
<EducationModal />
|
<EducationModal />
|
||||||
<AwardModal />
|
<AwardModal />
|
||||||
|
<CertificateModal />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -36,8 +36,8 @@ const AwardModal = () => {
|
|||||||
>
|
>
|
||||||
{(formik) => (
|
{(formik) => (
|
||||||
<DataModal
|
<DataModal
|
||||||
|
name="Award"
|
||||||
path="awards.items"
|
path="awards.items"
|
||||||
name="Awards"
|
|
||||||
event={ModalEvents.AWARD_MODAL}
|
event={ModalEvents.AWARD_MODAL}
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-2 gap-8">
|
<div className="grid grid-cols-2 gap-8">
|
||||||
|
|||||||
76
src/modals/sections/CertificateModal.js
Normal file
76
src/modals/sections/CertificateModal.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { Formik } from "formik";
|
||||||
|
import { get } from "lodash";
|
||||||
|
import React from "react";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import Input from "../../components/shared/Input";
|
||||||
|
import ModalEvents from "../../constants/ModalEvents";
|
||||||
|
import DataModal from "../DataModal";
|
||||||
|
|
||||||
|
const initialValues = {
|
||||||
|
title: "",
|
||||||
|
issuer: "",
|
||||||
|
date: "",
|
||||||
|
summary: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
const validationSchema = Yup.object().shape({
|
||||||
|
title: Yup.string().required("This is a required field."),
|
||||||
|
issuer: Yup.string().required("This is a required field."),
|
||||||
|
date: Yup.date().max(new Date()),
|
||||||
|
summary: Yup.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const CertificateModal = () => {
|
||||||
|
const getFieldProps = (formik, name) => ({
|
||||||
|
touched: get(formik, `touched.${name}`, false),
|
||||||
|
error: get(formik, `errors.${name}`, ""),
|
||||||
|
isRequired: get(validationSchema, `fields.${name}._exclusive.required`),
|
||||||
|
...formik.getFieldProps(name),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Formik
|
||||||
|
validateOnBlur
|
||||||
|
initialValues={initialValues}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
>
|
||||||
|
{(formik) => (
|
||||||
|
<DataModal
|
||||||
|
name="Certificate"
|
||||||
|
path="certifications.items"
|
||||||
|
event={ModalEvents.CERTIFICATION_MODAL}
|
||||||
|
>
|
||||||
|
<div className="grid grid-cols-2 gap-8">
|
||||||
|
<Input
|
||||||
|
label="Title"
|
||||||
|
className="col-span-2"
|
||||||
|
placeholder="CCNP"
|
||||||
|
{...getFieldProps(formik, "title")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="Issuer"
|
||||||
|
placeholder="Cisco Systems"
|
||||||
|
{...getFieldProps(formik, "issuer")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
type="date"
|
||||||
|
label="Date"
|
||||||
|
{...getFieldProps(formik, "date")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
type="textarea"
|
||||||
|
label="Summary"
|
||||||
|
className="col-span-2"
|
||||||
|
{...getFieldProps(formik, "summary")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DataModal>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CertificateModal;
|
||||||
@ -51,8 +51,8 @@ const EducationModal = () => {
|
|||||||
>
|
>
|
||||||
{(formik) => (
|
{(formik) => (
|
||||||
<DataModal
|
<DataModal
|
||||||
path="education.items"
|
|
||||||
name="Education"
|
name="Education"
|
||||||
|
path="education.items"
|
||||||
event={ModalEvents.EDUCATION_MODAL}
|
event={ModalEvents.EDUCATION_MODAL}
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-2 gap-8">
|
<div className="grid grid-cols-2 gap-8">
|
||||||
|
|||||||
Reference in New Issue
Block a user