Passed
Push — dev ( 15f923...8fee54 )
by Yonathan
05:40 queued 12s
created

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

Complexity

Total Complexity 4
Complexity/F 0

Size

Lines of Code 186
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 4
eloc 147
mnd 4
bc 4
fnc 0
dl 0
loc 186
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
import React from "react";
2
import { connect } from "react-redux";
3
import {
4
  FormattedMessage,
5
  WrappedComponentProps,
6
  injectIntl,
7
} from "react-intl";
8
import { Criteria, Skill } from "../../models/types";
9
import {
10
  assessmentType,
11
  assessmentTypeDescription,
12
  narrativeReviewStandardQuestion,
13
  skillLevelName,
14
  narrativeReviewStandardAnswer,
15
} from "../../models/localizedConstants";
16
import { AssessmentTypeId, SkillTypeId } from "../../models/lookupConstants";
17
import { RootState } from "../../store/store";
18
import {
19
  getCriteriaByJobAndAssessmentType,
20
  getCriteriaToSkills,
21
} from "../../store/Job/jobSelectorComplex";
22
import { getLocale, localizeFieldNonNull } from "../../helpers/localize";
23
24
interface RatingGuideNarrativeAssessmentProps {
25
  /** The id of the job Job Poster this is part of */
26
  jobId: number;
27
  /** Display index of this ratings guide assessment compared to others on the page */
28
  assessmentIndex: number;
29
  assessedCriteria: Criteria[];
30
  /** A map of criteria to their associated skills */
31
  criteriaToSkill: { [criteriaId: number]: Skill | null };
32
}
33
34
export const RatingGuideNarrativeAssessment: React.FunctionComponent<
35
  RatingGuideNarrativeAssessmentProps & WrappedComponentProps
36
> = ({
37
  jobId,
38
  assessmentIndex,
39
  assessedCriteria,
40
  criteriaToSkill,
41
  intl,
42
}): React.ReactElement | null => {
43
  const locale = getLocale(intl.locale);
44
  if (jobId === null) {
45
    return null;
46
  }
47
  const getCriteriaSkillType = (criterionId: number): number => {
48
    const skill = criteriaToSkill[criterionId];
49
    return skill ? skill.skill_type_id : SkillTypeId.Hard; // return hard type by default
50
  };
51
  const getCriteriaSkillName = (criterionId: number): string => {
52
    const skill = criteriaToSkill[criterionId];
53
    return skill ? localizeFieldNonNull(locale, skill, "name") : "";
54
  };
55
  return (
56
    <div>
57
      <h4
58
        data-c-font-size="h4"
59
        data-c-colour="c5"
60
        data-c-font-weight="bold"
61
        data-c-margin="top(double) bottom(normal)"
62
      >
63
        {/** TODO: This FormattedMessage is identical to one in RatingGuideAssessment.
64
                    This special Narrative Review section should be refactored to there. */}
65
        <FormattedMessage
66
          id="ratingGuideBuilder.narrativeSectionTitle"
67
          defaultMessage="Assessment {index}: {assessmentType}"
68
          description="Subtitle for the special Narrative Assessment section in the Rating Guide Builder."
69
          values={{
70
            index: assessmentIndex,
71
            assessmentType: intl.formatMessage(
72
              assessmentType(AssessmentTypeId.NarrativeAssessment),
73
            ),
74
          }}
75
        />
76
      </h4>
77
      <p>
78
        {intl.formatMessage(
79
          assessmentTypeDescription(AssessmentTypeId.NarrativeAssessment),
80
        )}
81
      </p>
82
83
      <div
84
        data-c-background="black(10)"
85
        data-c-border="all(thin, solid, black)"
86
        data-c-margin="top(normal) bottom(normal)"
87
        data-c-padding="bottom(normal)"
88
      >
89
        <div
90
          data-c-background="black(10)"
91
          data-c-border="bottom(thin, solid, black)"
92
          data-c-padding="top(normal) bottom(normal)"
93
        >
94
          <div data-c-grid="gutter middle">
95
            <div
96
              data-c-alignment="center"
97
              data-c-grid-item="base(1of1) tp(1of8)"
98
            >
99
              <p>
100
                <strong>{assessmentIndex}.</strong>
101
              </p>
102
            </div>
103
            <div data-c-grid-item="base(1of1) tp(7of8)">
104
              <p data-c-font-weight="800">
105
                {intl.formatMessage(narrativeReviewStandardQuestion())}
106
              </p>
107
            </div>
108
          </div>
109
        </div>
110
        {assessedCriteria.map(
111
          (criterion: Criteria): React.ReactElement => {
112
            let skillLevel = "";
113
            if (criteriaToSkill[criterion.id] !== undefined) {
114
              skillLevel = intl.formatMessage(
115
                skillLevelName(
116
                  criterion.skill_level_id,
117
                  getCriteriaSkillType(criterion.id),
118
                ),
119
              );
120
            }
121
            return (
122
              <div
123
                key={`narrative-review-criteria-${criterion.id}`}
124
                data-c-padding="top(normal) bottom(normal)"
125
              >
126
                <div data-c-grid="gutter middle">
127
                  <div data-c-grid-item="base(1of1) tp(1of8)" />
128
                  {criterion && skillLevel.length > 0 && (
129
                    <div data-c-grid-item="base(1of1) tp(2of8)">
130
                      <p>
131
                        <FormattedMessage
132
                          id="ratingGuideBuilder.criteriaName"
133
                          defaultMessage="{skillName} - {skillLevel}"
134
                          description="How each criteria is listed in Rating Guide Builder."
135
                          values={{
136
                            skillName: getCriteriaSkillName(criterion.id),
137
                            skillLevel,
138
                          }}
139
                        />
140
                      </p>
141
                    </div>
142
                  )}
143
                  <div data-c-grid-item="base(1of1) tp(5of8)">
144
                    <p>{intl.formatMessage(narrativeReviewStandardAnswer())}</p>
145
                  </div>
146
                </div>
147
              </div>
148
            );
149
          },
150
        )}
151
      </div>
152
    </div>
153
  );
154
};
155
156
interface RatingGuideNarrativeAssessmentContainerProps {
157
  jobId: number;
158
  assessmentIndex: number;
159
}
160
161
const mapStateToProps = (
162
  state: RootState,
163
  ownProps: RatingGuideNarrativeAssessmentContainerProps,
164
): {
165
  assessedCriteria: Criteria[];
166
  criteriaToSkill: { [criteriaId: number]: Skill | null };
167
} => {
168
  const narrativeCriteria: Criteria[] = getCriteriaByJobAndAssessmentType(
169
    state,
170
    {
171
      jobId: ownProps.jobId,
172
      assessmentTypeId: AssessmentTypeId.NarrativeAssessment,
173
    },
174
  );
175
  return {
176
    assessedCriteria: narrativeCriteria,
177
    criteriaToSkill: getCriteriaToSkills(state),
178
  };
179
};
180
181
const RatingGuideNarrativeAssessmentContainer = connect(mapStateToProps)(
182
  injectIntl(RatingGuideNarrativeAssessment),
183
);
184
185
export default RatingGuideNarrativeAssessmentContainer;
186