瀏覽代碼

unit tests for schedulePage and their components

pull/113/head
Dzenis Hadzifejzovic 3 年之前
父節點
當前提交
cee5e99be3

+ 16
- 10
package-lock.json 查看文件

@@ -6426,13 +6426,19 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001234",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001234.tgz",
"integrity": "sha512-a3gjUVKkmwLdNysa1xkUAwN2VfJUJyVW47rsi3aCbkRCtbHAfo+rOsCqVw29G6coQ8gzAPb5XBXwiGHwme3isA==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
}
"version": "1.0.30001439",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz",
"integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
}
]
},
"node_modules/capture-exit": {
"version": "2.0.0",
@@ -31741,9 +31747,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001234",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001234.tgz",
"integrity": "sha512-a3gjUVKkmwLdNysa1xkUAwN2VfJUJyVW47rsi3aCbkRCtbHAfo+rOsCqVw29G6coQ8gzAPb5XBXwiGHwme3isA=="
"version": "1.0.30001439",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz",
"integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A=="
},
"capture-exit": {
"version": "2.0.0",

+ 24
- 21
src/__tests__/ReduxTests/adsCandidatesPageReducer.test.js 查看文件

@@ -9,10 +9,11 @@ import { runSaga } from "redux-saga";
import { ADS_CANDIDATES_FETCH } from "../../store/actions/candidates/candidatesActionConstants";
import { getAdsCandidates } from "../../store/saga/candidatesSaga";
import {
fetchAdsCandidates,
fetchAdsCandidatesError,
fetchAdsCandidatesSuccess,
} from "../../store/actions/candidates/candidatesActions";
import AdsCandidatesPage from "../../pages/CandidatesPage/AdsCandidatesPage";
import * as helper from "../../util/helpers/rejectErrorCodeHelper";

describe("AdsCandidatesPage render tests", () => {
const cont = (
@@ -75,31 +76,33 @@ describe("AdsCandidatesPage render tests", () => {

await runSaga(fakeStore, getAdsCandidates, {}).done;
expect(api.getFilteredAdsCandidates.mock.calls.length).toBe(1);
expect(dispatchedActions[0].payload).toBe(
fetchAdsCandidates(mockedCall.data).payload
expect(dispatchedActions).toContainEqual(
fetchAdsCandidatesSuccess(mockedCall.data)
);
});

// it("should handle adsCandidates load errors in case of failure", async () => {
// const dispatchedActions = [];
it("should handle adsCandidates load errors in case of failure", async () => {
const dispatchedActions = [];

helper.rejectErrorCodeHelper = jest.fn(() => mockState.technologies.fetchTecnologiesErrorMessage);

// const error = {
// response: {
// data: { message: mockState.candidates.fetchCandidatesErrorMessage },
// },
// };
// api.getFilteredAdsCandidates = jest.fn(() => Promise.reject(error));
const error = {
response: {
data: { message: mockState.technologies.fetchTecnologiesErrorMessage },
},
};
api.getFilteredAdsCandidates = jest.fn(() => Promise.reject(error));

// const fakeStore = {
// getState: () => mockState.candidates.adsCandidates,
// dispatch: (action) => dispatchedActions.push(action),
// };
const fakeStore = {
getState: () => mockState.candidates.adsCandidates,
dispatch: (action) => dispatchedActions.push(action),
};

// await runSaga(fakeStore, getAdsCandidates,{}).done;
await runSaga(fakeStore, getAdsCandidates, {}).done;

// expect(api.getFilteredAdsCandidates.mock.calls.length).toBe(1);
// expect(dispatchedActions).toContainEqual(
// fetchAdsCandidates(error.response.data.message)
// );
// });
expect(api.getFilteredAdsCandidates.mock.calls.length).toBe(1);
expect(dispatchedActions).toContainEqual(
fetchAdsCandidatesError(error.response.data.message)
);
});
});

+ 23
- 18
src/__tests__/ReduxTests/candidatesPageReducer.test.js 查看文件

@@ -13,6 +13,7 @@ import {
setTechnologies,
setTechnologiesError,
} from "../../store/actions/technologies/technologiesActions";
import * as helper from "../../util/helpers/rejectErrorCodeHelper";

describe("CandidatesPage render tests", () => {
const cont = (
@@ -53,6 +54,8 @@ describe("CandidatesPage render tests", () => {
it("should load and handle techonologies in case of success", async () => {
const dispatchedActions = [];

helper.rejectErrorCodeHelper = jest.fn(()=> 'Server error')

const mockedCall = { data: mockState.technologies.technologies };
api.getAllTechnologies = jest.fn(() => Promise.resolve(mockedCall));

@@ -66,26 +69,28 @@ describe("CandidatesPage render tests", () => {
expect(dispatchedActions).toContainEqual(setTechnologies(mockedCall.data));
});

// it("should handle technologies load errors in case of failure", async () => {
// const dispatchedActions = [];
it("should handle technologies load errors in case of failure", async () => {
const dispatchedActions = [];

// const error = {
// response: {
// data: { message: mockState.technologies.fetchTecnologiesErrorMessage },
// },
// };
// api.getAllTechnologies = jest.fn(() => Promise.reject(error));
helper.rejectErrorCodeHelper = jest.fn(() => mockState.candidates.fetchCandidatesErrorMessage);

// const fakeStore = {
// getState: () => mockState.technologies.technologies,
// dispatch: (action) => dispatchedActions.push(action),
// };
const error = {
response: {
data: { message: mockState.candidates.fetchCandidatesErrorMessage },
},
};
api.getAllTechnologies = jest.fn(() => Promise.reject(error));

// await runSaga(fakeStore, getTechnologies).done;
const fakeStore = {
getState: () => mockState.technologies.technologies,
dispatch: (action) => dispatchedActions.push(action),
};

await runSaga(fakeStore, getTechnologies).done;

// expect(api.getAllTechnologies.mock.calls.length).toBe(1);
// expect(dispatchedActions).toContainEqual(
// setTechnologiesError(error.response.data.message)
// );
// });
expect(api.getAllTechnologies.mock.calls.length).toBe(1);
expect(dispatchedActions).toContainEqual(
setTechnologiesError(error.response.data.message)
);
});
});

+ 111
- 0
src/__tests__/ReduxTests/schedulePageReducer.test.js 查看文件

@@ -0,0 +1,111 @@
import * as redux from "react-redux";
import store from "../../store";
import { Router } from "react-router-dom";
import history from "../../store/utils/history";
import { mockState } from "../../mockState";
import { render } from "@testing-library/react";
import * as api from "../../request/scheduleRequest";
import { runSaga } from "redux-saga";
import { SCHEDULE_FETCH } from "../../store/actions/schedule/scheduleActionConstants";
import { getSchedule } from "../../store/saga/scheduleSaga";
import {
fetchScheduleSuccess,
fetchScheduleError,
} from "../../store/actions/schedule/scheduleActions";
import SchedulePage from "../../pages/SchedulePage/SchedulePage";
import ColorModeProvider from "../../context/ColorModeContext";
import * as helper from "../../util/helpers/rejectErrorCodeHelper";

describe("SchedulePage render tests", () => {
const cont = (
<ColorModeProvider>
<redux.Provider store={store}>
<Router history={history}>
<SchedulePage />
</Router>
</redux.Provider>
</ColorModeProvider>
);

let spyOnUseSelector;
let spyOnUseDispatch;
let mockDispatch;

beforeEach(() => {
spyOnUseSelector = jest.spyOn(redux, "useSelector");
spyOnUseSelector.mockReturnValueOnce(mockState.schedule.schedule);

spyOnUseDispatch = jest.spyOn(redux, "useDispatch");

mockDispatch = jest.fn();
spyOnUseDispatch.mockReturnValue(mockDispatch);
});

afterEach(() => {
jest.restoreAllMocks();
});

it("Should dispatch get schedule request when rendered", () => {
render(cont);
expect(mockDispatch).toHaveBeenCalledWith({
type: SCHEDULE_FETCH,
payload: {
month: 12,
year: 2022,
},
});
});

it("should load and handle schedule in case of success", async () => {
const dispatchedActions = [];

const mockedCall = { data: mockState.schedule.schedule };
api.getSpecificSchedule = jest.fn(() => Promise.resolve(mockedCall));

const fakeStore = {
getState: () => mockState.schedule.schedule,
dispatch: (action) => dispatchedActions.push(action),
};

await runSaga(fakeStore, getSchedule, {
payload: {
month: 12,
year: 2022,
},
}).done;
expect(api.getSpecificSchedule.mock.calls.length).toBe(1);
expect(dispatchedActions).toContainEqual(fetchScheduleSuccess(mockedCall.data));
});

it("should handle candidate load errors in case of failure", async () => {
const dispatchedActions = [];

helper.rejectErrorCodeHelper = jest.fn(
() => mockState.schedule.fetchScheduleErrorMessage
);

const error = {
response: {
data: { message: mockState.schedule.fetchScheduleErrorMessage },
},
};
api.getSpecificSchedule = jest.fn(() => Promise.reject(error));

const fakeStore = {
getState: () => mockState.schedule.schedule,
dispatch: (action) => dispatchedActions.push(action),
};

await runSaga(fakeStore, getSchedule, {
payload: {
month: 12,
year: 2022,
},
}).done;

expect(api.getSpecificSchedule.mock.calls.length).toBe(1);
expect(dispatchedActions).toContainEqual(
fetchScheduleError(error.response.data.message)
);
});
});

+ 14
- 10
src/__tests__/UITests/candidatesPageUI.test.js 查看文件

@@ -19,7 +19,7 @@ describe("CandidatesPage render tests", () => {

beforeEach(() => {
spyOnUseSelector = jest.spyOn(redux, "useSelector");
spyOnUseSelector.mockReturnValueOnce(mockState.technologies.technologies);
spyOnUseSelector.mockReturnValueOnce(mockState.technologies.technologies)
});

afterEach(() => {
@@ -53,11 +53,13 @@ describe("CandidatesPage render tests", () => {
);
});

// it("input for searching by name should be shown after clicking button for first time",() => {
// it("input for searching by name should be shown after clicking button for first time", () => {
// const { container } = render(cont);
// fireEvent.click(container.getElementsByClassName("candidate-btn")[1])
// expect(container.getElementsByClassName("proba")[0].style.visibility).toBe('vissible');
// })
// fireEvent.click(container.getElementsByClassName("candidate-btn")[1]);
// expect(container.getElementsByClassName("proba")[0].style.visibility).toBe(
// "vissible"
// );
// });

it("Should render TableViewPage component when page is initialy rendered", () => {
const { container } = render(cont);
@@ -66,9 +68,11 @@ describe("CandidatesPage render tests", () => {
).toBeDefined();
});

// it("should render AdsCandidatesPage component when button for switching to another view is clicked for the first time",() => {
// const { container } = render(cont);
// fireEvent.click(container.getElementsByClassName("candidate-btn")[0])
// expect(container.getElementsByClassName("ads-candidates-container")[0]).toBeDefined();
// })
// it("should render AdsCandidatesPage component when button for switching to another view is clicked for the first time", () => {
// const { container } = render(cont);
// fireEvent.click(container.getElementsByClassName("candidate-btn")[0]);
// expect(
// container.getElementsByClassName("ads-candidates-container")[0]
// ).toBeDefined();
// });
});

+ 46
- 0
src/__tests__/UITests/dayComponentUI.test.js 查看文件

@@ -0,0 +1,46 @@
import * as redux from "react-redux";
import store from "../../store";
import { Router } from "react-router-dom";
import { mockState } from "../../mockState";
import { render } from "@testing-library/react";
import DayComponent from "../../components/Schedules/DayComponent";
import history from "../../store/utils/history";

const props = {
numberOfDay: 1,
nameOfDay: "sre",
interviews: mockState.schedule.schedule,
onClick: jest.fn(),
};

describe("DayComponent render tests", () => {
const cont = (
<redux.Provider store={store}>
<Router history={history}>
<DayComponent {...props} />
</Router>
</redux.Provider>
);

afterEach(() => {
jest.restoreAllMocks();
});

it("Should render", () => {
const { container } = render(cont);
expect(
container.getElementsByClassName("day-component-container")[0]
).toBeDefined();
});

it("Should show only two interviews even if there is more interviews and span element which will tell us how many interviews is there", () => {
const { container } = render(cont);
expect(
container.getElementsByClassName("day-component-more")[0]
).toBeDefined();
expect(
container.getElementsByClassName("day-component-interviews-container")
.length
).toBe(2);
});
});

+ 47
- 0
src/__tests__/UITests/dayDetailsComponentUI.test.js 查看文件

@@ -0,0 +1,47 @@
import * as redux from "react-redux";
import store from "../../store";
import { Router } from "react-router-dom";
import { mockState } from "../../mockState";
import { render, screen } from "@testing-library/react";
import history from "../../store/utils/history";
import DayDetailsComponent from "../../components/Schedules/DayDetailsComponent";
import ColorModeProvider from "../../context/ColorModeContext";

const props = {
selectedDate: "20.12.2023",
selectionProcesses: mockState.schedule.schedule,
open: jest.fn(),
onClose: jest.fn(),
setCurrentlySelected: jest.fn(),
setCurrentlySelectedDay: jest.fn(),
currentlySelectedDay: 1,
numberOfDaysInMonth: 31,
};

describe("DayDetailsComponent render tests", () => {
const cont = (
<ColorModeProvider>
<redux.Provider store={store}>
<Router history={history}>
<DayDetailsComponent {...props} />
</Router>
</redux.Provider>
</ColorModeProvider>
);

afterEach(() => {
jest.restoreAllMocks();
});

it("Should render", () => {
render(cont);
expect(screen.getByTestId("day-component-dialog")).toBeDefined();
});

it("Should show all interviews which we pass to component", () => {
render(cont);
expect(screen.getAllByTestId("day-details-component-process").length).toBe(
mockState.schedule.schedule.length
);
});
});

+ 109
- 0
src/__tests__/UITests/schedulePageUI.test.js 查看文件

@@ -0,0 +1,109 @@
import { render, fireEvent, screen } from "@testing-library/react";
import * as redux from "react-redux";
import store from "../../store";
import { mockState } from "../../mockState";
import { Router } from "react-router-dom";
import history from "../../store/utils/history";
import SchedulePage from "../../pages/SchedulePage/SchedulePage";
import ColorModeProvider from "../../context/ColorModeContext";

describe("SchedulePage render tests", () => {
const cont = (
<ColorModeProvider>
<redux.Provider store={store}>
<Router history={history}>
<SchedulePage search="" />
</Router>
</redux.Provider>
</ColorModeProvider>
);

let spyOnUseSelector;

beforeEach(() => {
spyOnUseSelector = jest.spyOn(redux, "useSelector");
spyOnUseSelector
.mockReturnValueOnce(mockState.schedule.schedule)
.mockReturnValueOnce(mockState.schedule.schedule);
});

afterEach(() => {
jest.restoreAllMocks();
});

it("Should render", () => {
const { container } = render(cont);
expect(
container.getElementsByClassName("schedule-page-container")[0]
).toBeDefined();
});

it("Number of div's should be equal to the number of days in current month", () => {
const { container } = render(cont);
const date = new Date();
const numberOfDaysInCurrentMonth = new Date(
date.getFullYear(),
date.getMonth() + 1,
0
).getDate();
expect(
container.getElementsByClassName("day-component-container").length
).toBe(numberOfDaysInCurrentMonth);
});

it("should render two arrows", () => {
const { container } = render(cont);
expect(
container.getElementsByClassName("schedule-page-arrow-container").length
).toBe(2);
});

it("after clicking arrow for going back one month number of div's should be equal to number of days in new month", () => {
const { container } = render(cont);
fireEvent.click(
container.getElementsByClassName("schedule-page-arrow-container")[0]
);
const date = new Date();
const currentMonth = date.getMonth();
const currentYear = date.getFullYear();
const numberOfDaysInCurrentMonth = new Date(
currentMonth - 1 === -1 ? currentYear - 1 : currentYear,
currentMonth - 1 === -1 ? 12 : currentMonth,
0
).getDate();
expect(
container.getElementsByClassName("day-component-container").length
).toBe(numberOfDaysInCurrentMonth);
});

it("after clicking arrow for going forward one month number of div's should be equal to number of days in new month", () => {
const { container } = render(cont);
fireEvent.click(
container.getElementsByClassName("schedule-page-arrow-container")[1]
);
const date = new Date();
const currentMonth = date.getMonth();
const currentYear = date.getFullYear();
const numberOfDaysInCurrentMonth = new Date(
currentMonth + 1 === 12 ? currentYear + 1 : currentYear,
currentMonth + 1 === 12 ? 1 : currentMonth + 2,
0
).getDate();
expect(
container.getElementsByClassName("day-component-container").length
).toBe(numberOfDaysInCurrentMonth);
});

it("When page is initialy rendered DayDetailsComponent should not be rendered", () => {
render(cont);
expect(screen.queryByTestId("day-component-dialog")).toBeNull();
});

it("After clicking on some day DayDetailsComponent should be rendered", () => {
const { container } = render(cont);
fireEvent.click(
container.getElementsByClassName("day-component-container")[0]
);
expect(screen.getByTestId("day-component-dialog")).toBeDefined();
});
});

+ 4
- 4
src/components/Candidates/CandidateFilters.js 查看文件

@@ -92,11 +92,11 @@ const CandidateFilters = ({

const isThereSelectedFilter = () => {
let tech = technologies.filter(t => t.isChecked === true);
if(tech.length > 0){
if(tech && tech.length > 0){
return true;
}
let k = typesOfEmployments.filter(te => te.isChecked === true)
if(k.length > 0){
if(k && k.length > 0){
return true
}

@@ -125,7 +125,7 @@ const CandidateFilters = ({
currentPage,
minExperience: sliderValue[0],
maxExperience: sliderValue[1],
employmentType:selectedEmploymentType.length === 0 ? "" : selectedEmploymentType[0].name,
employmentType:selectedEmploymentType && selectedEmploymentType.length === 0 ? "" : selectedEmploymentType[0].name,
minDateOfApplication: startingDate,
maxDateOfApplication: endingDate,
technologies: tech,
@@ -139,7 +139,7 @@ const CandidateFilters = ({
currentPage,
minExperience: sliderValue[0],
maxExperience: sliderValue[1],
employmentType:selectedEmploymentType.length === 0 ? "" : selectedEmploymentType[0].name,
employmentType:selectedEmploymentType && selectedEmploymentType.length === 0 ? "" : selectedEmploymentType[0].name,
minDateOfApplication: startingDate,
maxDateOfApplication: endingDate,
technologies: tech,

+ 10
- 7
src/components/Schedules/DayComponent.js 查看文件

@@ -2,25 +2,28 @@ import React from "react";
import PropTypes from "prop-types";
import { formatTimeSrb } from "../../util/helpers/dateHelpers";

const DayComponent = ({ numberOfDay, nameOfDay, interviews,onClick }) => {
const interviewsToShow = interviews.slice(0, 2);
const DayComponent = ({ numberOfDay, nameOfDay, interviews, onClick }) => {
return (
<div className="day-component-container" onClick={onClick}>
<div className="day-component-day-informations-container">
<p className="day-component-day-number">{numberOfDay}</p>
<p className="day-component-day-name">{nameOfDay}</p>
</div>
{interviewsToShow.map((interview, index) => (
{interviews && interviews.slice(0, 2).map((interview, index) => (
<div
key={index}
className="day-component-interviews-container"
style={{ marginTop: "4px" }}
>
<p className="day-component-interviews-time">{formatTimeSrb(interview.date)}</p>
<p className="day-component-interviews-name">{interview.selectionLevel.name}</p>
<p className="day-component-interviews-time">
{formatTimeSrb(interview.date)}
</p>
<p className="day-component-interviews-name">
{interview.selectionLevel.name}
</p>
</div>
))}
{interviews.length > 2 && (
{interviews && interviews.length > 2 && (
<span className="day-component-more">
+{interviews.length - 2} stavke
</span>
@@ -33,7 +36,7 @@ DayComponent.propTypes = {
numberOfDay: PropTypes.number,
nameOfDay: PropTypes.string,
interviews: PropTypes.array,
onClick:PropTypes.func
onClick: PropTypes.func,
};

export default DayComponent;

+ 3
- 3
src/components/Schedules/DayDetailsComponent.js 查看文件

@@ -73,7 +73,7 @@ const DayDetailsComponent = ({
open={open}
maxWidth={!matches ? "549" : "339"}
>
<div className="day-details-sub-container">
<div className="day-details-sub-container" data-testid="day-component-dialog">
<DialogTitle className="day-datails-title-container">
<img src={calendar} className="day-details-calendar-image" />
<p className="day-details-main-header">Planer aktivnosti</p>
@@ -92,8 +92,8 @@ const DayDetailsComponent = ({
}}
>
<div className="day-details-content-sub-container">
{selectionProcesses.map((selectionProcess, index) => (
<div key={index}>
{selectionProcesses && selectionProcesses.map((selectionProcess, index) => (
<div key={index} data-testid="day-details-component-process">
<div style={{ display: "flex", alignItems: "center" }}>
<p className="day-details-time">
{formatTimeSrb(selectionProcess.date)}h

+ 57
- 0
src/mockState.js 查看文件

@@ -1,4 +1,61 @@
export const mockState = {
schedule: {
schedule: [
{
date: "2022-12-01T11:00:00",
link: "some link",
selectionLevel: {
id: 1,
name: "HR intervju",
},
applicant: {
applicantId: 1,
firstName: "Dzenis",
lastName: "Hadzifejzovic",
},
},
{
date: "2022-12-13T01:10:00",
link: null,
selectionLevel: {
id: 1,
name: "HR intervju",
},
applicant: {
applicantId: 25,
firstName: "Meris",
lastName: "Ahmatovic",
},
},
{
date: "2022-12-28T03:21:00",
link: null,
selectionLevel: {
id: 1,
name: "HR intervju",
},
applicant: {
applicantId: 1,
firstName: "Dzenis",
lastName: "Hadzifejzovic",
},
},
{
date: "2022-12-28T03:10:00",
link: null,
selectionLevel: {
id: 1,
name: "HR intervju",
},
applicant: {
applicantId: 25,
firstName: "Meris",
lastName: "Ahmatovic",
},
},
],
fetchScheduleErrorMessage: "Server error",
},
candidate: {
candidate: {
applicantId: 1,

+ 51
- 45
src/pages/CandidatesPage/TableViewPage.js 查看文件

@@ -8,12 +8,15 @@ import { filterCandidates } from "../../store/actions/candidates/candidatesActio
import { PAGE_SIZE_CANDIDATES } from "../../constants/keyCodeConstants";
import { useTheme } from "@mui/system";
import { useMediaQuery } from "@mui/material";
import { selectCandidates,selectPagination } from "../../store/selectors/candidatesSelectors";
import {
selectCandidates,
selectPagination,
} from "../../store/selectors/candidatesSelectors";

const TableViewPage = ({ history, setPage, page, search }) => {
const dispatch = useDispatch();
const candidates = useSelector(selectCandidates);
const pagination = useSelector(selectPagination); // pagination is total number of candidates on backend
const pagination = useSelector(selectPagination); // pagination is total number of candidates on backend
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.down("361"));

@@ -92,49 +95,52 @@ const TableViewPage = ({ history, setPage, page, search }) => {
</tr>
</thead>
<tbody>
{candidates
.filter((n) =>
(n.firstName + " " + n.lastName)
.toLowerCase()
.includes(search.toLowerCase())
)
.map((candidate, index) => (
<tr
key={index}
className="secondaryRow cadidate-row"
style={{
width: "800px",
height: "40px",
borderRadius: "12px",
cursor: "pointer",
}}
onClick={() => navigate(candidate.applicantId)}
>
<td>
{(candidate.firstName + " " + candidate.lastName).includes(
search
) ? (
formatLabel(
candidate.firstName + " " + candidate.lastName,
search
)
) : (
<span>
{candidate.firstName + " " + candidate.lastName}
</span>
)}
</td>
<td>{candidate.experience}</td>
<td>{formatDate(candidate.dateOfApplication)}</td>
<td>{candidate.position}</td>
<td>
<a href={candidate.CV} className="cvLink">
{candidate.firstName}
{candidate.lastName}.pdf
</a>
</td>
</tr>
))}
{candidates &&
candidates
.filter((n) =>
(n.firstName + " " + n.lastName)
.toLowerCase()
.includes(search.toLowerCase())
)
.map((candidate, index) => (
<tr
key={index}
className="secondaryRow cadidate-row"
style={{
width: "800px",
height: "40px",
borderRadius: "12px",
cursor: "pointer",
}}
onClick={() => navigate(candidate.applicantId)}
>
<td>
{(
candidate.firstName +
" " +
candidate.lastName
).includes(search) ? (
formatLabel(
candidate.firstName + " " + candidate.lastName,
search
)
) : (
<span>
{candidate.firstName + " " + candidate.lastName}
</span>
)}
</td>
<td>{candidate.experience}</td>
<td>{formatDate(candidate.dateOfApplication)}</td>
<td>{candidate.position}</td>
<td>
<a href={candidate.CV} className="cvLink">
{candidate.firstName}
{candidate.lastName}.pdf
</a>
</td>
</tr>
))}
</tbody>
</table>
</div>

+ 8
- 5
src/pages/SchedulePage/SchedulePage.js 查看文件

@@ -56,11 +56,14 @@ const SchedulePage = () => {
};

const getSelectionProcessesForSpecificDay = (day) => {
return selectionProcesses.filter(
(k) =>
new Date(k.date).getDate() === day &&
new Date(k.date).getFullYear() === currentYear &&
new Date(k.date).getMonth() === currentMonth
return (
selectionProcesses &&
selectionProcesses.filter(
(k) =>
new Date(k.date).getDate() === day &&
new Date(k.date).getFullYear() === currentYear &&
new Date(k.date).getMonth() === currentMonth
)
);
};


+ 41
- 28
src/store/saga/candidatesSaga.js 查看文件

@@ -8,7 +8,7 @@ import {
deleteCandidate,
getFilteredCandidates,
getCandidateOptions,
initializeProcessRequest
initializeProcessRequest,
} from "../../request/candidatesRequest";
import { authScopeStringGetHelper } from "../../util/helpers/authScopeHelpers";
import {
@@ -25,7 +25,7 @@ import {
fetchCandidateOptionsSuccess,
fetchCandidateOptionsError,
fetchInitProcessSuccess,
fetchInitProcessError
fetchInitProcessError,
} from "../actions/candidates/candidatesActions";
import { rejectErrorCodeHelper } from "../../util/helpers/rejectErrorCodeHelper";
import {
@@ -42,19 +42,20 @@ import {
DELETE_CANDIDATE,
} from "../actions/candidate/candidateActionConstants";


export function* filterCandidates({ payload }) {
try {
const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
yield call(addHeaderToken, JwtToken);
const {data} = yield call(getFilteredCandidates,payload);
const { data } = yield call(getFilteredCandidates, payload);
yield put(filterCandidatesSuccess(data));
if(payload.handleApiResponseSuccess){
yield call(payload.handleApiResponseSuccess)
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
}
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(filterCandidatesError(errorMessage));
if (error.response && error.response.data) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(filterCandidatesError(errorMessage));
}
}
}

@@ -65,8 +66,10 @@ export function* getSingleCandidate({ payload }) {
const { data } = yield call(getCandidate, payload.id);
yield put(fetchCandidateSuccess(data));
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(fetchCandidateError(errorMessage));
if (error.response && error.response.data) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(fetchCandidateError(errorMessage));
}
}
}

@@ -78,23 +81,27 @@ export function* addComment(data) {
yield call(createComment, myObj);
yield put(createCandidateCommentSuccess({ user, myObj }));
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(createCandidateCommentError(errorMessage));
if (error.response && error.response.data) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(createCandidateCommentError(errorMessage));
}
}
}

export function* getAdsCandidates({payload}) {
export function* getAdsCandidates({ payload }) {
try {
const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
yield call(addHeaderToken, JwtToken);
const { data } = yield call(getFilteredAdsCandidates,payload);
const { data } = yield call(getFilteredAdsCandidates, payload);
yield put(fetchAdsCandidatesSuccess(data));
if(payload.handleApiResponseSuccess){
yield call(payload.handleApiResponseSuccess)
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
}
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(fetchAdsCandidatesError(errorMessage));
if (error.response && error.response.data) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(fetchAdsCandidatesError(errorMessage));
}
}
}

@@ -102,33 +109,39 @@ export function* deleteSingleCandidate({ payload }) {
// console.log(payload)
try {
yield call(deleteCandidate, payload.id);
if(payload.handleApiResponseSuccess){
yield call(payload.handleApiResponseSuccess)
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
}
yield put(deleteCandidateSuccess());
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(deleteCandidateError(errorMessage));
if (error.response && error.response.data) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(deleteCandidateError(errorMessage));
}
}
}

export function* getOptions() {
try {
const { data } = yield call(getCandidateOptions);
const { data } = yield call(getCandidateOptions);
yield put(fetchCandidateOptionsSuccess(data));
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(fetchCandidateOptionsError(errorMessage));
if (error.response && error.response.data) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(fetchCandidateOptionsError(errorMessage));
}
}
}

export function* initializeProcess({payload}) {
export function* initializeProcess({ payload }) {
try {
yield call(initializeProcessRequest, payload.model);
yield put(fetchInitProcessSuccess());
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(fetchInitProcessError(errorMessage));
if (error.response && error.response.data) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(fetchInitProcessError(errorMessage));
}
}
}


+ 3
- 3
yarn.lock 查看文件

@@ -3701,9 +3701,9 @@
"lodash.uniq" "^4.5.0"

"caniuse-lite@^1.0.0", "caniuse-lite@^1.0.30000981", "caniuse-lite@^1.0.30001109", "caniuse-lite@^1.0.30001125", "caniuse-lite@^1.0.30001219":
"integrity" "sha512-a3gjUVKkmwLdNysa1xkUAwN2VfJUJyVW47rsi3aCbkRCtbHAfo+rOsCqVw29G6coQ8gzAPb5XBXwiGHwme3isA=="
"resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001234.tgz"
"version" "1.0.30001234"
"integrity" "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A=="
"resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz"
"version" "1.0.30001439"

"capture-exit@^2.0.0":
"integrity" "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g=="

Loading…
取消
儲存