Skip to content
Snippets Groups Projects
ConnectedComment.js 4.37 KiB
Newer Older
/* eslint-disable no-param-reassign */
chris's avatar
chris committed
/* eslint react/prop-types: 0 */
import React, { useContext, useMemo, useState, useEffect } from 'react';
chris's avatar
chris committed
import { TextSelection } from 'prosemirror-state';
chris's avatar
chris committed
import { last, maxBy, minBy } from 'lodash';
chris's avatar
chris committed
import styled from 'styled-components';
chris's avatar
chris committed
import { WaxContext, DocumentHelpers, Commands } from 'wax-prosemirror-core';
chris's avatar
chris committed
import { override } from '@pubsweet/ui-toolkit';
chris's avatar
chris committed
import CommentBox from './ui/comments/CommentBox';
chris's avatar
chris committed
import { AnnotationPluginKey } from '../plugins/AnnotationPlugin';
const ConnectedCommentStyled = styled.div`
chris's avatar
chris committed
  margin-left: ${props => (props.active ? `${-20}px` : `${50}px`)};
chris's avatar
chris committed
  transition: ${props =>
    props.active && props.length ? `none!important` : `all 1.3s`};
  width: 205px;
chris's avatar
chris committed
  @media (max-width: 600px) {
    margin-left: 15px;
  }
chris's avatar
chris committed

  ${override('Wax.CommentOuterBox')}
export default ({ comment, top, commentId, recalculateTops, users }) => {
chris's avatar
chris committed
  const context = useContext(WaxContext);
chris's avatar
chris committed
  const {
chris's avatar
chris committed
    pmViews,
    pmViews: {
chris's avatar
chris committed
      main: {
chris's avatar
chris committed
      },
chris's avatar
chris committed
    },
    app,
    activeView,
chris's avatar
chris committed
    activeViewId,
chris's avatar
chris committed
    options: { comments },
chris's avatar
chris committed
  } = context;
chris's avatar
chris committed

  const [isActive, setIsActive] = useState(false);
chris's avatar
chris committed
  const [clickPost, setClickPost] = useState(false);

chris's avatar
chris committed
  const { state, dispatch } = activeView;
  const { viewId, conversation } = comment.data;

chris's avatar
chris committed
  const styles = {
    top: `${top}px`,
  };
chris's avatar
chris committed
  const commentConfig = app.config.get('config.CommentsService');
  const isReadOnly =
    commentConfig && commentConfig.readOnly ? commentConfig.readOnly : false;
  const showTitle =
    commentConfig && commentConfig.showTitle ? commentConfig.showTitle : false;
chris's avatar
chris committed
  const commentPlugin = app.PmPlugins.get('commentPlugin');
  const activeComment = commentPlugin.getState(activeView.state).comment;
  useEffect(() => {
    setIsActive(false);
chris's avatar
chris committed
    recalculateTops();
chris's avatar
chris committed
    if (activeComment && commentId === activeComment.id) {
      setIsActive(true);
      recalculateTops();
    }
  }, [activeComment]);
chris's avatar
chris committed

  const onClickPost = ({ commentValue, title }) => {
chris's avatar
chris committed
    setClickPost(true);
    const currentUser = user || (users || []).find(u => u.currentUser === true);

chris's avatar
chris committed
    const obj = {
      content: commentValue,
      displayName: currentUser
        ? currentUser.displayName || currentUser.username
        : 'Anonymous',
      userId: currentUser ? currentUser.userId : '1',
Yannis Barlas's avatar
Yannis Barlas committed
      timestamp: Math.floor(Date.now()),
chris's avatar
chris committed
    };

    comment.attrs.title = title || comment.attrs.title;
chris's avatar
chris committed
    comment.attrs.conversation.push(obj);
chris's avatar
chris committed
    activeView.focus();
chris's avatar
chris committed
    recalculateTops();
chris's avatar
chris committed
  };
chris's avatar
chris committed

chris's avatar
chris committed
  const onClickBox = () => {
chris's avatar
chris committed
      pmViews[viewId].focus();
chris's avatar
chris committed
      return false;
    }
chris's avatar
chris committed

chris's avatar
chris committed
    if (viewId !== 'main') context.updateView({}, viewId);

chris's avatar
chris committed
    const maxPos = maxBy(allCommentsWithSameId, 'pos');
    maxPos.pos += last(allCommentsWithSameId).node.nodeSize;
chris's avatar
chris committed

chris's avatar
chris committed
    pmViews[viewId].dispatch(
      pmViews[viewId].state.tr.setSelection(
        new TextSelection(pmViews[viewId].state.tr.doc.resolve(maxPos.pos)),
chris's avatar
chris committed
      ),
chris's avatar
chris committed
    );
chris's avatar
chris committed

chris's avatar
chris committed
    pmViews[viewId].focus();
chris's avatar
chris committed
    return true;
  };

  const onClickResolve = () => {
chris's avatar
chris committed
    dispatch(
      state.tr.setMeta(AnnotationPluginKey, {
        type: 'deleteComment',
        id: activeComment.id,
      }),
    );
    recalculateTops();
chris's avatar
chris committed
    activeView.focus();
chris's avatar
chris committed
    setTimeout(() => {
      const newComments = comments.filter(comm => {
        return comm.id !== activeComment.id;
      });
      context.setOption({ comments: newComments });
    });
chris's avatar
chris committed
  };

  const onTextAreaBlur = () => {
chris's avatar
chris committed
    if (conversation.length === 0 && !clickPost) {
      onClickResolve();
      activeView.focus();
    }
chris's avatar
chris committed
  };
chris's avatar
chris committed

chris's avatar
chris committed
  const MemorizedComponent = useMemo(
    () => (
      <ConnectedCommentStyled
chris's avatar
chris committed
        data-box={commentId}
        length={conversation.length === 0}
chris's avatar
chris committed
        style={styles}
      >
        <CommentBox
          commentData={conversation}
          commentId={commentId}
chris's avatar
chris committed
          isReadOnly={isReadOnly}
chris's avatar
chris committed
          onClickBox={onClickBox}
          onClickPost={onClickPost}
chris's avatar
chris committed
          onClickResolve={onClickResolve}
          onTextAreaBlur={onTextAreaBlur}
          recalculateTops={recalculateTops}
          showTitle={showTitle}
chris's avatar
chris committed
          title={comment.data.title}
chris's avatar
chris committed
        />
      </ConnectedCommentStyled>
    ),
    [isActive, top, conversation.length, users],
chris's avatar
chris committed
  );
chris's avatar
chris committed
  return <>{MemorizedComponent}</>;
chris's avatar
chris committed
};