- implementing hobby, language and reference sections

- dynamic template selection
This commit is contained in:
Amruth Pillai
2020-07-09 10:41:16 +05:30
parent 9045e2983d
commit 9e98da038c
38 changed files with 470 additions and 187 deletions

15
package-lock.json generated
View File

@ -5496,9 +5496,9 @@
} }
}, },
"colorette": { "colorette": {
"version": "1.2.0", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.0.tgz", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
"integrity": "sha512-soRSroY+OF/8OdA3PTQXwaDJeMc7TfknKKrxeSCencL2a4+Tx5zhxmmv7hdpCjhKBjehzp8+bwe/T68K0hpIjw==" "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw=="
}, },
"colors": { "colors": {
"version": "1.4.0", "version": "1.4.0",
@ -16229,6 +16229,15 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.7.2.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.7.2.tgz",
"integrity": "sha512-u5l7fhAJXecWUJzVxzMRU2Zvw8m4QmDNHlTrT5uo3KBlYBhmChd7syAakBoay1yIiVhx/8Fi7a6v6kQZfsw81Q==" "integrity": "sha512-u5l7fhAJXecWUJzVxzMRU2Zvw8m4QmDNHlTrT5uo3KBlYBhmChd7syAakBoay1yIiVhx/8Fi7a6v6kQZfsw81Q=="
}, },
"react-scroll": {
"version": "1.7.16",
"resolved": "https://registry.npmjs.org/react-scroll/-/react-scroll-1.7.16.tgz",
"integrity": "sha512-f4M5AdL+3cw3MJ7c/T0hPMY2iHCeQLDXV13lRanAFQ6JIt9xyAdHCpTH9mLUQt9SQh4pRarD+Qc7KhU6qMx3Yg==",
"requires": {
"lodash.throttle": "^4.1.1",
"prop-types": "^15.5.8"
}
},
"react-side-effect": { "react-side-effect": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz", "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz",

View File

@ -45,11 +45,13 @@
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"react-icons": "^3.10.0", "react-icons": "^3.10.0",
"react-scroll": "^1.7.16",
"react-toastify": "^6.0.8", "react-toastify": "^6.0.8",
"uuid": "^8.2.0", "uuid": "^8.2.0",
"yup": "^0.29.1" "yup": "^0.29.1"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "^9.8.4",
"eslint": "^7.4.0", "eslint": "^7.4.0",
"eslint-config-airbnb": "^18.2.0", "eslint-config-airbnb": "^18.2.0",
"eslint-config-prettier": "^6.11.0", "eslint-config-prettier": "^6.11.0",

View File

@ -1,5 +1,6 @@
const tailwindcss = require('tailwindcss'); const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
module.exports = () => ({ module.exports = () => ({
plugins: [tailwindcss], plugins: [tailwindcss, autoprefixer],
}); });

View File

@ -6,8 +6,8 @@ import Onyx from '../../../templates/Onyx';
import styles from './Artboard.module.css'; import styles from './Artboard.module.css';
const Artboard = () => { const Artboard = () => {
const { blocks, colors } = useContext(TemplateContext); const { selected, blocks, colors } = useContext(TemplateContext);
const state = useSelector((s) => s); const state = useSelector((store) => store);
const { id, name } = state; const { id, name } = state;
return ( return (
@ -18,7 +18,9 @@ const Artboard = () => {
</Helmet> </Helmet>
<div id="artboard" className={styles.container}> <div id="artboard" className={styles.container}>
<Onyx data={state} layout={blocks} colors={colors} /> {selected === 'Onyx' && (
<Onyx data={state} layout={blocks} colors={colors} />
)}
</div> </div>
</div> </div>
); );

View File

@ -16,7 +16,7 @@ const LeftNavbar = () => (
<div className="grid grid-cols-1 gap-8"> <div className="grid grid-cols-1 gap-8">
{sections.map((x) => ( {sections.map((x) => (
<SectionIcon key={x.id} section={x} /> <SectionIcon key={x.id} section={x} containerId="LeftSidebar" />
))} ))}
</div> </div>

View File

@ -1,4 +1,5 @@
import React, { Fragment } from 'react'; import React from 'react';
import { Element } from 'react-scroll';
import sections from '../../../data/leftSections'; import sections from '../../../data/leftSections';
import LeftNavbar from './LeftNavbar'; import LeftNavbar from './LeftNavbar';
import styles from './LeftSidebar.module.css'; import styles from './LeftSidebar.module.css';
@ -7,12 +8,12 @@ const LeftSidebar = () => (
<div className="flex"> <div className="flex">
<LeftNavbar /> <LeftNavbar />
<div className={styles.container}> <div id="LeftSidebar" className={styles.container}>
{sections.map(({ id, name, event, component: Component }) => ( {sections.map(({ id, name, event, component: Component }) => (
<Fragment key={id}> <Element key={id} name={id}>
<Component id={id} name={name} event={event} /> <Component id={id} name={name} event={event} />
<hr /> <hr />
</Fragment> </Element>
))} ))}
</div> </div>
</div> </div>

View File

@ -1,9 +1,9 @@
import { get, isEmpty } from 'lodash'; import { get, isEmpty } from 'lodash';
import moment from 'moment';
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { MdAdd } from 'react-icons/md'; import { MdAdd } from 'react-icons/md';
import ModalContext from '../../../contexts/ModalContext'; import ModalContext from '../../../contexts/ModalContext';
import { useSelector } from '../../../contexts/ResumeContext'; import { useSelector } from '../../../contexts/ResumeContext';
import { formatDateRange } from '../../../utils';
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';
@ -17,6 +17,7 @@ const List = ({
subtitlePath, subtitlePath,
text, text,
textPath, textPath,
hasDate,
event, event,
}) => { }) => {
const items = useSelector((state) => get(state, path, [])); const items = useSelector((state) => get(state, path, []));
@ -26,13 +27,6 @@ const List = ({
const handleEdit = (data) => emitter.emit(event, data); const handleEdit = (data) => emitter.emit(event, data);
const formatDateRange = (x) =>
`${moment(x.startDate).format('MMMM Y')}${
moment(x.endDate).isValid()
? moment(x.endDate).format('MMMM Y')
: 'Present'
}`;
return ( return (
<div className="flex flex-col"> <div className="flex flex-col">
<div className={styles.list}> <div className={styles.list}>
@ -46,10 +40,11 @@ const List = ({
path={path} path={path}
title={title || get(x, titlePath, '')} title={title || get(x, titlePath, '')}
subtitle={ subtitle={
subtitle || get(x, subtitlePath, '') || formatDateRange(x) subtitle ||
get(x, subtitlePath, '') ||
(hasDate && formatDateRange(x))
} }
text={text || get(x, textPath, '')} text={text || get(x, textPath, '')}
className={styles.listItem}
onEdit={() => handleEdit(x)} onEdit={() => handleEdit(x)}
isFirst={i === 0} isFirst={i === 0}
isLast={i === items.length - 1} isLast={i === items.length - 1}

View File

@ -1,21 +1,3 @@
.list { .list {
@apply flex flex-col border border-secondary rounded; @apply flex flex-col border border-secondary rounded;
} }
.list-item {
@apply flex items-center justify-between border-t border-secondary px-8 py-5;
}
.list-item:first-child {
@apply border-t-0;
}
.menu {
@apply opacity-0;
@apply transition-opacity duration-200 ease-in-out;
}
.list-item:hover .menu {
@apply opacity-100;
@apply transition-opacity duration-200 ease-in-out;
}

View File

@ -64,7 +64,7 @@ const ListItem = ({
}; };
return ( return (
<div className={styles.container}> <div className={styles.listItem}>
<div className="grid"> <div className="grid">
<span className="font-medium truncate">{title}</span> <span className="font-medium truncate">{title}</span>

View File

@ -1,8 +1,8 @@
.container { .listItem {
@apply flex items-center justify-between border-t border-secondary px-6 py-5; @apply flex items-center justify-between border-t border-secondary px-6 py-5;
} }
.container:first-child { .listItem:first-child {
@apply border-t-0; @apply border-t-0;
} }
@ -11,7 +11,7 @@
@apply transition-opacity duration-200 ease-in-out; @apply transition-opacity duration-200 ease-in-out;
} }
.container:hover .menu { .listItem:hover .menu {
@apply opacity-100; @apply opacity-100;
@apply transition-opacity duration-200 ease-in-out; @apply transition-opacity duration-200 ease-in-out;
} }

View File

@ -10,6 +10,7 @@ const Education = ({ id, name, event }) => {
<Heading>{name}</Heading> <Heading>{name}</Heading>
<List <List
hasDate
path={path} path={path}
event={event} event={event}
titlePath="institution" titlePath="institution"

View File

@ -0,0 +1,17 @@
import React from 'react';
import Heading from '../../shared/Heading';
import List from '../lists/List';
const Hobbies = ({ id, name, event }) => {
const path = `${id}.items`;
return (
<section>
<Heading>{name}</Heading>
<List path={path} event={event} titlePath="name" />
</section>
);
};
export default Hobbies;

View File

@ -0,0 +1,17 @@
import React from 'react';
import Heading from '../../shared/Heading';
import List from '../lists/List';
const Languages = ({ id, name, event }) => {
const path = `${id}.items`;
return (
<section>
<Heading>{name}</Heading>
<List path={path} event={event} titlePath="name" subtitlePath="fluency" />
</section>
);
};
export default Languages;

View File

@ -0,0 +1,23 @@
import React from 'react';
import Heading from '../../shared/Heading';
import List from '../lists/List';
const References = ({ id, name, event }) => {
const path = `${id}.items`;
return (
<section>
<Heading>{name}</Heading>
<List
path={path}
event={event}
titlePath="name"
subtitlePath="position"
textPath="summary"
/>
</section>
);
};
export default References;

View File

@ -9,7 +9,13 @@ const Work = ({ id, name, event }) => {
<section> <section>
<Heading>{name}</Heading> <Heading>{name}</Heading>
<List path={path} event={event} titlePath="company" textPath="summary" /> <List
hasDate
path={path}
event={event}
titlePath="company"
textPath="summary"
/>
</section> </section>
); );
}; };

View File

@ -1,7 +1,7 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { MdAdd } from 'react-icons/md'; import { MdAdd } from 'react-icons/md';
import ModalContext from '../../contexts/ModalContext'; import ModalContext from '../../contexts/ModalContext';
import { handleKeyDown } from '../../utils'; import { handleKeyUp } from '../../utils';
import styles from './CreateResume.module.css'; import styles from './CreateResume.module.css';
const CreateResume = () => { const CreateResume = () => {
@ -19,7 +19,7 @@ const CreateResume = () => {
role="button" role="button"
className={styles.page} className={styles.page}
onClick={handleClick} onClick={handleClick}
onKeyDown={(e) => handleKeyDown(e, handleClick)} onKeyUp={(e) => handleKeyUp(e, handleClick)}
> >
<MdAdd size="48" /> <MdAdd size="48" />
</div> </div>

View File

@ -1,6 +1,6 @@
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';
import { handleKeyDown } from '../../utils'; import { handleKeyUp } from '../../utils';
import styles from './Button.module.css'; import styles from './Button.module.css';
const Button = ({ icon, title, onClick, outline, className, isLoading }) => { const Button = ({ icon, title, onClick, outline, className, isLoading }) => {
@ -12,7 +12,7 @@ const Button = ({ icon, title, onClick, outline, className, isLoading }) => {
return ( return (
<button <button
className={classes} className={classes}
onKeyDown={(e) => handleKeyDown(e, onClick)} onKeyUp={(e) => handleKeyUp(e, onClick)}
onClick={isLoading ? undefined : onClick} onClick={isLoading ? undefined : onClick}
> >
{icon && <Icon size="14" className="mr-2" />} {icon && <Icon size="14" className="mr-2" />}

View File

@ -1,10 +1,11 @@
import cx from 'classnames'; import cx from 'classnames';
import { get, isFunction } from 'lodash'; import { get, isFunction } from 'lodash';
import React from 'react'; import React, { useEffect, useState } from 'react';
import { FaAngleDown } from 'react-icons/fa';
import { MdClose } from 'react-icons/md'; import { MdClose } from 'react-icons/md';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { useDispatch, useSelector } from '../../contexts/ResumeContext'; import { useDispatch, useSelector } from '../../contexts/ResumeContext';
import { handleKeyDown } from '../../utils'; import { handleKeyUp } from '../../utils';
import styles from './Input.module.css'; import styles from './Input.module.css';
const Input = ({ const Input = ({
@ -14,8 +15,8 @@ const Input = ({
error, error,
value, value,
onBlur, onBlur,
options,
touched, touched,
checked,
onChange, onChange,
className, className,
isRequired, isRequired,
@ -24,11 +25,15 @@ const Input = ({
showDeleteItemButton, showDeleteItemButton,
type = 'text', type = 'text',
}) => { }) => {
const uuid = uuidv4(); const [uuid, setUuid] = useState(null);
const stateValue = useSelector((state) => get(state, path)); const stateValue = useSelector((state) => get(state, path));
const dispatch = useDispatch(); const dispatch = useDispatch();
value = value || stateValue; useEffect(() => {
setUuid(uuidv4());
}, []);
value = isFunction(onChange) ? value : stateValue;
onChange = isFunction(onChange) onChange = isFunction(onChange)
? onChange ? onChange
: (e) => { : (e) => {
@ -51,7 +56,7 @@ const Input = ({
)} )}
</span> </span>
{type === 'text' && ( {(type === 'text' || type === 'date') && (
<div className="relative grid items-center"> <div className="relative grid items-center">
<input <input
id={uuid} id={uuid}
@ -59,7 +64,6 @@ const Input = ({
type={type} type={type}
value={value} value={value}
onBlur={onBlur} onBlur={onBlur}
checked={checked}
onChange={onChange} onChange={onChange}
placeholder={placeholder} placeholder={placeholder}
/> />
@ -69,7 +73,7 @@ const Input = ({
size="16px" size="16px"
tabIndex="0" tabIndex="0"
onClick={onDeleteItem} onClick={onDeleteItem}
onKeyDown={(e) => handleKeyDown(e, onDeleteItem)} onKeyUp={(e) => handleKeyUp(e, onDeleteItem)}
className="absolute right-0 cursor-pointer opacity-50 hover:opacity-75 mx-4" className="absolute right-0 cursor-pointer opacity-50 hover:opacity-75 mx-4"
/> />
)} )}
@ -82,10 +86,8 @@ const Input = ({
id={uuid} id={uuid}
rows="4" rows="4"
name={name} name={name}
type={type}
value={value} value={value}
onBlur={onBlur} onBlur={onBlur}
checked={checked}
onChange={onChange} onChange={onChange}
placeholder={placeholder} placeholder={placeholder}
/> />
@ -104,6 +106,27 @@ const Input = ({
</div> </div>
)} )}
{type === 'dropdown' && (
<div className="relative grid items-center">
<select
id={uuid}
name={name}
value={value}
onBlur={onBlur}
onChange={onChange}
>
{options.map((x) => (
<option key={x}>{x}</option>
))}
</select>
<FaAngleDown
size="16px"
className="absolute right-0 opacity-50 hover:opacity-75 mx-4"
/>
</div>
)}
{error && touched && <p>{error}</p>} {error && touched && <p>{error}</p>}
</label> </label>
</div> </div>

View File

@ -3,17 +3,20 @@
} }
.container label input, .container label input,
.container label textarea { .container label textarea,
@apply py-3 px-4 rounded bg-secondary text-primary border border-secondary; .container label select {
@apply py-3 px-4 rounded bg-secondary text-primary border border-secondary appearance-none;
} }
.container label input::placeholder, .container label input::placeholder,
.container label textarea::placeholder { .container label textarea::placeholder,
.container label select::placeholder {
@apply text-primary opacity-50; @apply text-primary opacity-50;
} }
.container label input:focus, .container label input:focus,
.container label textarea:focus { .container label textarea:focus,
.container label select:focus {
@apply outline-none border-gray-500; @apply outline-none border-gray-500;
} }

View File

@ -1,7 +1,7 @@
import React, { useContext, useRef } from 'react'; import React, { useContext, useRef } from 'react';
import { MdFileUpload } from 'react-icons/md'; import { MdFileUpload } from 'react-icons/md';
import StorageContext from '../../contexts/StorageContext'; import StorageContext from '../../contexts/StorageContext';
import { handleKeyDown } from '../../utils'; import { handleKeyUp } from '../../utils';
import Input from './Input'; import Input from './Input';
import styles from './PhotoUpload.module.css'; import styles from './PhotoUpload.module.css';
@ -25,7 +25,7 @@ const PhotoUpload = () => {
tabIndex="0" tabIndex="0"
className={styles.circle} className={styles.circle}
onClick={handleIconClick} onClick={handleIconClick}
onKeyDown={(e) => handleKeyDown(e, handleIconClick)} onKeyUp={(e) => handleKeyUp(e, handleIconClick)}
> >
<MdFileUpload size="22px" /> <MdFileUpload size="22px" />
<input <input

View File

@ -1,13 +1,30 @@
import { Tooltip } from '@material-ui/core'; import { Tooltip } from '@material-ui/core';
import React from 'react'; import React from 'react';
import { scroller } from 'react-scroll';
import { handleKeyUp } from '../../utils';
const SectionIcon = ({ section, placement = 'right' }) => { const SectionIcon = ({ section, containerId, placement = 'right' }) => {
const { icon: Icon, name } = section; const { id, name, icon: Icon } = section;
const handleClick = () => {
scroller.scrollTo(id, {
duration: 500,
smooth: true,
containerId,
offset: -10,
});
};
return ( return (
<Tooltip title={name} placement={placement} arrow> <Tooltip title={name} placement={placement} arrow>
<div className="cursor-pointer"> <div
<Icon className="text-secondary-dark hover:text-primary" size="20px" /> tabIndex="0"
role="button"
className="cursor-pointer focus:outline-none"
onKeyUp={(e) => handleKeyUp(e, handleClick)}
onClick={handleClick}
>
<Icon className="text-secondary-dark hover:text-primary" size="16px" />
</div> </div>
</Tooltip> </Tooltip>
); );

View File

@ -7,6 +7,9 @@ const ModalEvents = {
AWARD_MODAL: 'award_modal', AWARD_MODAL: 'award_modal',
CERTIFICATION_MODAL: 'certification_modal', CERTIFICATION_MODAL: 'certification_modal',
SKILL_MODAL: 'skill_modal', SKILL_MODAL: 'skill_modal',
HOBBY_MODAL: 'hobby_modal',
LANGUAGE_MODAL: 'language_modal',
REFERENCE_MODAL: 'reference_modal',
}; };
export default ModalEvents; export default ModalEvents;

View File

@ -3,7 +3,7 @@ import React, { createContext, useState } from 'react';
import leftSections from '../data/leftSections'; import leftSections from '../data/leftSections';
const defaultState = { const defaultState = {
selected: 'Pikachu', selected: 'Onyx',
setSelected: () => {}, setSelected: () => {},
colors: { colors: {
textColor: '#212121', textColor: '#212121',

View File

@ -1,12 +1,20 @@
import { AiFillSafetyCertificate, AiOutlineTwitter } from 'react-icons/ai'; import { AiFillSafetyCertificate, AiOutlineTwitter } from 'react-icons/ai';
import { FaAward, FaTools } from 'react-icons/fa'; import { BsTools } from 'react-icons/bs';
import { IoMdBriefcase, IoMdDocument } from 'react-icons/io'; import { FaAward, FaUserFriends } from 'react-icons/fa';
import { MdPerson, MdSchool } from 'react-icons/md'; import {
IoLogoGameControllerB,
IoMdBriefcase,
IoMdDocument,
} from 'react-icons/io';
import { MdPerson, MdSchool, MdTranslate } 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 Certifications from '../components/builder/sections/Certifications';
import Education from '../components/builder/sections/Education'; import Education from '../components/builder/sections/Education';
import Hobbies from '../components/builder/sections/Hobbies';
import Languages from '../components/builder/sections/Languages';
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';
import References from '../components/builder/sections/References';
import Skills from '../components/builder/sections/Skills'; import Skills from '../components/builder/sections/Skills';
import Social from '../components/builder/sections/Social'; import Social from '../components/builder/sections/Social';
import Work from '../components/builder/sections/Work'; import Work from '../components/builder/sections/Work';
@ -63,8 +71,29 @@ export default [
{ {
id: 'skills', id: 'skills',
name: 'Skills', name: 'Skills',
icon: FaTools, icon: BsTools,
component: Skills, component: Skills,
event: ModalEvents.SKILL_MODAL, event: ModalEvents.SKILL_MODAL,
}, },
{
id: 'hobbies',
name: 'Hobbies',
icon: IoLogoGameControllerB,
component: Hobbies,
event: ModalEvents.HOBBY_MODAL,
},
{
id: 'languages',
name: 'Languages',
icon: MdTranslate,
component: Languages,
event: ModalEvents.LANGUAGE_MODAL,
},
{
id: 'references',
name: 'References',
icon: FaUserFriends,
component: References,
event: ModalEvents.REFERENCE_MODAL,
},
]; ];

View File

@ -5,7 +5,7 @@ import { isFunction } from 'lodash';
import React, { forwardRef, useImperativeHandle } from 'react'; import React, { forwardRef, useImperativeHandle } from 'react';
import { MdClose } from 'react-icons/md'; import { MdClose } from 'react-icons/md';
import Button from '../components/shared/Button'; import Button from '../components/shared/Button';
import { handleKeyDown } from '../utils'; import { handleKeyUp } from '../utils';
import styles from './BaseModal.module.css'; import styles from './BaseModal.module.css';
const BaseModal = forwardRef( const BaseModal = forwardRef(
@ -38,7 +38,7 @@ const BaseModal = forwardRef(
size="18" size="18"
tabIndex="0" tabIndex="0"
onClick={handleClose} onClick={handleClose}
onKeyDown={(e) => handleKeyDown(e, handleClose)} onKeyUp={(e) => handleKeyUp(e, handleClose)}
/> />
</div> </div>

View File

@ -41,7 +41,7 @@ const DataModal = ({
}, [data]); }, [data]);
const onSubmit = async (newData) => { const onSubmit = async (newData) => {
if (isEmpty(await validateForm(newData))) { if (isEmpty(await validateForm())) {
if (isEditMode) { if (isEditMode) {
if (data !== newData) { if (data !== newData) {
isFunction(onEdit) isFunction(onEdit)

View File

@ -4,6 +4,9 @@ import ResumeModal from './ResumeModal';
import AwardModal from './sections/AwardModal'; import AwardModal from './sections/AwardModal';
import CertificateModal from './sections/CertificateModal'; import CertificateModal from './sections/CertificateModal';
import EducationModal from './sections/EducationModal'; import EducationModal from './sections/EducationModal';
import HobbyModal from './sections/HobbyModal';
import LanguageModal from './sections/LanguageModal';
import ReferenceModal from './sections/ReferenceModal';
import SkillModal from './sections/SkillModal'; import SkillModal from './sections/SkillModal';
import SocialModal from './sections/SocialModal'; import SocialModal from './sections/SocialModal';
import WorkModal from './sections/WorkModal'; import WorkModal from './sections/WorkModal';
@ -19,6 +22,9 @@ const ModalRegistrar = () => {
<AwardModal /> <AwardModal />
<CertificateModal /> <CertificateModal />
<SkillModal /> <SkillModal />
<HobbyModal />
<LanguageModal />
<ReferenceModal />
</> </>
); );
}; };

View File

@ -1,17 +1,17 @@
import { Formik } from 'formik'; import { Formik } from 'formik';
import { get } from 'lodash';
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import * as Yup from 'yup'; import * as Yup from 'yup';
import Input from '../components/shared/Input'; import Input from '../components/shared/Input';
import ModalEvents from '../constants/ModalEvents'; import ModalEvents from '../constants/ModalEvents';
import DatabaseContext from '../contexts/DatabaseContext'; import DatabaseContext from '../contexts/DatabaseContext';
import { getFieldProps } from '../utils';
import DataModal from './DataModal'; import DataModal from './DataModal';
const initialValues = { const initialValues = {
name: '', name: '',
}; };
const validationSchema = Yup.object().shape({ const schema = Yup.object().shape({
name: Yup.string() name: Yup.string()
.min(5, 'Please enter at least 5 characters.') .min(5, 'Please enter at least 5 characters.')
.required('This is a required field.'), .required('This is a required field.'),
@ -20,18 +20,11 @@ const validationSchema = Yup.object().shape({
const ResumeModal = () => { const ResumeModal = () => {
const { createResume, updateResume } = useContext(DatabaseContext); const { createResume, updateResume } = useContext(DatabaseContext);
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 ( return (
<Formik <Formik
validateOnBlur validateOnBlur
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={schema}
> >
{(formik) => ( {(formik) => (
<DataModal <DataModal
@ -48,7 +41,7 @@ const ResumeModal = () => {
label="Name" label="Name"
className="mb-8" className="mb-8"
placeholder="Full Stack Web Developer" placeholder="Full Stack Web Developer"
{...getFieldProps(formik, 'name')} {...getFieldProps(formik, schema, 'name')}
/> />
<p> <p>

View File

@ -1,9 +1,9 @@
import { Formik } from 'formik'; import { Formik } from 'formik';
import { get } from 'lodash';
import React from 'react'; import React from 'react';
import * as Yup from 'yup'; import * as Yup from 'yup';
import Input from '../../components/shared/Input'; import Input from '../../components/shared/Input';
import ModalEvents from '../../constants/ModalEvents'; import ModalEvents from '../../constants/ModalEvents';
import { getFieldProps } from '../../utils';
import DataModal from '../DataModal'; import DataModal from '../DataModal';
const initialValues = { const initialValues = {
@ -13,7 +13,7 @@ const initialValues = {
summary: '', summary: '',
}; };
const validationSchema = Yup.object().shape({ const schema = Yup.object().shape({
title: Yup.string().required('This is a required field.'), title: Yup.string().required('This is a required field.'),
awarder: Yup.string().required('This is a required field.'), awarder: Yup.string().required('This is a required field.'),
date: Yup.date().max(new Date()), date: Yup.date().max(new Date()),
@ -21,18 +21,11 @@ const validationSchema = Yup.object().shape({
}); });
const AwardModal = () => { const AwardModal = () => {
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 ( return (
<Formik <Formik
validateOnBlur validateOnBlur
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={schema}
> >
{(formik) => ( {(formik) => (
<DataModal <DataModal
@ -45,26 +38,26 @@ const AwardModal = () => {
label="Title" label="Title"
className="col-span-2" className="col-span-2"
placeholder="Intl. Flutter Hackathon '19" placeholder="Intl. Flutter Hackathon '19"
{...getFieldProps(formik, 'title')} {...getFieldProps(formik, schema, 'title')}
/> />
<Input <Input
label="Awarder" label="Awarder"
placeholder="Google" placeholder="Google"
{...getFieldProps(formik, 'awarder')} {...getFieldProps(formik, schema, 'awarder')}
/> />
<Input <Input
type="date" type="date"
label="Date" label="Date"
{...getFieldProps(formik, 'date')} {...getFieldProps(formik, schema, 'date')}
/> />
<Input <Input
type="textarea" type="textarea"
label="Summary" label="Summary"
className="col-span-2" className="col-span-2"
{...getFieldProps(formik, 'summary')} {...getFieldProps(formik, schema, 'summary')}
/> />
</div> </div>
</DataModal> </DataModal>

View File

@ -1,9 +1,9 @@
import { Formik } from 'formik'; import { Formik } from 'formik';
import { get } from 'lodash';
import React from 'react'; import React from 'react';
import * as Yup from 'yup'; import * as Yup from 'yup';
import Input from '../../components/shared/Input'; import Input from '../../components/shared/Input';
import ModalEvents from '../../constants/ModalEvents'; import ModalEvents from '../../constants/ModalEvents';
import { getFieldProps } from '../../utils';
import DataModal from '../DataModal'; import DataModal from '../DataModal';
const initialValues = { const initialValues = {
@ -13,7 +13,7 @@ const initialValues = {
summary: '', summary: '',
}; };
const validationSchema = Yup.object().shape({ const schema = Yup.object().shape({
title: Yup.string().required('This is a required field.'), title: Yup.string().required('This is a required field.'),
issuer: Yup.string().required('This is a required field.'), issuer: Yup.string().required('This is a required field.'),
date: Yup.date().max(new Date()), date: Yup.date().max(new Date()),
@ -21,18 +21,11 @@ const validationSchema = Yup.object().shape({
}); });
const CertificateModal = () => { 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 ( return (
<Formik <Formik
validateOnBlur validateOnBlur
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={schema}
> >
{(formik) => ( {(formik) => (
<DataModal <DataModal
@ -45,26 +38,26 @@ const CertificateModal = () => {
label="Title" label="Title"
className="col-span-2" className="col-span-2"
placeholder="CCNP" placeholder="CCNP"
{...getFieldProps(formik, 'title')} {...getFieldProps(formik, schema, 'title')}
/> />
<Input <Input
label="Issuer" label="Issuer"
placeholder="Cisco Systems" placeholder="Cisco Systems"
{...getFieldProps(formik, 'issuer')} {...getFieldProps(formik, schema, 'issuer')}
/> />
<Input <Input
type="date" type="date"
label="Date" label="Date"
{...getFieldProps(formik, 'date')} {...getFieldProps(formik, schema, 'date')}
/> />
<Input <Input
type="textarea" type="textarea"
label="Summary" label="Summary"
className="col-span-2" className="col-span-2"
{...getFieldProps(formik, 'summary')} {...getFieldProps(formik, schema, 'summary')}
/> />
</div> </div>
</DataModal> </DataModal>

View File

@ -1,11 +1,10 @@
import { Field, FieldArray, Formik } from 'formik'; import { Field, FieldArray, Formik } from 'formik';
import { get } from 'lodash';
import React from 'react'; import React from 'react';
import { MdAdd } from 'react-icons/md'; import { MdAdd } from 'react-icons/md';
import * as Yup from 'yup'; import * as Yup from 'yup';
import Input from '../../components/shared/Input'; import Input from '../../components/shared/Input';
import ModalEvents from '../../constants/ModalEvents'; import ModalEvents from '../../constants/ModalEvents';
import { handleKeyDown } from '../../utils'; import { getFieldProps, handleKeyUp } from '../../utils';
import DataModal from '../DataModal'; import DataModal from '../DataModal';
const initialValues = { const initialValues = {
@ -19,7 +18,7 @@ const initialValues = {
temp: '', temp: '',
}; };
const validationSchema = Yup.object().shape({ const schema = Yup.object().shape({
institution: Yup.string().required('This is a required field.'), institution: Yup.string().required('This is a required field.'),
field: Yup.string().required('This is a required field.'), field: Yup.string().required('This is a required field.'),
degree: Yup.string(), degree: Yup.string(),
@ -27,27 +26,20 @@ const validationSchema = Yup.object().shape({
startDate: Yup.date().required('This is a required field.'), startDate: Yup.date().required('This is a required field.'),
endDate: Yup.date().when( endDate: Yup.date().when(
'startDate', 'startDate',
(startDate, schema) => (startDate, yupSchema) =>
startDate && startDate &&
schema.min(startDate, 'End Date must be later than Start Date'), yupSchema.min(startDate, 'End Date must be later than Start Date'),
), ),
courses: Yup.array().of(Yup.string().required('This is a required field.')), courses: Yup.array().of(Yup.string().required('This is a required field.')),
temp: Yup.string().ensure(), temp: Yup.string().ensure(),
}); });
const EducationModal = () => { const EducationModal = () => {
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 ( return (
<Formik <Formik
validateOnBlur validateOnBlur
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={schema}
> >
{(formik) => ( {(formik) => (
<DataModal <DataModal
@ -60,40 +52,40 @@ const EducationModal = () => {
label="Institution" label="Institution"
className="col-span-2" className="col-span-2"
placeholder="Dayananda Sagar College of Engineering" placeholder="Dayananda Sagar College of Engineering"
{...getFieldProps(formik, 'institution')} {...getFieldProps(formik, schema, 'institution')}
/> />
<Input <Input
label="Field of Study" label="Field of Study"
className="col-span-2" className="col-span-2"
placeholder="Computer Science &amp; Engineering" placeholder="Computer Science &amp; Engineering"
{...getFieldProps(formik, 'field')} {...getFieldProps(formik, schema, 'field')}
/> />
<Input <Input
label="Degree Type" label="Degree Type"
placeholder="Bachelor's Degree" placeholder="Bachelor's Degree"
{...getFieldProps(formik, 'degree')} {...getFieldProps(formik, schema, 'degree')}
/> />
<Input <Input
label="GPA" label="GPA"
placeholder="8.8" placeholder="8.8"
{...getFieldProps(formik, 'gpa')} {...getFieldProps(formik, schema, 'gpa')}
/> />
<Input <Input
type="date" type="date"
label="Start Date" label="Start Date"
placeholder="6th August 208" placeholder="6th August 208"
{...getFieldProps(formik, 'startDate')} {...getFieldProps(formik, schema, 'startDate')}
/> />
<Input <Input
type="date" type="date"
label="End Date" label="End Date"
placeholder="6th August 208" placeholder="6th August 208"
{...getFieldProps(formik, 'endDate')} {...getFieldProps(formik, schema, 'endDate')}
/> />
<FieldArray <FieldArray
@ -127,13 +119,13 @@ const EducationModal = () => {
<div className="flex items-center"> <div className="flex items-center">
<Input <Input
placeholder="Algorithms &amp; Data Structures" placeholder="Algorithms &amp; Data Structures"
{...getFieldProps(formik, 'temp')} {...getFieldProps(formik, schema, 'temp')}
/> />
<MdAdd <MdAdd
size="18px" size="18px"
tabIndex="0" tabIndex="0"
className="mx-4 cursor-pointer opacity-50 hover:opacity-75" className="mx-4 cursor-pointer opacity-50 hover:opacity-75"
onKeyDown={(e) => handleKeyDown(e, handleClickAdd)} onKeyUp={(e) => handleKeyUp(e, handleClickAdd)}
onClick={handleClickAdd} onClick={handleClickAdd}
/> />
</div> </div>

View File

@ -0,0 +1,44 @@
import { Formik } from 'formik';
import React from 'react';
import * as Yup from 'yup';
import Input from '../../components/shared/Input';
import ModalEvents from '../../constants/ModalEvents';
import { getFieldProps } from '../../utils';
import DataModal from '../DataModal';
const initialValues = {
name: '',
};
const schema = Yup.object().shape({
name: Yup.string().required('This is a required field.'),
});
const HobbyModal = () => {
return (
<Formik
validateOnBlur
initialValues={initialValues}
validationSchema={schema}
>
{(formik) => (
<DataModal
name="Hobby"
path="hobbies.items"
event={ModalEvents.HOBBY_MODAL}
>
<div className="grid grid-cols-2 gap-8">
<Input
label="Name"
placeholder="Fishing"
className="col-span-2"
{...getFieldProps(formik, schema, 'name')}
/>
</div>
</DataModal>
)}
</Formik>
);
};
export default HobbyModal;

View File

@ -0,0 +1,51 @@
import { Formik } from 'formik';
import React from 'react';
import * as Yup from 'yup';
import Input from '../../components/shared/Input';
import ModalEvents from '../../constants/ModalEvents';
import { getFieldProps } from '../../utils';
import DataModal from '../DataModal';
const initialValues = {
name: '',
fluency: '',
};
const schema = Yup.object().shape({
name: Yup.string().required('This is a required field.'),
fluency: Yup.string().required('This is a required field.'),
});
const LanguageModal = () => {
return (
<Formik
validateOnBlur
initialValues={initialValues}
validationSchema={schema}
>
{(formik) => (
<DataModal
name="Language"
path="languages.items"
event={ModalEvents.LANGUAGE_MODAL}
>
<div className="grid grid-cols-2 gap-8">
<Input
label="Name"
placeholder="German"
{...getFieldProps(formik, schema, 'name')}
/>
<Input
label="Fluency"
placeholder="Native/B1"
{...getFieldProps(formik, schema, 'fluency')}
/>
</div>
</DataModal>
)}
</Formik>
);
};
export default LanguageModal;

View File

@ -0,0 +1,76 @@
import { Formik } from 'formik';
import React from 'react';
import * as Yup from 'yup';
import Input from '../../components/shared/Input';
import ModalEvents from '../../constants/ModalEvents';
import { getFieldProps } from '../../utils';
import DataModal from '../DataModal';
const initialValues = {
name: '',
position: '',
contact: '',
email: '',
summary: '',
};
const schema = Yup.object().shape({
name: Yup.string().required('This is a required field.'),
position: Yup.string().required('This is a required field.'),
contact: Yup.string(),
email: Yup.string().email('Must be a valid email address.'),
summary: Yup.string(),
});
const ReferenceModal = () => {
return (
<Formik
validateOnBlur
initialValues={initialValues}
validationSchema={schema}
>
{(formik) => (
<DataModal
name="Reference"
path="references.items"
event={ModalEvents.REFERENCE_MODAL}
>
<div className="grid grid-cols-2 gap-8">
<Input
label="Name"
placeholder="Jane Doe"
{...getFieldProps(formik, schema, 'name')}
/>
<Input
label="position"
placeholder="Assistant Manager"
{...getFieldProps(formik, schema, 'position')}
/>
<Input
label="Phone Number"
placeholder="+1 (708) 756-6065"
{...getFieldProps(formik, schema, 'contact')}
/>
<Input
label="Email Address"
placeholder="janedoe@example.com"
{...getFieldProps(formik, schema, 'email')}
/>
<Input
type="textarea"
label="Summary"
className="col-span-2"
{...getFieldProps(formik, schema, 'summary')}
/>
</div>
</DataModal>
)}
</Formik>
);
};
export default ReferenceModal;

View File

@ -1,34 +1,37 @@
import { Formik } from 'formik'; import { Formik } from 'formik';
import { get } from 'lodash';
import React from 'react'; import React from 'react';
import * as Yup from 'yup'; import * as Yup from 'yup';
import Input from '../../components/shared/Input'; import Input from '../../components/shared/Input';
import ModalEvents from '../../constants/ModalEvents'; import ModalEvents from '../../constants/ModalEvents';
import { getFieldProps } from '../../utils';
import DataModal from '../DataModal'; import DataModal from '../DataModal';
const SKILL_LEVELS = [
'Fundamental Awareness',
'Novice',
'Intermediate',
'Advanced',
'Expert',
];
const initialValues = { const initialValues = {
name: '', name: '',
level: '', level: SKILL_LEVELS[0],
}; };
const validationSchema = Yup.object().shape({ const schema = Yup.object().shape({
name: Yup.string().required('This is a required field.'), name: Yup.string().required('This is a required field.'),
level: Yup.string().required('This is a required field.'), level: Yup.string()
.oneOf(SKILL_LEVELS, 'Must be one of the options above.')
.required('This is a required field.'),
}); });
const SkillModal = () => { const SkillModal = () => {
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 ( return (
<Formik <Formik
validateOnBlur validateOnBlur
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={schema}
> >
{(formik) => ( {(formik) => (
<DataModal <DataModal
@ -40,13 +43,14 @@ const SkillModal = () => {
<Input <Input
label="Name" label="Name"
placeholder="ReactJS" placeholder="ReactJS"
{...getFieldProps(formik, 'name')} {...getFieldProps(formik, schema, 'name')}
/> />
<Input <Input
type="select"
label="Level" label="Level"
{...getFieldProps(formik, 'level')} type="dropdown"
options={SKILL_LEVELS}
{...getFieldProps(formik, schema, 'level')}
/> />
</div> </div>
</DataModal> </DataModal>

View File

@ -1,9 +1,9 @@
import { Formik } from 'formik'; import { Formik } from 'formik';
import { get } from 'lodash';
import React from 'react'; import React from 'react';
import * as Yup from 'yup'; import * as Yup from 'yup';
import Input from '../../components/shared/Input'; import Input from '../../components/shared/Input';
import ModalEvents from '../../constants/ModalEvents'; import ModalEvents from '../../constants/ModalEvents';
import { getFieldProps } from '../../utils';
import DataModal from '../DataModal'; import DataModal from '../DataModal';
const initialValues = { const initialValues = {
@ -12,7 +12,7 @@ const initialValues = {
username: '', username: '',
}; };
const validationSchema = Yup.object().shape({ const schema = Yup.object().shape({
network: Yup.string() network: Yup.string()
.min(5, 'Please enter at least 5 characters.') .min(5, 'Please enter at least 5 characters.')
.required('This is a required field.'), .required('This is a required field.'),
@ -24,18 +24,11 @@ const validationSchema = Yup.object().shape({
}); });
const SocialModal = () => { const SocialModal = () => {
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 ( return (
<Formik <Formik
validateOnBlur validateOnBlur
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={schema}
> >
{(formik) => ( {(formik) => (
<DataModal <DataModal
@ -47,20 +40,20 @@ const SocialModal = () => {
<Input <Input
label="Network" label="Network"
placeholder="Twitter" placeholder="Twitter"
{...getFieldProps(formik, 'network')} {...getFieldProps(formik, schema, 'network')}
/> />
<Input <Input
label="Username" label="Username"
placeholder="KingOKings" placeholder="KingOKings"
{...getFieldProps(formik, 'username')} {...getFieldProps(formik, schema, 'username')}
/> />
<Input <Input
label="URL" label="URL"
className="col-span-2" className="col-span-2"
placeholder="https://twitter.com/KingOKings" placeholder="https://twitter.com/KingOKings"
{...getFieldProps(formik, 'url')} {...getFieldProps(formik, schema, 'url')}
/> />
</div> </div>
</DataModal> </DataModal>

View File

@ -1,11 +1,10 @@
import { Field, FieldArray, Formik } from 'formik'; import { Field, FieldArray, Formik } from 'formik';
import { get } from 'lodash';
import React from 'react'; import React from 'react';
import { MdAdd } from 'react-icons/md'; import { MdAdd } from 'react-icons/md';
import * as Yup from 'yup'; import * as Yup from 'yup';
import Input from '../../components/shared/Input'; import Input from '../../components/shared/Input';
import ModalEvents from '../../constants/ModalEvents'; import ModalEvents from '../../constants/ModalEvents';
import { handleKeyDown } from '../../utils'; import { getFieldProps, handleKeyUp } from '../../utils';
import DataModal from '../DataModal'; import DataModal from '../DataModal';
const initialValues = { const initialValues = {
@ -19,16 +18,16 @@ const initialValues = {
temp: '', temp: '',
}; };
const validationSchema = Yup.object().shape({ const schema = Yup.object().shape({
company: Yup.string().required('This is a required field.'), company: Yup.string().required('This is a required field.'),
position: 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'), website: Yup.string().url('Must be a valid URL'),
startDate: Yup.date().required('This is a required field.'), startDate: Yup.date().required('This is a required field.'),
endDate: Yup.date().when( endDate: Yup.date().when(
'startDate', 'startDate',
(startDate, schema) => (startDate, yupSchema) =>
startDate && startDate &&
schema.min(startDate, 'End Date must be later than Start Date'), yupSchema.min(startDate, 'End Date must be later than Start Date'),
), ),
summary: Yup.string().min(10, 'Please enter at least 10 characters.'), summary: Yup.string().min(10, 'Please enter at least 10 characters.'),
highlights: Yup.array().of( highlights: Yup.array().of(
@ -38,18 +37,11 @@ const validationSchema = Yup.object().shape({
}); });
const WorkModal = () => { const WorkModal = () => {
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 ( return (
<Formik <Formik
validateOnBlur validateOnBlur
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={schema}
> >
{(formik) => ( {(formik) => (
<DataModal <DataModal
@ -62,40 +54,40 @@ const WorkModal = () => {
label="Company" label="Company"
className="col-span-2" className="col-span-2"
placeholder="Postdot Technologies Pvt. Ltd." placeholder="Postdot Technologies Pvt. Ltd."
{...getFieldProps(formik, 'company')} {...getFieldProps(formik, schema, 'company')}
/> />
<Input <Input
label="Position" label="Position"
placeholder="Full Stack Web Developer" placeholder="Full Stack Web Developer"
{...getFieldProps(formik, 'position')} {...getFieldProps(formik, schema, 'position')}
/> />
<Input <Input
label="Website" label="Website"
placeholder="https://example.com/" placeholder="https://example.com/"
{...getFieldProps(formik, 'website')} {...getFieldProps(formik, schema, 'website')}
/> />
<Input <Input
type="date" type="date"
label="Start Date" label="Start Date"
placeholder="6th August 208" placeholder="6th August 208"
{...getFieldProps(formik, 'startDate')} {...getFieldProps(formik, schema, 'startDate')}
/> />
<Input <Input
type="date" type="date"
label="End Date" label="End Date"
placeholder="6th August 208" placeholder="6th August 208"
{...getFieldProps(formik, 'endDate')} {...getFieldProps(formik, schema, 'endDate')}
/> />
<Input <Input
type="textarea" type="textarea"
label="Summary" label="Summary"
className="col-span-2" className="col-span-2"
{...getFieldProps(formik, 'summary')} {...getFieldProps(formik, schema, 'summary')}
/> />
<FieldArray <FieldArray
@ -129,13 +121,13 @@ const WorkModal = () => {
<div className="flex items-center"> <div className="flex items-center">
<Input <Input
placeholder="Worked passionately in customer service in a high volume restaurant." placeholder="Worked passionately in customer service in a high volume restaurant."
{...getFieldProps(formik, 'temp')} {...getFieldProps(formik, schema, 'temp')}
/> />
<MdAdd <MdAdd
size="18px" size="18px"
tabIndex="0" tabIndex="0"
className="mx-4 cursor-pointer opacity-50 hover:opacity-75" className="mx-4 cursor-pointer opacity-50 hover:opacity-75"
onKeyDown={(e) => handleKeyDown(e, handleClickAdd)} onKeyUp={(e) => handleKeyUp(e, handleClickAdd)}
onClick={handleClickAdd} onClick={handleClickAdd}
/> />
</div> </div>

View File

@ -1,3 +1,6 @@
import { get } from 'lodash';
import moment from 'moment';
export const getModalText = (isEditMode, type) => { export const getModalText = (isEditMode, type) => {
return isEditMode ? `Edit ${type}` : `Add ${type}`; return isEditMode ? `Edit ${type}` : `Add ${type}`;
}; };
@ -8,7 +11,7 @@ export const transformCollectionSnapshot = (snapshot, setData) => {
setData(data); setData(data);
}; };
export const handleKeyDown = (event, action) => { export const handleKeyUp = (event, action) => {
(event.which === 13 || event.which === 32) && action(); (event.which === 13 || event.which === 32) && action();
}; };
@ -16,3 +19,15 @@ export const isFileImage = (file) => {
const acceptedImageTypes = ['image/jpeg', 'image/png']; const acceptedImageTypes = ['image/jpeg', 'image/png'];
return file && acceptedImageTypes.includes(file.type); return file && acceptedImageTypes.includes(file.type);
}; };
export const formatDateRange = (x) =>
`${moment(x.startDate).format('MMMM Y')}${
moment(x.endDate).isValid() ? moment(x.endDate).format('MMMM Y') : 'Present'
}`;
export const getFieldProps = (formik, schema, name) => ({
touched: get(formik, `touched.${name}`, false),
error: get(formik, `errors.${name}`, ''),
isRequired: get(schema, `fields.${name}._exclusive.required`),
...formik.getFieldProps(name),
});