Passed
Push — task/explore-skills-ui ( d41a63...af1244 )
by Yonathan
06:51 queued 10s
created

resources/assets/js/store/RatingGuideAnswer/ratingGuideAnswerSelectors.ts   A

Complexity

Total Complexity 6
Complexity/F 0

Size

Lines of Code 183
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 6
eloc 155
mnd 6
bc 6
fnc 0
dl 0
loc 183
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
import { createSelector } from "reselect";
2
import createCachedSelector from "re-reselect";
3
import isEqual from "lodash/isEqual";
4
import { RootState } from "../store";
5
import { RatingGuideAnswerState } from "./ratingGuideAnswerReducer";
6
import { RatingGuideAnswer } from "../../models/types";
7
import {
8
  getRatingGuideQuestionIdsByJob,
9
  getRatingGuideQuestionIdsByJobAndAssessmentType,
10
} from "../RatingGuideQuestion/ratingGuideQuestionSelectors";
11
import { hasKey, getId } from "../../helpers/queries";
12
import { deepEqualSelectorOptions } from "../cachedSelectors";
13
14
const stateSlice = (state: RootState): RatingGuideAnswerState =>
15
  state.ratingGuideAnswer;
16
17
export const getCanonAnswerState = (
18
  state: RootState,
19
): { [id: number]: RatingGuideAnswer } => stateSlice(state).ratingGuideAnswers;
20
21
export const getEditedAnswerState = (
22
  state: RootState,
23
): { [id: number]: RatingGuideAnswer } =>
24
  stateSlice(state).editedRatingGuideAnswers;
25
26
export const getTempAnswerState = (
27
  state: RootState,
28
): { [id: number]: RatingGuideAnswer } =>
29
  stateSlice(state).tempRatingGuideAnswers;
30
31
export const getCurrentAnswerState = createSelector(
32
  getCanonAnswerState,
33
  getEditedAnswerState,
34
  (canon, edited): { [id: number]: RatingGuideAnswer } => ({
35
    ...canon,
36
    ...edited,
37
  }),
38
);
39
40
export const getAnswerDeleteState = (
41
  state: RootState,
42
): { [id: number]: number } => stateSlice(state).ratingGuideAnswerDeletes;
43
44
/**
45
 * Returns current versions of all answers.
46
 * ie edited version if possible,
47
 * and not including those undergoing delete requests
48
 */
49
export const getCurrentRatingGuideAnswers = createSelector(
50
  getCurrentAnswerState,
51
  getAnswerDeleteState,
52
  (currentRatingGuideAnswers, deleteCount): RatingGuideAnswer[] =>
53
    Object.values(currentRatingGuideAnswers).filter(
54
      (ratingGuideAnswer): boolean =>
55
        !hasKey(deleteCount, ratingGuideAnswer.id) ||
56
        deleteCount[ratingGuideAnswer.id] <= 0,
57
    ),
58
);
59
60
export const getCanonRatingGuideAnswers = createSelector(
61
  getCanonAnswerState,
62
  (answerState): RatingGuideAnswer[] => Object.values(answerState),
63
);
64
65
export const getTempRatingGuideAnswers = createSelector(
66
  getTempAnswerState,
67
  (answerState): RatingGuideAnswer[] => Object.values(answerState),
68
);
69
70
/**
71
 * Returns current versions of all answers.
72
 * ie edited version if possible,
73
 * and not including those undergoing delete requests
74
 */
75
export const getRatingGuideAnswersByJob = createCachedSelector(
76
  getCurrentRatingGuideAnswers,
77
  getRatingGuideQuestionIdsByJob,
78
  (answers, jobQuestionIds): RatingGuideAnswer[] =>
79
    answers.filter((answer): boolean =>
80
      jobQuestionIds.includes(answer.rating_guide_question_id),
81
    ),
82
)((state, props): number => props.jobId);
83
84
/**
85
 * Returns current versions of answer, ie edited version if possible.
86
 */
87
export const getRatingGuideAnswerById = createCachedSelector(
88
  getCurrentAnswerState,
89
  (state: RootState, props: { answerId: number }): number => props.answerId,
90
  (answerState, id): RatingGuideAnswer | null =>
91
    hasKey(answerState, id) ? answerState[id] : null,
92
)((state, props): number => props.answerId);
93
94
export const getTempRatingGuideAnswerById = createCachedSelector(
95
  getTempAnswerState,
96
  (state: RootState, props: { answerId: number }): number => props.answerId,
97
  (answerState, id): RatingGuideAnswer | null =>
98
    hasKey(answerState, id) ? answerState[id] : null,
99
)((state, props): number => props.answerId);
100
101
export const getRatingGuideAnswersByQuestion = createCachedSelector(
102
  getCurrentRatingGuideAnswers,
103
  (state: RootState, props: { questionId: number }): number => props.questionId,
104
  (answers, questionId): RatingGuideAnswer[] =>
105
    answers.filter(
106
      (answer): boolean => answer.rating_guide_question_id === questionId,
107
    ),
108
)((state, props): number => props.questionId);
109
110
export const getRatingGuideAnswerIdsByQuestion = createCachedSelector(
111
  (state: RootState, props: { questionId: number }): number[] =>
112
    getRatingGuideAnswersByQuestion(state, props).map(getId),
113
  (answerIds): number[] => answerIds,
114
)({
115
  keySelector: (state, props): number => props.questionId,
116
  ...deepEqualSelectorOptions,
117
});
118
119
// TODO: rename to ByAssessmentType
120
export const getRatingGuideAnswersByAssessment = createCachedSelector(
121
  getRatingGuideQuestionIdsByJobAndAssessmentType,
122
  getCurrentRatingGuideAnswers, // This is here to refresh the cache when answers change
123
  (questionIds, answers): RatingGuideAnswer[] =>
124
    answers.filter((answer): boolean =>
125
      questionIds.includes(answer.rating_guide_question_id),
126
    ),
127
)((state, props): string => `${props.jobId} ${props.assessmentTypeId}`);
128
129
export const getTempRatingGuideAnswersByQuestion = createCachedSelector(
130
  getTempRatingGuideAnswers,
131
  (state: RootState, props: { questionId: number }): number => props.questionId,
132
  (answers, questionId): RatingGuideAnswer[] =>
133
    answers.filter(
134
      (answer): boolean => answer.rating_guide_question_id === questionId,
135
    ),
136
)((state, props): number => props.questionId);
137
138
export const getTempRatingGuideAnswerIdsByQuestion = createCachedSelector(
139
  (state: RootState, props: { questionId: number }): number[] =>
140
    getTempRatingGuideAnswersByQuestion(state, props).map(getId),
141
  (answerIds): number[] => answerIds,
142
)({
143
  keySelector: (state, props): number => props.questionId,
144
  ...deepEqualSelectorOptions,
145
});
146
147
export const getCanonRatingGuideAnswerById = createCachedSelector(
148
  getCanonAnswerState,
149
  (state: RootState, props: { answerId: number }): number => props.answerId,
150
  (answerState, answerId): RatingGuideAnswer | null =>
151
    hasKey(answerState, answerId) ? answerState[answerId] : null,
152
)((state, props): number => props.answerId);
153
154
export const getEditRatingGuideAnswerById = createCachedSelector(
155
  getEditedAnswerState,
156
  (state: RootState, props: { answerId: number }): number => props.answerId,
157
  (answerState, answerId): RatingGuideAnswer | null =>
158
    hasKey(answerState, answerId) ? answerState[answerId] : null,
159
)((state, props): number => props.answerId);
160
161
/** Returns true if there is an edited verision which differs from canonical version */
162
export const ratingGuideAnswerIsEdited = createCachedSelector(
163
  getCanonRatingGuideAnswerById,
164
  getEditRatingGuideAnswerById,
165
  (canon, edited): boolean => edited !== null && !isEqual(edited, canon),
166
)((state, props): number => props.answerId);
167
168
export const ratingGuideAnswerIsUpdating = (
169
  state: RootState,
170
  id: number,
171
): boolean =>
172
  hasKey(stateSlice(state).ratingGuideAnswerUpdates, id)
173
    ? stateSlice(state).ratingGuideAnswerUpdates[id] > 0
174
    : false;
175
176
export const tempRatingGuideAnswerIsSaving = (
177
  state: RootState,
178
  id: number,
179
): boolean =>
180
  hasKey(stateSlice(state).tempRatingGuideAnswerSaving, id)
181
    ? stateSlice(state).tempRatingGuideAnswerSaving[id]
182
    : false;
183