Passed
Push — task/refactor-formik-forms ( f7beb8 )
by Yonathan
05:18 queued 11s
created

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

Complexity

Total Complexity 18
Complexity/F 0

Size

Lines of Code 275
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 18
eloc 224
mnd 18
bc 18
fnc 0
dl 0
loc 275
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
      const baseUrl = window.location.origin;
121
      window.location.href = `${baseUrl}${jobBuilderDetails(
122
        chosenLang,
123
        newJob.id,
124
      )}`;
125
    }
126
  };
127
128
  return (
129
    <JobBuilderStepContainer jobId={jobId} currentPage="intro">
130
      {/** Show the form when the existing job has loaded, or if this is a new job */}
131
      {manager === null && (
132
        <div
133
          data-c-container="form"
134
          data-c-padding="top(triple) bottom(triple)"
135
        >
136
          <div
137
            data-c-background="white(100)"
138
            data-c-card
139
            data-c-padding="all(double)"
140
            data-c-radius="rounded"
141
            data-c-align="base(centre)"
142
          >
143
            <p>
144
              <FormattedMessage
145
                id="jobBuilder.intro.managerLoading"
146
                defaultMessage="Your Manager Profile is loading..."
147
                description="Message indicating that the manager profile is still being loaded."
148
              />
149
            </p>
150
          </div>
151
        </div>
152
      )}
153
      {manager !== null &&
154
        user !== null &&
155
        (job !== null || jobId === null) && (
156
          <JobIntro
157
            job={job}
158
            manager={manager}
159
            user={user}
160
            departments={departments}
161
            handleSubmit={handleSubmit}
162
            handleContinue={handleContinue}
163
          />
164
        )}
165
    </JobBuilderStepContainer>
166
  );
167
};
168
169
const mapStateToProps = (
170
  state: RootState,
171
  { jobId }: { jobId: number | null },
172
): {
173
  job: Job | null;
174
  manager: Manager | null;
175
  departments: Department[];
176
  user: User | null;
177
  keyTasks: JobPosterKeyTask[];
178
  criteria: Criteria[];
179
} => ({
180
  job: getSelectedJob(state),
181
  manager: getSelectedManager(state),
182
  departments: getDepartments(state),
183
  user: getUserById(state, {
184
    // eslint-disable-next-line camelcase, @typescript-eslint/camelcase
185
    userId: getSelectedManager(state)?.user_id || 0,
186
  }),
187
  keyTasks: jobId !== null ? getTasksByJob(state, { jobId }) : [],
188
  criteria: jobId !== null ? getCriteriaByJob(state, { jobId }) : [],
189
});
190
191
const mapDispatchToProps = (
192
  dispatch: DispatchType,
193
): {
194
  handleCreateJob: (newJob: Job) => Promise<Job>;
195
  handleUpdateJob: (newJob: Job) => Promise<Job>;
196
  handleUpdateManager: (newManager: Manager) => Promise<Manager>;
197
  loadManager: (id: number) => Promise<void>;
198
  loadCurrentManager: () => Promise<void>;
199
  handleFetchUser: (userId: number) => Promise<void>;
200
} => ({
201
  handleCreateJob: async (newJob: Job): Promise<Job> => {
202
    const result = await dispatch(createJob(newJob));
203
    if (!result.error) {
204
      const resultJob = await result.payload;
205
      dispatch(setSelectedJob(resultJob.id));
206
      return resultJob;
207
    }
208
    return Promise.reject(result.payload);
209
  },
210
  handleUpdateJob: async (newJob: Job): Promise<Job> => {
211
    const result = await dispatch(updateJob(newJob));
212
    if (!result.error) {
213
      const resultJob = await result.payload;
214
      return resultJob;
215
    }
216
    return Promise.reject(result.payload);
217
  },
218
  handleUpdateManager: async (newManager: Manager): Promise<Manager> => {
219
    const result = await dispatch(updateManager(newManager));
220
    if (!result.error) {
221
      const resultManager = await result.payload;
222
      dispatch(setSelectedManager(resultManager.id));
223
      return resultManager;
224
    }
225
    return Promise.reject(result.payload);
226
  },
227
  loadManager: async (id: number): Promise<void> => {
228
    const result = await dispatch(fetchManager(id));
229
    if (!result.error) {
230
      const resultManager = await result.payload;
231
      dispatch(setSelectedManager(resultManager.id));
232
      return Promise.resolve();
233
    }
234
    return Promise.reject(result.error);
235
  },
236
  loadCurrentManager: async (): Promise<void> => {
237
    const result = await dispatch(fetchCurrentManager());
238
    if (!result.error) {
239
      const resultManager = await result.payload;
240
      dispatch(setSelectedManager(resultManager.id));
241
      return Promise.resolve();
242
    }
243
    return Promise.reject(result.error);
244
  },
245
  handleFetchUser: async (userId: number): Promise<void> => {
246
    const result = await dispatch(fetchUser(userId));
247
    if (!result.error) {
248
      return Promise.resolve();
249
    }
250
    return Promise.reject(result.error);
251
  },
252
});
253
254
const JobIntroPageContainer = connect(
255
  mapStateToProps,
256
  mapDispatchToProps,
257
)(JobIntroPage);
258
259
if (document.getElementById("job-builder-intro")) {
260
  const container: HTMLElement = document.getElementById(
261
    "job-builder-intro",
262
  ) as HTMLElement;
263
  const jobIdAttr = container.getAttribute("data-job-id");
264
  const jobId = jobIdAttr ? Number(jobIdAttr) : null;
265
266
  ReactDOM.render(
267
    <RootContainer>
268
      <JobIntroPageContainer jobId={jobId} />
269
    </RootContainer>,
270
    container,
271
  );
272
}
273
274
export default JobIntroPageContainer;
275