132 lines
4.3 KiB
React
Executable File
132 lines
4.3 KiB
React
Executable File
/*!
|
|
* Copyright (c) 2024 PLANKA Software GmbH
|
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
|
*/
|
|
|
|
import React, { useCallback, useState } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import classNames from 'classnames';
|
|
import { shallowEqual, useSelector } from 'react-redux';
|
|
import { useInView } from 'react-intersection-observer';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { Button, Icon, Loader } from 'semantic-ui-react';
|
|
import { Tooltip } from '../../../lib/custom-ui';
|
|
|
|
import selectors from '../../../selectors';
|
|
import { BoardMembershipRoles } from '../../../constants/Enums';
|
|
import Card from '../../cards/Card';
|
|
import AddCard from '../../cards/AddCard';
|
|
import PlusMathIcon from '../../../assets/images/plus-math-icon.svg?react';
|
|
|
|
import styles from './ListView.module.scss';
|
|
|
|
const ListView = React.memo(
|
|
({ cardIds, isCardsFetching, isAllCardsFetched, onCardsFetch, onCardCreate, onCardPaste }) => {
|
|
const clipboard = useSelector(selectors.selectClipboard);
|
|
|
|
const { canAddCard, canPasteCard } = useSelector((state) => {
|
|
const boardMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state);
|
|
const isEditor = !!boardMembership && boardMembership.role === BoardMembershipRoles.EDITOR;
|
|
|
|
return {
|
|
canAddCard: isEditor,
|
|
canPasteCard: isEditor,
|
|
};
|
|
}, shallowEqual);
|
|
|
|
const [t] = useTranslation();
|
|
const [isAddCardOpened, setIsAddCardOpened] = useState(false);
|
|
|
|
const [inViewRef] = useInView({
|
|
threshold: 1,
|
|
onChange: (inView) => {
|
|
if (inView && onCardsFetch) {
|
|
onCardsFetch();
|
|
}
|
|
},
|
|
});
|
|
|
|
const handleAddCardClick = useCallback(() => {
|
|
setIsAddCardOpened(true);
|
|
}, []);
|
|
|
|
const handleAddCardClose = useCallback(() => {
|
|
setIsAddCardOpened(false);
|
|
}, []);
|
|
|
|
return (
|
|
<div className={styles.wrapper}>
|
|
{canAddCard &&
|
|
(onCardCreate && isAddCardOpened ? (
|
|
<div className={styles.segment}>
|
|
<AddCard onCreate={onCardCreate} onClose={handleAddCardClose} />
|
|
</div>
|
|
) : (
|
|
<div className={styles.addCardButtonWrapper}>
|
|
<Button
|
|
type="button"
|
|
disabled={!onCardCreate}
|
|
className={styles.addCardButton}
|
|
onClick={handleAddCardClick}
|
|
>
|
|
<PlusMathIcon className={styles.addCardButtonIcon} />
|
|
<span className={styles.addCardButtonText}>
|
|
{onCardCreate ? t('action.addCard') : t('common.atLeastOneListMustBePresent')}
|
|
</span>
|
|
</Button>
|
|
{onCardPaste && clipboard && canPasteCard && (
|
|
<Tooltip content={t('action.paste')}>
|
|
<Button
|
|
type="button"
|
|
disabled={!onCardCreate}
|
|
className={classNames(styles.addCardButton, styles.paste)}
|
|
onClick={onCardPaste}
|
|
>
|
|
<Icon fitted name="paste" />
|
|
</Button>
|
|
</Tooltip>
|
|
)}
|
|
</div>
|
|
))}
|
|
{cardIds.length > 0 && (
|
|
<div className={classNames(styles.segment, styles.cards)}>
|
|
{cardIds.map((cardId, cardIndex) => (
|
|
<div key={cardId} className={styles.card}>
|
|
<Card isInline id={cardId} index={cardIndex} />
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
{isCardsFetching !== undefined && isAllCardsFetched !== undefined && (
|
|
<div className={styles.loaderWrapper}>
|
|
{isCardsFetching ? (
|
|
<Loader active inverted inline="centered" size="small" />
|
|
) : (
|
|
!isAllCardsFetched && <div ref={inViewRef} />
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
},
|
|
);
|
|
|
|
ListView.propTypes = {
|
|
cardIds: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
|
|
isCardsFetching: PropTypes.bool,
|
|
isAllCardsFetched: PropTypes.bool,
|
|
onCardsFetch: PropTypes.func,
|
|
onCardCreate: PropTypes.func,
|
|
onCardPaste: PropTypes.func,
|
|
};
|
|
|
|
ListView.defaultProps = {
|
|
isCardsFetching: undefined,
|
|
isAllCardsFetched: undefined,
|
|
onCardsFetch: undefined,
|
|
onCardCreate: undefined,
|
|
onCardPaste: undefined,
|
|
};
|
|
|
|
export default ListView;
|