List component: added support for drag & drop

This commit is contained in:
gianantoniopini
2021-02-09 05:59:32 +01:00
parent 89936b651a
commit 23bf495a5a
2 changed files with 123 additions and 68 deletions

View File

@ -1,10 +1,11 @@
import { get, isEmpty } from 'lodash'; import { get, isEmpty } from 'lodash';
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
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 { useDispatch, useSelector } from '../../../contexts/ResumeContext';
import { formatDateRange } from '../../../utils'; import { formatDateRange, reorder } 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';
@ -24,18 +25,49 @@ const List = ({
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const items = useSelector(path, []); const items = useSelector(path, []);
const { emitter } = useContext(ModalContext); const { emitter } = useContext(ModalContext);
const dispatch = useDispatch();
const handleAdd = () => emitter.emit(event); const handleAdd = () => emitter.emit(event);
const handleEdit = (data) => emitter.emit(event, data); const handleEdit = (data) => emitter.emit(event, data);
const onDragEnd = (result) => {
const { source, destination } = result;
if (!destination) {
return;
}
const sourceDroppableId = source.droppableId;
const destinationDroppableId = destination.droppableId;
if (sourceDroppableId !== destinationDroppableId) {
return;
}
const itemsReordered = reorder(items, source.index, destination.index);
dispatch({
type: 'on_input',
payload: {
path,
value: itemsReordered,
},
});
};
return ( return (
<div className="flex flex-col"> <div className="flex flex-col">
<div className={styles.list}> <div className={styles.list}>
{isEmpty(items) ? ( {isEmpty(items) ? (
<EmptyList /> <EmptyList />
) : ( ) : (
items.map((x, i) => ( <DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId={path}>
{(dropProvided) => (
<div
ref={dropProvided.innerRef}
{...dropProvided.droppableProps}
>
{items.map((x, i) => (
<ListItem <ListItem
key={x.id} key={x.id}
data={x} data={x}
@ -58,8 +90,14 @@ const List = ({
onEdit={() => handleEdit(x)} onEdit={() => handleEdit(x)}
isFirst={i === 0} isFirst={i === 0}
isLast={i === items.length - 1} isLast={i === items.length - 1}
index={i}
/> />
)) ))}
{dropProvided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
)} )}
</div> </div>

View File

@ -1,5 +1,6 @@
import { Menu, MenuItem } from '@material-ui/core'; import { Menu, MenuItem } from '@material-ui/core';
import React, { memo, useState } from 'react'; import React, { memo, useState } from 'react';
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';
@ -15,6 +16,7 @@ const ListItem = ({
isFirst, isFirst,
isLast, isLast,
onEdit, onEdit,
index,
}) => { }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
@ -66,16 +68,27 @@ const ListItem = ({
}; };
return ( return (
<div className={styles.listItem}> <Draggable draggableId={data.id} index={index}>
{(dragProvided) => (
<div
ref={dragProvided.innerRef}
className={styles.listItem}
{...dragProvided.draggableProps}
{...dragProvided.dragHandleProps}
>
<div className="grid"> <div className="grid">
<span className="font-medium truncate">{title}</span> <span className="font-medium truncate">{title}</span>
{subtitle && ( {subtitle && (
<span className="mt-1 text-sm opacity-75 truncate">{subtitle}</span> <span className="mt-1 text-sm opacity-75 truncate">
{subtitle}
</span>
)} )}
{text && ( {text && (
<span className="w-4/5 mt-5 text-sm opacity-75 truncate">{text}</span> <span className="w-4/5 mt-5 text-sm opacity-75 truncate">
{text}
</span>
)} )}
</div> </div>
@ -100,7 +113,9 @@ const ListItem = ({
<IoIosArrowDown size="18px" /> <IoIosArrowDown size="18px" />
</MenuItem> </MenuItem>
</div> </div>
<MenuItem onClick={handleEdit}>{t('shared.buttons.edit')}</MenuItem> <MenuItem onClick={handleEdit}>
{t('shared.buttons.edit')}
</MenuItem>
<MenuItem onClick={handleDelete}> <MenuItem onClick={handleDelete}>
<span className="text-red-600 font-medium"> <span className="text-red-600 font-medium">
{t('shared.buttons.delete')} {t('shared.buttons.delete')}
@ -109,6 +124,8 @@ const ListItem = ({
</Menu> </Menu>
</div> </div>
</div> </div>
)}
</Draggable>
); );
}; };