Skip to content
Snippets Groups Projects
CommentReply.js 5.76 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')};
  }

  /* stylelint-disable-next-line order/properties-alphabetical-order */
  ${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)};
  
  /* stylelint-disable-next-line order/properties-alphabetical-order */
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;
chris's avatar
chris committed
  > textarea {
    background: ${th('colorBackgroundHue')};
    border: 3px solid ${th('colorBackgroundTabs')};
    font-family: ${th('fontWriting')};
chris's avatar
chris committed
    padding: 2px;

    &:focus {
      outline: 1px solid ${th('colorPrimary')};
    }
  }
chris's avatar
chris committed
  ${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}>
      <TextWrapper>
        {isNewComment && showTitle && (
          <CommentTitle
            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}
          />
        )}

        <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();
              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'
                }...`
          }
          ref={commentInput}
          rows="4"
          value={commentValue}
        >
          {usersMentionList &&
            usersMentionList.map(item => (
              <Option key={item.id} value={item.displayName}>
                {item.displayName}
              </Option>
            ))}
        </StyledMentions>
      </TextWrapper>

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

          <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
    </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;