Skip to content
Snippets Groups Projects
NumericalAnswerContainerComponent.js 5.86 KiB
Newer Older
chris's avatar
chris committed
import React, { useContext, useEffect, useRef, useState } from 'react';
chris's avatar
chris committed
import styled from 'styled-components';
chris's avatar
chris committed
import { th } from '@pubsweet/ui-toolkit';
import { WaxContext, DocumentHelpers, Icon } from 'wax-prosemirror-core';
chris's avatar
chris committed
import EditorComponent from '../../MultipleChoiceQuestionService/components/EditorComponent';
chris's avatar
chris committed
import FeedbackComponent from '../../MultipleChoiceQuestionService/components/FeedbackComponent';
chris's avatar
chris committed
import NumericalAnswerDropDownCompontent from './NumericalAnswerDropDownCompontent';
chris's avatar
chris committed
import ExactAnswerComponent from './ExactAnswerComponent';
import PreciseAnswerComponent from './PreciseAnswerComponent';
import RangeAnswerComponent from './RangeAnswerComponent';
chris's avatar
chris committed

const NumericalAnswerWrapper = styled.div`
  margin: 0px 38px 15px 38px;
  margin-top: 10px;
`;

const NumericalAnswerContainer = styled.div`
  border: 3px solid #f5f5f7;
  margin-bottom: 30px;
`;

const NumericalAnswerContainerTool = styled.div`
  border: 3px solid #f5f5f7;
  border-bottom: none;
chris's avatar
chris committed
  height: 33px;
chris's avatar
chris committed
  display: flex;
  flex-direction: row;
chris's avatar
chris committed
`;

const NumericalAnswerOption = styled.div`
  padding: 8px;
`;
chris's avatar
chris committed

chris's avatar
chris committed
const ActionButton = styled.button`
  background: transparent;
  cursor: pointer;
  border: none;
chris's avatar
chris committed
  margin-left: auto;
chris's avatar
chris committed
  z-index: 999;
chris's avatar
chris committed
`;

chris's avatar
chris committed
const StyledIconContainer = styled.span`
  float: right;
  position: relative;
  top: 3px;
`;

const StyledIconAction = styled(Icon)`
  position: relative;
  right: 4px;
  cursor: pointer;
  height: 24px;
  width: 24px;
chris's avatar
chris committed
  z-index: 999;
chris's avatar
chris committed
`;

const InfoMsg = styled.div`
  color: #fff;
  display: none;
  user-select: none;
  position: absolute;
chris's avatar
chris committed
  width: 100%;
chris's avatar
chris committed
  span {
    background: ${th('colorPrimary')};
chris's avatar
chris committed
    bottom: 35px;
    border-radius: 4px;
    float: right;
    right: 162px;
    padding: 4px;
chris's avatar
chris committed
    position: relative;
  }
`;

chris's avatar
chris committed
const StyledIconActionRemove = styled(Icon)`
  height: 24px;
  width: 24px;
`;

export default ({ node, view, getPos }) => {
  const context = useContext(WaxContext);
  const {
chris's avatar
chris committed
    options,
chris's avatar
chris committed
    pmViews: { main },
chris's avatar
chris committed
    setOption,
chris's avatar
chris committed
  } = context;
chris's avatar
chris committed

chris's avatar
chris committed
  const customProps = main.props.customValues;
chris's avatar
chris committed

  const { testMode, showFeedBack } = customProps;
chris's avatar
chris committed
  const infoMsgRef = useRef();
  const [infoMsgIsOpen, setInfoMsgIsOpen] = useState(false);
chris's avatar
chris committed

  const isEditable = main.props.editable(editable => {
    return editable;
  });

  const readOnly = !isEditable;
  const { feedback } = node.attrs;

  const removeQuestion = () => {
    const allNodes = getNodes(context.pmViews.main);
    allNodes.forEach(singleNode => {
      if (singleNode.node.attrs.id === node.attrs.id) {
        context.pmViews.main.dispatch(
          context.pmViews.main.state.tr.delete(
            singleNode.pos,
            singleNode.pos + singleNode.node.nodeSize,
          ),
        );
      }
    });
  };

chris's avatar
chris committed
  useEffect(() => {
chris's avatar
chris committed
    setOption({
      [node.attrs.id]: { numericalAnswer: node.attrs.answerType },
chris's avatar
chris committed
    });
  }, []);

chris's avatar
chris committed
  const displayInfoMsg = () => {
    if (infoMsgRef.current && !infoMsgIsOpen)
      infoMsgRef.current.style.display = 'block';

    if (infoMsgRef.current && infoMsgIsOpen)
      infoMsgRef.current.style.display = 'none';

    setInfoMsgIsOpen(!infoMsgIsOpen);
  };

chris's avatar
chris committed
  return (
    <NumericalAnswerWrapper>
      <div>
        {!testMode && !readOnly && (
          <NumericalAnswerContainerTool>
            <NumericalAnswerDropDownCompontent node={node} />
chris's avatar
chris committed
            <ActionButton
              aria-label="delete this question"
              onClick={removeQuestion}
              type="button"
            >
              <StyledIconActionRemove name="deleteOutlinedQuestion" />
            </ActionButton>
chris's avatar
chris committed
            {options[node.attrs.id]?.numericalAnswer === 'preciseAnswer' && (
              <StyledIconContainer
                onClick={displayInfoMsg}
                onKeyPress={() => {}}
                role="button"
                tabIndex={0}
              >
                <StyledIconAction name="help" />
              </StyledIconContainer>
            )}

            <InfoMsg ref={infoMsgRef}>
              <span>Separate answer variants with a semi colon</span>
            </InfoMsg>
chris's avatar
chris committed
          </NumericalAnswerContainerTool>
        )}
      </div>
      <NumericalAnswerContainer className="numerical-answer">
chris's avatar
chris committed
        <EditorComponent
          getPos={getPos}
          node={node}
          QuestionType="NumericalAnswer"
chris's avatar
chris committed
          view={view}
        />
        <NumericalAnswerOption>
chris's avatar
chris committed
          {options[node.attrs.id]?.numericalAnswer === '' && (
chris's avatar
chris committed
            <>No Type Selected</>
          )}
chris's avatar
chris committed
          {options[node.attrs.id]?.numericalAnswer === 'exactAnswer' && (
chris's avatar
chris committed
            <ExactAnswerComponent
              node={node}
              readOnly={readOnly}
chris's avatar
chris committed
              showFeedBack={showFeedBack}
chris's avatar
chris committed
              testMode={testMode}
            />
chris's avatar
chris committed
          )}
chris's avatar
chris committed
          {options[node.attrs.id]?.numericalAnswer === 'rangeAnswer' && (
chris's avatar
chris committed
            <RangeAnswerComponent
              node={node}
              readOnly={readOnly}
chris's avatar
chris committed
              showFeedBack={showFeedBack}
chris's avatar
chris committed
              testMode={testMode}
            />
chris's avatar
chris committed
          )}
chris's avatar
chris committed
          {options[node.attrs.id]?.numericalAnswer === 'preciseAnswer' && (
chris's avatar
chris committed
            <PreciseAnswerComponent
              node={node}
              readOnly={readOnly}
chris's avatar
chris committed
              showFeedBack={showFeedBack}
chris's avatar
chris committed
              testMode={testMode}
            />
chris's avatar
chris committed
          )}
        </NumericalAnswerOption>
chris's avatar
chris committed
        {!testMode && !(readOnly && feedback === '') && (
          <FeedbackComponent
            getPos={getPos}
            node={node}
            readOnly={readOnly}
            view={view}
          />
        )}
      </NumericalAnswerContainer>
    </NumericalAnswerWrapper>
  );
};

const getNodes = view => {
  const allNodes = DocumentHelpers.findBlockNodes(view.state.doc);
  const numericalAnswerpContainerNodes = [];
  allNodes.forEach(node => {
    if (node.node.type.name === 'numerical_answer_container') {
      numericalAnswerpContainerNodes.push(node);
    }
  });
  return numericalAnswerpContainerNodes;
};