Skip to content
Snippets Groups Projects
ConnectedComment.js 3.39 KiB
Newer Older
chris's avatar
chris committed
/* eslint react/prop-types: 0 */
chris's avatar
chris committed
import React, { useContext, memo } from 'react';
chris's avatar
chris committed
import { TextSelection } from 'prosemirror-state';
import { last, maxBy } from 'lodash';
chris's avatar
chris committed
import styled from 'styled-components';
import { DocumentHelpers } from 'wax-prosemirror-utilities';
import { WaxContext } from 'wax-prosemirror-core';
import CommentBox from '../../ui/comments/CommentBox';

const ConnectedCommentStyled = styled.div`
  position: absolute;
`;

chris's avatar
chris committed
export default ({ comment, top, commentId }) => {
chris's avatar
chris committed
  const MemorizedComponent = memo(() => {
chris's avatar
chris committed
    const {
      view,
      view: {
        main: {
          props: { user },
        },
      },
      app,
      activeView,
    } = useContext(WaxContext);
chris's avatar
chris committed

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

    const allCommentsWithSameId = DocumentHelpers.findAllMarksWithSameId(
chris's avatar
chris committed
      view[viewId].state,
chris's avatar
chris committed
      comment,
    );
chris's avatar
chris committed

chris's avatar
chris committed
    const commentMark = state.schema.marks.comment;

chris's avatar
chris committed
    let active = false;

    const styles = {
      top: `${top}px`,
    };

chris's avatar
chris committed
    const commentPlugin = app.PmPlugins.get('commentPlugin');
    const activeComment = commentPlugin.getState(activeView.state).comment;

    if (activeComment && commentId === activeComment.attrs.id) active = true;
chris's avatar
chris committed

    const onClickPost = content => {
      const { tr } = state;

      const obj = {
        content,
        displayName: user.username,
        timestamp: Math.floor(Date.now() / 300000),
      };

chris's avatar
chris committed
      comment.attrs.conversation.push(obj);
chris's avatar
chris committed

      allCommentsWithSameId.forEach(singleComment => {
        dispatch(
          tr.addMark(
            singleComment.pos,
            singleComment.pos + singleComment.nodeSize,
            commentMark.create({
chris's avatar
chris committed
              ...((comment && comment.attrs) || {}),
              conversation: comment.attrs.conversation,
chris's avatar
chris committed
            }),
          ),
        );
      });
    };

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

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

      view[viewId].dispatch(
        view[viewId].state.tr.setSelection(
          new TextSelection(
            view[viewId].state.tr.doc.resolve(maxPos.pos, maxPos.pos),
          ),
        ),
      );

      view[viewId].focus();
      return true;
    };

    const onClickResolve = () => {
      let maxPos = comment.pos;
      let minPos = comment.pos;

      allCommentsWithSameId.forEach(singleComment => {
        const markPosition = DocumentHelpers.findMarkPosition(
          state,
          singleComment.pos,
          'comment',
        );
        if (markPosition.from < minPos) minPos = markPosition.from;
        if (markPosition.to > maxPos) maxPos = markPosition.to;
      });

      if (allCommentsWithSameId.length > 1)
        maxPos += last(allCommentsWithSameId).node.nodeSize;
      dispatch(state.tr.removeMark(minPos, maxPos, commentMark));
      activeView.focus();
    };

chris's avatar
chris committed
    return (
      <ConnectedCommentStyled data-box={commentId} style={styles}>
        <CommentBox
          key={commentId}
          active={active}
          commentId={commentId}
chris's avatar
chris committed
          commentData={comment.attrs.conversation}
chris's avatar
chris committed
          onClickPost={onClickPost}
chris's avatar
chris committed
          onClickBox={onClickBox}
          onClickResolve={onClickResolve}
        />
      </ConnectedCommentStyled>
chris's avatar
chris committed
    );
  });
  return <MemorizedComponent />;
};