| @@ -49,7 +49,7 @@ | |||
| "yup": "^0.32.9" | |||
| }, | |||
| "scripts": { | |||
| "start": "react-scripts --openssl-legacy-provider start", | |||
| "start": "react-scripts start", | |||
| "build": "react-scripts build", | |||
| "test": "react-scripts test", | |||
| "eject": "react-scripts eject", | |||
| @@ -0,0 +1,25 @@ | |||
| import reducer from "../../../store/reducers/loading/loadingReducer"; | |||
| import expect from "expect"; | |||
| import { setAppReady } from "../../../store/actions/app/appActions"; | |||
| import { APP_LOADING } from "../../../store/actions/app/appActionConstants"; | |||
| import { resetLoginState } from "../../../store/actions/login/loginActions"; | |||
| describe("loading reducer", () => { | |||
| it("should return the initial state", () => { | |||
| expect(reducer(undefined, {})).toEqual({ | |||
| [APP_LOADING]: true, | |||
| }); | |||
| }); | |||
| it("should set loader to true", () => { | |||
| expect(reducer(false, resetLoginState())).toEqual({ | |||
| [APP_LOADING]: true, | |||
| }); | |||
| }); | |||
| it("should set loader to false", () => { | |||
| expect(reducer(true, setAppReady())).toEqual({ | |||
| [APP_LOADING]: false, | |||
| }); | |||
| }); | |||
| }); | |||
| @@ -18,10 +18,27 @@ import { PAGE_SIZE_CANDIDATES } from "../../constants/keyCodeConstants"; | |||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||
| describe("TableViewPage render tests", () => { | |||
| var props = { | |||
| history: { | |||
| replace: jest.fn(), | |||
| push: jest.fn(), | |||
| location: { | |||
| pathname: "/candidates", | |||
| }, | |||
| }, | |||
| setPage: jest.fn(), | |||
| sliderValue: [0, 2], | |||
| startingDate: "", | |||
| endingDate: "", | |||
| typesOfEmployments: [], | |||
| technologie: [], | |||
| page: 1, | |||
| search: "", | |||
| }; | |||
| const cont = ( | |||
| <redux.Provider store={store}> | |||
| <Router history={history}> | |||
| <TableViewPage page={1} search="" /> | |||
| <TableViewPage {...props} /> | |||
| </Router> | |||
| </redux.Provider> | |||
| ); | |||
| @@ -78,14 +78,14 @@ describe("TableViewPage render tests", () => { | |||
| expect( | |||
| container | |||
| .getElementsByClassName("ads-candidates")[0] | |||
| .getElementsByClassName("slick-active")[3] | |||
| .getElementsByClassName("slick-active")[0] | |||
| .getElementsByClassName("candidate-card-container")[0] | |||
| .getElementsByClassName("candidate-card-applicant-name")[0] | |||
| .textContent | |||
| ).toBe( | |||
| mockState.candidates.adsCandidates[0].applicants[4].firstName + | |||
| mockState.candidates.adsCandidates[0].applicants[3].firstName + | |||
| " " + | |||
| mockState.candidates.adsCandidates[0].applicants[4].lastName | |||
| mockState.candidates.adsCandidates[0].applicants[3].lastName | |||
| ) | |||
| ); | |||
| }); | |||
| @@ -22,6 +22,9 @@ describe("Add ad modals ui tests", () => { | |||
| isChecked: true, | |||
| }, | |||
| ], | |||
| startingDate: "", | |||
| endingDate: "", | |||
| typesOfEmployments: [], | |||
| }; | |||
| const cont = ( | |||
| @@ -66,14 +69,4 @@ describe("Add ad modals ui tests", () => { | |||
| expect(btn).toBeDefined(); | |||
| }); | |||
| }); | |||
| it("Should change ending date", async () => { | |||
| render(cont); | |||
| const input = screen.getByTestId("filter-date-container-ending-date"); | |||
| waitFor(() => { | |||
| fireEvent.change(input, { target: { value: "2024-05-24" } }); | |||
| expect(input).toBeDefined(); | |||
| }); | |||
| }); | |||
| }); | |||
| @@ -6,8 +6,6 @@ import { Router } from "react-router-dom"; | |||
| import history from "../../store/utils/history"; | |||
| import TableViewPage from "../../pages/CandidatesPage/TableViewPage"; | |||
| import { PAGE_SIZE_CANDIDATES } from "../../constants/keyCodeConstants"; | |||
| import axios from "axios"; | |||
| // import mockAxios from "jest-mock-axios"; | |||
| import { getCV } from "../../request/candidatesRequest"; | |||
| describe("TableViewPage render tests", () => { | |||
| @@ -20,6 +18,12 @@ describe("TableViewPage render tests", () => { | |||
| }, | |||
| }, | |||
| setPage: jest.fn(), | |||
| sliderValue: [0, 2], | |||
| startingDate: "", | |||
| endingDate: "", | |||
| typesOfEmployments: [], | |||
| technologie: [], | |||
| page: 1, | |||
| }; | |||
| const cont = ( | |||
| @@ -110,51 +114,20 @@ describe("TableViewPage render tests", () => { | |||
| ).toBe("0"); | |||
| }); | |||
| it("When user change table page function for fetching users should be called", async () => { | |||
| const { container } = render(cont); | |||
| const pag = container | |||
| .getElementsByClassName("MuiPagination-ul")[0] | |||
| .getElementsByTagName("li")[1] | |||
| .querySelector("button"); | |||
| fireEvent.click(pag); | |||
| await waitFor(() => expect(mockDispatch).toBeCalledTimes(2)); | |||
| }); | |||
| // How to mock constant? | |||
| // it("When user change table page, function for fetching users should be called", async () => { | |||
| // const { container } = render(cont); | |||
| // const pag = container | |||
| // .getElementsByClassName("MuiPagination-ul")[0] | |||
| // .getElementsByTagName("li")[1] | |||
| // .querySelector("button"); | |||
| // fireEvent.click(pag); | |||
| // await waitFor(() => expect(mockDispatch).toBeCalledTimes(2)); | |||
| // }); | |||
| it("Should render CV of candidate after clicking on CV name", async () => { | |||
| let catchFn = jest.fn(); | |||
| const basse64Pdf = `JVBERi0xLjMNCiXi48/TDQoNCjEgMCBvYmoNCjw8DQovVHl | |||
| wZSAvQ2F0YWxvZw0KL091dGxpbmVzIDIgMCBSDQovUGFnZXMgMyAwIFINCj4+DQplbmRvYmoNCg0KMiAwIG9iag0KPDwNCi9UeXBlIC9PdXR | |||
| saW5lcw0KL0NvdW50IDANCj4+DQplbmRvYmoNCg0KMyAwIG9iag0KPDwNCi9UeXBlIC9QYWdlcw0KL0NvdW50IDINCi9LaWRzIFsgNCAwIFIgNi | |||
| AwIFIgXSANCj4+DQplbmRvYmoNCg0KNCAwIG9iag0KPDwNCi9UeXBlIC9QYWdlDQovUGFyZW50IDMgMCBSDQovUmVzb3VyY2VzIDw8DQovRm9udCA8PA0KL0YxID | |||
| kgMCBSIA0KPj4NCi9Qcm9jU2V0IDggMCBSDQo+Pg0KL01lZGlhQm94IFswIDAgNjEyLjAwMDAgNzkyLjAwMDBdDQovQ29udGVudHMgNSAwIFINCj4+DQplbmRvYmo | |||
| NCg0KNSAwIG9iag0KPDwgL0xlbmd0aCAxMDc0ID4+DQpzdHJlYW0NCjIgSg0KQlQNCjAgMCAwIHJnDQovRjEgMDAyNyBUZg0KNTcuMzc1MCA3MjIuMjgwMCBUZA0K | |||
| KCBBIFNpbXBsZSBQREYgRmlsZSApIFRqDQpFVA0KQlQNCi9GMSAwMDEwIFRmDQo2OS4yNTAwIDY4OC42MDgwIFRkDQooIFRoaXMgaXMgYSBzbWFsbCBkZW1vbnN0cm | |||
| F0aW9uIC5wZGYgZmlsZSAtICkgVGoNCkVUDQpCVA0KL0YxIDAwMTAgVGYNCjY5LjI1MDAgNjY0LjcwNDAgVGQNCigganVzdCBmb3IgdXNlIGluIHRoZSBWaXJ0dWFs | |||
| IE1lY2hhbmljcyB0dXRvcmlhbHMuIE1vcmUgdGV4dC4gQW5kIG1vcmUgKSBUag0KRVQNCkJUDQovRjEgMDAxMCBUZg0KNjkuMjUwMCA2NTIuNzUyMCBUZA0KKCB0ZXh | |||
| 0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiApIFRqDQpFVA0KQlQNCi9GMSAwMDEwIFRmDQo2OS4yNTAwIDYyOC44NDgwIFRkDQ | |||
| ooIEFuZCBtb3JlIHRleHQuIEFuZCBtb3JlIHRleHQuIEFuZCBtb3JlIHRleHQuIEFuZCBtb3JlIHRleHQuIEFuZCBtb3JlICkgVGoNCkVUDQpCVA0KL0YxIDAwMTAgV | |||
| GYNCjY5LjI1MDAgNjE2Ljg5NjAgVGQNCiggdGV4dC4gQW5kIG1vcmUgdGV4dC4gQm9yaW5nLCB6enp6ei4gQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gQW5 | |||
| kICkgVGoNCkVUDQpCVA0KL0YxIDAwMTAgVGYNCjY5LjI1MDAgNjA0Ljk0NDAgVGQNCiggbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbm | |||
| QgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiApIFRqDQpFVA0KQlQNCi9GMSAwMDEwIFRmDQo2OS4yNTAwIDU5Mi45OTIwIFRkDQooIEFuZCBtb3JlIHRleHQuIEFu | |||
| ZCBtb3JlIHRleHQuICkgVGoNCkVUDQpCVA0KL0YxIDAwMTAgVGYNCjY5LjI1MDAgNTY5LjA4ODAgVGQNCiggQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gQW | |||
| 5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgKSBUag0KRVQNCkJUDQovRjEgMDAxMCBUZg0KNjkuMjUwMCA1NTcuMTM2MCBUZA0KKCB0ZXh0LiB | |||
| BbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBFdmVuIG1vcmUuIENvbnRpbnVlZCBvbiBwYWdlIDIgLi4uKSBUag0KRVQNCmVuZHN0cmVhbQ0KZW5kb2JqDQoNC | |||
| jYgMCBvYmoNCjw8DQovVHlwZSAvUGFnZQ0KL1BhcmVudCAzIDAgUg0KL1Jlc291cmNlcyA8PA0KL0ZvbnQgPDwNCi9GMSA5IDAgUiANCj4+DQovUHJvY1NldCA4IDA | |||
| gUg0KPj4NCi9NZWRpYUJveCBbMCAwIDYxMi4wMDAwIDc5Mi4wMDAwXQ0KL0NvbnRlbnRzIDcgMCBSDQo+Pg0KZW5kb2JqDQoNCjcgMCBvYmoNCjw8IC9MZW5ndGggN | |||
| jc2ID4+DQpzdHJlYW0NCjIgSg0KQlQNCjAgMCAwIHJnDQovRjEgMDAyNyBUZg0KNTcuMzc1MCA3MjIuMjgwMCBUZA0KKCBTaW1wbGUgUERGIEZpbGUgMiApIFRqDQp | |||
| FVA0KQlQNCi9GMSAwMDEwIFRmDQo2OS4yNTAwIDY4OC42MDgwIFRkDQooIC4uLmNvbnRpbnVlZCBmcm9tIHBhZ2UgMS4gWWV0IG1vcmUgdGV4dC4gQW5kIG1vcmUgd | |||
| GV4dC4gQW5kIG1vcmUgdGV4dC4gKSBUag0KRVQNCkJUDQovRjEgMDAxMCBUZg0KNjkuMjUwMCA2NzYuNjU2MCBUZA0KKCBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB | |||
| 0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSB0ZXh0LiBBbmQgbW9yZSApIFRqDQpFVA0KQlQNCi9GMSAwMDEwIFRmDQo2OS4yNTAwIDY2NC43MDQwIFRkDQooIH | |||
| RleHQuIE9oLCBob3cgYm9yaW5nIHR5cGluZyB0aGlzIHN0dWZmLiBCdXQgbm90IGFzIGJvcmluZyBhcyB3YXRjaGluZyApIFRqDQpFVA0KQlQNCi9GMSAwMDEwIFRm | |||
| DQo2OS4yNTAwIDY1Mi43NTIwIFRkDQooIHBhaW50IGRyeS4gQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC4gQW5kIG1vcmUgdGV4dC | |||
| 4gKSBUag0KRVQNCkJUDQovRjEgMDAxMCBUZg0KNjkuMjUwMCA2NDAuODAwMCBUZA0KKCBCb3JpbmcuICBNb3JlLCBhIGxpdHRsZSBtb3JlIHRleHQuIFRoZSBlbmQs | |||
| IGFuZCBqdXN0IGFzIHdlbGwuICkgVGoNCkVUDQplbmRzdHJlYW0NCmVuZG9iag0KDQo4IDAgb2JqDQpbL1BERiAvVGV4dF0NCmVuZG9iag0KDQo5IDAgb2JqDQo8PA0 | |||
| KL1R5cGUgL0ZvbnQNCi9TdWJ0eXBlIC9UeXBlMQ0KL05hbWUgL0YxDQovQmFzZUZvbnQgL0hlbHZldGljYQ0KL0VuY29kaW5nIC9XaW5BbnNpRW5jb2RpbmcNCj4+D | |||
| QplbmRvYmoNCg0KMTAgMCBvYmoNCjw8DQovQ3JlYXRvciAoUmF2ZSBcKGh0dHA6Ly93d3cubmV2cm9uYS5jb20vcmF2ZVwpKQ0KL1Byb2R1Y2VyIChOZXZyb25hIER | |||
| lc2lnbnMpDQovQ3JlYXRpb25EYXRlIChEOjIwMDYwMzAxMDcyODI2KQ0KPj4NCmVuZG9iag0KDQp4cmVmDQowIDExDQowMDAwMDAwMDAwIDY1NTM1IGYNCjAwMDAwM | |||
| DAwMTkgMDAwMDAgbg0KMDAwMDAwMDA5MyAwMDAwMCBuDQowMDAwMDAwMTQ3IDAwMDAwIG4NCjAwMDAwMDAyMjIgMDAwMDAgbg0KMDAwMDAwMDM5MCAwMDAwMCBuDQow | |||
| MDAwMDAxNTIyIDAwMDAwIG4NCjAwMDAwMDE2OTAgMDAwMDAgbg0KMDAwMDAwMjQyMyAwMDAwMCBuDQowMDAwMDAyNDU2IDAwMDAwIG4NCjAwMDAwMDI1NzQgMDAwMD | |||
| Agbg0KDQp0cmFpbGVyDQo8PA0KL1NpemUgMTENCi9Sb290IDEgMCBSDQovSW5mbyAxMCAwIFINCj4+DQoNCnN0YXJ0eHJlZg0KMjcxNA0KJSVFT0YNCg==`; | |||
| const basse64Pdf = "some base64 string"; | |||
| getCV("name od pdf file") | |||
| .then(() => basse64Pdf) | |||
| .catch(catchFn); | |||
| @@ -167,10 +140,10 @@ describe("TableViewPage render tests", () => { | |||
| .getElementsByTagName("span")[0] | |||
| ); | |||
| waitFor(() => | |||
| waitFor(() => { | |||
| expect( | |||
| container.getElementsByClassName("candidates-cv")[0].style.opacity | |||
| ).toBe("1") | |||
| ); | |||
| ).toBe("1"); | |||
| }); | |||
| }); | |||
| }); | |||
| @@ -270,6 +270,7 @@ | |||
| .candidates-pagination { | |||
| margin-top: 20px; | |||
| margin-left: 350px; | |||
| padding-bottom: 20px; | |||
| } | |||
| .candidates-cv { | |||
| @@ -316,8 +317,4 @@ | |||
| .left-move-candidateAd-page { | |||
| margin-left: -12px; | |||
| } | |||
| .candidates-pagination { | |||
| margin-left: 55px; | |||
| } | |||
| } | |||
| @@ -10,11 +10,14 @@ import filterIcon from "../../assets/images/filter_vector.png"; | |||
| import x from "../../assets/images/x.png"; | |||
| import { | |||
| filterCandidates, | |||
| fetchAdsCandidates | |||
| fetchAdsCandidates, | |||
| } from "../../store/actions/candidates/candidatesActions"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { formatDateInput } from "../../util/helpers/dateHelpers"; | |||
| import { changeIsCheckedValue,resetIsCheckedValue } from "../../store/actions/technologies/technologiesActions"; | |||
| import { | |||
| changeIsCheckedValue, | |||
| resetIsCheckedValue, | |||
| } from "../../store/actions/technologies/technologiesActions"; | |||
| const CandidateFilters = ({ | |||
| open, | |||
| @@ -23,19 +26,19 @@ const CandidateFilters = ({ | |||
| currentPage, | |||
| isTableView, | |||
| technologies, | |||
| sliderValue, | |||
| startingDate, | |||
| endingDate, | |||
| typesOfEmployments, | |||
| setSliderValue, | |||
| setStartingDate, | |||
| setEndingDate, | |||
| setTypesOfEmployments, | |||
| }) => { | |||
| const dispatch = useDispatch(); | |||
| const [sliderValue, setSliderValue] = useState([0, 0]); | |||
| const [startingDate, setStartingDate] = useState(""); | |||
| const [endingDate, setEndingDate] = useState(""); | |||
| const [typesOfEmployments, setTypesOfEmployments] = useState([ | |||
| { name: "Posao", isChecked: false }, | |||
| { name: "Intership", isChecked: false }, | |||
| ]); | |||
| const [isInitial, setIsInitial] = useState(true) | |||
| const [isInitial, setIsInitial] = useState(true); | |||
| useEffect(() => { | |||
| // console.log(isTableView); | |||
| }, [isTableView]); | |||
| const handleSliderChange = (_, newValue) => { | |||
| @@ -47,19 +50,19 @@ const CandidateFilters = ({ | |||
| { name: "Posao", isChecked: false }, | |||
| { name: "Intership", isChecked: false }, | |||
| ]); | |||
| setSliderValue([0,0]) | |||
| setEndingDate("") | |||
| setStartingDate("") | |||
| setSliderValue([0, 0]); | |||
| setEndingDate(""); | |||
| setStartingDate(""); | |||
| }; | |||
| useEffect(() => { | |||
| if(isInitial) { | |||
| setIsInitial(false) | |||
| if (isInitial) { | |||
| setIsInitial(false); | |||
| return; | |||
| } | |||
| dispatch(resetIsCheckedValue()) | |||
| dispatch(resetIsCheckedValue()); | |||
| resetFilters(); | |||
| }, [isTableView]) | |||
| }, [isTableView]); | |||
| const updateTypeState = (name, value) => { | |||
| const newState = typesOfEmployments.map((obj) => { | |||
| @@ -91,24 +94,24 @@ const CandidateFilters = ({ | |||
| }; | |||
| const isThereSelectedFilter = () => { | |||
| let tech = technologies.filter(t => t.isChecked === true); | |||
| if(tech && tech.length > 0){ | |||
| let tech = technologies.filter((t) => t.isChecked === true); | |||
| if (tech && tech.length > 0) { | |||
| return true; | |||
| } | |||
| let k = typesOfEmployments.filter(te => te.isChecked === true) | |||
| if(k && k.length > 0){ | |||
| return true | |||
| let k = typesOfEmployments.filter((te) => te.isChecked === true); | |||
| if (k && k.length > 0) { | |||
| return true; | |||
| } | |||
| if(sliderValue[0] !== 0 || sliderValue[1] !== 0) { | |||
| return true | |||
| if (sliderValue[0] !== 0 || sliderValue[1] !== 0) { | |||
| return true; | |||
| } | |||
| if(startingDate !== "" || endingDate !== ""){ | |||
| if (startingDate !== "" || endingDate !== "") { | |||
| return true; | |||
| } | |||
| return false | |||
| } | |||
| return false; | |||
| }; | |||
| const fiterItems = () => { | |||
| const tech = technologies | |||
| @@ -117,44 +120,46 @@ const CandidateFilters = ({ | |||
| const selectedEmploymentType = getSelectedEmploymentType(); | |||
| isTableView ? | |||
| dispatch( | |||
| filterCandidates({ | |||
| pageSize, | |||
| currentPage, | |||
| minExperience: sliderValue[0], | |||
| maxExperience: sliderValue[1], | |||
| employmentType:selectedEmploymentType && selectedEmploymentType.length === 0 ? "" : selectedEmploymentType[0].name, | |||
| minDateOfApplication: startingDate, | |||
| maxDateOfApplication: endingDate, | |||
| technologies: tech, | |||
| handleApiResponseSuccess, | |||
| }) | |||
| ) : | |||
| dispatch( | |||
| fetchAdsCandidates({ | |||
| pageSize, | |||
| currentPage, | |||
| minExperience: sliderValue[0], | |||
| maxExperience: sliderValue[1], | |||
| employmentType:selectedEmploymentType && selectedEmploymentType.length === 0 ? "" : selectedEmploymentType[0].name, | |||
| minDateOfApplication: startingDate, | |||
| maxDateOfApplication: endingDate, | |||
| technologies: tech, | |||
| handleApiResponseSuccess, | |||
| }) | |||
| ); | |||
| isTableView | |||
| ? dispatch( | |||
| filterCandidates({ | |||
| pageSize, | |||
| currentPage, | |||
| minExperience: sliderValue[0], | |||
| maxExperience: sliderValue[1], | |||
| employmentType: | |||
| selectedEmploymentType && selectedEmploymentType.length === 0 | |||
| ? "" | |||
| : selectedEmploymentType[0].name, | |||
| minDateOfApplication: startingDate, | |||
| maxDateOfApplication: endingDate, | |||
| technologies: tech, | |||
| handleApiResponseSuccess, | |||
| }) | |||
| ) | |||
| : dispatch( | |||
| fetchAdsCandidates({ | |||
| pageSize, | |||
| currentPage, | |||
| minExperience: sliderValue[0], | |||
| maxExperience: sliderValue[1], | |||
| employmentType: | |||
| selectedEmploymentType && selectedEmploymentType.length === 0 | |||
| ? "" | |||
| : selectedEmploymentType[0].name, | |||
| minDateOfApplication: startingDate, | |||
| maxDateOfApplication: endingDate, | |||
| technologies: tech, | |||
| handleApiResponseSuccess, | |||
| }) | |||
| ); | |||
| }; | |||
| const handleChangeStartingDate = (event) => { | |||
| // console.log(event); | |||
| setStartingDate(event.target.value); | |||
| }; | |||
| const handleChangeEndingDate = (event) => { | |||
| // console.log(event); | |||
| setEndingDate(event.target.value); | |||
| }; | |||
| @@ -272,7 +277,11 @@ const CandidateFilters = ({ | |||
| </div> | |||
| </div> | |||
| <div className="ad-filters-search" style={{ marginTop: "45px" }}> | |||
| <button className="c-btn c-btn--primary" onClick={fiterItems} disabled={!isThereSelectedFilter()}> | |||
| <button | |||
| className="c-btn c-btn--primary" | |||
| onClick={fiterItems} | |||
| disabled={!isThereSelectedFilter()} | |||
| > | |||
| Pretrazi | |||
| </button> | |||
| </div> | |||
| @@ -297,6 +306,14 @@ CandidateFilters.propTypes = { | |||
| pageSize: PropType.number, | |||
| isTableView: PropType.bool, | |||
| technologies: PropType.array, | |||
| sliderValue: PropType.array, | |||
| startingDate: PropType.string, | |||
| endingDate: PropType.string, | |||
| typesOfEmployments: PropType.array, | |||
| setSliderValue: PropType.func, | |||
| setStartingDate: PropType.func, | |||
| setEndingDate: PropType.func, | |||
| setTypesOfEmployments: PropType.func, | |||
| }; | |||
| export default CandidateFilters; | |||
| @@ -1,2 +1,2 @@ | |||
| /* istanbul ignore file */ | |||
| export const PAGE_SIZE_CANDIDATES = 9; | |||
| export const PAGE_SIZE_CANDIDATES = 12; | |||
| @@ -583,8 +583,25 @@ export const mockState = { | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| applicantId: 66, | |||
| firstName: "dasd", | |||
| lastName: "dasdas", | |||
| dateOfApplication: "2022-02-11T00:00:00", | |||
| cv: "link", | |||
| experience: 1, | |||
| technologyApplicants: [ | |||
| { | |||
| technology: { | |||
| technologyId: 1, | |||
| technologyType: "Backend", | |||
| name: ".NET", | |||
| }, | |||
| }, | |||
| ], | |||
| }, | |||
| ], | |||
| nubmerOfApplicants: 5, | |||
| nubmerOfApplicants: 6, | |||
| }, | |||
| { | |||
| id: 2, | |||
| @@ -38,8 +38,8 @@ const AdsCandidatesPage = ({ history, search }) => { | |||
| dots: false, | |||
| infinite: false, | |||
| speed: 400, | |||
| slidesToShow: 4, | |||
| slidesToScroll: 4, | |||
| slidesToShow: 3, | |||
| slidesToScroll: 3, | |||
| initialSlide: 0, | |||
| arrows: true, | |||
| variableWidth: true, | |||
| @@ -47,8 +47,8 @@ const AdsCandidatesPage = ({ history, search }) => { | |||
| { | |||
| breakpoint: 1024, | |||
| settings: { | |||
| slidesToShow: 3, | |||
| slidesToScroll: 3, | |||
| slidesToShow: 2, | |||
| slidesToScroll: 2, | |||
| infinite: true, | |||
| dots: false, | |||
| }, | |||
| @@ -56,8 +56,8 @@ const AdsCandidatesPage = ({ history, search }) => { | |||
| { | |||
| breakpoint: 900, | |||
| settings: { | |||
| slidesToShow: 2, | |||
| slidesToScroll: 2, | |||
| slidesToShow: 1, | |||
| slidesToScroll: 1, | |||
| initialSlide: 0, | |||
| }, | |||
| }, | |||
| @@ -120,7 +120,10 @@ const AdsCandidatesPage = ({ history, search }) => { | |||
| <button onClick={() => activeAdsArrowLeftHandler(index)}> | |||
| <img src={arrow_left} alt="arrow-left" /> | |||
| </button> | |||
| <button onClick={() => activeAdsArrowRightHandler(index)} className="kp"> | |||
| <button | |||
| onClick={() => activeAdsArrowRightHandler(index)} | |||
| className="kp" | |||
| > | |||
| <img src={arrow_right} alt="arrow-right" /> | |||
| </button> | |||
| </div> | |||
| @@ -26,6 +26,14 @@ const CandidatesPage = ({ history }) => { | |||
| const [search, setSearch] = useState(""); | |||
| const [isSearchFieldVisible, setIsSearchFieldVisible] = useState(false); | |||
| const [sliderValue, setSliderValue] = useState([0, 0]); | |||
| const [startingDate, setStartingDate] = useState(""); | |||
| const [endingDate, setEndingDate] = useState(""); | |||
| const [typesOfEmployments, setTypesOfEmployments] = useState([ | |||
| { name: "Posao", isChecked: false }, | |||
| { name: "Intership", isChecked: false }, | |||
| ]); | |||
| useEffect(() => { | |||
| dispatch(setTechnologiesReq()); | |||
| }, []); | |||
| @@ -73,6 +81,14 @@ const CandidatesPage = ({ history }) => { | |||
| currentPage={page} | |||
| isTableView={isTableView} | |||
| technologies={technologies} | |||
| sliderValue={sliderValue} | |||
| startingDate={startingDate} | |||
| endingDate={endingDate} | |||
| typesOfEmployments={typesOfEmployments} | |||
| setSliderValue={setSliderValue} | |||
| setStartingDate={setStartingDate} | |||
| setEndingDate={setEndingDate} | |||
| setTypesOfEmployments={setTypesOfEmployments} | |||
| /> | |||
| <div className="l-t-rectangle"></div> | |||
| <div className="r-b-rectangle"></div> | |||
| @@ -192,6 +208,11 @@ const CandidatesPage = ({ history }) => { | |||
| page={page} | |||
| setPage={setPage} | |||
| search={search} | |||
| sliderValue={sliderValue} | |||
| startingDate={startingDate} | |||
| endingDate={endingDate} | |||
| typesOfEmployments={typesOfEmployments} | |||
| technologies={technologies} | |||
| /> | |||
| ) : ( | |||
| <AdsCandidatesPage history={history} search={search} /> | |||
| @@ -14,12 +14,16 @@ import { | |||
| } from "../../store/selectors/candidatesSelectors"; | |||
| import { getCV } from "../../request/candidatesRequest"; | |||
| import Fade from "@mui/material/Fade"; | |||
| const TableViewPage = ({ | |||
| history, | |||
| setPage, | |||
| page, | |||
| search, | |||
| sliderValue, | |||
| startingDate, | |||
| endingDate, | |||
| typesOfEmployments, | |||
| technologies, | |||
| }) => { | |||
| const dispatch = useDispatch(); | |||
| const candidates = useSelector(selectCandidates); | |||
| @@ -44,17 +48,28 @@ const TableViewPage = ({ | |||
| ); | |||
| }, [dispatch]); | |||
| const getSelectedEmploymentType = () => { | |||
| return typesOfEmployments.filter((e) => e.isChecked === true); | |||
| }; | |||
| const selectedEmploymentType = getSelectedEmploymentType(); | |||
| const handleChange = (_, value) => { | |||
| dispatch( | |||
| filterCandidates({ | |||
| currentPage: value, | |||
| pageSize: PAGE_SIZE_CANDIDATES, | |||
| minExperience: 0, | |||
| maxExperience: 0, | |||
| employmentType: "", | |||
| minDateOfApplication: "", | |||
| maxDateOfApplication: "", | |||
| technologies: [], | |||
| minExperience: sliderValue[0], | |||
| maxExperience: sliderValue[1], | |||
| employmentType: | |||
| selectedEmploymentType && selectedEmploymentType.length === 0 | |||
| ? "" | |||
| : selectedEmploymentType[0].name, | |||
| minDateOfApplication: startingDate, | |||
| maxDateOfApplication: endingDate, | |||
| technologies: technologies | |||
| .filter((tech) => tech.isChecked === true) | |||
| .map((tech) => tech.name), | |||
| }) | |||
| ); | |||
| setPage(value); | |||
| @@ -98,6 +113,14 @@ const TableViewPage = ({ | |||
| }); | |||
| }; | |||
| const filterCandidatesByName = () => { | |||
| return candidates.filter((n) => | |||
| (n.firstName + " " + n.lastName) | |||
| .toLowerCase() | |||
| .includes(search.toLowerCase()) | |||
| ); | |||
| }; | |||
| return ( | |||
| <div className="candidates-table"> | |||
| <div | |||
| @@ -105,12 +128,15 @@ const TableViewPage = ({ | |||
| overflowX: "auto", | |||
| marginLeft: matches ? 36 : 72, | |||
| display: "flex", | |||
| justifyContent:'space-between' | |||
| justifyContent: "space-between", | |||
| }} | |||
| > | |||
| <table | |||
| className="usersTable" | |||
| style={{ width: isCVDisplayed ? "784px" : "914px" }} | |||
| style={{ | |||
| width: isCVDisplayed ? "784px" : "914px", | |||
| height: "fit-content", | |||
| }} | |||
| > | |||
| <thead> | |||
| <tr className="headingRow"> | |||
| @@ -123,77 +149,74 @@ const TableViewPage = ({ | |||
| </thead> | |||
| <tbody> | |||
| {candidates && | |||
| candidates | |||
| .filter((n) => | |||
| (n.firstName + " " + n.lastName) | |||
| .toLowerCase() | |||
| .includes(search.toLowerCase()) | |||
| ) | |||
| .map((candidate, index) => ( | |||
| <tr | |||
| key={index} | |||
| className="secondaryRow cadidate-row" | |||
| style={{ | |||
| cursor: "pointer", | |||
| }} | |||
| onClick={() => | |||
| navigateToCandidateDetailsPage(candidate.applicantId) | |||
| } | |||
| > | |||
| <td> | |||
| {( | |||
| candidate.firstName + | |||
| " " + | |||
| candidate.lastName | |||
| ).includes(search) ? ( | |||
| formatLabel( | |||
| candidate.firstName + " " + candidate.lastName, | |||
| search | |||
| ) | |||
| ) : ( | |||
| <span> | |||
| {candidate.firstName + " " + candidate.lastName} | |||
| </span> | |||
| )} | |||
| </td> | |||
| {!isCVDisplayed && ( | |||
| <td style={{ paddingLeft: 80 }}> | |||
| {candidate.experience} | |||
| </td> | |||
| )} | |||
| <td style={{ paddingLeft: 55 }}> | |||
| {formatDate(candidate.dateOfApplication)} | |||
| </td> | |||
| <td>{candidate.position}</td> | |||
| <td> | |||
| <span | |||
| onClick={(e) => onClickCV(e, candidate.cv)} | |||
| className="cvLink" | |||
| > | |||
| {candidate.firstName} | |||
| {candidate.lastName}.pdf | |||
| filterCandidatesByName().map((candidate, index) => ( | |||
| <tr | |||
| key={index} | |||
| className="secondaryRow cadidate-row" | |||
| style={{ | |||
| cursor: "pointer", | |||
| }} | |||
| onClick={() => | |||
| navigateToCandidateDetailsPage(candidate.applicantId) | |||
| } | |||
| > | |||
| <td> | |||
| {(candidate.firstName + " " + candidate.lastName).includes( | |||
| search | |||
| ) ? ( | |||
| formatLabel( | |||
| candidate.firstName + " " + candidate.lastName, | |||
| search | |||
| ) | |||
| ) : ( | |||
| <span> | |||
| {candidate.firstName + " " + candidate.lastName} | |||
| </span> | |||
| </td> | |||
| </tr> | |||
| ))} | |||
| )} | |||
| </td> | |||
| {!isCVDisplayed && ( | |||
| <td style={{ paddingLeft: 80 }}>{candidate.experience}</td> | |||
| )} | |||
| <td style={{ paddingLeft: 55 }}> | |||
| {formatDate(candidate.dateOfApplication)} | |||
| </td> | |||
| <td>{candidate.position}</td> | |||
| <td> | |||
| <span | |||
| onClick={(e) => onClickCV(e, candidate.cv)} | |||
| className="cvLink" | |||
| > | |||
| {candidate.firstName} | |||
| {candidate.lastName}.pdf | |||
| </span> | |||
| </td> | |||
| </tr> | |||
| ))} | |||
| </tbody> | |||
| </table> | |||
| <Fade in={isCVDisplayed} timeout={400}> | |||
| <embed src={`data:application/pdf;base64,${linkToCV}`} className="candidates-cv"/> | |||
| <embed | |||
| src={`data:application/pdf;base64,${linkToCV}`} | |||
| className="candidates-cv" | |||
| /> | |||
| </Fade> | |||
| </div> | |||
| <Pagination | |||
| size={matches ? "small" : "medium"} | |||
| count={ | |||
| parseInt(pagination) <= PAGE_SIZE_CANDIDATES | |||
| ? 1 | |||
| : Math.ceil(parseInt(pagination) / PAGE_SIZE_CANDIDATES) | |||
| } | |||
| color="primary" | |||
| className="candidates-pagination" | |||
| onChange={handleChange} | |||
| shape="rounded" | |||
| /> | |||
| {search.length > 0 ? ( | |||
| "" | |||
| ) : ( | |||
| <Pagination | |||
| size={matches ? "small" : "medium"} | |||
| count={ | |||
| parseInt(pagination) <= PAGE_SIZE_CANDIDATES | |||
| ? 1 | |||
| : Math.ceil(parseInt(pagination) / PAGE_SIZE_CANDIDATES) | |||
| } | |||
| color="primary" | |||
| className="candidates-pagination" | |||
| onChange={handleChange} | |||
| shape="rounded" | |||
| /> | |||
| )} | |||
| </div> | |||
| ); | |||
| }; | |||
| @@ -209,6 +232,11 @@ TableViewPage.propTypes = { | |||
| setPage: PropTypes.func, | |||
| page: PropTypes.number, | |||
| search: PropTypes.string, | |||
| sliderValue: PropTypes.array, | |||
| startingDate: PropTypes.string, | |||
| endingDate: PropTypes.string, | |||
| typesOfEmployments: PropTypes.array, | |||
| technologies: PropTypes.array, | |||
| }; | |||
| export default TableViewPage; | |||
| @@ -91,11 +91,12 @@ const SchedulePage = ({ history }) => { | |||
| }; | |||
| const goForwardOneMonth = () => { | |||
| // console.log(currentMonth) | |||
| console.log(currentMonth); | |||
| console.log(currentYear); | |||
| dispatch( | |||
| fetchSchedule({ | |||
| month: currentMonth - 1 === -1 ? 12 : currentMonth + 2, | |||
| year: currentMonth - 1 === -1 ? currentYear - 1 : currentYear, | |||
| month: currentMonth + 1 === 12 ? 1 : currentMonth + 2, | |||
| year: currentMonth + 1 === 12 ? currentYear + 1 : currentYear, | |||
| }) | |||
| ); | |||
| setNumberOfDaysInMonth( | |||
| @@ -1,71 +0,0 @@ | |||
| import { | |||
| deleteRequest, | |||
| getRequest, | |||
| patchRequest, | |||
| replaceInUrl, | |||
| postRequest, | |||
| } from './index'; | |||
| import apiEndpoints from './apiEndpoints'; | |||
| export const getAccount = (accountUid) => | |||
| getRequest(replaceInUrl(apiEndpoints.accounts.get, { accountUid })); | |||
| export const getAccountUsers = (accountUid) => | |||
| getRequest(replaceInUrl(apiEndpoints.accounts.getUsers, { accountUid })); | |||
| export const getUserPermissions = (currentAccountUid, currentUserUid) => | |||
| getRequest( | |||
| replaceInUrl(apiEndpoints.accounts.getCurrentUserPermissions, { | |||
| currentAccountUid, | |||
| currentUserUid, | |||
| }), | |||
| ); | |||
| export const getAccountAddresses = (accountUid) => | |||
| getRequest(replaceInUrl(apiEndpoints.accounts.getAddresses, { accountUid })); | |||
| export const getAccountSettingsRequest = (accountUid) => | |||
| getRequest(replaceInUrl(apiEndpoints.accounts.getSettings, { accountUid })); | |||
| export const updateAccountAddressRequest = (accountUid, addressUid, data) => | |||
| patchRequest( | |||
| replaceInUrl(apiEndpoints.accounts.updateAddress, { | |||
| accountUid, | |||
| addressUid, | |||
| }), | |||
| data, | |||
| ); | |||
| export const deleteAccountAddressRequest = (accountUid, addressUid) => | |||
| deleteRequest( | |||
| replaceInUrl(apiEndpoints.accounts.deleteAddress, { | |||
| accountUid, | |||
| addressUid, | |||
| }), | |||
| ); | |||
| export const postNewAccountUserRequest = (accountUid, data) => | |||
| postRequest( | |||
| replaceInUrl(apiEndpoints.accounts.createUser, { | |||
| accountUid, | |||
| }), | |||
| data, | |||
| ); | |||
| export const updateAccountUserRequest = ( | |||
| accountUid, | |||
| userUid, | |||
| actionType, | |||
| data, | |||
| ) => | |||
| patchRequest( | |||
| replaceInUrl(apiEndpoints.accounts.updateUser, { | |||
| accountUid, | |||
| userUid, | |||
| actionType, | |||
| }), | |||
| data, | |||
| ); | |||
| export const postAgreementRequest = (data) => | |||
| postRequest(apiEndpoints.accounts.agreement, data); | |||