Reactive-Resume/apps/client/components/shared/List.tsx

96 lines
2.6 KiB
TypeScript

import { ListItem as ListItemType } from '@reactive-resume/schema';
import clsx from 'clsx';
import get from 'lodash/get';
import isArray from 'lodash/isArray';
import isEmpty from 'lodash/isEmpty';
import isFunction from 'lodash/isFunction';
import { useTranslation } from 'next-i18next';
import { useCallback } from 'react';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { deleteItem, setResumeState } from '@/store/resume/resumeSlice';
import styles from './List.module.scss';
import ListItem from './ListItem';
type Props = {
path: string;
titleKey?: string;
subtitleKey?: string;
onEdit?: (item: ListItemType) => void;
onDuplicate?: (item: ListItemType) => void;
className?: string;
};
const List: React.FC<Props> = ({
path,
titleKey = 'title',
subtitleKey = 'subtitle',
onEdit,
onDuplicate,
className,
}) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const list: Array<ListItemType> = useAppSelector((state) => get(state.resume, path, []));
const handleEdit = (item: ListItemType) => {
isFunction(onEdit) && onEdit(item);
};
const handleDuplicate = (item: ListItemType) => {
isFunction(onDuplicate) && onDuplicate(item);
};
const handleDelete = (item: ListItemType) => {
dispatch(deleteItem({ path, value: item }));
};
const handleMove = useCallback(
(dragIndex: number, hoverIndex: number) => {
const dragItem = list[dragIndex];
const newList = [...list];
newList.splice(dragIndex, 1);
newList.splice(hoverIndex, 0, dragItem);
dispatch(setResumeState({ path, value: newList }));
},
[list, dispatch, path]
);
return (
<DndProvider backend={HTML5Backend}>
<div className={clsx(styles.container, className)}>
{isEmpty(list) && <div className={styles.empty}>{t('builder.common.list.empty-text')}</div>}
{list.map((item, index) => {
const title = get(item, titleKey, '');
const subtitleObj = get(item, subtitleKey);
const subtitle: string = isArray(subtitleObj) ? subtitleObj.join(', ') : subtitleObj;
return (
<ListItem
key={item.id}
item={item}
index={index}
title={title}
subtitle={subtitle}
onMove={handleMove}
onEdit={handleEdit}
onDelete={handleDelete}
onDuplicate={handleDuplicate}
/>
);
})}
</div>
</DndProvider>
);
};
export default List;