Passed
Push — feature/azure-webapp-pipeline-... ( 33e0f0...f382c1 )
by Grant
05:11
created

resources/assets/js/components/AssessmentPlan/RatingGuideQuestionWithAnswers.tsx   A

Complexity

Total Complexity 6
Complexity/F 0

Size

Lines of Code 158
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 124
dl 0
loc 158
rs 10
c 0
b 0
f 0
wmc 6
mnd 6
bc 6
fnc 0
bpm 0
cpm 0
noi 0
1
import React, { ReactElement } from "react";
2
import { connect } from "react-redux";
3
import RatingGuideQuestionComponent from "./RatingGuideQuestion";
4
import RatingGuideAnswerComponent from "./RatingGuideAnswer";
5
import { RootState } from "../../store/store";
6
import {
7
  getRatingGuideAnswerIdsByQuestion,
8
  getTempRatingGuideAnswerIdsByQuestion,
9
} from "../../store/RatingGuideAnswer/ratingGuideAnswerSelectors";
10
import { getCriteriaIdsByJobAndAssessmentType } from "../../store/Job/jobSelectorComplex";
11
import { DispatchType } from "../../configureStore";
12
import { createTempRatingGuideAnswer } from "../../store/RatingGuideAnswer/ratingGuideAnswerActions";
13
import {
14
  getCurrentRatingGuideQuestionById,
15
  getTempRatingGuideQuestionById,
16
} from "../../store/RatingGuideQuestion/ratingGuideQuestionSelectors";
17
18
interface RatingGuideQuestionWithAnswersProps {
19
  questionId: number;
20
  questionIndex: number;
21
  /** If this is a Temp question */
22
  temp?: boolean;
23
  /** Expected answers to this question */
24
  answerIds: number[];
25
  tempAnswerIds: number[];
26
  /** Whether the Add Answer button should be shown */
27
  allowMoreAnswers: boolean;
28
  /** Handler function for creating a new RatingGuideAnswer */
29
  createAnswer: (ratingGuideQuestionId: number) => void;
30
}
31
32
export const RatingGuideQuestionWithAnswers: React.FunctionComponent<RatingGuideQuestionWithAnswersProps> = ({
33
  questionId,
34
  questionIndex,
35
  temp,
36
  answerIds,
37
  tempAnswerIds,
38
  allowMoreAnswers,
39
  createAnswer,
40
}): React.ReactElement => {
41
  return (
42
    <div
43
      key={questionId}
44
      data-c-background="black(10)"
45
      data-c-border="all(thin, solid, black)"
46
      data-c-margin="top(normal) bottom(normal)"
47
      data-c-padding="bottom(normal)"
48
    >
49
      <RatingGuideQuestionComponent
50
        key={questionId}
51
        ratingGuideQuestionId={questionId}
52
        questionIndex={questionIndex}
53
        temp={temp}
54
      />
55
56
      <div data-c-padding="top(normal)">
57
        {answerIds.map((answerId: number): ReactElement | null => (
58
          <RatingGuideAnswerComponent key={answerId} answerId={answerId} />
59
        ))}
60
        {tempAnswerIds.map((answerId: number): ReactElement | null => (
61
          <RatingGuideAnswerComponent key={answerId} answerId={answerId} temp />
62
        ))}
63
        {allowMoreAnswers && (
64
          <div data-c-grid="gutter middle">
65
            <div
66
              data-c-alignment="center"
67
              data-c-grid-item="base(1of1) tp(1of8)"
68
            >
69
              <button
70
                className="button-plus"
71
                type="button"
72
                onClick={(): void => createAnswer(questionId)}
73
              >
74
                +
75
              </button>
76
            </div>
77
          </div>
78
        )}
79
      </div>
80
    </div>
81
  );
82
};
83
84
interface RatingGuideQuestionWithAnswersContainerProps {
85
  questionId: number;
86
  questionIndex: number;
87
  /** If this is a Temp question */
88
  temp?: boolean;
89
}
90
91
/**
92
 * Only allow more answers to be added, if there are currently less answers than criteria to be answered.
93
 * @param state
94
 * @param ownProps
95
 */
96
const allowMoreAnswers = (
97
  state: RootState,
98
  ownProps: RatingGuideQuestionWithAnswersContainerProps,
99
): boolean => {
100
  // Require questions to save before adding answers
101
  if (ownProps.temp) {
102
    return false;
103
  }
104
105
  const answerIds = getRatingGuideAnswerIdsByQuestion(state, ownProps);
106
  const tempAnswerIds = getTempRatingGuideAnswerIdsByQuestion(state, ownProps);
107
  const allAnswerIds = answerIds.concat(tempAnswerIds);
108
  const question = ownProps.temp
109
    ? getTempRatingGuideQuestionById(state, ownProps.questionId)
110
    : getCurrentRatingGuideQuestionById(state, ownProps.questionId);
111
  if (question === null) {
112
    return false;
113
  }
114
  const criteriaIdsForQuestion = getCriteriaIdsByJobAndAssessmentType(state, {
115
    jobId: question.job_poster_id,
116
    assessmentTypeId: question.assessment_type_id,
117
  });
118
  return allAnswerIds.length < criteriaIdsForQuestion.length;
119
};
120
121
const mapStateToProps = (
122
  state: RootState,
123
  ownProps: RatingGuideQuestionWithAnswersContainerProps,
124
): {
125
  answerIds: number[];
126
  tempAnswerIds: number[];
127
  /** Whether the Add Answer button should be shown */
128
  allowMoreAnswers: boolean;
129
} => {
130
  // We decided a temp question must be saved before it can contain answers.
131
  return {
132
    answerIds: ownProps.temp
133
      ? []
134
      : getRatingGuideAnswerIdsByQuestion(state, ownProps),
135
    tempAnswerIds: ownProps.temp
136
      ? []
137
      : getTempRatingGuideAnswerIdsByQuestion(state, ownProps),
138
    allowMoreAnswers: ownProps.temp ? false : allowMoreAnswers(state, ownProps),
139
  };
140
};
141
142
const mapDispatchToProps = (
143
  dispatch: DispatchType,
144
): {
145
  createAnswer: (ratingGuideQuestionId: number) => void;
146
} => ({
147
  createAnswer: (ratingGuideQuestionId: number): void => {
148
    dispatch(createTempRatingGuideAnswer(ratingGuideQuestionId, null, null));
149
  },
150
});
151
152
export const RatingGuideQuestionWithAnswersContainer = connect(
153
  mapStateToProps,
154
  mapDispatchToProps,
155
)(RatingGuideQuestionWithAnswers);
156
157
export default RatingGuideQuestionWithAnswersContainer;
158