Passed
Push — feature/azure-webapp-pipeline-... ( 9e9b64...fdb227 )
by Grant
07:49 queued 11s
created

resources/assets/js/store/RatingGuideQuestion/ratingGuideQuestionSelectors.ts   A

Complexity

Total Complexity 11
Complexity/F 0

Size

Lines of Code 266
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 11
eloc 234
mnd 11
bc 11
fnc 0
dl 0
loc 266
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
import isEqual from "lodash/isEqual";
2
import { createSelector } from "reselect";
3
import createCachedSelector from "re-reselect";
4
import { RootState } from "../store";
5
import { RatingGuideQuestionState } from "./ratingGuideQuestionReducer";
6
import { RatingGuideQuestion } from "../../models/types";
7
import { getId, hasKey, mapToObjectTrans } from "../../helpers/queries";
8
import { deepEqualSelectorOptions } from "../cachedSelectors";
9
10
const stateSlice = (state: RootState): RatingGuideQuestionState =>
11
  state.ratingGuideQuestion;
12
13
const getCanonQuestionState = (
14
  state: RootState,
15
): { [id: number]: RatingGuideQuestion } =>
16
  stateSlice(state).ratingGuideQuestions;
17
18
const getTempQuestionState = (
19
  state: RootState,
20
): { [id: number]: RatingGuideQuestion } =>
21
  stateSlice(state).tempRatingGuideQuestions;
22
23
const getEditedQuestionState = (
24
  state: RootState,
25
): { [id: number]: RatingGuideQuestion } =>
26
  stateSlice(state).editedRatingGuideQuestions;
27
28
const getQuestionDeletes = (state: RootState): { [id: number]: number } =>
29
  stateSlice(state).ratingGuideQuestionDeletes;
30
31
const getTempQuestionSaving = (state: RootState): { [id: number]: boolean } =>
32
  stateSlice(state).tempRatingGuideQuestionSaving;
33
34
const getQuestionUpdates = (state: RootState): { [id: number]: number } =>
35
  stateSlice(state).ratingGuideQuestionUpdates;
36
37
const getCurrentQuestionState = createSelector(
38
  getCanonQuestionState,
39
  getEditedQuestionState,
40
  (canonQuestions, editedQuestions): { [id: number]: RatingGuideQuestion } => ({
41
    ...canonQuestions,
42
    ...editedQuestions,
43
  }),
44
);
45
46
/**
47
 * Returns current versions of all assessments.
48
 * ie edited version if possible,
49
 * and not including those undergoing delete requests
50
 */
51
export const getCurrentRatingGuideQuestions = createSelector(
52
  [getCanonQuestionState, getEditedQuestionState, getQuestionDeletes],
53
  (questionState, editedQuestionState, deleteCount): RatingGuideQuestion[] => {
54
    const currentRatingGuideQuestions = {
55
      ...questionState,
56
      ...editedQuestionState,
57
    };
58
    return Object.values(currentRatingGuideQuestions).filter(
59
      (ratingGuideQuestion): boolean =>
60
        !hasKey(deleteCount, ratingGuideQuestion.id) ||
61
        deleteCount[ratingGuideQuestion.id] <= 0,
62
    );
63
  },
64
);
65
66
export const getTempRatingGuideQuestions = createSelector(
67
  getTempQuestionState,
68
  (tempQuestionState): RatingGuideQuestion[] =>
69
    Object.values(tempQuestionState),
70
);
71
72
export const getRatingGuideQuestionIds = createSelector(
73
  getCurrentQuestionState,
74
  (currentQuestions): number[] =>
75
    Object.keys(currentQuestions).map((id) => Number(id)),
76
);
77
78
export const getTempRatingGuideQuestionIds = createSelector(
79
  getTempQuestionState,
80
  (tempQuestions): number[] =>
81
    Object.keys(tempQuestions).map((id) => Number(id)),
82
);
83
84
/**
85
 * Returns edited version, if available
86
 * */
87
export const getCurrentRatingGuideQuestionById = createSelector(
88
  getCurrentQuestionState,
89
  (state: RootState, id: number) => id,
90
  (questions, id): RatingGuideQuestion | null =>
91
    hasKey(questions, id) ? questions[id] : null,
92
);
93
94
export const getCanonRatingGuideQuestionById = createCachedSelector(
95
  getCanonQuestionState,
96
  (state: RootState, id: number): number => id,
97
  (questions, id): RatingGuideQuestion | null =>
98
    hasKey(questions, id) ? questions[id] : null,
99
)((state, id) => id);
100
101
export const getEditRatingGuideQuestionById = createCachedSelector(
102
  getEditedQuestionState,
103
  (state: RootState, id: number): number => id,
104
  (questions, id): RatingGuideQuestion | null =>
105
    hasKey(questions, id) ? questions[id] : null,
106
)((state, id) => id);
107
108
export const getTempRatingGuideQuestionById = createCachedSelector(
109
  getTempQuestionState,
110
  (state: RootState, id: number): number => id,
111
  (questions, id): RatingGuideQuestion | null =>
112
    hasKey(questions, id) ? questions[id] : null,
113
)((state, id) => id);
114
115
export const getRatingGuideQuestionsByJob = createCachedSelector(
116
  getCurrentRatingGuideQuestions,
117
  (state: RootState, props: { jobId: number }): number => props.jobId,
118
  (questions, jobId): RatingGuideQuestion[] =>
119
    questions.filter((question): boolean => question.job_poster_id === jobId),
120
)((state, props): number => props.jobId);
121
122
export const getRatingGuideQuestionIdsByJob = createCachedSelector(
123
  getRatingGuideQuestionsByJob,
124
  (questions): number[] => questions.map(getId),
125
)((state, props): number => props.jobId);
126
127
export const getRatingGuideQuestionsByJobAndAssessmentType = createCachedSelector(
128
  getCurrentRatingGuideQuestions,
129
  (
130
    state: RootState,
131
    props: { jobId: number; assessmentTypeId: number },
132
  ): number => props.jobId,
133
  (
134
    state: RootState,
135
    props: { jobId: number; assessmentTypeId: number },
136
  ): number => props.assessmentTypeId,
137
  (questions, jobId, assessmentTypeId): RatingGuideQuestion[] =>
138
    questions.filter(
139
      (question): boolean =>
140
        question.job_poster_id === jobId &&
141
        question.assessment_type_id === assessmentTypeId,
142
    ),
143
)((state, props): string => `${props.jobId} ${props.assessmentTypeId}`);
144
145
export const getRatingGuideQuestionIdsByJobAndAssessmentType = createCachedSelector(
146
  (
147
    state: RootState,
148
    props: { jobId: number; assessmentTypeId: number },
149
  ): number[] =>
150
    getRatingGuideQuestionsByJobAndAssessmentType(state, props).map(getId),
151
  (questionsIds): number[] => questionsIds,
152
)({
153
  keySelector: (state, props): string =>
154
    `${props.jobId} ${props.assessmentTypeId}`,
155
  ...deepEqualSelectorOptions,
156
});
157
158
export const getTempRatingGuideQuestionsByAssessment = createCachedSelector(
159
  getTempRatingGuideQuestions,
160
  (
161
    state: RootState,
162
    props: { jobId: number; assessmentTypeId: number },
163
  ): number => props.jobId,
164
  (
165
    state: RootState,
166
    props: { jobId: number; assessmentTypeId: number },
167
  ): number => props.assessmentTypeId,
168
  (questions, jobId, assessmentTypeId): RatingGuideQuestion[] =>
169
    questions.filter(
170
      (question): boolean =>
171
        question.job_poster_id === jobId &&
172
        question.assessment_type_id === assessmentTypeId,
173
    ),
174
)((state, props): string => `${props.jobId} ${props.assessmentTypeId}`);
175
176
export const getTempRatingGuideQuestionIdsByAssessment = createCachedSelector(
177
  (
178
    state: RootState,
179
    props: { jobId: number; assessmentTypeId: number },
180
  ): number[] =>
181
    getTempRatingGuideQuestionsByAssessment(state, props).map(getId),
182
  (questionsIds): number[] => questionsIds,
183
)({
184
  keySelector: (state, props): string =>
185
    `${props.jobId} ${props.assessmentTypeId}`,
186
  ...deepEqualSelectorOptions,
187
});
188
189
// TODO: test that this works like I think it does -- Tristan
190
/** Returns true if there is an edited version which differs from canonical version */
191
export const ratingGuideQuestionIsEdited = createCachedSelector(
192
  getCanonRatingGuideQuestionById,
193
  getEditRatingGuideQuestionById,
194
  (canon, edited): boolean => {
195
    if (canon === null) {
196
      return true;
197
    }
198
    return edited !== null && !isEqual(edited, canon);
199
  },
200
)((state: RootState, id: number): number => id);
201
202
export const ratingGuideQuestionsAreEditedByAssessment = createCachedSelector(
203
  getRatingGuideQuestionIdsByJobAndAssessmentType,
204
  getCanonQuestionState,
205
  getEditedQuestionState,
206
  (questionIds, canonState, editedState): { [id: number]: boolean } =>
207
    mapToObjectTrans(
208
      questionIds,
209
      (id): number => id,
210
      (questionId): boolean => {
211
        const canon = hasKey(canonState, questionId)
212
          ? canonState[questionId]
213
          : null;
214
        const edited = hasKey(editedState, questionId)
215
          ? editedState[questionId]
216
          : null;
217
        return edited !== null && !isEqual(edited, canon);
218
      },
219
    ),
220
)((state, props): string => `${props.jobId}:${props.assessmentTypeId}`);
221
222
export const tempRatingGuideQuestionIsSaving = createCachedSelector(
223
  getTempQuestionSaving,
224
  (state: RootState, id: number): number => id,
225
  (tempSaving, id): boolean =>
226
    hasKey(tempSaving, id) ? tempSaving[id] : false,
227
)((state: RootState, id: number): number => id);
228
229
export const tempRatingGuideQuestionsAreSavingByAssessment = createCachedSelector(
230
  getTempRatingGuideQuestionIdsByAssessment,
231
  getTempQuestionSaving,
232
  (questionIds, savingState): { [id: number]: boolean } =>
233
    mapToObjectTrans(
234
      questionIds,
235
      (id): number => id,
236
      (questionId): boolean =>
237
        hasKey(savingState, questionId) ? savingState[questionId] : false,
238
    ),
239
)((state, props): string => `${props.jobId}:${props.assessmentTypeId}`);
240
241
export const ratingGuideQuestionIsUpdating = createCachedSelector(
242
  getQuestionUpdates,
243
  (state: RootState, id: number): number => id,
244
  (updateCounts, id): boolean =>
245
    hasKey(updateCounts, id) ? updateCounts[id] > 0 : false,
246
)((state: RootState, id: number): number => id);
247
248
export const ratingGuideQuestionsAreUpdatingByAssessment = createCachedSelector(
249
  getRatingGuideQuestionIdsByJobAndAssessmentType,
250
  getQuestionUpdates,
251
  (questionIds, updateCounts): { [id: number]: boolean } =>
252
    questionIds.reduce(
253
      (
254
        result: { [id: number]: boolean },
255
        questionId: number,
256
      ): { [id: number]: boolean } => {
257
        // eslint-disable-next-line no-param-reassign
258
        result[questionId] = hasKey(updateCounts, questionId)
259
          ? updateCounts[questionId] > 0
260
          : false;
261
        return result;
262
      },
263
      {},
264
    ),
265
)((state, jobId, assessmentTypeId): string => `${jobId} ${assessmentTypeId}`);
266