|
|
|
|
@ -16,14 +16,23 @@ import { ReactComponent as PlusMathIcon } from '../../assets/images/plus-math-ic
|
|
|
|
|
import styles from './List.module.scss';
|
|
|
|
|
|
|
|
|
|
const List = React.memo(
|
|
|
|
|
({ id, index, name, isPersisted, cardIds, canEdit, onUpdate, onDelete, onCardCreate }) => {
|
|
|
|
|
// eslint-disable-next-line prettier/prettier
|
|
|
|
|
({ id, index, name, isPersisted, isCollapsed, cardIds, isFiltered, filteredCardIds, canEdit, onUpdate, onDelete, onCardCreate }) => {
|
|
|
|
|
const [t] = useTranslation();
|
|
|
|
|
const [isAddCardOpened, setIsAddCardOpened] = useState(false);
|
|
|
|
|
|
|
|
|
|
const nameEdit = useRef(null);
|
|
|
|
|
const listWrapper = useRef(null);
|
|
|
|
|
|
|
|
|
|
const handleHeaderClick = useCallback(() => {
|
|
|
|
|
const handleToggleCollapseClick = useCallback(() => {
|
|
|
|
|
if (isPersisted && canEdit) {
|
|
|
|
|
onUpdate({
|
|
|
|
|
isCollapsed: !isCollapsed,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}, [isPersisted, canEdit, onUpdate, isCollapsed]);
|
|
|
|
|
|
|
|
|
|
const handleHeaderNameClick = useCallback(() => {
|
|
|
|
|
if (isPersisted && canEdit) {
|
|
|
|
|
nameEdit.current.open();
|
|
|
|
|
}
|
|
|
|
|
@ -58,7 +67,7 @@ const List = React.memo(
|
|
|
|
|
if (isAddCardOpened) {
|
|
|
|
|
listWrapper.current.scrollTop = listWrapper.current.scrollHeight;
|
|
|
|
|
}
|
|
|
|
|
}, [cardIds, isAddCardOpened]);
|
|
|
|
|
}, [filteredCardIds, isAddCardOpened]);
|
|
|
|
|
|
|
|
|
|
const ActionsPopup = usePopup(ActionsStep);
|
|
|
|
|
|
|
|
|
|
@ -72,7 +81,7 @@ const List = React.memo(
|
|
|
|
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
|
|
|
<div {...droppableProps} ref={innerRef}>
|
|
|
|
|
<div className={styles.cards}>
|
|
|
|
|
{cardIds.map((cardId, cardIndex) => (
|
|
|
|
|
{filteredCardIds.map((cardId, cardIndex) => (
|
|
|
|
|
<CardContainer key={cardId} id={cardId} index={cardIndex} />
|
|
|
|
|
))}
|
|
|
|
|
{placeholder}
|
|
|
|
|
@ -89,6 +98,55 @@ const List = React.memo(
|
|
|
|
|
</Droppable>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const cardsCountText = () => {
|
|
|
|
|
return (
|
|
|
|
|
[
|
|
|
|
|
isFiltered
|
|
|
|
|
? `${filteredCardIds.length} ${t('common.of')} ${cardIds.length} `
|
|
|
|
|
: `${cardIds.length} `,
|
|
|
|
|
] + [cardIds.length !== 1 ? t('common.cards') : t('common.card')]
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (isCollapsed) {
|
|
|
|
|
return (
|
|
|
|
|
<Draggable
|
|
|
|
|
draggableId={`list:${id}`}
|
|
|
|
|
index={index}
|
|
|
|
|
isDragDisabled={!isPersisted || !canEdit}
|
|
|
|
|
>
|
|
|
|
|
{({ innerRef, draggableProps, dragHandleProps }) => (
|
|
|
|
|
<div
|
|
|
|
|
{...draggableProps} // eslint-disable-line react/jsx-props-no-spreading
|
|
|
|
|
data-drag-scroller
|
|
|
|
|
ref={innerRef}
|
|
|
|
|
className={styles.innerWrapperCollapsed}
|
|
|
|
|
>
|
|
|
|
|
<div className={styles.outerWrapper}>
|
|
|
|
|
<div
|
|
|
|
|
{...dragHandleProps} // eslint-disable-line react/jsx-props-no-spreading
|
|
|
|
|
className={styles.headerCollapsed}
|
|
|
|
|
>
|
|
|
|
|
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,
|
|
|
|
|
jsx-a11y/no-static-element-interactions */}
|
|
|
|
|
<div
|
|
|
|
|
className={classNames(
|
|
|
|
|
styles.headerCollapseButtonCollapsed,
|
|
|
|
|
canEdit && styles.headerEditable,
|
|
|
|
|
)}
|
|
|
|
|
onClick={handleToggleCollapseClick}
|
|
|
|
|
>
|
|
|
|
|
<Icon fitted name="triangle down" />
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles.headerNameCollapsed}>{name}</div>
|
|
|
|
|
<div className={styles.headerCardsCountCollapsed}>{cardsCountText()}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</Draggable>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return (
|
|
|
|
|
<Draggable draggableId={`list:${id}`} index={index} isDragDisabled={!isPersisted || !canEdit}>
|
|
|
|
|
{({ innerRef, draggableProps, dragHandleProps }) => (
|
|
|
|
|
@ -99,15 +157,30 @@ const List = React.memo(
|
|
|
|
|
className={styles.innerWrapper}
|
|
|
|
|
>
|
|
|
|
|
<div className={styles.outerWrapper}>
|
|
|
|
|
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,
|
|
|
|
|
jsx-a11y/no-static-element-interactions */}
|
|
|
|
|
<div
|
|
|
|
|
{...dragHandleProps} // eslint-disable-line react/jsx-props-no-spreading
|
|
|
|
|
className={classNames(styles.header, canEdit && styles.headerEditable)}
|
|
|
|
|
onClick={handleHeaderClick}
|
|
|
|
|
className={styles.header}
|
|
|
|
|
>
|
|
|
|
|
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,
|
|
|
|
|
jsx-a11y/no-static-element-interactions */}
|
|
|
|
|
<div
|
|
|
|
|
className={classNames(
|
|
|
|
|
styles.headerCollapseButton,
|
|
|
|
|
canEdit && styles.headerEditable,
|
|
|
|
|
)}
|
|
|
|
|
onClick={handleToggleCollapseClick}
|
|
|
|
|
>
|
|
|
|
|
<Icon fitted name="triangle right" />
|
|
|
|
|
</div>
|
|
|
|
|
<NameEdit ref={nameEdit} defaultValue={name} onUpdate={handleNameUpdate}>
|
|
|
|
|
<div className={styles.headerName}>{name}</div>
|
|
|
|
|
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,
|
|
|
|
|
jsx-a11y/no-static-element-interactions */}
|
|
|
|
|
<div
|
|
|
|
|
className={classNames(styles.headerName, canEdit && styles.headerEditable)}
|
|
|
|
|
onClick={handleHeaderNameClick}
|
|
|
|
|
>
|
|
|
|
|
{name}
|
|
|
|
|
</div>
|
|
|
|
|
</NameEdit>
|
|
|
|
|
{isPersisted && canEdit && (
|
|
|
|
|
<ActionsPopup
|
|
|
|
|
@ -120,6 +193,7 @@ const List = React.memo(
|
|
|
|
|
</Button>
|
|
|
|
|
</ActionsPopup>
|
|
|
|
|
)}
|
|
|
|
|
<div className={styles.headerCardsCount}>{cardsCountText()}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
ref={listWrapper}
|
|
|
|
|
@ -139,7 +213,7 @@ const List = React.memo(
|
|
|
|
|
>
|
|
|
|
|
<PlusMathIcon className={styles.addCardButtonIcon} />
|
|
|
|
|
<span className={styles.addCardButtonText}>
|
|
|
|
|
{cardIds.length > 0 ? t('action.addAnotherCard') : t('action.addCard')}
|
|
|
|
|
{filteredCardIds.length > 0 ? t('action.addAnotherCard') : t('action.addCard')}
|
|
|
|
|
</span>
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
@ -155,8 +229,11 @@ List.propTypes = {
|
|
|
|
|
id: PropTypes.string.isRequired,
|
|
|
|
|
index: PropTypes.number.isRequired,
|
|
|
|
|
name: PropTypes.string.isRequired,
|
|
|
|
|
isCollapsed: PropTypes.bool.isRequired,
|
|
|
|
|
isPersisted: PropTypes.bool.isRequired,
|
|
|
|
|
cardIds: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
|
|
|
|
|
isFiltered: PropTypes.bool.isRequired,
|
|
|
|
|
filteredCardIds: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
|
|
|
|
|
canEdit: PropTypes.bool.isRequired,
|
|
|
|
|
onUpdate: PropTypes.func.isRequired,
|
|
|
|
|
onDelete: PropTypes.func.isRequired,
|
|
|
|
|
|