mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-23 05:01:49 +10:00
List component: added support for drag & drop
This commit is contained in:
@ -1,10 +1,11 @@
|
||||
import { get, isEmpty } from 'lodash';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MdAdd } from 'react-icons/md';
|
||||
import ModalContext from '../../../contexts/ModalContext';
|
||||
import { useSelector } from '../../../contexts/ResumeContext';
|
||||
import { formatDateRange } from '../../../utils';
|
||||
import { useDispatch, useSelector } from '../../../contexts/ResumeContext';
|
||||
import { formatDateRange, reorder } from '../../../utils';
|
||||
import Button from '../../shared/Button';
|
||||
import EmptyList from './EmptyList';
|
||||
import styles from './List.module.css';
|
||||
@ -24,42 +25,79 @@ const List = ({
|
||||
const { t, i18n } = useTranslation();
|
||||
const items = useSelector(path, []);
|
||||
const { emitter } = useContext(ModalContext);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleAdd = () => emitter.emit(event);
|
||||
|
||||
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 (
|
||||
<div className="flex flex-col">
|
||||
<div className={styles.list}>
|
||||
{isEmpty(items) ? (
|
||||
<EmptyList />
|
||||
) : (
|
||||
items.map((x, i) => (
|
||||
<ListItem
|
||||
key={x.id}
|
||||
data={x}
|
||||
path={path}
|
||||
title={title || get(x, titlePath, '')}
|
||||
subtitle={
|
||||
subtitle ||
|
||||
get(x, subtitlePath, '') ||
|
||||
(hasDate &&
|
||||
formatDateRange(
|
||||
{
|
||||
startDate: x.startDate,
|
||||
endDate: x.endDate,
|
||||
language: i18n.language,
|
||||
},
|
||||
t,
|
||||
))
|
||||
}
|
||||
text={text || get(x, textPath, '')}
|
||||
onEdit={() => handleEdit(x)}
|
||||
isFirst={i === 0}
|
||||
isLast={i === items.length - 1}
|
||||
/>
|
||||
))
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<Droppable droppableId={path}>
|
||||
{(dropProvided) => (
|
||||
<div
|
||||
ref={dropProvided.innerRef}
|
||||
{...dropProvided.droppableProps}
|
||||
>
|
||||
{items.map((x, i) => (
|
||||
<ListItem
|
||||
key={x.id}
|
||||
data={x}
|
||||
path={path}
|
||||
title={title || get(x, titlePath, '')}
|
||||
subtitle={
|
||||
subtitle ||
|
||||
get(x, subtitlePath, '') ||
|
||||
(hasDate &&
|
||||
formatDateRange(
|
||||
{
|
||||
startDate: x.startDate,
|
||||
endDate: x.endDate,
|
||||
language: i18n.language,
|
||||
},
|
||||
t,
|
||||
))
|
||||
}
|
||||
text={text || get(x, textPath, '')}
|
||||
onEdit={() => handleEdit(x)}
|
||||
isFirst={i === 0}
|
||||
isLast={i === items.length - 1}
|
||||
index={i}
|
||||
/>
|
||||
))}
|
||||
{dropProvided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Menu, MenuItem } from '@material-ui/core';
|
||||
import React, { memo, useState } from 'react';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IoIosArrowDown, IoIosArrowUp } from 'react-icons/io';
|
||||
import { MdMoreVert } from 'react-icons/md';
|
||||
@ -15,6 +16,7 @@ const ListItem = ({
|
||||
isFirst,
|
||||
isLast,
|
||||
onEdit,
|
||||
index,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
@ -66,49 +68,64 @@ const ListItem = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.listItem}>
|
||||
<div className="grid">
|
||||
<span className="font-medium truncate">{title}</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 className={styles.menu}>
|
||||
<MdMoreVert
|
||||
size="18px"
|
||||
aria-haspopup="true"
|
||||
onClick={handleClick}
|
||||
className="cursor-context-menu"
|
||||
/>
|
||||
<Menu
|
||||
keepMounted
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
open={Boolean(anchorEl)}
|
||||
<Draggable draggableId={data.id} index={index}>
|
||||
{(dragProvided) => (
|
||||
<div
|
||||
ref={dragProvided.innerRef}
|
||||
className={styles.listItem}
|
||||
{...dragProvided.draggableProps}
|
||||
{...dragProvided.dragHandleProps}
|
||||
>
|
||||
<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 className="grid">
|
||||
<span className="font-medium truncate">{title}</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>
|
||||
<MenuItem onClick={handleEdit}>{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 className={styles.menu}>
|
||||
<MdMoreVert
|
||||
size="18px"
|
||||
aria-haspopup="true"
|
||||
onClick={handleClick}
|
||||
className="cursor-context-menu"
|
||||
/>
|
||||
<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 onClick={handleDelete}>
|
||||
<span className="text-red-600 font-medium">
|
||||
{t('shared.buttons.delete')}
|
||||
</span>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user