Passed
Push — feature/checkbox-group-field ( 5ddbcf...8f8586 )
by Tristan
04:31
created

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

Complexity

Total Complexity 6
Complexity/F 0

Size

Lines of Code 177
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 151
dl 0
loc 177
rs 10
c 0
b 0
f 0
wmc 6
mnd 6
bc 6
fnc 0
bpm 0
cpm 0
noi 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 verisons 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 verisons 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 verison 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
)((state, props): number => props.questionId, deepEqualSelectorOptions);
115
116
// TODO: rename to ByAssessmentType
117
export const getRatingGuideAnswersByAssessment = createCachedSelector(
118
  getRatingGuideQuestionIdsByJobAndAssessmentType,
119
  getCurrentRatingGuideAnswers, // This is here to refresh the cache when answers change
120
  (questionIds, answers): RatingGuideAnswer[] =>
121
    answers.filter((answer): boolean =>
122
      questionIds.includes(answer.rating_guide_question_id),
123
    ),
124
)((state, props): string => `${props.jobId} ${props.assessmentTypeId}`);
125
126
export const getTempRatingGuideAnswersByQuestion = createCachedSelector(
127
  getTempRatingGuideAnswers,
128
  (state: RootState, props: { questionId: number }): number => props.questionId,
129
  (answers, questionId): RatingGuideAnswer[] =>
130
    answers.filter(
131
      (answer): boolean => answer.rating_guide_question_id === questionId,
132
    ),
133
)((state, props): number => props.questionId);
134
135
export const getTempRatingGuideAnswerIdsByQuestion = createCachedSelector(
136
  (state: RootState, props: { questionId: number }): number[] =>
137
    getTempRatingGuideAnswersByQuestion(state, props).map(getId),
138
  (answerIds): number[] => answerIds,
139
)((state, props): number => props.questionId, deepEqualSelectorOptions);
140
141
export const getCanonRatingGuideAnswerById = createCachedSelector(
142
  getCanonAnswerState,
143
  (state: RootState, props: { answerId: number }): number => props.answerId,
144
  (answerState, answerId): RatingGuideAnswer | null =>
145
    hasKey(answerState, answerId) ? answerState[answerId] : null,
146
)((state, props): number => props.answerId);
147
148
export const getEditRatingGuideAnswerById = createCachedSelector(
149
  getEditedAnswerState,
150
  (state: RootState, props: { answerId: number }): number => props.answerId,
151
  (answerState, answerId): RatingGuideAnswer | null =>
152
    hasKey(answerState, answerId) ? answerState[answerId] : null,
153
)((state, props): number => props.answerId);
154
155
/** Returns true if there is an edited verision which differs from canonical version */
156
export const ratingGuideAnswerIsEdited = createCachedSelector(
157
  getCanonRatingGuideAnswerById,
158
  getEditRatingGuideAnswerById,
159
  (canon, edited): boolean => edited !== null && !isEqual(edited, canon),
160
)((state, props): number => props.answerId);
161
162
export const ratingGuideAnswerIsUpdating = (
163
  state: RootState,
164
  id: number,
165
): boolean =>
166
  hasKey(stateSlice(state).ratingGuideAnswerUpdates, id)
167
    ? stateSlice(state).ratingGuideAnswerUpdates[id] > 0
168
    : false;
169
170
export const tempRatingGuideAnswerIsSaving = (
171
  state: RootState,
172
  id: number,
173
): boolean =>
174
  hasKey(stateSlice(state).tempRatingGuideAnswerSaving, id)
175
    ? stateSlice(state).tempRatingGuideAnswerSaving[id]
176
    : false;
177