Passed
Push — dev ( 4d1389...d99312 )
by
unknown
05:37
created

resources/assets/js/components/JobBuilder/Intro/JobIntroPage.tsx   A

Complexity

Total Complexity 19
Complexity/F 0

Size

Lines of Code 267
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 19
eloc 218
mnd 19
bc 19
fnc 0
dl 0
loc 267
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
import React, { useEffect } from "react";
2
import nprogress from "nprogress";
3
import { FormattedMessage, useIntl } from "react-intl";
4
import { connect } from "react-redux";
5
import ReactDOM from "react-dom";
6
import JobIntro from "./JobIntro";
7
import {
8
  Job,
9
  Department,
10
  JobPosterKeyTask,
11
  Criteria,
12
  Manager,
13
  User,
14
} from "../../../models/types";
15
import { RootState } from "../../../store/store";
16
import {
17
  getSelectedJob,
18
  getTasksByJob,
19
  getCriteriaByJob,
20
} from "../../../store/Job/jobSelector";
21
import { DispatchType } from "../../../configureStore";
22
import {
23
  setSelectedJob,
24
  createJob,
25
  updateJob,
26
} from "../../../store/Job/jobActions";
27
import RootContainer from "../../RootContainer";
28
import { jobBuilderDetails } from "../../../helpers/routes";
29
import JobBuilderStepContainer from "../JobBuilderStep";
30
import { getDepartments } from "../../../store/Department/deptSelector";
31
import { navigate } from "../../../helpers/router";
32
import { getSelectedManager } from "../../../store/Manager/managerSelector";
33
import {
34
  updateManager,
35
  setSelectedManager,
36
  fetchManager,
37
  fetchCurrentManager,
38
} from "../../../store/Manager/managerActions";
39
import { getUserById } from "../../../store/User/userSelector";
40
import { fetchUser } from "../../../store/User/userActions";
41
import { getLocale } from "../../../helpers/localize";
42
43
interface JobIntroPageProps {
44
  // The id of the edited job, or null for a new job.
45
  jobId: number | null;
46
  // List of known department options.
47
  departments: Department[];
48
  // If not null, used to prepopulate form values.
49
  // Note: its possible for jobId to be non-null, but job to be null, if the data hasn't been loaded yet.
50
  job: Job | null;
51
  // The manager of this job.
52
  manager: Manager | null;
53
  // The user associated with the manager.
54
  user: User | null;
55
  // Creates a new job. Must return the new job if successful.
56
  handleCreateJob: (newJob: Job) => Promise<Job>;
57
  // Updates an existing job. Must return the updated job if successful.
58
  handleUpdateJob: (newJob: Job) => Promise<Job>;
59
  // Updates an existing Manager. Must return the updated manager if successful.
60
  handleUpdateManager: (manager: Manager) => Promise<Manager>;
61
  // Load a manager with a particular id.
62
  loadManager: (managerId: number) => Promise<void>;
63
  // Load the manager profile of the current authenticated user.
64
  loadCurrentManager: () => Promise<void>;
65
  handleFetchUser: (userId: number) => Promise<void>;
66
}
67
68
const JobIntroPage: React.FunctionComponent<JobIntroPageProps> = ({
69
  jobId,
70
  manager,
71
  user,
72
  job,
73
  departments,
74
  handleCreateJob,
75
  handleUpdateJob,
76
  handleUpdateManager,
77
  loadManager,
78
  loadCurrentManager,
79
  handleFetchUser,
80
}): React.ReactElement => {
81
  const intl = useIntl();
82
  const locale = getLocale(intl.locale);
83
  useEffect((): void => {
84
    if (manager === null) {
85
      nprogress.start();
86
      if (jobId === null) {
87
        loadCurrentManager();
88
      }
89
      if (job !== null) {
90
        loadManager(job.manager_id);
91
      }
92
    } else {
93
      nprogress.done();
94
    }
95
  }, [manager, jobId, job, loadCurrentManager, loadManager]);
96
97
  // Load user after Manager has loaded
98
  // eslint-disable-next-line camelcase
99
  const userId = manager?.user_id;
100
  useEffect((): void => {
101
    if (userId) {
102
      handleFetchUser(userId);
103
    }
104
  }, [handleFetchUser, userId]);
105
106
  const submitJob = job ? handleUpdateJob : handleCreateJob;
107
  const handleSubmit = async (
108
    updatedJob: Job,
109
    updatedManager: Manager,
110
  ): Promise<Job> => {
111
    const jobPromise = submitJob(updatedJob);
112
    await handleUpdateManager(updatedManager);
113
    return jobPromise;
114
  };
115
116
  const handleContinue = (chosenLang: string, newJob: Job): void => {
117
    if (locale === chosenLang) {
118
      navigate(jobBuilderDetails(chosenLang, newJob.id));
119
    } else {
120
      window.location.href = `${jobBuilderDetails(chosenLang, newJob.id)}`;
121
    }
122
  };
123
124
  return (
125
    <JobBuilderStepContainer jobId={jobId} currentPage="intro">
126
      {/** Show the form when the existing job has loaded, or if this is a new job */}
127
      {manager !== null && user !== null && (job !== null || jobId === null) ? (
128
        <JobIntro
129
          job={job}
130
          manager={manager}
131
          user={user}
132
          departments={departments}
133
          handleSubmit={handleSubmit}
134
          handleContinue={handleContinue}
135
        />
136
      ) : (
137
        <div
138
          data-c-container="form"
139
          data-c-padding="top(triple) bottom(triple)"
140
        >
141
          <div
142
            data-c-background="white(100)"
143
            data-c-card
144
            data-c-padding="all(double)"
145
            data-c-radius="rounded"
146
            data-c-align="base(centre)"
147
          >
148
            <p>
149
              <FormattedMessage
150
                id="jobBuilder.intro.managerLoading"
151
                defaultMessage="Your Manager Profile is loading..."
152
                description="Message indicating that the manager profile is still being loaded."
153
              />
154
            </p>
155
          </div>
156
        </div>
157
      )}
158
    </JobBuilderStepContainer>
159
  );
160
};
161
162
const mapStateToProps = (
163
  state: RootState,
164
  { jobId }: { jobId: number | null },
165
): {
166
  job: Job | null;
167
  manager: Manager | null;
168
  departments: Department[];
169
  user: User | null;
170
  keyTasks: JobPosterKeyTask[];
171
  criteria: Criteria[];
172
} => ({
173
  job: getSelectedJob(state),
174
  manager: getSelectedManager(state),
175
  departments: getDepartments(state),
176
  user: getUserById(state, {
177
    userId: getSelectedManager(state)?.user_id || 0,
178
  }),
179
  keyTasks: jobId !== null ? getTasksByJob(state, { jobId }) : [],
180
  criteria: jobId !== null ? getCriteriaByJob(state, { jobId }) : [],
181
});
182
183
const mapDispatchToProps = (
184
  dispatch: DispatchType,
185
): {
186
  handleCreateJob: (newJob: Job) => Promise<Job>;
187
  handleUpdateJob: (newJob: Job) => Promise<Job>;
188
  handleUpdateManager: (newManager: Manager) => Promise<Manager>;
189
  loadManager: (id: number) => Promise<void>;
190
  loadCurrentManager: () => Promise<void>;
191
  handleFetchUser: (userId: number) => Promise<void>;
192
} => ({
193
  handleCreateJob: async (newJob: Job): Promise<Job> => {
194
    const result = await dispatch(createJob(newJob));
195
    if (!result.error) {
196
      const resultJob = await result.payload;
197
      dispatch(setSelectedJob(resultJob.id));
198
      return resultJob;
199
    }
200
    return Promise.reject(result.payload);
201
  },
202
  handleUpdateJob: async (newJob: Job): Promise<Job> => {
203
    const result = await dispatch(updateJob(newJob));
204
    if (!result.error) {
205
      const resultJob = await result.payload;
206
      return resultJob;
207
    }
208
    return Promise.reject(result.payload);
209
  },
210
  handleUpdateManager: async (newManager: Manager): Promise<Manager> => {
211
    const result = await dispatch(updateManager(newManager));
212
    if (!result.error) {
213
      const resultManager = await result.payload;
214
      dispatch(setSelectedManager(resultManager.id));
215
      return resultManager;
216
    }
217
    return Promise.reject(result.payload);
218
  },
219
  loadManager: async (id: number): Promise<void> => {
220
    const result = await dispatch(fetchManager(id));
221
    if (!result.error) {
222
      const resultManager = await result.payload;
223
      dispatch(setSelectedManager(resultManager.id));
224
      return Promise.resolve();
225
    }
226
    return Promise.reject(result.error);
227
  },
228
  loadCurrentManager: async (): Promise<void> => {
229
    const result = await dispatch(fetchCurrentManager());
230
    if (!result.error) {
231
      const resultManager = await result.payload;
232
      dispatch(setSelectedManager(resultManager.id));
233
      return Promise.resolve();
234
    }
235
    return Promise.reject(result.error);
236
  },
237
  handleFetchUser: async (userId: number): Promise<void> => {
238
    const result = await dispatch(fetchUser(userId));
239
    if (!result.error) {
240
      return Promise.resolve();
241
    }
242
    return Promise.reject(result.error);
243
  },
244
});
245
246
const JobIntroPageContainer = connect(
247
  mapStateToProps,
248
  mapDispatchToProps,
249
)(JobIntroPage);
250
251
if (document.getElementById("job-builder-intro")) {
252
  const container: HTMLElement = document.getElementById(
253
    "job-builder-intro",
254
  ) as HTMLElement;
255
  const jobIdAttr = container.getAttribute("data-job-id");
256
  const jobId = jobIdAttr ? Number(jobIdAttr) : null;
257
258
  ReactDOM.render(
259
    <RootContainer>
260
      <JobIntroPageContainer jobId={jobId} />
261
    </RootContainer>,
262
    container,
263
  );
264
}
265
266
export default JobIntroPageContainer;
267