Skip to content
Snippets Groups Projects
ConnectedComment.js 4.61 KiB
Newer Older
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';
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`
chris's avatar
chris committed
  margin-left: ${props => (props.active ? `${-20}px` : `${50}px`)};
chris's avatar
chris committed
  width: 200px;
chris's avatar
chris committed
  @media (max-width: 600px) {
    margin-left: 15px;
  }
chris's avatar
chris committed
export default ({ comment, top, commentId, recalculateTops }) => {
chris's avatar
chris committed
  const context = useContext(WaxContext);
chris's avatar
chris committed
  const {
    view,
    view: {
      main: {
        props: { user },
chris's avatar
chris committed
      },
chris's avatar
chris committed
    },
    app,
    activeView,
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 = comment.attrs.viewid;
chris's avatar
chris committed
  let allCommentsWithSameId = [];
chris's avatar
chris committed

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

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

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 : 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();
    if (activeComment && commentId === activeComment.attrs.id) {
      setIsActive(true);
      recalculateTops();
    }
  }, [activeComment]);
chris's avatar
chris committed

chris's avatar
chris committed
  const onClickPost = content => {
    const { tr } = state;
chris's avatar
chris committed
    setClickPost(true);
chris's avatar
chris committed
    const obj = {
      content,
      displayName: user.username,
Yannis Barlas's avatar
Yannis Barlas committed
      timestamp: Math.floor(Date.now()),
chris's avatar
chris committed
    };

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

chris's avatar
chris committed
    allCommentsWithSameId.forEach(singleComment => {
      dispatch(
chris's avatar
chris committed
        tr
          .addMark(
            singleComment.pos,
            singleComment.pos + singleComment.nodeSize,
            commentMark.create({
              ...((comment && comment.attrs) || {}),
              conversation: comment.attrs.conversation,
            }),
          )
          .setMeta('forceUpdate', true),
chris's avatar
chris committed
      );
chris's avatar
chris committed
    });
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
      view[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
    view[viewId].dispatch(
      view[viewId].state.tr.setSelection(
chris's avatar
chris committed
        new TextSelection(view[viewId].state.tr.doc.resolve(maxPos.pos)),
chris's avatar
chris committed
      ),
chris's avatar
chris committed
    );
chris's avatar
chris committed

    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;
    });
chris's avatar
chris committed
    // if (allCommentsWithSameId.length > 1);
    // maxPos += last(allCommentsWithSameId).node.nodeSize;
    recalculateTops();
chris's avatar
chris committed
    dispatch(state.tr.removeMark(minPos, maxPos, commentMark));
    activeView.focus();
  };

chris's avatar
chris committed
  const onTextAreaBlur = (content, isNewComment) => {
    // TODO Save into local storage
chris's avatar
chris committed
    // if (content !== '') {
    //   onClickPost(content);
    // }
chris's avatar
chris committed
    setTimeout(() => {
chris's avatar
chris committed
      if (
        comment.attrs.conversation.length === 0 &&
        isNewComment &&
        !clickPost
      ) {
chris's avatar
chris committed
        onClickResolve();
        activeView.focus();
      }
chris's avatar
chris committed
    }, 400);
chris's avatar
chris committed
  };

chris's avatar
chris committed
  const MemorizedComponent = useMemo(
    () => (
      <ConnectedCommentStyled
chris's avatar
chris committed
        data-box={commentId}
        style={styles}
      >
        <CommentBox
chris's avatar
chris committed
          commentData={comment.attrs.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}
chris's avatar
chris committed
        />
      </ConnectedCommentStyled>
    ),
    [isActive, top, comment.attrs.conversation.length],
chris's avatar
chris committed
  );
chris's avatar
chris committed
  return <>{MemorizedComponent}</>;
chris's avatar
chris committed
};