feat: adding a toggle switch for left panel items

This commit is contained in:
Anuraag Gupta
2021-02-26 02:05:51 +05:30
parent d98e591fee
commit cf47447102
17 changed files with 18168 additions and 72 deletions

View File

@ -4,6 +4,7 @@ import { Draggable } from 'react-beautiful-dnd';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
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 Switch from '@material-ui/core/Switch';
import { useDispatch } from '../../../contexts/ResumeContext'; import { useDispatch } from '../../../contexts/ResumeContext';
import styles from './ListItem.module.css'; import styles from './ListItem.module.css';
@ -25,6 +26,7 @@ const ListItem = ({
const [anchorEl, setAnchorEl] = useState(null); const [anchorEl, setAnchorEl] = useState(null);
const handleClick = (event) => setAnchorEl(event.currentTarget); const handleClick = (event) => setAnchorEl(event.currentTarget);
const toggleSwitchState = 'isVisible' in data ? data.isVisible : true;
const handleClose = () => setAnchorEl(null); const handleClose = () => setAnchorEl(null);
@ -69,6 +71,16 @@ const ListItem = ({
handleClose(); handleClose();
}; };
const handleToggleUse = () => {
dispatch({
type: 'on_toggle_use_item',
payload: {
path,
value: data,
},
});
};
return ( return (
<Draggable draggableId={data.id} index={index}> <Draggable draggableId={data.id} index={index}>
{(dragProvided) => ( {(dragProvided) => (
@ -94,37 +106,47 @@ const ListItem = ({
</span> </span>
)} )}
</div> </div>
<div className={styles.toggleButton}>
<div className={styles.menu}> <Switch
<MdMoreVert checked={toggleSwitchState}
size="18px" onChange={handleToggleUse}
aria-haspopup="true" color="primary"
onClick={handleClick} name="toggleSwitch"
className="cursor-context-menu" className="toggle-button"
inputProps={{ 'aria-label': 'primary checkbox' }}
/> />
<Menu
keepMounted <div className={styles.menu}>
anchorEl={anchorEl} <MdMoreVert
onClose={handleClose} size="18px"
open={Boolean(anchorEl)} aria-haspopup="true"
> onClick={handleClick}
<div className="flex items-center space-around"> className="cursor-context-menu"
<MenuItem disabled={isFirst} onClick={handleMoveUp}> />
<IoIosArrowUp size="18px" /> <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}>
{t('shared.buttons.edit')}
</MenuItem> </MenuItem>
<MenuItem disabled={isLast} onClick={handleMoveDown}> <MenuItem onClick={handleDelete}>
<IoIosArrowDown size="18px" /> <span className="text-red-600 font-medium">
{t('shared.buttons.delete')}
</span>
</MenuItem> </MenuItem>
</div> </Menu>
<MenuItem onClick={handleEdit}> </div>
{t('shared.buttons.edit')}
</MenuItem>
<MenuItem onClick={handleDelete}>
<span className="text-red-600 font-medium">
{t('shared.buttons.delete')}
</span>
</MenuItem>
</Menu>
</div> </div>
</div> </div>
)} )}

View File

@ -15,3 +15,7 @@
@apply opacity-100; @apply opacity-100;
@apply transition-opacity duration-200 ease-in-out; @apply transition-opacity duration-200 ease-in-out;
} }
.toggle-button {
@apply flex items-center justify-center
}

View File

@ -68,6 +68,18 @@ const ResumeProvider = ({ children }) => {
debouncedUpdateResume(newState); debouncedUpdateResume(newState);
return newState; return newState;
case 'on_toggle_use_item':
items = get(state, payload.path);
index = findIndex(items, ['id', payload.value.id]);
if ('isVisible' in items[index]) {
items[index].isVisible = !items[index].isVisible;
} else {
items[index].isVisible = false;
}
newState = setWith(clone(state), payload.path, items, clone);
debouncedUpdateResume(newState);
return newState;
case 'on_move_item_up': case 'on_move_item_up':
items = get(state, payload.path); items = get(state, payload.path);
index = findIndex(items, ['id', payload.value.id]); index = findIndex(items, ['id', payload.value.id]);

View File

@ -1,7 +1,7 @@
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { formatDate, safetyCheck } from '../../../utils'; import { formatDate, safetyCheck, isItemVisible } from '../../../utils';
const AwardItem = ({ item, language }) => ( const AwardItem = ({ item, language }) => (
<div> <div>
@ -29,9 +29,16 @@ const AwardsA = () => {
<div> <div>
<Heading>{data.awards.heading}</Heading> <Heading>{data.awards.heading}</Heading>
<div className="grid gap-4"> <div className="grid gap-4">
{data.awards.items.map((x) => ( {data.awards.items.map(
<AwardItem key={x.id} item={x} language={data.metadata.language} /> (x) =>
))} isItemVisible(x) && (
<AwardItem
key={x.id}
item={x}
language={data.metadata.language}
/>
),
)}
</div> </div>
</div> </div>
) : null; ) : null;

View File

@ -1,7 +1,7 @@
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { formatDate, safetyCheck } from '../../../utils'; import { formatDate, safetyCheck, isItemVisible } from '../../../utils';
const CertificationItem = ({ item, language }) => ( const CertificationItem = ({ item, language }) => (
<div> <div>
@ -29,13 +29,16 @@ const CertificationsA = () => {
<div> <div>
<Heading>{data.certifications.heading}</Heading> <Heading>{data.certifications.heading}</Heading>
<div className="grid gap-4"> <div className="grid gap-4">
{data.certifications.items.map((x) => ( {data.certifications.items.map(
<CertificationItem (x) =>
key={x.id} isItemVisible(x) && (
item={x} <CertificationItem
language={data.metadata.language} key={x.id}
/> item={x}
))} language={data.metadata.language}
/>
),
)}
</div> </div>
</div> </div>
) : null; ) : null;

View File

@ -2,7 +2,7 @@ import React, { memo, useContext } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { formatDateRange, safetyCheck } from '../../../utils'; import { formatDateRange, safetyCheck, isItemVisible } from '../../../utils';
const EducationItem = ({ item, language }) => { const EducationItem = ({ item, language }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -50,13 +50,16 @@ const EducationA = () => {
<div> <div>
<Heading>{data.education.heading}</Heading> <Heading>{data.education.heading}</Heading>
<div className="grid gap-4"> <div className="grid gap-4">
{data.education.items.map((x) => ( {data.education.items.map(
<EducationItem (x) =>
key={x.id} isItemVisible(x) && (
item={x} <EducationItem
language={data.metadata.language} key={x.id}
/> item={x}
))} language={data.metadata.language}
/>
),
)}
</div> </div>
</div> </div>
) : null; ) : null;

View File

@ -1,6 +1,6 @@
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { safetyCheck } from '../../../utils'; import { safetyCheck, isItemVisible } from '../../../utils';
const HobbyA = (x) => ( const HobbyA = (x) => (
<div key={x.id}> <div key={x.id}>
@ -14,7 +14,9 @@ const HobbiesA = () => {
return safetyCheck(data.hobbies) ? ( return safetyCheck(data.hobbies) ? (
<div> <div>
<Heading>{data.hobbies.heading}</Heading> <Heading>{data.hobbies.heading}</Heading>
<div className="grid gap-2">{data.hobbies.items.map(HobbyA)}</div> <div className="grid gap-2">
{data.hobbies.items.map((x) => isItemVisible(x) && HobbyA(x))}
</div>
</div> </div>
) : null; ) : null;
}; };

View File

@ -1,6 +1,6 @@
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { safetyCheck } from '../../../utils'; import { safetyCheck, isItemVisible } from '../../../utils';
const LanguageItem = (x) => ( const LanguageItem = (x) => (
<div key={x.id} className="flex flex-col"> <div key={x.id} className="flex flex-col">
@ -16,7 +16,7 @@ const LanguagesA = () => {
<div> <div>
<Heading>{data.languages.heading}</Heading> <Heading>{data.languages.heading}</Heading>
<div className="grid grid-cols-2 gap-2"> <div className="grid grid-cols-2 gap-2">
{data.languages.items.map(LanguageItem)} {data.languages.items.map((x) => isItemVisible(x) && LanguageItem(x))}
</div> </div>
</div> </div>
) : null; ) : null;

View File

@ -1,6 +1,6 @@
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { safetyCheck } from '../../../utils'; import { safetyCheck, isItemVisible } from '../../../utils';
const LanguageItem = (x) => ( const LanguageItem = (x) => (
<div key={x.id} className="flex flex-col"> <div key={x.id} className="flex flex-col">
@ -15,7 +15,9 @@ const LanguagesB = () => {
return safetyCheck(data.languages) ? ( return safetyCheck(data.languages) ? (
<div> <div>
<Heading>{data.languages.heading}</Heading> <Heading>{data.languages.heading}</Heading>
<div className="grid gap-2">{data.languages.items.map(LanguageItem)}</div> <div className="grid gap-2">
{data.languages.items.map((x) => isItemVisible(x) && LanguageItem(x))}
</div>
</div> </div>
) : null; ) : null;
}; };

View File

@ -2,7 +2,7 @@ import React, { memo, useContext } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { formatDateRange, safetyCheck } from '../../../utils'; import { formatDateRange, isItemVisible, safetyCheck } from '../../../utils';
const ProjectItem = ({ item, language }) => { const ProjectItem = ({ item, language }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -49,9 +49,16 @@ const ProjectsA = () => {
<div> <div>
<Heading>{data.projects.heading}</Heading> <Heading>{data.projects.heading}</Heading>
<div className="grid gap-4"> <div className="grid gap-4">
{data.projects.items.map((x) => ( {data.projects.items.map(
<ProjectItem key={x.id} item={x} language={data.metadata.language} /> (x) =>
))} isItemVisible(x) && (
<ProjectItem
key={x.id}
item={x}
language={data.metadata.language}
/>
),
)}
</div> </div>
</div> </div>
) : null; ) : null;

View File

@ -1,7 +1,7 @@
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { safetyCheck } from '../../../utils'; import { isItemVisible, safetyCheck } from '../../../utils';
const ReferenceItem = (x) => ( const ReferenceItem = (x) => (
<div key={x.id} className="flex flex-col"> <div key={x.id} className="flex flex-col">
@ -22,7 +22,7 @@ const ReferencesA = () => {
<div> <div>
<Heading>{data.references.heading}</Heading> <Heading>{data.references.heading}</Heading>
<div className="grid grid-cols-3 gap-4"> <div className="grid grid-cols-3 gap-4">
{data.references.items.map(ReferenceItem)} {data.references.items.map((x) => isItemVisible(x) && ReferenceItem(x))}
</div> </div>
</div> </div>
) : null; ) : null;

View File

@ -1,7 +1,7 @@
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { safetyCheck } from '../../../utils'; import { isItemVisible, safetyCheck } from '../../../utils';
const ReferenceItem = (x) => ( const ReferenceItem = (x) => (
<div key={x.id} className="flex flex-col"> <div key={x.id} className="flex flex-col">
@ -22,7 +22,7 @@ const ReferencesB = () => {
<div> <div>
<Heading>{data.references.heading}</Heading> <Heading>{data.references.heading}</Heading>
<div className="grid gap-4"> <div className="grid gap-4">
{data.references.items.map(ReferenceItem)} {data.references.items.map((x) => isItemVisible(x) && ReferenceItem(x))}
</div> </div>
</div> </div>
) : null; ) : null;

View File

@ -1,6 +1,6 @@
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { safetyCheck } from '../../../utils'; import { safetyCheck, isItemVisible } from '../../../utils';
const SkillItem = (x) => ( const SkillItem = (x) => (
<div key={x.id} className="flex flex-col"> <div key={x.id} className="flex flex-col">
@ -16,7 +16,7 @@ const SkillsA = () => {
<div> <div>
<Heading>{data.skills.heading}</Heading> <Heading>{data.skills.heading}</Heading>
<div className="grid grid-cols-2 gap-y-2 gap-x-4"> <div className="grid grid-cols-2 gap-y-2 gap-x-4">
{data.skills.items.map(SkillItem)} {data.skills.items.map((x) => isItemVisible(x) && SkillItem(x))}
</div> </div>
</div> </div>
) : null; ) : null;

View File

@ -1,6 +1,6 @@
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { safetyCheck } from '../../../utils'; import { safetyCheck, isItemVisible } from '../../../utils';
const SkillItem = (x) => ( const SkillItem = (x) => (
<li key={x.id} className="text-sm py-1"> <li key={x.id} className="text-sm py-1">
@ -14,7 +14,7 @@ const SkillsA = () => {
return safetyCheck(data.skills) ? ( return safetyCheck(data.skills) ? (
<div> <div>
<Heading>{data.skills.heading}</Heading> <Heading>{data.skills.heading}</Heading>
<ul>{data.skills.items.map(SkillItem)}</ul> <ul>{data.skills.items.map((x) => isItemVisible(x) && SkillItem(x))}</ul>
</div> </div>
) : null; ) : null;
}; };

View File

@ -2,7 +2,12 @@ import React, { memo, useContext } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import PageContext from '../../../contexts/PageContext'; import PageContext from '../../../contexts/PageContext';
import { formatDateRange, safetyCheck } from '../../../utils'; import {
formatDateRange,
safetyCheck,
isItemVisible,
genericFilter,
} from '../../../utils';
const WorkItem = ({ item, language }) => { const WorkItem = ({ item, language }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -40,14 +45,16 @@ const WorkItem = ({ item, language }) => {
const WorkA = () => { const WorkA = () => {
const { data, heading: Heading } = useContext(PageContext); const { data, heading: Heading } = useContext(PageContext);
return safetyCheck(data.work) ? ( return safetyCheck(data.work) ? (
<div> <div>
<Heading>{data.work.heading}</Heading> <Heading>{data.work.heading}</Heading>
<div className="grid gap-4"> <div className="grid gap-4">
{data.work.items.map((x) => ( {data.work.items.map(
<WorkItem key={x.id} item={x} language={data.metadata.language} /> (x) =>
))} isItemVisible(x) && (
<WorkItem key={x.id} item={x} language={data.metadata.language} />
),
)}
</div> </div>
</div> </div>
) : null; ) : null;

View File

@ -1,5 +1,5 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { get, isEmpty } from 'lodash'; import { get, isEmpty, clone } from 'lodash';
export const getModalText = (isEditMode, type, t) => export const getModalText = (isEditMode, type, t) =>
isEditMode isEditMode
@ -9,6 +9,18 @@ export const getModalText = (isEditMode, type, t) =>
export const safetyCheck = (section, path = 'items') => export const safetyCheck = (section, path = 'items') =>
!!(section && section.visible === true && !isEmpty(section[path])); !!(section && section.visible === true && !isEmpty(section[path]));
export const isItemVisible = (section) =>
section && section.isVisible !== false;
// Thought about creating a generic function to filter out non-visible items
export const genericFilter = (key, data) => {
const clonedData = clone(data);
clonedData[`${key}`].items = clonedData[`${key}`].items.filter((x) =>
isItemVisible(x),
);
return data;
};
export const handleKeyUp = (event, action) => { export const handleKeyUp = (event, action) => {
(event.which === 13 || event.which === 32) && action(); (event.which === 13 || event.which === 32) && action();
}; };

18015
yarn.lock Normal file

File diff suppressed because it is too large Load Diff