Passed
Push — feature/experience-step-functi... ( 08ee43...953886 )
by Tristan
04:33
created

experienceSelector.ts ➔ getExperienceSkillsByGroup   F

Complexity

Conditions 31

Size

Total Lines 71
Code Lines 64

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 64
dl 0
loc 71
rs 0
c 0
b 0
f 0
cc 31

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like experienceSelector.ts ➔ getExperienceSkillsByGroup often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import { createSelector } from "reselect";
2
import createCachedSelector from "re-reselect";
3
import { RootState } from "../store";
4
import { EntityState, UiState, ExperienceSection } from "./experienceReducer";
5
import {
6
  ExperienceWork,
7
  ExperienceEducation,
8
  ExperienceCommunity,
9
  ExperienceAward,
10
  ExperiencePersonal,
11
  ExperienceSkill,
12
  Experience,
13
} from "../../models/types";
14
import { notEmpty, hasKey } from "../../helpers/queries";
15
16
const entities = (state: RootState): EntityState => state.experience.entities;
17
const ui = (state: RootState): UiState => state.experience.ui;
18
19
interface ExperienceSet {
20
  work: ExperienceWork[];
21
  education: ExperienceEducation[];
22
  community: ExperienceCommunity[];
23
  award: ExperienceAward[];
24
  personal: ExperiencePersonal[];
25
}
26
27
const getWorkState = (state: RootState): ExperienceSection<ExperienceWork> =>
28
  entities(state).work;
29
const getEducationState = (
30
  state: RootState,
31
): ExperienceSection<ExperienceEducation> => entities(state).education;
32
const getCommunityState = (
33
  state: RootState,
34
): ExperienceSection<ExperienceCommunity> => entities(state).community;
35
const getAwardState = (state: RootState): ExperienceSection<ExperienceAward> =>
36
  entities(state).award;
37
const getPersonalState = (
38
  state: RootState,
39
): ExperienceSection<ExperiencePersonal> => entities(state).personal;
40
41
const stateByType = {
42
  work: getWorkState,
43
  education: getEducationState,
44
  community: getCommunityState,
45
  award: getAwardState,
46
  personal: getPersonalState,
47
};
48
49
function getStateOfType<T extends keyof typeof stateByType>(
50
  type: T,
51
): typeof stateByType[T] {
52
  return stateByType[type];
53
}
54
55
const extractId = (state: RootState, ownProps: { id: number }): number =>
56
  ownProps.id;
57
const extractApplicantId = (
58
  state: RootState,
59
  ownProps: { applicantId: number },
60
): number => ownProps.applicantId;
61
const extractApplicationId = (
62
  state: RootState,
63
  ownProps: { applicationId: number },
64
): number => ownProps.applicationId;
65
66
function experienceByApplicant<T>(
67
  experienceState: ExperienceSection<T>,
68
  applicantId: number,
69
): T[] {
70
  const idsForApplicant = experienceState.idsByApplicant[applicantId];
71
  return idsForApplicant
72
    ? idsForApplicant.map((id) => experienceState.byId[id]).filter(notEmpty)
73
    : [];
74
}
75
76
function experienceByApplication<T>(
77
  experienceState: ExperienceSection<T>,
78
  applicationId: number,
79
): T[] {
80
  const idsForApplication = experienceState.idsByApplication[applicationId];
81
  return idsForApplication
82
    ? idsForApplication.map((id) => experienceState.byId[id]).filter(notEmpty)
83
    : [];
84
}
85
86
function experienceById<T>(
87
  experienceState: ExperienceSection<T>,
88
  id: number,
89
): T | null {
90
  return hasKey(experienceState.byId, id) ? experienceState.byId[id] : null;
91
}
92
93
function getExperienceTypeByApplicant<T>(
94
  getState: (state: RootState) => ExperienceSection<T>,
95
) {
96
  return createCachedSelector(
97
    getState,
98
    extractApplicantId,
99
    experienceByApplicant,
100
  )(extractApplicantId);
101
}
102
function getExperienceTypeByApplication<T>(
103
  getState: (state: RootState) => ExperienceSection<T>,
104
) {
105
  return createCachedSelector(
106
    getState,
107
    extractApplicationId,
108
    experienceByApplication,
109
  )(extractApplicationId);
110
}
111
112
export const getWorkByApplicant = getExperienceTypeByApplicant(getWorkState);
113
export const getEducationByApplicant = getExperienceTypeByApplicant(
114
  getEducationState,
115
);
116
export const getCommunityByApplicant = getExperienceTypeByApplicant(
117
  getCommunityState,
118
);
119
export const getAwardByApplicant = getExperienceTypeByApplicant(getAwardState);
120
export const getPersonalByApplicant = getExperienceTypeByApplicant(
121
  getPersonalState,
122
);
123
124
export const getExperienceByApplicant = createSelector(
125
  getWorkByApplicant,
126
  getEducationByApplicant,
127
  getCommunityByApplicant,
128
  getAwardByApplicant,
129
  getPersonalByApplicant,
130
  (work, education, community, award, personal) => ({
131
    work,
132
    education,
133
    community,
134
    award,
135
    personal,
136
  }),
137
);
138
139
export const getWorkByApplication = getExperienceTypeByApplication(
140
  getWorkState,
141
);
142
export const getEducationByApplication = getExperienceTypeByApplication(
143
  getEducationState,
144
);
145
export const getCommunityByApplication = getExperienceTypeByApplication(
146
  getCommunityState,
147
);
148
export const getAwardByApplication = getExperienceTypeByApplication(
149
  getAwardState,
150
);
151
export const getPersonalByApplication = getExperienceTypeByApplication(
152
  getPersonalState,
153
);
154
155
export const getExperienceByApplication = createSelector(
156
  getWorkByApplication,
157
  getEducationByApplication,
158
  getCommunityByApplication,
159
  getAwardByApplication,
160
  getPersonalByApplication,
161
  (work, education, community, award, personal) => ({
162
    work,
163
    education,
164
    community,
165
    award,
166
    personal,
167
  }),
168
);
169
170
function getExperienceTypeById<T>(
171
  getState: (state: RootState) => ExperienceSection<T>,
172
) {
173
  return createCachedSelector(getState, extractId, experienceById)(extractId);
174
}
175
176
export const getWorkById = getExperienceTypeById(getWorkState);
177
export const getEducationById = getExperienceTypeById(getEducationState);
178
export const getCommunityById = getExperienceTypeById(getCommunityState);
179
export const getAwardById = getExperienceTypeById(getAwardState);
180
export const getPersonalById = getExperienceTypeById(getPersonalState);
181
182
export const getUpdatingByApplicant = (
183
  state: RootState,
184
  { applicantId }: { applicantId: number },
185
): boolean => {
186
  return ui(state).updatingByApplicant[applicantId] ?? false;
187
};
188
189
export const getUpdatingByApplication = (
190
  state: RootState,
191
  { applicationId }: { applicationId: number },
192
): boolean => {
193
  return ui(state).updatingByApplication[applicationId] ?? false;
194
};
195
196
export const getUpdatingByTypeAndId = (
197
  state: RootState,
198
  { id, type }: { id: number; type: keyof UiState["updatingByTypeAndId"] },
199
): boolean => {
200
  return ui(state).updatingByTypeAndId[type][id] ?? false;
201
};
202
203
export const getExperienceSkillById = (
204
  state: RootState,
205
  id: number,
206
): ExperienceSkill | null => {
207
  const expSkills = entities(state).experienceSkills.byId;
208
  return hasKey(expSkills, id) ? expSkills[id] : null;
209
};
210
211
const getExperienceSkillByIdState = (state: RootState) =>
212
  entities(state).experienceSkills.byId;
213
214
const getExperienceSkillByWorkState = (state: RootState) =>
215
  entities(state).experienceSkills.idsByWork;
216
const getExperienceSkillByEducationState = (state: RootState) =>
217
  entities(state).experienceSkills.idsByEducation;
218
const getExperienceSkillByCommunityState = (state: RootState) =>
219
  entities(state).experienceSkills.idsByCommunity;
220
const getExperienceSkillByAwardState = (state: RootState) =>
221
  entities(state).experienceSkills.idsByAward;
222
const getExperienceSkillByPersonalState = (state: RootState) =>
223
  entities(state).experienceSkills.idsByPersonal;
224
225
export const getExperienceSkillsByWork = createCachedSelector(
226
  getExperienceSkillByIdState,
227
  getExperienceSkillByWorkState,
228
  (state: RootState, { workId }: { workId: number }) => workId,
229
  (expSkillById, idsByWork, workId): ExperienceSkill[] => {
230
    const expSkillIds = idsByWork[workId] ?? [];
231
    return expSkillIds.map((id) => expSkillById[id]).filter(notEmpty);
232
  },
233
)((state, { workId }) => workId);
234
235
export const getExperienceSkillsByEducation = createCachedSelector(
236
  getExperienceSkillByIdState,
237
  getExperienceSkillByEducationState,
238
  (state: RootState, { educationId }: { educationId: number }) => educationId,
239
  (expSkillById, idsByWork, educationId): ExperienceSkill[] => {
240
    const expSkillIds = idsByWork[educationId] ?? [];
241
    return expSkillIds.map((id) => expSkillById[id]).filter(notEmpty);
242
  },
243
)((state, { educationId }) => educationId);
244
245
export const getExperienceSkillsByCommunity = createCachedSelector(
246
  getExperienceSkillByIdState,
247
  getExperienceSkillByCommunityState,
248
  (state: RootState, { communityId }: { communityId: number }) => communityId,
249
  (expSkillById, idsByWork, communityId): ExperienceSkill[] => {
250
    const expSkillIds = idsByWork[communityId] ?? [];
251
    return expSkillIds.map((id) => expSkillById[id]).filter(notEmpty);
252
  },
253
)((state, { communityId }) => communityId);
254
255
export const getExperienceSkillsByAward = createCachedSelector(
256
  getExperienceSkillByIdState,
257
  getExperienceSkillByAwardState,
258
  (state: RootState, { awardId }: { awardId: number }) => awardId,
259
  (expSkillById, idsByWork, awardId): ExperienceSkill[] => {
260
    const expSkillIds = idsByWork[awardId] ?? [];
261
    return expSkillIds.map((id) => expSkillById[id]).filter(notEmpty);
262
  },
263
)((state, { awardId }) => awardId);
264
265
export const getExperienceSkillsByPersonal = createCachedSelector(
266
  getExperienceSkillByIdState,
267
  getExperienceSkillByPersonalState,
268
  (state: RootState, { personalId }: { personalId: number }) => personalId,
269
  (expSkillById, idsByWork, personalId): ExperienceSkill[] => {
270
    const expSkillIds = idsByWork[personalId] ?? [];
271
    return expSkillIds.map((id) => expSkillById[id]).filter(notEmpty);
272
  },
273
)((state, { personalId }) => personalId);
274
275
export const getExperienceSkillIdsByWork = (
276
  state: RootState,
277
  id: number,
278
): number[] => entities(state).experienceSkills.idsByWork[id] ?? [];
279
export const getExperienceSkillIdsByEducation = (
280
  state: RootState,
281
  id: number,
282
): number[] => entities(state).experienceSkills.idsByEducation[id] ?? [];
283
export const getExperienceSkillIdsByCommunity = (
284
  state: RootState,
285
  id: number,
286
): number[] => entities(state).experienceSkills.idsByCommunity[id] ?? [];
287
export const getExperienceSkillIdsByAward = (
288
  state: RootState,
289
  id: number,
290
): number[] => entities(state).experienceSkills.idsByAward[id] ?? [];
291
export const getExperienceSkillIdsByPersonal = (
292
  state: RootState,
293
  id: number,
294
): number[] => entities(state).experienceSkills.idsByPersonal[id] ?? [];
295
296
export const getExperienceSkillUpdating = (
297
  state: RootState,
298
  id: number,
299
): boolean => {
300
  return ui(state).updatingExperienceSkill[id] ?? false;
301
};
302
303
function getExperienceSkillsByGroup<T>(
304
  getExperience: (
305
    state: RootState,
306
    props: T,
307
  ) => {
308
    award: ExperienceAward[];
309
    community: ExperienceCommunity[];
310
    education: ExperienceEducation[];
311
    personal: ExperiencePersonal[];
312
    work: ExperienceWork[];
313
  },
314
) {
315
  return createCachedSelector(
316
    getExperience,
317
    getExperienceSkillByIdState,
318
    getExperienceSkillByAwardState,
319
    getExperienceSkillByCommunityState,
320
    getExperienceSkillByEducationState,
321
    getExperienceSkillByPersonalState,
322
    getExperienceSkillByWorkState,
323
    (
324
      experiences,
325
      expSkills,
326
      idsByAward,
327
      idsByCommunity,
328
      idsByEducation,
329
      idsByPersonal,
330
      idsByWork,
331
    ): ExperienceSkill[] => {
332
      const experienceToSkillsFactory = (expIdToSkillId: {
333
        [expId: number]: number[];
334
      }) => (
335
        experienceSkills: ExperienceSkill[],
336
        experience: Experience,
337
      ): ExperienceSkill[] => {
338
        const expSkillIds = hasKey(expIdToSkillId, experience.id)
339
          ? expIdToSkillId[experience.id]
340
          : [];
341
        const newExpSkills = expSkillIds
342
          .map((id) => expSkills[id])
343
          .filter(notEmpty);
344
        return [...newExpSkills, ...experienceSkills];
345
      };
346
347
      const awardSkills = experiences.award.reduce(
348
        experienceToSkillsFactory(idsByAward),
349
        [],
350
      );
351
      const communitySkills = experiences.community.reduce(
352
        experienceToSkillsFactory(idsByCommunity),
353
        [],
354
      );
355
      const educationSkills = experiences.education.reduce(
356
        experienceToSkillsFactory(idsByEducation),
357
        [],
358
      );
359
      const personalSkills = experiences.personal.reduce(
360
        experienceToSkillsFactory(idsByPersonal),
361
        [],
362
      );
363
      const workSkills = experiences.work.reduce(
364
        experienceToSkillsFactory(idsByWork),
365
        [],
366
      );
367
      return [
368
        ...awardSkills,
369
        ...communitySkills,
370
        ...educationSkills,
371
        ...personalSkills,
372
        ...workSkills,
373
      ];
374
    },
375
  );
376
}
377
378
export const getExperienceSkillsByApplication = getExperienceSkillsByGroup(
379
  getExperienceByApplication,
380
)((state, { applicationId }) => applicationId);
381
382
export const getExperienceSkillsByApplicant = getExperienceSkillsByGroup(
383
  getExperienceByApplicant,
384
)((state, { applicantId }) => applicantId);
385