Passed
Push — dev ( 018c8a...dd051f )
by
unknown
04:31
created

resources/assets/js/hooks/apiResourceHooks.tsx   A

Complexity

Total Complexity 3
Complexity/F 0

Size

Lines of Code 120
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 3
eloc 85
mnd 3
bc 3
fnc 0
dl 0
loc 120
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
/* eslint-disable @typescript-eslint/no-unused-vars */
2
/* eslint-disable camelcase */
3
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
4
import { useContext } from "react";
5
import { getApplicantSkillsEndpoint } from "../api/applicantSkills";
6
import {
7
  getApplicantExperienceEndpoint,
8
  getApplicantExperienceSkillsEndpoint,
9
  getCreateExperienceEndpoint,
10
  getExperienceEndpoint,
11
  getExperienceSkillEndpoint,
12
  parseSingleExperience,
13
} from "../api/experience";
14
import { getSkillCategoriesEndpoint, getSkillsEndpoint } from "../api/skill";
15
import {
16
  Experience,
17
  ExperienceSkill,
18
  Skill,
19
  SkillCategory,
20
} from "../models/types";
21
import { useResource, useResourceIndex } from "./webResourceHooks";
22
import { ErrorContext } from "../components/ErrorContainer";
23
import { FetchError } from "../helpers/httpRequests";
24
25
export const useSkills = () => {
26
  // The skills endpoint doesn't allow updates, so don't return that function.
27
  const { update, ...resource } = useResource<Skill[]>(getSkillsEndpoint(), []);
28
  return resource;
29
};
30
31
export const useSkillCategories = () => {
32
  // The SkillCategories endpoint doesn't allow updates, so don't return that function.
33
  const { update, ...resource } = useResource<SkillCategory[]>(
34
    getSkillCategoriesEndpoint(),
35
    [],
36
  );
37
  return resource;
38
};
39
40
/**
41
 * If the error is a FetchError and the response body contains a message field, use that to construct the message.
42
 * Otherwise, simply use the error object's message.
43
 * @param error
44
 */
45
const errorToMessage = async (error: Error | FetchError): Promise<string> => {
46
  if (error instanceof FetchError && error.response.status) {
47
    try {
48
      const responseBody = await error.response.json();
49
      if (responseBody.message) {
50
        return `${error.response.status} - ${responseBody.message}`;
51
      }
52
    } catch (e) {
53
      // Can't parse response json body; fall through and return normal error message.
54
    }
55
  }
56
  return error.message;
57
};
58
59
/**
60
 * This hook returns a handleError function which tries to push the error into the ErrorContext queue.
61
 * If no ErrorContext Provider exists in the component hierarchy, simply nothing will happen.
62
 */
63
const useErrorHandler = () => {
64
  const { dispatch } = useContext(ErrorContext);
65
  const handleError = (error: Error | FetchError): void => {
66
    errorToMessage(error).then((message) =>
67
      dispatch({
68
        type: "push",
69
        payload: message,
70
      }),
71
    );
72
  };
73
  return handleError;
74
};
75
76
export const useApplicantSkillIds = (applicantId: number) => {
77
  const handleError = useErrorHandler();
78
  return useResource<{ skill_ids: number[] }>(
79
    getApplicantSkillsEndpoint(applicantId),
80
    {
81
      skill_ids: [],
82
    },
83
    {
84
      handleError,
85
    },
86
  );
87
};
88
89
export const useApplicantExperience = (applicantId: number) => {
90
  const handleError = useErrorHandler();
91
  return useResourceIndex<Experience>(
92
    getApplicantExperienceEndpoint(applicantId),
93
    {
94
      parseEntityResponse: (response) =>
95
        parseSingleExperience(response).experience,
96
      resolveEntityEndpoint: (_, entity) =>
97
        getExperienceEndpoint(entity.id, entity.type),
98
      resolveCreateEndpoint: (_, entity) =>
99
        getCreateExperienceEndpoint(applicantId, entity.type),
100
      // Need a custom keyFn because different types of experience may have same id,
101
      // meaning default keyFn (getId) may cause collisions in the map of items and they may overwriting each other.
102
      keyFn: (experience) => `${experience.type}-${experience.id}`,
103
      handleError,
104
    },
105
  );
106
};
107
108
export const useApplicantExperienceSkills = (applicantId: number) => {
109
  const handleError = useErrorHandler();
110
  return useResourceIndex<ExperienceSkill>(
111
    getApplicantExperienceSkillsEndpoint(applicantId),
112
    {
113
      resolveEntityEndpoint: (_, entity) =>
114
        getExperienceSkillEndpoint(entity.id),
115
      resolveCreateEndpoint: (_, entity) => getExperienceSkillEndpoint(null),
116
      handleError,
117
    },
118
  );
119
};
120