Skip to content
Snippets Groups Projects
CommentReply.js 5.84 KiB
Newer Older
chris's avatar
chris committed
/* eslint-disable react/prop-types */
import React, { useState, useRef, useEffect } from 'react';
import PropTypes from 'prop-types';
import styled, { css } from 'styled-components';
import { isEmpty } from 'lodash';
import { useTranslation } from 'react-i18next';
chris's avatar
chris committed
import { grid, th, override } from '@pubsweet/ui-toolkit';
import { useOnClickOutside } from 'wax-prosemirror-core';
chris's avatar
chris committed
import Mentions from 'rc-mentions';
import './mentions.css';
Yannis Barlas's avatar
Yannis Barlas committed
const Wrapper = styled.div`
chris's avatar
chris committed
  background: ${th('colorBackgroundHue')};
Yannis Barlas's avatar
Yannis Barlas committed
  display: flex;
  flex-direction: column;
  padding: ${grid(2)} ${grid(4)};
Yannis Barlas's avatar
Yannis Barlas committed

const TextWrapper = styled.div``;
Yannis Barlas's avatar
Yannis Barlas committed

const CommentTitle = styled.input`
  background: ${th('colorBackgroundHue')};
  border: 3px solid ${th('colorBackgroundTabs')};
  font-family: ${th('fontWriting')};
  margin-bottom: 10px;
  position: relative;
  width: 100%;

  &:focus {
    outline: 1px solid ${th('colorPrimary')};
  }

  ${override('Wax.CommentTitle')}
`;

Yannis Barlas's avatar
Yannis Barlas committed
const ActionWrapper = styled.div`
  display: flex;
chris's avatar
chris committed
  justify-content: flex-start;
Yannis Barlas's avatar
Yannis Barlas committed
  margin-top: 4px;
Yannis Barlas's avatar
Yannis Barlas committed

const primary = css`
chris's avatar
chris committed
  background: ${th('colorPrimary')};
Yannis Barlas's avatar
Yannis Barlas committed
  color: white;
Yannis Barlas's avatar
Yannis Barlas committed

const Button = styled.button`
  border: 0;
  border-radius: 5px;
  color: gray;
chris's avatar
chris committed
  cursor: pointer;
  padding: ${grid(2)} ${grid(4)};
Yannis Barlas's avatar
Yannis Barlas committed

  ${props => props.primary && primary}
chris's avatar
chris committed
  ${props => props.disabled && `cursor: not-allowed; opacity: 0.3;`}
chris's avatar
chris committed

  ${override('Wax.CommentButtons')}
Yannis Barlas's avatar
Yannis Barlas committed

const ButtonGroup = styled.div`
  > button:not(:last-of-type) {
    margin-right: 8px;
  }
chris's avatar
chris committed
  ${override('Wax.CommentButtonGroup')}
Yannis Barlas's avatar
Yannis Barlas committed

chris's avatar
chris committed
const StyledMentions = styled(Mentions)`
  border: none;
  > textarea {
    font-size: 14px;
    background: ${th('colorBackgroundHue')};
    border: 3px solid ${th('colorBackgroundTabs')};
    font-family: ${th('fontWriting')};
    padding: 2px;

    &:focus {
      outline: 1px solid ${th('colorPrimary')};
    }

    &:focus {
      outline: 1px solid ${th('colorPrimary')};
    }
  }
  ${override('Wax.CommentTextArea')}
`;

Yannis Barlas's avatar
Yannis Barlas committed
const CommentReply = props => {
chris's avatar
chris committed
  const {
    className,
    isNewComment,
    onClickPost,
    isReadOnly,
    onTextAreaBlur,
chris's avatar
chris committed
    usersMentionList,
chris's avatar
chris committed
  } = props;
  const { t, i18n } = useTranslation();
  const commentInput = useRef(null);
  const commentTitle = useRef(null);
chris's avatar
chris committed
  const [commentValue, setCommentValue] = useState('');
  const [title, setTitle] = useState('');
  const ref = useRef(null);

  useOnClickOutside(ref, onTextAreaBlur);

  useEffect(() => {
chris's avatar
chris committed
    setTimeout(() => {
      if (commentTitle.current && isNewComment) commentTitle.current.focus();
      if (!commentTitle.current && isNewComment) commentInput.current.focus();
    });
  }, []);
Yannis Barlas's avatar
Yannis Barlas committed

  const handleSubmit = e => {
    e.preventDefault();
chris's avatar
chris committed
    e.stopPropagation();
    onClickPost({ title, commentValue });
chris's avatar
chris committed
    setCommentValue('');
Yannis Barlas's avatar
Yannis Barlas committed

  const resetValue = e => {
    e.preventDefault();
chris's avatar
chris committed
    setCommentValue('');
Yannis Barlas's avatar
Yannis Barlas committed

chris's avatar
chris committed
  const { Option } = Mentions;

Yannis Barlas's avatar
Yannis Barlas committed
  return (
    <Wrapper className={className} ref={ref}>
Yannis Barlas's avatar
Yannis Barlas committed
      <form onSubmit={handleSubmit}>
        <TextWrapper>
          {isNewComment && showTitle && (
              name="title"
              onChange={e => {
                setTitle(e.target.value);
              }}
              placeholder={`${
                !isEmpty(i18n) && i18n.exists(`Wax.Comments.Write title`)
                  ? t(`Wax.Comments.Write title`)
                  : 'Write title'
              }...`}
              ref={commentTitle}
              type="text"
              value={title}
            />
          )}
chris's avatar
chris committed
          <StyledMentions
            onChange={text => {
              setCommentValue(text);
            }}
            onPressEnter={e => {
              const mentionsOptionsEl = document.getElementsByClassName(
                'rc-mentions-measure',
              );

              if (
                e.keyCode === 13 &&
                !e.shiftKey &&
                mentionsOptionsEl.length === 0
              ) {
                e.preventDefault();
chris's avatar
chris committed
                if (commentValue) handleSubmit(e);
            placeholder={
              isNewComment
                ? `${
                    !isEmpty(i18n) && i18n.exists(`Wax.Comments.Write comment`)
                      ? t(`Wax.Comments.Write comment`)
                      : 'Write comment'
                  }...`
                : `${
                    !isEmpty(i18n) && i18n.exists(`Wax.Comments.Reply`)
                      ? t(`Wax.Comments.Reply`)
                      : 'Reply'
                  }...`
            }
chris's avatar
chris committed
            ref={commentInput}
chris's avatar
chris committed
            rows="4"
chris's avatar
chris committed
            value={commentValue}
chris's avatar
chris committed
          >
chris's avatar
chris committed
            {usersMentionList &&
              usersMentionList.map(item => (
                <Option key={item.id} value={item.displayName}>
                  {item.displayName}
                </Option>
              ))}
chris's avatar
chris committed
          </StyledMentions>
Yannis Barlas's avatar
Yannis Barlas committed
        </TextWrapper>

        <ActionWrapper>
          <ButtonGroup>
chris's avatar
chris committed
            <Button
              disabled={commentValue.length === 0 || isReadOnly}
              primary
              type="submit"
            >
              {!isEmpty(i18n) && i18n.exists(`Wax.Comments.Post`)
                ? t(`Wax.Comments.Post`)
                : 'Post'}
chris's avatar
chris committed
            <Button disabled={commentValue.length === 0} onClick={resetValue}>
              {!isEmpty(i18n) && i18n.exists(`Wax.Comments.Cancel`)
                ? t(`Wax.Comments.Cancel`)
                : 'Cancel'}
            </Button>
          </ButtonGroup>
        </ActionWrapper>
Yannis Barlas's avatar
Yannis Barlas committed
      </form>
    </Wrapper>
Yannis Barlas's avatar
Yannis Barlas committed

CommentReply.propTypes = {
  isNewComment: PropTypes.bool.isRequired,
Yannis Barlas's avatar
Yannis Barlas committed
  onClickPost: PropTypes.func.isRequired,
chris's avatar
chris committed
  isReadOnly: PropTypes.bool.isRequired,
chris's avatar
chris committed
  onTextAreaBlur: PropTypes.func.isRequired,
  showTitle: PropTypes.bool.isRequired,
Yannis Barlas's avatar
Yannis Barlas committed

CommentReply.defaultProps = {};
Yannis Barlas's avatar
Yannis Barlas committed

export default CommentReply;