/*! * Copyright (c) 2024 PLANKA Software GmbH * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md */ import React, { useCallback, useContext, useMemo, useState } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { Comment } from 'semantic-ui-react'; import { useDidUpdate } from '../../../lib/hooks'; import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; import { usePopupInClosableContext } from '../../../hooks'; import { isListArchiveOrTrash } from '../../../utils/record-helpers'; import { StaticUserIds } from '../../../constants/StaticUsers'; import { BoardMembershipRoles } from '../../../constants/Enums'; import { ClosableContext } from '../../../contexts'; import Edit from './Edit'; import TimeAgo from '../../common/TimeAgo'; import Markdown from '../../common/Markdown'; import ConfirmationStep from '../../common/ConfirmationStep'; import UserAvatar from '../../users/UserAvatar'; import styles from './Item.module.scss'; const Item = React.memo(({ id }) => { const selectCommentById = useMemo(() => selectors.makeSelectCommentById(), []); const selectUserById = useMemo(() => selectors.makeSelectUserById(), []); const selectListById = useMemo(() => selectors.makeSelectListById(), []); const comment = useSelector((state) => selectCommentById(state, id)); const user = useSelector((state) => selectUserById(state, comment.userId)); const isCurrentUser = useSelector( (state) => comment.userId === selectors.selectCurrentUserId(state), ); const { canEdit, canDelete } = useSelector((state) => { const { listId } = selectors.selectCurrentCard(state); const list = selectListById(state, listId); if (isListArchiveOrTrash(list)) { return { canEdit: false, canDelete: false, }; } const isManager = selectors.selectIsCurrentUserManagerForCurrentProject(state); const boardMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state); let isMember = false; let isEditor = false; if (boardMembership) { isMember = true; isEditor = boardMembership.role === BoardMembershipRoles.EDITOR; } return { canEdit: isMember && comment.userId === boardMembership.userId && (isEditor || boardMembership.canComment), canDelete: isManager || isEditor || (isMember && comment.userId === boardMembership.userId && boardMembership.canComment), }; }, shallowEqual); const dispatch = useDispatch(); const [t] = useTranslation(); const [isEditOpened, setIsEditOpened] = useState(false); const [, , setIsClosableActive] = useContext(ClosableContext); const handleDeleteConfirm = useCallback(() => { dispatch(entryActions.deleteComment(id)); }, [id, dispatch]); const handleEditClick = useCallback(() => { setIsEditOpened(true); }, []); const handleEditClose = useCallback(() => { setIsEditOpened(false); }, []); useDidUpdate(() => { setIsClosableActive(isEditOpened); }, [isEditOpened]); const ConfirmationPopup = usePopupInClosableContext(ConfirmationStep); return ( {!isCurrentUser && ( )}
{isEditOpened ? ( ) : (
{user.id === StaticUserIds.DELETED ? t(`common.${user.name}`, { context: 'title', }) : user.name}
{comment.text} {(canEdit || canDelete) && ( {canEdit && ( )} {canDelete && ( )} )}
)}
); }); Item.propTypes = { id: PropTypes.string.isRequired, }; export default Item;