| import { useLocation } from "react-router-dom"; | import { useLocation } from "react-router-dom"; | ||||
| import { | import { | ||||
| // ADS_PAGE, | |||||
| // AD_DETAILS_PAGE, | |||||
| FORGOT_PASSWORD_PAGE, | FORGOT_PASSWORD_PAGE, | ||||
| FORGOT_PASSWORD_CONFIRMATION_PAGE, | FORGOT_PASSWORD_CONFIRMATION_PAGE, | ||||
| NOT_FOUND_PAGE, | NOT_FOUND_PAGE, | ||||
| BASE_PAGE, | BASE_PAGE, | ||||
| RESET_PASSWORD_PAGE, | RESET_PASSWORD_PAGE, | ||||
| USERS_PAGE, | USERS_PAGE, | ||||
| // CANDIDATES_PAGE, | |||||
| USER_DETAILS_PAGE, | USER_DETAILS_PAGE, | ||||
| // CANDIDATES_DETAILS_PAGE, | |||||
| // SELECTION_PROCESS_PAGE, | |||||
| // SELECTION_PROCESS_OF_APPLICANT_PAGE, | |||||
| // PATTERNS_PAGE, | |||||
| // PATTERN_DETAILS_PAGE, | |||||
| // SCHEDULE_PAGE, | |||||
| // STATS_PAGE, | |||||
| REGISTER_PAGE, | |||||
| // CREATE_AD_PAGE, | |||||
| // FILES_VIEW_PAGE, | |||||
| ADD_FILE, | ADD_FILE, | ||||
| FILES_PAGE, | FILES_PAGE, | ||||
| FILES_DEPTH_PAGE | |||||
| FILES_DEPTH_PAGE, | |||||
| REGISTER_PAGE, | |||||
| } from "./constants/pages"; | } from "./constants/pages"; | ||||
| import LoginPage from "./pages/LoginPage/LoginPageMUI"; | import LoginPage from "./pages/LoginPage/LoginPageMUI"; | ||||
| // import AdsPage from "./pages/AdsPage/AdsPage"; | |||||
| import NotFoundPage from "./pages/ErrorPages/NotFoundPage"; | import NotFoundPage from "./pages/ErrorPages/NotFoundPage"; | ||||
| import ErrorPage from "./pages/ErrorPages/ErrorPage"; | import ErrorPage from "./pages/ErrorPages/ErrorPage"; | ||||
| import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI"; | import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI"; | ||||
| import ForgotPasswordConfirmationPage from "./pages/ForgotPasswordPage/ForgotPasswordConfirmationPageMUI"; | import ForgotPasswordConfirmationPage from "./pages/ForgotPasswordPage/ForgotPasswordConfirmationPageMUI"; | ||||
| import ResetPasswordPage from "./pages/ForgotPasswordPage/ResetPasswordPageMUI"; | import ResetPasswordPage from "./pages/ForgotPasswordPage/ResetPasswordPageMUI"; | ||||
| import UsersPage from "./pages/UsersPage/UsersPage"; | import UsersPage from "./pages/UsersPage/UsersPage"; | ||||
| // import CandidatesPage from "./pages/CandidatesPage/CandidatesPage"; | |||||
| // import AdDetailsPage from "./pages/AdsPage/AdDetailsPage"; | |||||
| import UserDetails from "./pages/UsersPage/UserDetails"; | import UserDetails from "./pages/UsersPage/UserDetails"; | ||||
| // import CandidateDetailsPage from "./pages/CandidatesPage/CandidateDetailsPage"; | |||||
| // import SelectionProcessPage from "./pages/SelectionProcessPage/SelectionProcessPage"; | |||||
| // import SelectionProcessOfApplicantPage from "./pages/SelectionProcessPage/SelectionProcessOfApplicantPage"; | |||||
| // import PatternsPage from "./pages/PatternsPage/PatternsPage"; | |||||
| // import PatternDetailsPage from "./pages/PatternsPage/PatternDetailsPage"; | |||||
| // import SchedulePage from "./pages/SchedulePage/SchedulePage"; | |||||
| // import StatsPage from "./pages/StatsPage/StatsPage"; | |||||
| import RegisterPage from "./pages/RegisterPage/RegisterPage"; | import RegisterPage from "./pages/RegisterPage/RegisterPage"; | ||||
| // import CreateAdPage from "./pages/AdsPage/CreateAdPage"; | |||||
| // import FilesViewPage from "./pages/FilesPage/FilesViewPage"; | |||||
| import AddFile from "./pages/FilesPage/AddFile"; | import AddFile from "./pages/FilesPage/AddFile"; | ||||
| import FilesPage from "./pages/FilesPage/FilesPage"; | import FilesPage from "./pages/FilesPage/FilesPage"; | ||||
| <Switch> | <Switch> | ||||
| <Route exact path={BASE_PAGE} component={LoginPage} /> | <Route exact path={BASE_PAGE} component={LoginPage} /> | ||||
| <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | ||||
| {/* <Route path={USERS_PAGE} component={UsersPage} /> */} | |||||
| <Route path={ERROR_PAGE} component={ErrorPage} /> | <Route path={ERROR_PAGE} component={ErrorPage} /> | ||||
| <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | ||||
| <Route | <Route | ||||
| /> | /> | ||||
| <Route exact path={REGISTER_PAGE} component={RegisterPage} /> | <Route exact path={REGISTER_PAGE} component={RegisterPage} /> | ||||
| <Route path={RESET_PASSWORD_PAGE} component={ResetPasswordPage} /> | <Route path={RESET_PASSWORD_PAGE} component={ResetPasswordPage} /> | ||||
| {/* <PrivateRoute exact path={ADS_PAGE} component={AdsPage} /> */} | |||||
| {/* <PrivateRoute exact path={AD_DETAILS_PAGE} component={AdDetailsPage} /> */} | |||||
| <PrivateRoute exact path={USER_DETAILS_PAGE} component={UserDetails} /> | <PrivateRoute exact path={USER_DETAILS_PAGE} component={UserDetails} /> | ||||
| <PrivateRoute exact path={USERS_PAGE} component={UsersPage} /> | <PrivateRoute exact path={USERS_PAGE} component={UsersPage} /> | ||||
| {/* <PrivateRoute exact path={CANDIDATES_PAGE} component={CandidatesPage} /> | |||||
| <PrivateRoute exact path={CREATE_AD_PAGE} component={CreateAdPage} /> */} | |||||
| {/* <PrivateRoute exact path={FILES_PAGE} component={FilesPage} /> */} | |||||
| {/* <PrivateRoute exact path={FILES_VIEW_PAGE} component={FilesViewPage} /> */} | |||||
| <PrivateRoute exact path={ADD_FILE} component={AddFile}/> | |||||
| <PrivateRoute exact path={FILES_PAGE} component={FilesPage}/> | |||||
| <PrivateRoute exact path={FILES_DEPTH_PAGE} component={FilesPage}/> | |||||
| {/* <PrivateRoute | |||||
| exact | |||||
| path={CANDIDATES_DETAILS_PAGE} | |||||
| component={CandidateDetailsPage} | |||||
| /> | |||||
| <PrivateRoute | |||||
| exact | |||||
| path={SELECTION_PROCESS_PAGE} | |||||
| component={SelectionProcessPage} | |||||
| /> | |||||
| <PrivateRoute | |||||
| exact | |||||
| path={SELECTION_PROCESS_OF_APPLICANT_PAGE} | |||||
| component={SelectionProcessOfApplicantPage} | |||||
| /> | |||||
| <PrivateRoute | |||||
| exact | |||||
| path={PATTERN_DETAILS_PAGE} | |||||
| component={PatternDetailsPage} | |||||
| /> | |||||
| <PrivateRoute exact path={PATTERNS_PAGE} component={PatternsPage} /> | |||||
| <PrivateRoute exact path={SCHEDULE_PAGE} component={SchedulePage} /> | |||||
| <PrivateRoute exact path={STATS_PAGE} component={StatsPage} /> */} | |||||
| <PrivateRoute exact path={ADD_FILE} component={AddFile} /> | |||||
| <PrivateRoute exact path={FILES_PAGE} component={FilesPage} /> | |||||
| <PrivateRoute exact path={FILES_DEPTH_PAGE} component={FilesPage} /> | |||||
| <Redirect from="*" to={NOT_FOUND_PAGE} /> | <Redirect from="*" to={NOT_FOUND_PAGE} /> | ||||
| </Switch> | </Switch> | ||||
| ); | ); |
| import reducer from "../../../../store/reducers/ad/adReducer"; | |||||
| import expect from "expect"; | |||||
| import { setAd, setAdError } from "../../../../store/actions/ad/adActions"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("ad reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| ad: null, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setAdError("Error"))).toEqual({ | |||||
| ad: null, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect(reducer(undefined, setAd(mockState.ads.ads[0]))).toEqual({ | |||||
| ad: mockState.ads.ads[0], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/ad/adsReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setAds, | |||||
| setAdsError, | |||||
| setFilteredAds, | |||||
| setFilteredAdsError, | |||||
| } from "../../../../store/actions/ads/adsAction"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("ads reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| ads: [], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error when setAdsError is called", () => { | |||||
| expect(reducer(undefined, setAdsError("Error"))).toEqual({ | |||||
| ads: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set ads when setAds is called", () => { | |||||
| expect(reducer(undefined, setAds(mockState.ads.ads[0]))).toEqual({ | |||||
| ads: mockState.ads.ads[0], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error when setFilteredAdsError is called", () => { | |||||
| expect(reducer(undefined, setFilteredAdsError("Error"))).toEqual({ | |||||
| ads: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set ads when setFilteredAds is called", () => { | |||||
| expect(reducer(undefined, setFilteredAds(mockState.ads.ads[0]))).toEqual({ | |||||
| ads: mockState.ads.ads[0], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/ad/archiveActiveAdReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| archiveActiveAd, | |||||
| archiveActiveAdError, | |||||
| } from "../../../../store/actions/archiveActiveAd/archiveActiveAdActions"; | |||||
| describe("archiveActiveAd reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, archiveActiveAdError("Error"))).toEqual({ | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect(reducer(undefined, archiveActiveAd())).toEqual({ | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/ad/archiveAdsReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setArchiveAds, | |||||
| setArchiveAdsError, | |||||
| } from "../../../../store/actions/archiveAds/archiveAdsActions"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("archiveAdsReducer reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| archiveAds: [], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setArchiveAdsError("Error"))).toEqual({ | |||||
| archiveAds: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect(reducer(undefined, setArchiveAds(mockState.ads.ads))).toEqual({ | |||||
| archiveAds: mockState.ads.ads, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/ad/createAdReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setCreateAd, | |||||
| setCreateAdError, | |||||
| } from "../../../../store/actions/createAd/createAdActions"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("createAd reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| ad: null, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setCreateAdError("Error"))).toEqual({ | |||||
| ad: null, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect(reducer(undefined, setCreateAd(mockState.ads.ads[0]))).toEqual({ | |||||
| ad: mockState.ads.ads[0], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/technology/addAddTechnologiesReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| changeIsCheckedAddAdValue, | |||||
| resetIsCheckedAddAdValue, | |||||
| setTechnologiesAddAd, | |||||
| setTechnologiesAddAdError, | |||||
| } from "../../../store/actions/addAdTechnologies/addAdTechnologiesActions"; | |||||
| describe("ad technologies reducer", () => { | |||||
| it("should set techologies", () => { | |||||
| expect( | |||||
| reducer(undefined, setTechnologiesAddAd(["tech1", "tech2"])) | |||||
| ).toEqual({ | |||||
| technologies: ["tech1", "tech2"], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set error", () => { | |||||
| expect(reducer(undefined, setTechnologiesAddAdError("Error"))).toEqual({ | |||||
| technologies: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should check tech", () => { | |||||
| expect( | |||||
| reducer( | |||||
| { | |||||
| technologies: [ | |||||
| { technologyId: 1, name: "T1", isChecked: false }, | |||||
| { technologyId: 2, name: "T2", isChecked: false }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }, | |||||
| changeIsCheckedAddAdValue(1) | |||||
| ) | |||||
| ).toEqual({ | |||||
| technologies: [ | |||||
| { technologyId: 1, name: "T1", isChecked: true }, | |||||
| { technologyId: 2, name: "T2", isChecked: false }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should reset checked tech", () => { | |||||
| expect( | |||||
| reducer( | |||||
| { | |||||
| technologies: [ | |||||
| { technologyId: 1, name: "T1", isChecked: true }, | |||||
| { technologyId: 2, name: "T2", isChecked: true }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }, | |||||
| resetIsCheckedAddAdValue() | |||||
| ) | |||||
| ).toEqual({ | |||||
| technologies: [ | |||||
| { technologyId: 1, name: "T1", isChecked: false }, | |||||
| { technologyId: 2, name: "T2", isChecked: false }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/applicants/applyForAdReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| applyForAd, | |||||
| applyForAdError, | |||||
| } from "../../../store/actions/applyForAd/applyForAdActions"; | |||||
| describe("applyForAd reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, applyForAdError("Error"))).toEqual({ | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect(reducer(undefined, applyForAd())).toEqual({ | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/candidates/candidateOptionsReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| fetchCandidateOptionsSuccess, | |||||
| fetchCandidateOptionsError, | |||||
| } from "../../../store/actions/candidates/candidatesActions"; | |||||
| import { mockState } from "../../../mockState"; | |||||
| describe("candidatesOptions reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| options: [], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, fetchCandidateOptionsError("Error"))).toEqual({ | |||||
| options: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set options", () => { | |||||
| expect( | |||||
| reducer( | |||||
| undefined, | |||||
| fetchCandidateOptionsSuccess(mockState.options.options) | |||||
| ) | |||||
| ).toEqual({ | |||||
| options: mockState.options.options, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/candidate/candidateReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| fetchCandidateSuccess, | |||||
| fetchCandidateError, | |||||
| createCandidateCommentSuccess, | |||||
| createCandidateCommentError, | |||||
| deleteCandidateError, | |||||
| deleteCandidateSuccess, | |||||
| } from "../../../store/actions/candidate/candidateActions"; | |||||
| import { mockState } from "../../../mockState"; | |||||
| describe("candidate reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| candidate: {}, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error when fetchCandidateError is called", () => { | |||||
| expect(reducer(undefined, fetchCandidateError("Error"))).toEqual({ | |||||
| candidate: {}, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set candidate when fetchCandidateSuccess is called", () => { | |||||
| expect( | |||||
| reducer(undefined, fetchCandidateSuccess(mockState.candidate.candidate)) | |||||
| ).toEqual({ | |||||
| candidate: mockState.candidate.candidate, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error when createCandidateCommentError is called", () => { | |||||
| expect(reducer(undefined, createCandidateCommentError("Error"))).toEqual({ | |||||
| candidate: {}, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| // problem with comparing dateOfSending property of two states | |||||
| // it("should add new comment for canidate", () => { | |||||
| // const obj = { | |||||
| // myObj: { content: "sfsdfsd" }, | |||||
| // user: mockState.user.user, | |||||
| // }; | |||||
| // expect( | |||||
| // reducer( | |||||
| // { candidate: mockState.candidate.candidate, errorMessage: "" }, | |||||
| // createCandidateCommentSuccess(obj) | |||||
| // ) | |||||
| // ).toEqual({ | |||||
| // candidate: { ...mockState.candidate.candidate, obj }, | |||||
| // errorMessage: "", | |||||
| // }); | |||||
| // }); | |||||
| it("should set the state error when deleteCandidateError is called", () => { | |||||
| expect(reducer(undefined, deleteCandidateError("Error"))).toEqual({ | |||||
| candidate: {}, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set candidate when deleteCandidateSuccess is called", () => { | |||||
| fetchCandidateSuccess(mockState.candidate.candidate); | |||||
| expect(reducer(undefined, deleteCandidateSuccess())).toEqual({ | |||||
| candidate: {}, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/candidates/candidatesReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| filterCandidatesError, | |||||
| filterCandidatesSuccess, | |||||
| fetchAdsCandidatesSuccess, | |||||
| fetchAdsCandidatesError, | |||||
| } from "../../../store/actions/candidates/candidatesActions"; | |||||
| import { mockState } from "../../../mockState"; | |||||
| describe("candidates reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| candidates: [], | |||||
| adsCandidates: [], | |||||
| errorMessage: "", | |||||
| pagination: 0, | |||||
| }); | |||||
| }); | |||||
| it("should set the state error when filterCandidates is called", () => { | |||||
| expect(reducer(undefined, filterCandidatesError("Error"))).toEqual({ | |||||
| candidates: [], | |||||
| adsCandidates: [], | |||||
| errorMessage: "Error", | |||||
| pagination: 0, | |||||
| }); | |||||
| }); | |||||
| it("should set candidates and pagination", () => { | |||||
| expect( | |||||
| reducer( | |||||
| undefined, | |||||
| filterCandidatesSuccess({ items: [mockState.candidates[0]], total: 1 }) | |||||
| ) | |||||
| ).toEqual({ | |||||
| candidates: [mockState.candidates[0]], | |||||
| adsCandidates: [], | |||||
| errorMessage: "", | |||||
| pagination: 1, | |||||
| }); | |||||
| }); | |||||
| it("should set the state error when fetchAdsCandidates is called ", () => { | |||||
| expect(reducer(undefined, fetchAdsCandidatesError("Error"))).toEqual({ | |||||
| candidates: [], | |||||
| adsCandidates: [], | |||||
| errorMessage: "Error", | |||||
| pagination: 0, | |||||
| }); | |||||
| }); | |||||
| it("should set adsCandidates", () => { | |||||
| expect( | |||||
| reducer( | |||||
| undefined, | |||||
| fetchAdsCandidatesSuccess(mockState.candidates.adsCandidates) | |||||
| ) | |||||
| ).toEqual({ | |||||
| candidates: [], | |||||
| adsCandidates: mockState.candidates.adsCandidates, | |||||
| errorMessage: "", | |||||
| pagination: 0, | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/pattern/createPatternReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| createPattern, | |||||
| createPatternError, | |||||
| } from "../../../../store/actions/createPattern/createPatternActions"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("createPattern reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| pattern: null, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, createPatternError("Error"))).toEqual({ | |||||
| pattern: null, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect( | |||||
| reducer(undefined, createPattern(mockState.patterns.patterns)) | |||||
| ).toEqual({ | |||||
| pattern: mockState.patterns.patterns, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/pattern/patternApplicantsReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setPatternApplicants, | |||||
| setPatternApplicantsError, | |||||
| } from "../../../../store/actions/patternApplicants/patternApplicantsActions"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("patternApplicants reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| patternApplicants: [], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setPatternApplicantsError("Error"))).toEqual({ | |||||
| patternApplicants: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect( | |||||
| reducer(undefined, setPatternApplicants(mockState.patterns.patterns)) | |||||
| ).toEqual({ | |||||
| patternApplicants: mockState.patterns.patterns, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/pattern/patternReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setPattern, | |||||
| setPatternError, | |||||
| } from "../../../../store/actions/pattern/patternActions"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("pattern reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| pattern: null, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setPatternError("Error"))).toEqual({ | |||||
| pattern: null, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect( | |||||
| reducer(undefined, setPattern(mockState.patterns.patterns[0])) | |||||
| ).toEqual({ | |||||
| pattern: mockState.patterns.patterns[0], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/pattern/patternsReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setPatterns, | |||||
| setPatternsError, | |||||
| setFilteredPatterns, | |||||
| setFilteredPatternsError, | |||||
| } from "../../../../store/actions/patterns/patternsActions"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("patterns reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| patterns: [], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error when setPatternsError is called", () => { | |||||
| expect(reducer(undefined, setPatternsError("Error"))).toEqual({ | |||||
| patterns: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success when setPatterns is called", () => { | |||||
| expect( | |||||
| reducer(undefined, setPatterns(mockState.patterns.patterns)) | |||||
| ).toEqual({ | |||||
| patterns: mockState.patterns.patterns, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error when setFilteredPatternsError is called", () => { | |||||
| expect(reducer(undefined, setFilteredPatternsError("Error"))).toEqual({ | |||||
| patterns: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success when setFilteredPatterns is called", () => { | |||||
| expect( | |||||
| reducer(undefined, setFilteredPatterns(mockState.patterns.patterns)) | |||||
| ).toEqual({ | |||||
| patterns: mockState.patterns.patterns, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/pattern/scheduleAppointmentReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| scheduleAppointment, | |||||
| scheduleAppointmentError, | |||||
| clearNotSentEmailsArray, | |||||
| } from "../../../../store/actions/scheduleAppointment/scheduleAppointmentActions"; | |||||
| describe("patterns reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| notSentEmails: null, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error when setScheduleAppointmentErrorMessage is called", () => { | |||||
| expect(reducer(undefined, scheduleAppointmentError("Error"))).toEqual({ | |||||
| notSentEmails: null, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success when scheduleAppointment with an empty array as argument is called", () => { | |||||
| expect( | |||||
| reducer(undefined, scheduleAppointment({ notSentEmails: [] })) | |||||
| ).toEqual({ | |||||
| notSentEmails: [], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success when scheduleAppointment with an null as argument is called", () => { | |||||
| expect(reducer(undefined, scheduleAppointment(null))).toEqual({ | |||||
| notSentEmails: null, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success when clearNotSentEmailsArray is called", () => { | |||||
| expect( | |||||
| reducer( | |||||
| { notSentEmails: [], errorMessage: "" }, | |||||
| clearNotSentEmailsArray() | |||||
| ) | |||||
| ).toEqual({ | |||||
| notSentEmails: null, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/pattern/updatePatternReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| updatePattern, | |||||
| updatePatternError, | |||||
| } from "../../../../store/actions/updatePattern/updatePatternActions"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("updatePattern reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| pattern: null, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, updatePatternError("Error"))).toEqual({ | |||||
| pattern: null, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect( | |||||
| reducer(undefined, updatePattern(mockState.patterns.patterns[0])) | |||||
| ).toEqual({ | |||||
| pattern: mockState.patterns.patterns[0], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/processes/applicantWithProcessesReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setApplicant, | |||||
| setApplicantError | |||||
| } from "../../../../store/actions/processes/applicantAction"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("createPattern reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| applicant: {}, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setApplicantError("Error"))).toEqual({ | |||||
| applicant: {}, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect( | |||||
| reducer(undefined, setApplicant(mockState.candidate.candidate)) | |||||
| ).toEqual({ | |||||
| applicant: mockState.candidate.candidate, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/processes/interviewerUpdateReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setUpdateInterviewerSucc, | |||||
| setUpdateInterviewerReq, | |||||
| setUpdateInterviewerErr | |||||
| } from "../../../../store/actions/processes/processAction"; | |||||
| describe("interviewerUpdateReducer reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| updateSuccess: false, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setUpdateInterviewerErr("Error"))).toEqual({ | |||||
| updateSuccess: false, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the updateSuccess to true", () => { | |||||
| expect(reducer(undefined, setUpdateInterviewerSucc())).toEqual({ | |||||
| updateSuccess: true, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the updateSuccess to false", () => { | |||||
| expect(reducer(undefined, setUpdateInterviewerReq())).toEqual({ | |||||
| updateSuccess: false, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/processes/processReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setDoneProcess, | |||||
| setDoneProcessError, | |||||
| } from "../../../../store/actions/processes/processAction"; | |||||
| describe("process reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| doneProcess: false, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setDoneProcessError("Error"))).toEqual({ | |||||
| doneProcess: false, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the doneProcess to true", () => { | |||||
| expect(reducer(undefined, setDoneProcess(true))).toEqual({ | |||||
| doneProcess: true, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the doneProcess to false", () => { | |||||
| expect(reducer(undefined, setDoneProcess(false))).toEqual({ | |||||
| doneProcess: false, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/processes/processesReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setProcesses, | |||||
| setProcessesError, | |||||
| } from "../../../../store/actions/processes/processesAction"; | |||||
| import { mockState } from "../../../../mockState"; | |||||
| describe("processes reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| processes: [], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setProcessesError("Error"))).toEqual({ | |||||
| processes: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect( | |||||
| reducer(undefined, setProcesses(mockState.patterns.processes)) | |||||
| ).toEqual({ | |||||
| processes: mockState.patterns.processes, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/processes/statusReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setStatuses, | |||||
| setStatusesError, | |||||
| changeStatusIsCheckedValue, | |||||
| } from "../../../../store/actions/processes/statusAction"; | |||||
| describe("status reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| statuses: [], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setStatusesError("Error"))).toEqual({ | |||||
| statuses: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the state success", () => { | |||||
| expect(reducer(undefined, setStatuses(["option1", "option2"]))).toEqual({ | |||||
| statuses: ["option1", "option2"], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should not change status because there is no option with name which we send as argument", async () => { | |||||
| expect( | |||||
| reducer( | |||||
| { | |||||
| statuses: [{ name: "option1" }, { name: "option2" }], | |||||
| errorMessage: "", | |||||
| }, | |||||
| changeStatusIsCheckedValue("option3") | |||||
| ) | |||||
| ).toEqual({ | |||||
| statuses: [{ name: "option1" }, { name: "option2" }], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should not change status because there is option with name which we send as argument", async () => { | |||||
| expect( | |||||
| reducer( | |||||
| { | |||||
| statuses: [ | |||||
| { name: "option1", isChecked: false }, | |||||
| { name: "option2", isChecked: false }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }, | |||||
| changeStatusIsCheckedValue("option1") | |||||
| ) | |||||
| ).toEqual({ | |||||
| statuses: [ | |||||
| { name: "option1", isChecked: true }, | |||||
| { name: "option2", isChecked: false }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../../store/reducers/processes/statusUpdateReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| setUpdateStatusReq, | |||||
| setUpdateStatusSucc, | |||||
| setUpdateStatusErr, | |||||
| } from "../../../../store/actions/processes/processAction"; | |||||
| describe("process reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| success: false, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the state error", () => { | |||||
| expect(reducer(undefined, setUpdateStatusErr("Error"))).toEqual({ | |||||
| success: false, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set the success to true", () => { | |||||
| expect(reducer(undefined, setUpdateStatusSucc())).toEqual({ | |||||
| success: true, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set the success to false", () => { | |||||
| expect(reducer(undefined, setUpdateStatusReq())).toEqual({ | |||||
| success: false, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/schedule/scheduleReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| fetchScheduleError, | |||||
| fetchScheduleSuccess, | |||||
| } from "../../../store/actions/schedule/scheduleActions"; | |||||
| describe("schedule reducer", () => { | |||||
| it("should set schedule", () => { | |||||
| expect(reducer(undefined, fetchScheduleSuccess(["1", "2"]))).toEqual({ | |||||
| schedule: ["1", "2"], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set error", () => { | |||||
| expect(reducer(undefined, fetchScheduleError("Error"))).toEqual({ | |||||
| schedule: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/screeningTests/screeningTestsReducer"; | |||||
| import expect from "expect"; | |||||
| import { fetchScreeningTestsError, fetchScreeningTestsSuccess } from "../../../store/actions/screeningTests/screeningTestActions"; | |||||
| describe("screening tests reducer", () => { | |||||
| it("should set tests", () => { | |||||
| expect( | |||||
| reducer(undefined, fetchScreeningTestsSuccess(["test1", "test2"])) | |||||
| ).toEqual({ | |||||
| screeningTests: ["test1", "test2"], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set error", () => { | |||||
| expect(reducer(undefined, fetchScreeningTestsError("Error"))).toEqual({ | |||||
| screeningTests: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/stats/statsReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| getStatsError, | |||||
| getStatsSuccess, | |||||
| } from "../../../store/actions/stats/statsActions"; | |||||
| describe("stats reducer", () => { | |||||
| it("should return the initial state", () => { | |||||
| expect(reducer(undefined, {})).toEqual({ | |||||
| fetchStatsErrorMessage: "", | |||||
| stats: {}, | |||||
| }); | |||||
| }); | |||||
| it("should set error message", () => { | |||||
| expect(reducer(undefined, getStatsError("Error"))).toEqual({ | |||||
| stats: {}, | |||||
| fetchStatsErrorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("Should set state stats", () => { | |||||
| expect(reducer(undefined, getStatsSuccess({ data: "mockData" }))).toEqual({ | |||||
| stats: { data: "mockData" }, | |||||
| fetchStatsErrorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/processes/statusUpdateReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| registerError, | |||||
| registerSuccess, | |||||
| } from "../../../store/actions/register/registerActions"; | |||||
| import { | |||||
| setUpdateStatusErr, | |||||
| setUpdateStatusReq, | |||||
| setUpdateStatusSucc, | |||||
| } from "../../../store/actions/processes/processAction"; | |||||
| describe("status update reducer", () => { | |||||
| it("should set success", () => { | |||||
| expect(reducer(undefined, setUpdateStatusSucc())).toEqual({ | |||||
| success: true, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set error", () => { | |||||
| expect(reducer(undefined, setUpdateStatusErr("Error"))).toEqual({ | |||||
| success: false, | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should set error", () => { | |||||
| expect(reducer(undefined, setUpdateStatusReq("any"))).toEqual({ | |||||
| success: false, | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| import reducer from "../../../store/reducers/technology/technologiesReducer"; | |||||
| import expect from "expect"; | |||||
| import { | |||||
| changeIsCheckedValue, | |||||
| resetIsCheckedValue, | |||||
| setTechnologies, | |||||
| setTechnologiesError, | |||||
| } from "../../../store/actions/technologies/technologiesActions"; | |||||
| describe("technologies reducer", () => { | |||||
| it("should set techologies", () => { | |||||
| expect(reducer(undefined, setTechnologies(["tech1", "tech2"]))).toEqual({ | |||||
| technologies: ["tech1", "tech2"], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should set error", () => { | |||||
| expect(reducer(undefined, setTechnologiesError("Error"))).toEqual({ | |||||
| technologies: [], | |||||
| errorMessage: "Error", | |||||
| }); | |||||
| }); | |||||
| it("should check tech", () => { | |||||
| expect( | |||||
| reducer( | |||||
| { | |||||
| technologies: [ | |||||
| { id: 1, name: "T1", isChecked: false }, | |||||
| { id: 2, name: "T2", isChecked: false }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }, | |||||
| changeIsCheckedValue("T1") | |||||
| ) | |||||
| ).toEqual({ | |||||
| technologies: [ | |||||
| { id: 1, name: "T1", isChecked: true }, | |||||
| { id: 2, name: "T2", isChecked: false }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| it("should reset checked techs", () => { | |||||
| expect( | |||||
| reducer( | |||||
| { | |||||
| technologies: [ | |||||
| { id: 1, name: "T1", isChecked: true }, | |||||
| { id: 2, name: "T2", isChecked: true }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }, | |||||
| resetIsCheckedValue("T1") | |||||
| ) | |||||
| ).toEqual({ | |||||
| technologies: [ | |||||
| { id: 1, name: "T1", isChecked: false }, | |||||
| { id: 2, name: "T2", isChecked: false }, | |||||
| ], | |||||
| errorMessage: "", | |||||
| }); | |||||
| }); | |||||
| }); |
| 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/candidatesRequest"; | |||||
| import { runSaga } from "redux-saga"; | |||||
| import { ADS_CANDIDATES_FETCH } from "../../store/actions/candidates/candidatesActionConstants"; | |||||
| import { getAdsCandidates } from "../../store/saga/candidatesSaga"; | |||||
| import { | |||||
| 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 = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <AdsCandidatesPage search="" /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.candidates.adsCandidates) | |||||
| .mockReturnValueOnce(mockState.candidates.adsCandidates); | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should dispatch get adsCandidates request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: ADS_CANDIDATES_FETCH, | |||||
| payload: { | |||||
| currentPage: 0, | |||||
| employmentType: "", | |||||
| maxDateOfApplication: "", | |||||
| maxExperience: 0, | |||||
| minDateOfApplication: "", | |||||
| minExperience: 0, | |||||
| pageSize: 0, | |||||
| technologies: [], | |||||
| }, | |||||
| }); | |||||
| }); | |||||
| it("should load and handle adsCandidates in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: mockState.candidates.adsCandidates }; | |||||
| api.getFilteredAdsCandidates = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.candidates.adsCandidates, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getAdsCandidates, {}).done; | |||||
| expect(api.getFilteredAdsCandidates.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| fetchAdsCandidatesSuccess(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| 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.technologies.fetchTecnologiesErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getFilteredAdsCandidates = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.candidates.adsCandidates, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getAdsCandidates, {}).done; | |||||
| expect(api.getFilteredAdsCandidates.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| fetchAdsCandidatesError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| }); |
| 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 AdsPage from "../../pages/AdsPage/AdsPage"; | |||||
| import * as api from "../../request/adsRequest"; | |||||
| import { runSaga } from "redux-saga"; | |||||
| import { FETCH_ADS_REQ } from "../../store/actions/ads/adsActionConstants"; | |||||
| import ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import * as fc from "../../store/saga/adsSaga"; | |||||
| import { setAds, setFilteredAds } from "../../store/actions/ads/adsAction"; | |||||
| import { setArchiveAds } from "../../store/actions/archiveAds/archiveAdsActions"; | |||||
| import { setCreateAd } from "../../store/actions/createAd/createAdActions"; | |||||
| import { setAd, setAdError } from "../../store/actions/ad/adActions"; | |||||
| import { archiveActiveAd } from "../../store/actions/archiveActiveAd/archiveActiveAdActions"; | |||||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| describe("Ads reducer tests", () => { | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <AdsPage /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce(mockState.ads); | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should dispatch get ads request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: FETCH_ADS_REQ, | |||||
| }); | |||||
| }); | |||||
| it("Should load and handle ads in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: mockState.ads.ads }; | |||||
| api.getAllAds = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.getAds, {}).done; | |||||
| expect(api.getAllAds.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setAds(mockedCall.data)); | |||||
| }); | |||||
| it("Should load and handle filtered ads in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const filter = { | |||||
| minimumExperience: 0, | |||||
| maximumExperience: 0, | |||||
| technologies: [1], | |||||
| workHour: "FullTime", | |||||
| employmentType: "Work", | |||||
| }; | |||||
| const filteredData = mockState.ads.ads.filter( | |||||
| (ad) => | |||||
| ad.minimumExperience >= filter.minimumExperience && | |||||
| ad.minimumExperience <= filter.maximumExperience && | |||||
| ad.workHour === filter.workHour && | |||||
| ad.employmentType === filter.employmentType | |||||
| ); | |||||
| const mockedCall = { data: filteredData }; | |||||
| api.getAllFilteredAds = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.getFilteredAds, filter).done; | |||||
| expect(api.getAllFilteredAds.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setFilteredAds(mockedCall.data)); | |||||
| }); | |||||
| it("Should load and handle archived ads in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const date = new Date(); | |||||
| const filteredData = mockState.ads.ads.filter((ad) => ad.expiredAt < date); | |||||
| const mockedCall = { data: filteredData }; | |||||
| api.getAllArchiveAds = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.getArchiveAds, {}).done; | |||||
| expect(api.getAllArchiveAds.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setArchiveAds(mockedCall.data)); | |||||
| }); | |||||
| it("Should load and handle ad by id in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const id = 1; | |||||
| const filteredData = mockState.ads.ads.filter((ad) => ad.id === id); | |||||
| const mockedCall = { data: filteredData }; | |||||
| api.getAdDetailsById = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.getAd, { payload: id }).done; | |||||
| expect(api.getAdDetailsById.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setAd(mockedCall.data)); | |||||
| }); | |||||
| it("Should create ad", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { | |||||
| data: { | |||||
| title: "React Developer", | |||||
| minimumExperience: 1, | |||||
| createdAt: new Date(), | |||||
| expiredAt: new Date("2023-5-5"), | |||||
| keyResponsibilities: "key responsibilities", | |||||
| requirements: "requirements", | |||||
| offer: "offer", | |||||
| workHour: "PartTime", | |||||
| employmentType: "Intership", | |||||
| technologiesIds: [1, 2], | |||||
| onSuccessAddAd: jest.fn, | |||||
| }, | |||||
| }; | |||||
| api.createNewAd = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.createAd, { | |||||
| payload: { | |||||
| title: "React Developer", | |||||
| minimumExperience: 1, | |||||
| createdAt: new Date(), | |||||
| expiredAt: new Date("2023-5-5"), | |||||
| keyResponsibilities: "key responsibilities", | |||||
| requirements: "requirements", | |||||
| offer: "offer", | |||||
| workHour: "PartTime", | |||||
| employmentType: "Intership", | |||||
| technologiesIds: [1, 2], | |||||
| onSuccessAddAd: jest.fn, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.createNewAd.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setCreateAd(mockedCall.data)); | |||||
| }); | |||||
| it("Archive ad", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { | |||||
| data: { | |||||
| id: 1, | |||||
| navigateToAds: jest.fn, | |||||
| }, | |||||
| }; | |||||
| api.archiveActiveAdRequest = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.archiveActiveAdSaga, { | |||||
| payload: { | |||||
| id: 1, | |||||
| navigateToAds: jest.fn, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.archiveActiveAdRequest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(archiveActiveAd(mockedCall.data)); | |||||
| }); | |||||
| it("Should not return ads when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.getAllAds = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.getAds, {}).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not return filtered ads when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| const filter = { | |||||
| minimumExperience: 0, | |||||
| maximumExperience: 0, | |||||
| technologies: [1], | |||||
| workHour: "FullTime", | |||||
| employmentType: "Work", | |||||
| }; | |||||
| api.getFilteredAds = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.getFilteredAds, filter).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not return ad when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.getAd = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.getAd, { | |||||
| payload: { | |||||
| id: 1, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not return archived ad when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.getAd = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.getArchiveAds, {}).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not create ad when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.createNewAd = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.createAd, { | |||||
| payload: { | |||||
| title: "React Developer", | |||||
| minimumExperience: 1, | |||||
| createdAt: new Date(), | |||||
| expiredAt: new Date("2023-5-5"), | |||||
| keyResponsibilities: "key responsibilities", | |||||
| requirements: "requirements", | |||||
| offer: "offer", | |||||
| workHour: "PartTime", | |||||
| employmentType: "Intership", | |||||
| technologiesIds: [1, 2], | |||||
| onSuccessAddAd: jest.fn, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should archive active ad when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.createNewAd = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.archiveActiveAdSaga, { | |||||
| payload: { | |||||
| id: 1, | |||||
| navigateToAds: jest.fn, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("should handle ad load errors in case of failure", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.getAd = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.ads.ads, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.getAd, { | |||||
| payload: { | |||||
| id: 1, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.getAdDetailsById.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setAdError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| }); |
| import { runSaga } from "redux-saga"; | |||||
| import * as api from "../../request/applicantRequest"; | |||||
| import * as redux from "react-redux"; | |||||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| import { applyForAd, applyForAdError } from "../../store/actions/applyForAd/applyForAdActions"; | |||||
| import { applyForAdSaga } from "../../store/saga/applicantsSaga"; | |||||
| describe("applicants tests saga tests", () => { | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce("anything"); | |||||
| // Mock useDispatch hook | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should handle applyForAdSaga saga with actions", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: "Data" }; | |||||
| api.applyForAdRequest = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.users, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| const mockfn = jest.fn() | |||||
| await runSaga(fakeStore, applyForAdSaga, { | |||||
| payload: { | |||||
| adId: "", | |||||
| firstName: "", | |||||
| lastName: "", | |||||
| gender: "", | |||||
| dateOfBirth: "", | |||||
| phoneNumber: "", | |||||
| professionalQualification: "", | |||||
| technologiesIds: "", | |||||
| experience: "", | |||||
| linkedinLink: "", | |||||
| githubLink: "", | |||||
| bitBucketLink: "", | |||||
| email: "", | |||||
| coverLetter: "", | |||||
| pdfFile: "", | |||||
| handleApiResponseSuccess: mockfn | |||||
| }, | |||||
| }).done; | |||||
| expect(api.applyForAdRequest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(applyForAd(mockedCall.data)); | |||||
| expect(mockfn).toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should handle apply for ad saga with errors", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| const mockedCall = { response: { data: { message: "Error" } } }; | |||||
| api.applyForAdRequest = jest.fn(() => Promise.reject(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.users, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, applyForAdSaga, { | |||||
| payload: { | |||||
| adId: "", | |||||
| firstName: "", | |||||
| lastName: "", | |||||
| gender: "", | |||||
| dateOfBirth: "", | |||||
| phoneNumber: "", | |||||
| professionalQualification: "", | |||||
| technologiesIds: "", | |||||
| experience: "", | |||||
| linkedinLink: "", | |||||
| githubLink: "", | |||||
| bitBucketLink: "", | |||||
| email: "", | |||||
| coverLetter: "", | |||||
| pdfFile: "", | |||||
| }, | |||||
| }).done; | |||||
| expect(api.applyForAdRequest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(applyForAdError("Error")); | |||||
| }); | |||||
| }); |
| 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/candidatesRequest"; | |||||
| import * as api2 from '../../request/usersRequest'; | |||||
| import { runSaga } from "redux-saga"; | |||||
| import { CANDIDATE_FETCH } from "../../store/actions/candidate/candidateActionConstants"; | |||||
| import { FETCH_USERS_REQ } from "../../store/actions/users/usersActionConstants"; | |||||
| import { getSingleCandidate } from "../../store/saga/candidatesSaga"; | |||||
| import {getUsers} from '../../store/saga/usersSaga' | |||||
| import { | |||||
| fetchCandidateSuccess, | |||||
| fetchCandidateError, | |||||
| } from "../../store/actions/candidate/candidateActions"; | |||||
| import { | |||||
| setUsers, | |||||
| setUsersError | |||||
| } from "../../store/actions/users/usersActions"; | |||||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| import CandidateDetailsPage from "../../pages/CandidatesPage/CandidateDetailsPage"; | |||||
| const mockHistoryPush = jest.fn(); | |||||
| // mock param which we send as part of URL | |||||
| jest.mock("react-router-dom", () => ({ | |||||
| ...jest.requireActual("react-router-dom"), | |||||
| useHistory: () => ({ | |||||
| push: mockHistoryPush, | |||||
| }), | |||||
| useParams: () => ({ | |||||
| id: 1, | |||||
| }), | |||||
| })); | |||||
| describe("CandidateDetailsPage render tests", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <CandidateDetailsPage {...props} /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.users.users) | |||||
| .mockReturnValueOnce(mockState.users.user) | |||||
| .mockReturnValueOnce(mockState.candidate.candidate); | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should dispatch fetch candidate request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| payload: { id: 1 }, | |||||
| type: CANDIDATE_FETCH, | |||||
| }); | |||||
| }); | |||||
| it("Should dispatch fetch users request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: FETCH_USERS_REQ, | |||||
| }); | |||||
| }); | |||||
| it("should load and handle candidate in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: mockState.candidate.candidate }; | |||||
| api.getCandidate = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.candidate.candidate, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getSingleCandidate, { payload: { id: 1 } }).done; | |||||
| expect(api.getCandidate.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| fetchCandidateSuccess(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| it("should load and handle users in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: mockState.users.users }; | |||||
| api2.getAllUsers = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.users.users, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getUsers).done; | |||||
| expect(api2.getAllUsers.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setUsers(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| it("should handle candidate load errors in case of failure", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn( | |||||
| () => mockState.candidate.fetchCandidateErrorMessage | |||||
| ); | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.candidate.fetchCandidateErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getCandidate = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.candidate.candidate, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getSingleCandidate, { payload: { id: 1 } }).done; | |||||
| expect(api.getCandidate.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| fetchCandidateError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| it("should handle users load errors in case of failure", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn( | |||||
| () => mockState.users.fetchUsersErrorMessage | |||||
| ); | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.users.fetchUsersErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api2.getAllUsers = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.users.users, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getUsers).done; | |||||
| expect(api2.getAllUsers.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setUsersError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| }); |
| 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 CandidatesPage from "../../pages/CandidatesPage/CandidatesPage"; | |||||
| import * as api from "../../request/technologiesRequest"; | |||||
| import { runSaga } from "redux-saga"; | |||||
| import { FETCH_TECHNOLOGIES_REQ } from "../../store/actions/technologies/technologiesActionConstants"; | |||||
| import { getTechnologies } from "../../store/saga/technologiesSaga"; | |||||
| import { | |||||
| setTechnologies, | |||||
| setTechnologiesError, | |||||
| } from "../../store/actions/technologies/technologiesActions"; | |||||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| describe("CandidatesPage render tests", () => { | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <CandidatesPage /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce(mockState.technologies.technologies); | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should dispatch get technologies request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: FETCH_TECHNOLOGIES_REQ, | |||||
| }); | |||||
| }); | |||||
| it("should load and handle techonologies in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: mockState.technologies.technologies }; | |||||
| api.getAllTechnologies = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| 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(setTechnologies(mockedCall.data)); | |||||
| }); | |||||
| it("should handle technologies load errors in case of failure", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => mockState.candidates.fetchCandidatesErrorMessage); | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.candidates.fetchCandidatesErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getAllTechnologies = jest.fn(() => Promise.reject(error)); | |||||
| 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) | |||||
| ); | |||||
| }); | |||||
| }); |
| import * as redux from "react-redux"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import * as api from "../../request/candidatesRequest"; | |||||
| import { | |||||
| filterCandidatesError, | |||||
| filterCandidatesSuccess, | |||||
| fetchCandidateOptionsSuccess, | |||||
| fetchCandidateOptionsError, | |||||
| fetchInitProcessError, | |||||
| fetchInitProcessSuccess, | |||||
| } from "../../store/actions/candidates/candidatesActions"; | |||||
| import { | |||||
| fetchCandidateError, | |||||
| fetchCandidateSuccess, | |||||
| deleteCandidateError, | |||||
| deleteCandidateSuccess, | |||||
| createCandidateComment, | |||||
| createCandidateCommentError, | |||||
| createCandidateCommentSuccess, | |||||
| } from "../../store/actions/candidate/candidateActions"; | |||||
| import { runSaga } from "redux-saga"; | |||||
| import { | |||||
| filterCandidates as k, | |||||
| getSingleCandidate, | |||||
| deleteSingleCandidate, | |||||
| getOptions, | |||||
| initializeProcess, | |||||
| addComment, | |||||
| } from "../../store/saga/candidatesSaga"; | |||||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| describe("candidatesSaga reducer tests", () => { | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce(mockState.candidates.candidates); | |||||
| // Mock useDispatch hook | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| // filterCandidates | |||||
| it("should run filterCandidates saga function with actions", async () => { | |||||
| const dispatchedActions = []; | |||||
| api.getFilteredCandidates = jest.fn(() => Promise.resolve({})); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, k, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.getFilteredCandidates.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(filterCandidatesSuccess()); | |||||
| }); | |||||
| it("should call handleApiResponseSuccess inside filterCandidates saga function", async () => { | |||||
| const dispatchedActions = []; | |||||
| api.getFilteredCandidates = jest.fn(() => Promise.resolve({})); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| const mockFn = jest.fn(); | |||||
| await runSaga(fakeStore, k, { | |||||
| payload: { | |||||
| data: {}, | |||||
| handleApiResponseSuccess: mockFn, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockFn).toHaveBeenCalled(); | |||||
| }); | |||||
| it("should handle error inside filterCandidates saga function", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { response: { data: { message: "Error" } } }; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| api.getFilteredCandidates = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, k, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.getFilteredCandidates.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(filterCandidatesError("Error")); | |||||
| }); | |||||
| // getSingleCandidate | |||||
| it("should run getSingleCandidate saga function with actions", async () => { | |||||
| const dispatchedActions = []; | |||||
| api.getCandidate = jest.fn(() => Promise.resolve({})); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getSingleCandidate, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.getCandidate.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(fetchCandidateSuccess()); | |||||
| }); | |||||
| it("should handle error inside getSingleCandidate saga function", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { response: { data: { message: "Error" } } }; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| api.getCandidate = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getSingleCandidate, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.getCandidate.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(fetchCandidateError("Error")); | |||||
| }); | |||||
| // addComment | |||||
| // it("should run addComment saga function with actions", async () => { | |||||
| // const dispatchedActions = []; | |||||
| // api.createComment = jest.fn(() => | |||||
| // Promise.resolve({ payload: { user: {} } }) | |||||
| // ); | |||||
| // const fakeStore = { | |||||
| // getState: () => ({ | |||||
| // isSuccess: false, | |||||
| // errorMessage: "", | |||||
| // }), | |||||
| // dispatch: (action) => dispatchedActions.push(action), | |||||
| // }; | |||||
| // await runSaga(fakeStore, addComment, { | |||||
| // payload: { user: {} }, | |||||
| // }).done; | |||||
| // expect(api.createComment.mock.calls.length).toBe(1); | |||||
| // expect(dispatchedActions).toContainEqual(createCandidateCommentSuccess()); | |||||
| // }); | |||||
| it("should handle error inside getSingleCandidate saga function", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { response: { data: { message: "Error" } } }; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| api.createComment = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, addComment, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.createComment.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| createCandidateCommentError("Error") | |||||
| ); | |||||
| }); | |||||
| // deleteSingleCandidate | |||||
| it("should run deleteSingleCandidate saga function with actions", async () => { | |||||
| const dispatchedActions = []; | |||||
| api.deleteCandidate = jest.fn(() => Promise.resolve({})); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, deleteSingleCandidate, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.deleteCandidate.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(deleteCandidateSuccess()); | |||||
| }); | |||||
| it("should call handleApiResponseSuccess inside filterCandidates saga function", async () => { | |||||
| const dispatchedActions = []; | |||||
| api.deleteCandidate = jest.fn(() => Promise.resolve({})); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| const mockFn = jest.fn(); | |||||
| await runSaga(fakeStore, deleteSingleCandidate, { | |||||
| payload: { | |||||
| data: {}, | |||||
| handleApiResponseSuccess: mockFn, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockFn).toHaveBeenCalled(); | |||||
| }); | |||||
| it("should handle error inside deleteSingleCandidate saga function", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { response: { data: { message: "Error" } } }; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| api.deleteCandidate = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, deleteSingleCandidate, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.deleteCandidate.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(deleteCandidateError("Error")); | |||||
| }); | |||||
| // getOptions | |||||
| it("should run getOptions saga function with actions", async () => { | |||||
| const dispatchedActions = []; | |||||
| api.getCandidateOptions = jest.fn(() => Promise.resolve({})); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getOptions, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.getCandidateOptions.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(fetchCandidateOptionsSuccess()); | |||||
| }); | |||||
| it("should handle error inside getOptions saga function", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { response: { data: { message: "Error" } } }; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| api.getCandidateOptions = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getOptions, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.getCandidateOptions.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| fetchCandidateOptionsError("Error") | |||||
| ); | |||||
| }); | |||||
| // initializeProcess | |||||
| it("should run initializeProcess saga function with actions", async () => { | |||||
| const dispatchedActions = []; | |||||
| api.initializeProcessRequest = jest.fn(() => Promise.resolve({})); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, initializeProcess, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.initializeProcessRequest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(fetchInitProcessSuccess()); | |||||
| }); | |||||
| it("should handle error inside initializeProcess saga function", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { response: { data: { message: "Error" } } }; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| api.initializeProcessRequest = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => ({ | |||||
| isSuccess: false, | |||||
| errorMessage: "", | |||||
| }), | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, initializeProcess, { | |||||
| payload: { | |||||
| data: {}, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.initializeProcessRequest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(fetchInitProcessError("Error")); | |||||
| }); | |||||
| }); |
| 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 PatternsPage from "../../pages/PatternsPage/PatternsPage"; | |||||
| import * as api from "../../request/patternsRequest"; | |||||
| import { runSaga } from "redux-saga"; | |||||
| import { FETCH_PATTERNS_REQ } from "../../store/actions/patterns/patternsActionConstants"; | |||||
| import ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import * as fc from "../../store/saga/patternsSaga"; | |||||
| import { | |||||
| setFilteredPatterns, | |||||
| setPatterns, | |||||
| } from "../../store/actions/patterns/patternsActions"; | |||||
| import { setPattern } from "../../store/actions/pattern/patternActions"; | |||||
| import { setPatternApplicants } from "../../store/actions/patternApplicants/patternApplicantsActions"; | |||||
| import { createPattern } from "../../store/actions/createPattern/createPatternActions"; | |||||
| import { updatePattern } from "../../store/actions/updatePattern/updatePatternActions"; | |||||
| import { scheduleAppointment } from "../../store/actions/scheduleAppointment/scheduleAppointmentActions"; | |||||
| describe("Patterns reducer tests", () => { | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <PatternsPage /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce(mockState.patterns); | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should dispatch get patterns request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: FETCH_PATTERNS_REQ, | |||||
| }); | |||||
| }); | |||||
| it("Should load and handle patterns in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: mockState.patterns.patterns }; | |||||
| api.getAllPatterns = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.getPatterns, {}).done; | |||||
| expect(api.getAllPatterns.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setPatterns(mockedCall.data)); | |||||
| }); | |||||
| it("Should load and handle pattern by id in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const id = 1; | |||||
| const filteredData = mockState.patterns.patterns.filter( | |||||
| (pattern) => pattern.id === id | |||||
| ); | |||||
| const mockedCall = { data: filteredData }; | |||||
| api.getPatternById = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.getPattern, { payload: id }).done; | |||||
| expect(api.getPatternById.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setPattern(mockedCall.data)); | |||||
| }); | |||||
| it("Should load and handle pattern applicants in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const id = 1; | |||||
| const filteredData = mockState.patterns.patterns.filter( | |||||
| (pattern) => pattern.id === id | |||||
| ); | |||||
| const mockedCall = { | |||||
| data: { | |||||
| ...filteredData[0].selectionLevel.selectionProcesses[0].applicant, | |||||
| }, | |||||
| }; | |||||
| api.getPatternApplicantsById = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.getPatternApplicants, { payload: id }).done; | |||||
| expect(api.getPatternApplicantsById.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setPatternApplicants(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| it("Should load and handle filtered patterns in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const filters = { | |||||
| fromDate: new Date("2-2-2021"), | |||||
| toDate: new Date("3-3-2023"), | |||||
| selectionLevels: [1, 2], | |||||
| }; | |||||
| const filteredData = mockState.patterns.patterns.filter( | |||||
| (pattern) => | |||||
| pattern.createdAt >= filters.fromDate && | |||||
| pattern.createdAt <= filters.toDate | |||||
| ); | |||||
| const mockedCall = { | |||||
| data: filteredData, | |||||
| }; | |||||
| api.getFilteredPatterns = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.filterPatterns, filters).done; | |||||
| expect(api.getFilteredPatterns.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setFilteredPatterns(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| it("Should create new pattern", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { | |||||
| data: { | |||||
| title: "Neuspesan korak", | |||||
| selectionLevelId: 1, | |||||
| message: "Poruka", | |||||
| }, | |||||
| }; | |||||
| api.createPatternRequest = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.createPatternSaga, { | |||||
| payload: { | |||||
| title: "Neuspesan korak", | |||||
| selectionLevelId: 1, | |||||
| message: "Poruka", | |||||
| }, | |||||
| }).done; | |||||
| expect(api.createPatternRequest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(createPattern(mockedCall.data)); | |||||
| }); | |||||
| it("Should update pattern", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { | |||||
| data: { | |||||
| id: 1, | |||||
| title: "Zakazan intervju", | |||||
| createdAt: new Date(), | |||||
| selectionLevelId: 1, | |||||
| message: "Message", | |||||
| }, | |||||
| }; | |||||
| api.updatePatternRequest = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.updatePatternSaga, { | |||||
| payload: { | |||||
| id: 1, | |||||
| title: "Zakazan intervju", | |||||
| createdAt: new Date(), | |||||
| selectionLevelId: 1, | |||||
| message: "Message", | |||||
| }, | |||||
| }).done; | |||||
| expect(api.updatePatternRequest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(updatePattern(mockedCall.data)); | |||||
| }); | |||||
| it("Should schedule appointment", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { | |||||
| data: { | |||||
| emails: ["ermin.bronja@dilig.net"], | |||||
| patternId: 1, | |||||
| handleApiResponseSuccess: jest.fn, | |||||
| }, | |||||
| }; | |||||
| api.scheduleAppointmentRequest = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.scheduleAppointmentSaga, { | |||||
| payload: { | |||||
| emails: ["ermin.bronja@dilig.net"], | |||||
| patternId: 1, | |||||
| handleApiResponseSuccess: jest.fn, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.scheduleAppointmentRequest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| scheduleAppointment(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| it("Should not return patterns when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.getAllPatterns = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.getPatterns, {}).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not return pattern when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.getPatternById = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.getPattern, { | |||||
| payload: { | |||||
| id: 1, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not return pattern applicants when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.getPatternApplicants = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.getPatternApplicants, { | |||||
| payload: { | |||||
| id: 1, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not return filtered patterns when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.getFilteredPatterns = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.filterPatterns, { | |||||
| fromDate: new Date("2-2-2021"), | |||||
| toDate: new Date("3-3-2023"), | |||||
| selectionLevels: [1, 2], | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not create pattern when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.createPatternRequest = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.createPatternSaga, { | |||||
| payload: { | |||||
| title: "Neuspesan korak", | |||||
| selectionLevelId: 1, | |||||
| message: "Poruka", | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not update pattern when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.updatePatternRequest = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.updatePatternSaga, { | |||||
| payload: { | |||||
| id: 1, | |||||
| title: "Zakazan intervju", | |||||
| createdAt: new Date(), | |||||
| selectionLevelId: 1, | |||||
| message: "Message", | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should not chedule appointment when exception was thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: "Error" }, | |||||
| }, | |||||
| }; | |||||
| api.scheduleAppointmentRequest = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.patterns.patterns, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, fc.scheduleAppointmentSaga, { | |||||
| payload: { | |||||
| emails: ["ermin.bronja@dilig.net"], | |||||
| patternId: 1, | |||||
| handleApiResponseSuccess: jest.fn, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| }); |
| import { runSaga } from "redux-saga"; | |||||
| import * as api from "../../request/processesReguest"; | |||||
| import { render } from "@testing-library/react"; | |||||
| import * as redux from "react-redux"; | |||||
| import SelectionProcessPage from "../../pages/selectionProcessPage/selectionProcessPage"; | |||||
| ("../../pages/SelectionProcessPage/SelectionProcessPage"); | |||||
| import store from "../../store"; | |||||
| import "../../i18n"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { FETCH_PROCESSES_REQ } from "../../store/actions/processes/processesActionConstants"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import history from "../../store/utils/history"; | |||||
| import { | |||||
| getProcesses, | |||||
| getFilteredProcesses, | |||||
| finishProcess, | |||||
| changeStatus, | |||||
| changeInterviewer, | |||||
| getApplicantProcesses, | |||||
| } from "../../store/saga/processSaga"; | |||||
| import { | |||||
| setProcesses, | |||||
| setProcessesError, | |||||
| } from "../../store/actions/processes/processesAction"; | |||||
| import { SelectionProvider } from "../../context/SelectionContext"; | |||||
| import { | |||||
| setDoneProcess, | |||||
| setDoneProcessError, | |||||
| setUpdateInterviewerErr, | |||||
| setUpdateInterviewerSucc, | |||||
| setUpdateStatusErr, | |||||
| setUpdateStatusSucc, | |||||
| } from "../../store/actions/processes/processAction"; | |||||
| import { | |||||
| setApplicant, | |||||
| setApplicantError, | |||||
| } from "../../store/actions/processes/applicantAction"; | |||||
| describe("SelectionProcessPage render tests", () => { | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <SelectionProvider> | |||||
| <Router history={history}> | |||||
| <SelectionProcessPage /> | |||||
| </Router> | |||||
| </SelectionProvider> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.selections) | |||||
| .mockReturnValueOnce(mockState.selections.processes) | |||||
| .mockReturnValueOnce(mockState.selections.statuses); | |||||
| // Mock useDispatch hook | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should dispatch get processes request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: FETCH_PROCESSES_REQ, | |||||
| }); | |||||
| }); | |||||
| it("should load and handle levels with processes in case of success", async () => { | |||||
| // we push all dispatched actions to make assertions easier | |||||
| // and our tests less brittle | |||||
| const dispatchedActions = []; | |||||
| // we don't want to perform an actual api call in our tests | |||||
| // so we will mock the getAllUsers api with jest | |||||
| // this will mutate the dependency which we may reset if other tests | |||||
| // are dependent on it | |||||
| const mockedCall = { data: mockState.selections.processes }; | |||||
| api.getAllLevels = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, getProcesses).done; | |||||
| expect(api.getAllLevels.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setProcesses(mockedCall.data)); | |||||
| }); | |||||
| it("should handle processes load errors in case of failure", async () => { | |||||
| const dispatchedActions = []; | |||||
| // we simulate an error by rejecting the promise | |||||
| // then we assert if our saga dispatched the action(s) correctly | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.selections.fetchSelectionsErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getAllLevels = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.users.users, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getProcesses).done; | |||||
| expect(api.getAllLevels.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setProcessesError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| it("should load and handle levels with filtered processes in case of success", async () => { | |||||
| // we push all dispatched actions to make assertions easier | |||||
| // and our tests less brittle | |||||
| const dispatchedActions = []; | |||||
| const filter = { | |||||
| statuses: ["Zakazan", "Odrađen"], | |||||
| dateStart: new Date(2023, 0, 5), | |||||
| dateEnd: new Date(2024, 1, 1), | |||||
| }; | |||||
| const filteredData = []; | |||||
| mockState.selections.processes.forEach((level) => { | |||||
| const filteredLevel = level; | |||||
| filteredLevel.selectionProcesses = level.selectionProcesses.filter( | |||||
| (v) => | |||||
| v.date >= filter.dateStart && | |||||
| v.date <= filter.dateEnd && | |||||
| filter.statuses.includes(v.status) | |||||
| ); | |||||
| filteredData.push(filteredLevel); | |||||
| }); | |||||
| // we don't want to perform an actual api call in our tests | |||||
| // so we will mock the getAllUsers api with jest | |||||
| // this will mutate the dependency which we may reset if other tests | |||||
| // are dependent on it | |||||
| const mockedCall = { data: filteredData }; | |||||
| api.getAllFilteredProcessesReq = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, getFilteredProcesses, filter).done; | |||||
| expect(api.getAllFilteredProcessesReq.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setProcesses(filteredData)); | |||||
| }); | |||||
| it("should handle error in case of exception", async () => { | |||||
| const dispatchedActions = []; | |||||
| const filter = { | |||||
| statuses: ["Zakazan", "Odrađen"], | |||||
| dateStart: new Date(2023, 0, 5), | |||||
| dateEnd: new Date(2024, 1, 1), | |||||
| }; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.selections.fetchSelectionsErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getAllFilteredProcessesReq = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, getFilteredProcesses, filter).done; | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setProcessesError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| it("should handle process to set it done in case of success", async () => { | |||||
| // we push all dispatched actions to make assertions easier | |||||
| // and our tests less brittle | |||||
| const dispatchedActions = []; | |||||
| const filter = { | |||||
| statuses: ["Zakazan", "Odrađen"], | |||||
| dateStart: new Date(2023, 0, 5), | |||||
| dateEnd: new Date(2024, 1, 1), | |||||
| }; | |||||
| const filteredData = []; | |||||
| mockState.selections.processes.forEach((level) => { | |||||
| const filteredLevel = level; | |||||
| filteredLevel.selectionProcesses = level.selectionProcesses.filter( | |||||
| (v) => | |||||
| v.date >= filter.dateStart && | |||||
| v.date <= filter.dateEnd && | |||||
| filter.statuses.includes(v.status) | |||||
| ); | |||||
| filteredData.push(filteredLevel); | |||||
| }); | |||||
| // we don't want to perform an actual api call in our tests | |||||
| // so we will mock the getAllUsers api with jest | |||||
| // this will mutate the dependency which we may reset if other tests | |||||
| // are dependent on it | |||||
| const mockedCall = { data: filteredData }; | |||||
| api.getAllFilteredProcessesReq = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, getFilteredProcesses, filter).done; | |||||
| expect(api.getAllFilteredProcessesReq.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setProcesses(filteredData)); | |||||
| }); | |||||
| it("should handle process to set it done in case of finish success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: { isSuccess: true } }; | |||||
| api.doneProcess = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, finishProcess, { | |||||
| payload: { | |||||
| id: 1, | |||||
| name: "Some random name", | |||||
| applicantId: 5, | |||||
| schedulerId: 10, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.doneProcess.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setDoneProcess(mockedCall.data)); | |||||
| }); | |||||
| it("should handle error in case of finish process exception", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.selections.fetchSelectionsErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.doneProcess = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, finishProcess, { | |||||
| payload: { | |||||
| id: 1, | |||||
| name: "Some random name", | |||||
| applicantId: 5, | |||||
| schedulerId: 10, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.doneProcess.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setDoneProcessError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| it("should handle process status update", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: { isSuccess: true } }; | |||||
| api.updateStatus = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, changeStatus, { | |||||
| payload: { | |||||
| data: { | |||||
| schedulerId: 3, | |||||
| appointment: "22-10-2023", | |||||
| newStatus: "Odrađen", | |||||
| processId: 1, | |||||
| }, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.updateStatus.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setUpdateStatusSucc()); | |||||
| }); | |||||
| it("should call responsehandler while handling process status update", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: { isSuccess: true } }; | |||||
| api.updateStatus = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, changeStatus, { | |||||
| payload: { | |||||
| data: { | |||||
| schedulerId: 3, | |||||
| appointment: "22-10-2023", | |||||
| newStatus: "Odrađen", | |||||
| processId: 1, | |||||
| }, | |||||
| responseHandler: mockfn, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).toHaveBeenCalled(); | |||||
| }); | |||||
| it("should handle process status update error if exception is thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.selections.fetchSelectionsErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.updateStatus = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, changeStatus, { | |||||
| payload: { | |||||
| data: { | |||||
| schedulerId: 3, | |||||
| appointment: "22-10-2023", | |||||
| newStatus: "Odrađen", | |||||
| processId: 1, | |||||
| }, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.updateStatus.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setUpdateStatusErr(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| it("should not call responseHandler if exception is thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.selections.fetchSelectionsErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.updateStatus = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, changeStatus, { | |||||
| payload: { | |||||
| data: { | |||||
| schedulerId: 3, | |||||
| appointment: "22-10-2023", | |||||
| newStatus: "Odrađen", | |||||
| processId: 1, | |||||
| }, | |||||
| responseHandler: mockfn, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("should handle interviewer update", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: { isSuccess: true } }; | |||||
| api.updateInterviewer = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, changeInterviewer, { | |||||
| payload: { | |||||
| data: { | |||||
| schedulerId: 1, | |||||
| processId: 2, | |||||
| }, | |||||
| // responseHandler: apiSuccess, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.updateInterviewer.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setUpdateInterviewerSucc()); | |||||
| }); | |||||
| it("should call response handler on change success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: { isSuccess: true } }; | |||||
| api.updateInterviewer = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| const mockfn = jest.fn(); | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, changeInterviewer, { | |||||
| payload: { | |||||
| data: { | |||||
| schedulerId: 1, | |||||
| processId: 2, | |||||
| }, | |||||
| responseHandler: mockfn, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).toHaveBeenCalled(); | |||||
| }); | |||||
| it("should handle interviewer update error if exception is thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.selections.fetchSelectionsErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.updateInterviewer = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, changeInterviewer, { | |||||
| payload: { | |||||
| data: { | |||||
| schedulerId: 1, | |||||
| processId: 2, | |||||
| }, | |||||
| // responseHandler: mockfn, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.updateInterviewer.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setUpdateInterviewerErr(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| it("should not call response handler if exception is thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.selections.fetchSelectionsErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.updateInterviewer = jest.fn(() => Promise.reject(error)); | |||||
| const mockfn = jest.fn(); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, changeInterviewer, { | |||||
| payload: { | |||||
| data: { | |||||
| schedulerId: 1, | |||||
| processId: 2, | |||||
| }, | |||||
| responseHandler: mockfn, | |||||
| }, | |||||
| }).done; | |||||
| expect(mockfn).not.toHaveBeenCalled(); | |||||
| }); | |||||
| it("should handle applicant processess if succeeded", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: {} }; | |||||
| api.getProcessesOfApplicant = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, getApplicantProcesses, { | |||||
| payload: { | |||||
| id: 1, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.getProcessesOfApplicant.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(setApplicant(mockedCall.data)); | |||||
| }); | |||||
| it("should handle applicant processess error if exception is thrown", async () => { | |||||
| const dispatchedActions = []; | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.selections.fetchSelectionsErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getProcessesOfApplicant = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.selections.processes, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| // wait for saga to complete | |||||
| await runSaga(fakeStore, getApplicantProcesses, { | |||||
| payload: { | |||||
| id: 1, | |||||
| }, | |||||
| }).done; | |||||
| expect(api.getProcessesOfApplicant.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| setApplicantError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| }); |
| 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); | |||||
| const date = new Date() | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: SCHEDULE_FETCH, | |||||
| payload: { | |||||
| month: date.getMonth() + 1, | |||||
| year: date.getFullYear(), | |||||
| }, | |||||
| }); | |||||
| }); | |||||
| 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) | |||||
| ); | |||||
| }); | |||||
| }); |
| import { runSaga } from "redux-saga"; | |||||
| import { | |||||
| createScreeningTestError, | |||||
| createScreeningTestSuccess, | |||||
| fetchScreeningTestsError, | |||||
| fetchScreeningTestsSuccess, | |||||
| } from "../../store/actions/screeningTests/screeningTestActions"; | |||||
| import { | |||||
| createScreeningTest, | |||||
| getScreeningTests, | |||||
| } from "../../store/saga/screeningTestsSaga"; | |||||
| import * as api from "../../request/screeningTestRequest"; | |||||
| import * as redux from "react-redux"; | |||||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| describe("screening tests saga tests", () => { | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce("anything"); | |||||
| // Mock useDispatch hook | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should handle get tests saga with actions", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: "Data" }; | |||||
| api.getTests = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.users, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getScreeningTests).done; | |||||
| expect(api.getTests.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| fetchScreeningTestsSuccess(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| it("Should handle get tests saga with errors", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| const mockedCall = { response: { data: { message: "Error" } } }; | |||||
| api.getTests = jest.fn(() => Promise.reject(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.users, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getScreeningTests).done; | |||||
| expect(api.getTests.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(fetchScreeningTestsError("Error")); | |||||
| }); | |||||
| it("Should handle create screening tests saga with actions", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: "Data" }; | |||||
| api.createTest = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.users, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, createScreeningTest, { payload: {} }).done; | |||||
| expect(api.createTest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| createScreeningTestSuccess(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| it("Should handle create screening tests saga with errors", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn(() => "Error"); | |||||
| const mockedCall = { response: { data: { message: "Error" } } }; | |||||
| api.createTest = jest.fn(() => Promise.reject(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.users, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, createScreeningTest, { payload: {} }).done; | |||||
| expect(api.createTest.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(createScreeningTestError("Error")); | |||||
| }); | |||||
| }); |
| 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 StatsPage from "../../pages/StatsPage/StatsPage"; | |||||
| import * as api from "../../request/statsRequests"; | |||||
| import { runSaga } from "redux-saga"; | |||||
| import { | |||||
| getStatsSuccess, | |||||
| getStatsError, | |||||
| } from "../../store/actions/stats/statsActions"; | |||||
| import { FETCH_STATS_REQ } from "../../store/actions/stats/statsActionConstants"; | |||||
| import { getAppStats } from "../../store/saga/statsSaga"; | |||||
| import * as helper from "../../util/helpers/rejectErrorCodeHelper"; | |||||
| describe("Stats reducer tests", () => { | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <StatsPage /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce(mockState); | |||||
| // Mock useDispatch hook | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should dispatch get stats request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: FETCH_STATS_REQ, | |||||
| }); | |||||
| }); | |||||
| it("should load and handle stats in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: mockState }; | |||||
| api.getStats = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getAppStats).done; | |||||
| expect(api.getStats.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual(getStatsSuccess(mockedCall.data)); | |||||
| }); | |||||
| it("should handle stats load errors in case of failure", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn( | |||||
| () => mockState.stats.fetchStatsErrorMessage | |||||
| ); | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.stats.fetchStatsErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getStats = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, getAppStats).done; | |||||
| expect(api.getStats.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| getStatsError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| }); |
| 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 { FILTER_CANDIDATES } from "../../store/actions/candidates/candidatesActionConstants"; | |||||
| import TableViewPage from "../../pages/CandidatesPage/TableViewPage"; | |||||
| import * as api from "../../request/candidatesRequest"; | |||||
| import { runSaga } from "redux-saga"; | |||||
| import * as fc from "../../store/saga/candidatesSaga"; | |||||
| import { | |||||
| filterCandidatesSuccess, | |||||
| filterCandidatesError, | |||||
| } from "../../store/actions/candidates/candidatesActions"; | |||||
| 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 {...props} /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.candidates.candidates) | |||||
| .mockReturnValueOnce(mockState.candidates.pagination); | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should dispatch filter candidates request when rendered", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toHaveBeenCalledWith({ | |||||
| type: FILTER_CANDIDATES, | |||||
| payload: { | |||||
| currentPage: 1, | |||||
| employmentType: "", | |||||
| maxDateOfApplication: "", | |||||
| maxExperience: 0, | |||||
| minDateOfApplication: "", | |||||
| minExperience: 0, | |||||
| pageSize: PAGE_SIZE_CANDIDATES, | |||||
| technologies: [], | |||||
| }, | |||||
| }); | |||||
| }); | |||||
| it("should load and handle candidates in case of success", async () => { | |||||
| const dispatchedActions = []; | |||||
| const mockedCall = { data: mockState.candidates.items }; | |||||
| api.getFilteredCandidates = jest.fn(() => Promise.resolve(mockedCall)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.candidates.items, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.filterCandidates, {}).done; | |||||
| expect(api.getFilteredCandidates.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| filterCandidatesSuccess(mockedCall.data) | |||||
| ); | |||||
| }); | |||||
| it("should handle technologies load errors in case of failure", async () => { | |||||
| const dispatchedActions = []; | |||||
| helper.rejectErrorCodeHelper = jest.fn( | |||||
| () => mockState.candidates.fetchCandidatesErrorMessage | |||||
| ); | |||||
| const error = { | |||||
| response: { | |||||
| data: { message: mockState.candidates.fetchCandidatesErrorMessage }, | |||||
| }, | |||||
| }; | |||||
| api.getFilteredCandidates = jest.fn(() => Promise.reject(error)); | |||||
| const fakeStore = { | |||||
| getState: () => mockState.candidates.candidates, | |||||
| dispatch: (action) => dispatchedActions.push(action), | |||||
| }; | |||||
| await runSaga(fakeStore, fc.filterCandidates, {}).done; | |||||
| expect(api.getFilteredCandidates.mock.calls.length).toBe(1); | |||||
| expect(dispatchedActions).toContainEqual( | |||||
| filterCandidatesError(error.response.data.message) | |||||
| ); | |||||
| }); | |||||
| }); |
| import { Router } from "react-router-dom"; | |||||
| import { SelectionProvider } from "../../context/SelectionContext"; | |||||
| import * as redux from "react-redux"; | |||||
| import { fireEvent, render, screen } from "@testing-library/react"; | |||||
| import store from "../../store"; | |||||
| import history from "../../store/utils/history"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import SelectionCard from "../../components/Selection/SelectionCard"; | |||||
| import userEvent from "@testing-library/user-event"; | |||||
| describe("SelectionProcessPage render tests *first in order", () => { | |||||
| var props = { | |||||
| item: mockState.selections.processes[1].selectionProcesses[0], | |||||
| click: jest.fn(), | |||||
| dragStart: jest.fn(), | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <SelectionProvider> | |||||
| <Router history={history}> | |||||
| <SelectionCard {...props} /> | |||||
| </Router> | |||||
| </SelectionProvider> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| // Mock useDisptach hook | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render card", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("sel-card")).toBeDefined(); | |||||
| }); | |||||
| it("Should render schedule", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("process-date")).toBeDefined(); | |||||
| }); | |||||
| // to be completed | |||||
| // it("Should dispatch status change action when option 'done' is selected", async () => { | |||||
| // render(cont); | |||||
| // fireEvent.click(screen.getByTestId("status-btn")); | |||||
| // var select = screen.getByTestId("status-select-drop"); | |||||
| // fireEvent.change(select, { target: { value: "Odrađen" } }); | |||||
| // // userEvent.click(screen.getByRole(screen.getByTestId("status-select-drop"), "button")); | |||||
| // // await waitFor(() => userEvent.click(screen.getByText(/odrađen/i))); | |||||
| // // expect(screen.getByRole("heading")).toHaveTextContent(/odrađen/i); | |||||
| // expect(mockDispatch).toHaveBeenCalledWith( | |||||
| // setDoneProcessReq({ | |||||
| // id: props.item.id, | |||||
| // name: "Some random name", | |||||
| // applicantId: props.item.applicant.applicantId, | |||||
| // }) | |||||
| // ); | |||||
| // }); | |||||
| }); |
| import { Router } from "react-router-dom"; | |||||
| import { SelectionProvider } from "../../context/SelectionContext"; | |||||
| import * as redux from "react-redux"; | |||||
| import Selection from "../../components/Selection/Selection"; | |||||
| import { fireEvent, render, screen } from "@testing-library/react"; | |||||
| import store from "../../store"; | |||||
| import history from "../../store/utils/history"; | |||||
| describe("SelectionProcessPage render tests *first in order", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/selectionFlow", | |||||
| }, | |||||
| }, | |||||
| order: 0, | |||||
| modalEvent: jest.fn(), | |||||
| selection: { | |||||
| id: 1, | |||||
| name: "HR intervju", | |||||
| selectionProcesses: [], | |||||
| // PropTypes.arrayOf( | |||||
| // PropTypes.shape({ | |||||
| // id: PropTypes.number, | |||||
| // name: PropTypes.string, | |||||
| // date: PropTypes.string, | |||||
| // status: PropTypes.string, | |||||
| // currentSelection: PropTypes.number, | |||||
| // map: PropTypes.func, | |||||
| // applicant: PropTypes.shape({ | |||||
| // firstName: PropTypes.string, | |||||
| // lastName: PropTypes.string, | |||||
| // }), | |||||
| // }) | |||||
| // ), | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <SelectionProvider> | |||||
| <Router history={history}> | |||||
| <Selection {...props} /> | |||||
| </Router> | |||||
| </SelectionProvider> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render add button if selection is first in order", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("interview-image")).toBeDefined(); | |||||
| }); | |||||
| it("Should render empty selection message if no proccesses exist", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("empty-selection")).toBeDefined(); | |||||
| }); | |||||
| it("Should call modal event if add button has been clicked", () => { | |||||
| render(cont); | |||||
| fireEvent.click(screen.getByTestId("interview-image")); | |||||
| expect(props.modalEvent).toHaveBeenCalled(); | |||||
| }); | |||||
| }); | |||||
| describe("SelectionProcessPage render tests *first in order", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/selectionFlow", | |||||
| }, | |||||
| }, | |||||
| order: 1, | |||||
| modalEvent: jest.fn(), | |||||
| selection: { | |||||
| id: 1, | |||||
| name: "HR intervju", | |||||
| selectionProcesses: [ | |||||
| { | |||||
| id: 1, | |||||
| name: "random", | |||||
| date: "02-05-2022", | |||||
| status: "Zakazan", | |||||
| currentSelection: 1, | |||||
| applicant: { | |||||
| firstName: "Meris", | |||||
| lastName: "Ahmatovic", | |||||
| }, | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <SelectionProvider> | |||||
| <Router history={history}> | |||||
| <Selection {...props} /> | |||||
| </Router> | |||||
| </SelectionProvider> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should not render add button if not first in order", () => { | |||||
| render(cont); | |||||
| expect(screen.queryByTestId("interview-image")).toBe(null); | |||||
| }); | |||||
| it("Should render empty selection message if no proccesses exist", () => { | |||||
| render(cont); | |||||
| expect(screen.queryByTestId("empty-selection")).toBe(null); | |||||
| }); | |||||
| }); |
| import { render, screen, waitFor, fireEvent } from "@testing-library/react"; | |||||
| 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 ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import AdDetailsCandidateCard from "../../components/Ads/AdDetailsCandidateCard"; | |||||
| describe("Ad details candidate card ui tests", () => { | |||||
| const props = { | |||||
| className: "ad-details-card", | |||||
| id: 1, | |||||
| firstName: "Ermin", | |||||
| lastName: "Bronja", | |||||
| experience: 1, | |||||
| cv: "http://", | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/ads/1", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <AdDetailsCandidateCard {...props} /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValue(mockState.ads.ads); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should load ad details candidate card component", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("ad-details-candidate")).toBeDefined(); | |||||
| }); | |||||
| it("Should navigate on candidates page when button clicked", async () => { | |||||
| render(cont); | |||||
| waitFor(() => { | |||||
| fireEvent.click(screen.getByTestId("ad-details-candidate-title-link")); | |||||
| expect(props.history.push).toHaveBeenCalledWith("/candidates/1"); | |||||
| }); | |||||
| }); | |||||
| }); |
| import { render, screen, fireEvent, waitFor } from "@testing-library/react"; | |||||
| import * as redux from "react-redux"; | |||||
| import AdDetailsPage from "../../pages/AdsPage/AdDetailsPage"; | |||||
| import store from "../../store"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import history from "../../store/utils/history"; | |||||
| import ColorModeProvider from "../../context/ColorModeContext"; | |||||
| describe("AdDetailsPage render tests", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/ads/1", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <AdDetailsPage {...props} /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValue(mockState.ads.ads[0]); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.resetAllMocks(); | |||||
| }); | |||||
| it("Should render AdDetailsPage", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("ad-details-page")).toBeDefined(); | |||||
| }); | |||||
| it("Should render modal when click archive ad button", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(container.getElementsByClassName("archive-ad-button")[0]); | |||||
| expect(screen.getByTestId("alert-container")).toBeDefined(); | |||||
| }); | |||||
| it("Should render ads page when confirm archive ad modal", async () => { | |||||
| const { container } = render(cont); | |||||
| waitFor(() => { | |||||
| fireEvent.click(container.getElementsByClassName("archive-ad-button")[0]); | |||||
| fireEvent.click(container.getElementsByClassName("dialog-btn")[1]); | |||||
| waitFor(() => expect(props.history.push).toHaveBeenCalledWith('/ads')); | |||||
| }); | |||||
| }); | |||||
| it("Should render apply for ad button", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("apply-for-ad-button")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render apply for ad modal after click button", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(container.getElementsByClassName("apply-for-ad-button")[0]); | |||||
| const a = screen.getByTestId("custom-modal-test-id"); | |||||
| expect(screen.getByTestId("custom-modal-test-id")).toBeDefined(); | |||||
| }); | |||||
| it("Should render go back button", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("ad-details-buttons-link")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should go back when click button", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("ad-details-buttons-link")[0] | |||||
| ); | |||||
| const arg = { pathname: "/ads" }; | |||||
| waitFor(() => expect(props.history.push).toHaveBeenCalledWith(arg)); | |||||
| }); | |||||
| }); |
| import { render, fireEvent, waitFor } 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 AdsCandidatesPage from "../../pages/CandidatesPage/AdsCandidatesPage"; | |||||
| describe("TableViewPage render tests", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/candidates", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <AdsCandidatesPage search="" {...props} /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce(mockState.candidates.adsCandidates); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("ads-candidates-container")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Number of sliders should be equal to length of our adsCandidates array", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("ads-candidates").length).toBe( | |||||
| mockState.candidates.adsCandidates.length | |||||
| ); | |||||
| }); | |||||
| it("Number of candidates in slider (vissible and hidden) should be equal to the number of candidates which applied for ad", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container | |||||
| .getElementsByClassName("ads-candidates")[0] | |||||
| .getElementsByClassName("slick-slide").length | |||||
| ).toBe(mockState.candidates.adsCandidates[0].applicants.length); | |||||
| }); | |||||
| it("Number of arrows (left and right) should be 1 because there is more than 4 candidates which applied for ad", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("active-ads-ads-arrows").length | |||||
| ).toBe(1); | |||||
| }); | |||||
| it("After clicking on right arrow of first slider, first slider should show fifth candidate as forth card of slider", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container | |||||
| .getElementsByClassName("active-ads-ads-arrows")[0] | |||||
| .getElementsByTagName("button")[1] | |||||
| ); | |||||
| await waitFor(() => | |||||
| expect( | |||||
| container | |||||
| .getElementsByClassName("ads-candidates")[0] | |||||
| .getElementsByClassName("slick-active")[0] | |||||
| .getElementsByClassName("candidate-card-container")[0] | |||||
| .getElementsByClassName("candidate-card-applicant-name")[0] | |||||
| .textContent | |||||
| ).toBe( | |||||
| mockState.candidates.adsCandidates[0].applicants[3].firstName + | |||||
| " " + | |||||
| mockState.candidates.adsCandidates[0].applicants[3].lastName | |||||
| ) | |||||
| ); | |||||
| }); | |||||
| it("Should render candidate details page after clicking on candidate card", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("candidate-card-container")[0] | |||||
| ); | |||||
| const arg = { pathname: "/candidates/1" }; | |||||
| expect(props.history.push).toHaveBeenCalledWith(arg); | |||||
| }); | |||||
| }); |
| import { render, screen, fireEvent, waitFor } from "@testing-library/react"; | |||||
| import * as redux from "react-redux"; | |||||
| import AdsPage from "../../pages/AdsPage/AdsPage"; | |||||
| import store from "../../store"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import history from "../../store/utils/history"; | |||||
| import ColorModeProvider from "../../context/ColorModeContext"; | |||||
| describe("AdsPage render tests", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/ads", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <AdsPage {...props} /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.ads.ads) | |||||
| .mockReturnValueOnce([ | |||||
| { | |||||
| name: ".NET", | |||||
| technologyId: 1, | |||||
| technologyType: "Backend", | |||||
| isChecked: false, | |||||
| }, | |||||
| ]) | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.resetAllMocks(); | |||||
| }); | |||||
| it("Should render ads", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("ads-page")).toBeDefined(); | |||||
| }); | |||||
| it("Should be rendered button which is used for showing input responsible for searching by name", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("ads-page-btn")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should be rendered button for toggling filters modal", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("ads-page-btn")[1]).toBeDefined(); | |||||
| }); | |||||
| it("Should be rendered button for adding new ad", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("ads-page-btn")[2]).toBeDefined(); | |||||
| }); | |||||
| it("Should render CreateAdPage when click Add Ad button", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(container.getElementsByClassName("ads-page-btn")[2]); | |||||
| expect(props.history.push).toHaveBeenCalledWith("/create-ad"); | |||||
| }); | |||||
| it("Input for searching by title should not be shown when component is initialy rendered", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("ads-page-search-by-title")[0].style | |||||
| .visibility | |||||
| ).toBe("hidden"); | |||||
| }); | |||||
| it("Should be rendered ad cards", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("ad-card").length).toBeGreaterThan( | |||||
| 0 | |||||
| ); | |||||
| }); | |||||
| it("Should be rendered archive ad cards", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("archive-ad").length).toBe(0); | |||||
| }); | |||||
| it("Should render filter drawer after click filter button", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(container.getElementsByClassName("fltr-btn")[0]); | |||||
| expect(screen.getByTestId("ad-filters-drawer")).toBeDefined(); | |||||
| }); | |||||
| it("Should render arrow buttons for active ads slider", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("active-ads-ads-arrows") | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render arrow buttons for archived ads slider", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("archived-ads-ads-arrows") | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should filter ads when click search button", async () => { | |||||
| const { container } = render(cont); | |||||
| waitFor(() => { | |||||
| fireEvent.click(container.getElementsByClassName("fltr-btn")[0]); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("ad-filters-checkbox")[0] | |||||
| ); | |||||
| fireEvent.click(container.getByTestId("ad-filters-submit")[0]); | |||||
| expect( | |||||
| container.getElementsByClassName("ad-card").length | |||||
| ).toBeGreaterThan(0); | |||||
| }); | |||||
| }); | |||||
| it("Should render Ads", async () => { | |||||
| const { container } = render(cont); | |||||
| waitFor(() => | |||||
| expect( | |||||
| container.getElementsByClassName("ad-card").length | |||||
| ).toBeGreaterThan(0) | |||||
| ); | |||||
| }); | |||||
| it("Should navigate to ad details when click on ad card", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(container.getElementsByClassName("ad-card")[0]); | |||||
| expect(props.history.push).toHaveBeenCalledWith("/ads/1"); | |||||
| }); | |||||
| }); |
| import { render, screen } from "@testing-library/react"; | |||||
| import { Provider } from "react-redux"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import SelectionProcessOfApplicantPage from "../../pages/SelectionProcessPage/SelectionProcessOfApplicantPage"; | |||||
| import store from "../../store"; | |||||
| import history from "../../store/utils/history"; | |||||
| import * as redux from "react-redux"; | |||||
| import { mockState } from "../../mockState"; | |||||
| describe("applicant selection process details test", () => { | |||||
| var cont = ( | |||||
| <Router history={history}> | |||||
| <Provider store={store}> | |||||
| <ColorModeProvider> | |||||
| <SelectionProcessOfApplicantPage /> | |||||
| </ColorModeProvider> | |||||
| </Provider> | |||||
| </Router> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValue(mockState.applSelection); | |||||
| // Mock useDispatch hook | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| // Mock dispatch function returned from useDispatch | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValueOnce(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("should render", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("appl-sel")).toBeDefined(); | |||||
| }); | |||||
| // ? | |||||
| // it("should render applicant selection", () => { | |||||
| // render(cont); | |||||
| // expect(screen.getByTestId("appSelection")).toBeDefined(); | |||||
| // }); | |||||
| }); |
| import { render, screen, waitFor, fireEvent } from "@testing-library/react"; | |||||
| 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 ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import ApplyForAdFirstStage from "../../components/Ads/ApplyForAdFirstStage"; | |||||
| describe("Apply for ad first stage ui tests", () => { | |||||
| const props = { | |||||
| firstName: "E", | |||||
| setFirstName: jest.fn(), | |||||
| lastName: "B", | |||||
| gender: "Male", | |||||
| setGender: jest.fn(), | |||||
| setLastName: jest.fn(), | |||||
| dateOfBirth: new Date(), | |||||
| setDateOfBirth: jest.fn(), | |||||
| phoneNumber: "0", | |||||
| setPhoneNumber: jest.fn(), | |||||
| onIncreaseStage: jest.fn(), | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <ApplyForAdFirstStage {...props} /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValue(mockState.ads.ads); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render firstName input", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("apply-for-ad-modal-first-name-input")).toBeDefined(); | |||||
| }); | |||||
| it("Should change firstName on changing input", async () => { | |||||
| render(cont); | |||||
| fireEvent.change( | |||||
| screen.getByTestId("apply-for-ad-modal-first-name-input"), | |||||
| { target: { value: "Ermin" } } | |||||
| ); | |||||
| waitFor(() => expect(props.setFirstName).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should change last on changing input", async () => { | |||||
| render(cont); | |||||
| fireEvent.change(screen.getByTestId("apply-for-ad-modal-last-name-input"), { | |||||
| target: { value: "Bronja" }, | |||||
| }); | |||||
| waitFor(() => expect(props.setLastName).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should select male gender", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("apply-for-ad-modal-gender-input")[0] | |||||
| ); | |||||
| waitFor(() => expect(props.setGender).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should select female gender", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("apply-for-ad-modal-gender-input")[1] | |||||
| ); | |||||
| waitFor(() => expect(props.setGender).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should change date of birth", async () => { | |||||
| render(cont); | |||||
| fireEvent.change(screen.getByTestId("apply-for-ad-modal-date-of-birth"), { | |||||
| target: { value: "1998-05-05" }, | |||||
| }); | |||||
| waitFor(() => expect(props.setDateOfBirth).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should change phone number", async () => { | |||||
| render(cont); | |||||
| fireEvent.change(screen.getByTestId("apply-for-ad-modal-phone-number"), { target: { value: "0000000000" } }); | |||||
| waitFor(() => expect(props.setPhoneNumber).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should click go forward button", async () => { | |||||
| render(cont); | |||||
| fireEvent.click(screen.getByTestId("apply-for-ad-modal-go-forward-button")); | |||||
| waitFor(() => expect(props.onIncreaseStage).toHaveBeenCalled()); | |||||
| }); | |||||
| }); |
| import { render, screen, waitFor, fireEvent } from "@testing-library/react"; | |||||
| 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 ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import ApplyForAdFourthStage from "../../components/Ads/ApplyForAdFourthStage"; | |||||
| describe("Apply for ad fourth stage ui tests", () => { | |||||
| const props = { | |||||
| coverLetter: "", | |||||
| setCoverLetter: jest.fn(), | |||||
| pdfFile: null, | |||||
| setPdfFile: jest.fn(), | |||||
| onDecreaseStage: jest.fn(), | |||||
| onFinishedFourStages: jest.fn(), | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <ApplyForAdFourthStage {...props} /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let file; | |||||
| beforeEach(() => { | |||||
| file = new File(["(⌐□_□)"], "test.png", { type: "image/png" }); | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValue(mockState.ads.ads); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render apply for ad fourth stage modal", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("apply-for-ad-modal-fourth-stage")).toBeDefined(); | |||||
| }); | |||||
| it("Should change pdfFile", async () => { | |||||
| render(cont); | |||||
| fireEvent.change( | |||||
| screen.getByTestId("apply-for-ad-modal-fourth-stage-pdf-input"), | |||||
| { target: { files: [file] } } | |||||
| ); | |||||
| waitFor(() => expect(props.setPdfFile).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should change coverLetter", async () => { | |||||
| render(cont); | |||||
| fireEvent.change( | |||||
| screen.getByTestId("apply-for-ad-modal-fourth-stage-cover-letter-input"), | |||||
| { target: { value: "Cover Letter" } } | |||||
| ); | |||||
| waitFor(() => expect(props.setPdfFile).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should go back on click button", async () => { | |||||
| render(cont); | |||||
| fireEvent.click( | |||||
| screen.getByTestId("apply-for-ad-modal-fourth-stage-go-back-button") | |||||
| ); | |||||
| waitFor(() => expect(props.onDecreaseStage).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should finish stages on click button", async () => { | |||||
| render(cont); | |||||
| fireEvent.click( | |||||
| screen.getByTestId("apply-for-ad-modal-fourth-stage-go-forward-button") | |||||
| ); | |||||
| waitFor(() => expect(props.onFinishedFourStages).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Drag and drop", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.drop(container.getElementsByClassName("uploadCV-input")[0], { | |||||
| dataTransfer: { files: [file] }, | |||||
| }); | |||||
| }); | |||||
| it("Drag and drop over", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.dragOver(container.getElementsByClassName("uploadCV-input")[0], { | |||||
| dataTransfer: { files: [file] }, | |||||
| }); | |||||
| }); | |||||
| it("Drag and drop leave", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.dragOver(container.getElementsByClassName("uploadCV-input")[0], { | |||||
| dataTransfer: { files: [file] }, | |||||
| }); | |||||
| }); | |||||
| }); |
| import { render, screen, waitFor, fireEvent } from "@testing-library/react"; | |||||
| 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 ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import ApplyForAdSecondStage from "../../components/Ads/ApplyForAdSecondStage"; | |||||
| describe("Apply for ad second stage ui tests", () => { | |||||
| const props = { | |||||
| professionalQualification: "Professional Qualification", | |||||
| setProfessionalQualification: jest.fn(), | |||||
| technologies: [ | |||||
| { | |||||
| value: ".NET", | |||||
| isChecked: false, | |||||
| technologyId: 1, | |||||
| technologyType: "Backend", | |||||
| }, | |||||
| { | |||||
| value: "React", | |||||
| isChecked: false, | |||||
| technologyId: 2, | |||||
| technologyType: "Frontend", | |||||
| }, | |||||
| { | |||||
| value: "Git", | |||||
| isChecked: false, | |||||
| technologyId: 3, | |||||
| technologyType: "Other", | |||||
| }, | |||||
| ], | |||||
| setTechnologies: jest.fn(), | |||||
| experience: 1, | |||||
| setExperience: jest.fn(), | |||||
| onIncreaseStage: jest.fn(), | |||||
| onDecreaseStage: jest.fn(), | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <ApplyForAdSecondStage {...props} /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValue(mockState.ads.ads); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render apply for ad second stage", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("apply-for-ad-second-stage")).toBeDefined(); | |||||
| }); | |||||
| it("Should change professional qualification input", () => { | |||||
| render(cont); | |||||
| fireEvent.change( | |||||
| screen.getByTestId( | |||||
| "apply-for-ad-second-stage-professional-qualification" | |||||
| ), | |||||
| { | |||||
| target: { value: "Faculty" }, | |||||
| } | |||||
| ); | |||||
| expect(props.setProfessionalQualification).toHaveBeenCalled(); | |||||
| }); | |||||
| it("Should render backend technology", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("apply-for-ad-second-stage-checkbox")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render frontend technology", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("apply-for-ad-second-stage-checkbox")[1] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render others technology", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("apply-for-ad-second-stage-checkbox")[2] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should change experience", async () => { | |||||
| render(cont); | |||||
| fireEvent.change( | |||||
| screen.getByTestId("apply-for-ad-second-stage-experience-input"), | |||||
| { target: { value: 2 } } | |||||
| ); | |||||
| waitFor(() => expect(props.professionalQualification).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should change backend technology to checked", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("apply-for-ad-second-stage-checkbox")[0] | |||||
| ); | |||||
| waitFor(() => expect(props.technologies[0]).toBe(true)); | |||||
| }); | |||||
| }); |
| import { render, screen, waitFor, fireEvent } from "@testing-library/react"; | |||||
| 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 ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import ApplyForAdThirdStage from "../../components/Ads/ApplyForAdThirdStage"; | |||||
| describe("Apply for ad third stage ui tests", () => { | |||||
| const props = { | |||||
| onIncreaseStage: jest.fn(), | |||||
| onDecreaseStage: jest.fn(), | |||||
| linkedinLink: "", | |||||
| setLinkedinLink: jest.fn(), | |||||
| githubLink: "", | |||||
| setGithubLink: jest.fn(), | |||||
| bitBucketLink: "", | |||||
| setBitBucketLink: jest.fn(), | |||||
| email: "", | |||||
| setEmail: jest.fn(), | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <ApplyForAdThirdStage {...props} /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValue(mockState.ads.ads); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should change linkedin input", async () => { | |||||
| render(cont); | |||||
| fireEvent.change( | |||||
| screen.getByTestId("apply-for-ad-modal-third-stage-linkedin-input"), | |||||
| { target: { value: "https://linkedin" } } | |||||
| ); | |||||
| waitFor(() => expect(props.linkedinLink).toBe("https://linkedin")); | |||||
| }); | |||||
| it("Should render linkedin input", () => { | |||||
| render(cont); | |||||
| expect( | |||||
| screen.getByTestId("apply-for-ad-modal-third-stage-linkedin-input") | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should change github input", async () => { | |||||
| render(cont); | |||||
| fireEvent.change( | |||||
| screen.getByTestId("apply-for-ad-modal-third-stage-github-input"), | |||||
| { target: { value: "https://github" } } | |||||
| ); | |||||
| waitFor(() => expect(props.githubLink).toBe("https://github")); | |||||
| }); | |||||
| it("Should change bitbucket input", async () => { | |||||
| render(cont); | |||||
| fireEvent.change( | |||||
| screen.getByTestId("apply-for-ad-modal-third-stage-bitbucket-input"), | |||||
| { target: { value: "https://bitbucket" } } | |||||
| ); | |||||
| waitFor(() => expect(props.bitBucketLink).toBe("https://bitbucket")); | |||||
| }); | |||||
| it("Should change email input", async () => { | |||||
| render(cont); | |||||
| fireEvent.change( | |||||
| screen.getByTestId("apply-for-ad-modal-third-stage-email-input"), | |||||
| { target: { value: "ermin.bronja@dilig.net" } } | |||||
| ); | |||||
| waitFor(() => expect(props.email).toBe("ermin.bronja@dilig.net")); | |||||
| }); | |||||
| it("Should go back when button clicked", async () => { | |||||
| render(cont); | |||||
| fireEvent.click( | |||||
| screen.getByTestId("apply-for-ad-modal-third-stage-go-back-button") | |||||
| ); | |||||
| waitFor(() => expect(props.onDecreaseStage).toHaveBeenCalled()); | |||||
| }); | |||||
| it("Should go forward when button clicked", async () => { | |||||
| render(cont); | |||||
| fireEvent.click( | |||||
| screen.getByTestId("apply-for-ad-modal-third-stage-go-forward-button") | |||||
| ); | |||||
| waitFor(() => expect(props.onIncreaseStage).toHaveBeenCalled()); | |||||
| }); | |||||
| }); |
| import { render, fireEvent, screen, waitFor } 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 CandidateDetailsPage from "../../pages/CandidatesPage/CandidateDetailsPage"; | |||||
| import mediaQuery from "css-mediaquery"; | |||||
| function createMatchMedia(width) { | |||||
| return (query) => ({ | |||||
| matches: mediaQuery.match(query, { width }), | |||||
| addListener: () => {}, | |||||
| removeListener: () => {}, | |||||
| }); | |||||
| } | |||||
| describe("CandidateDetailsPage render tests", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/candidates/1", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <CandidateDetailsPage {...props} /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| window.matchMedia = createMatchMedia(362); | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.users.users) | |||||
| .mockReturnValueOnce(mockState.users.user) | |||||
| .mockReturnValueOnce(mockState.candidate.candidate) | |||||
| .mockReturnValueOnce(mockState.users.users) | |||||
| .mockReturnValueOnce(mockState.users.user) | |||||
| .mockReturnValueOnce(mockState.candidate.candidate) | |||||
| .mockReturnValueOnce(mockState.users.users) | |||||
| .mockReturnValueOnce(mockState.users.user) | |||||
| .mockReturnValueOnce(mockState.candidate.candidate); | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("main-candidate-container")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Initialy should dispatch two methods", () => { | |||||
| render(cont); | |||||
| expect(mockDispatch).toBeCalledTimes(2); | |||||
| }); | |||||
| it("Should render candidate name", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("candidate-lower-header")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render button for deleting candidate", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("candidate-btn")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should represent one year of experience for the candidate", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("candidate-experience").textContent).toBe( | |||||
| "candidates.experience:1" | |||||
| ); | |||||
| }); | |||||
| it("Should represent all technologies of candidate", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("technology-candidate-card").length | |||||
| ).toBe(2); | |||||
| }); | |||||
| it("It should show Muski inside paragraph for gender because value of gender property of our candidate is M", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("candidate-gender").textContent).toBe("common.male"); | |||||
| }); | |||||
| it("Should render dialog after clicking button for deleting candidate", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(container.getElementsByClassName("candidate-btn")[0]); | |||||
| expect(screen.getByTestId("alert-container")).toBeDefined(); | |||||
| }); | |||||
| it("Should render input for sending comment", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("comment-input")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Initially mention should not be rendered", async () => { | |||||
| const { container } = render(cont); | |||||
| await waitFor(() => | |||||
| expect( | |||||
| container.getElementsByClassName("comment-input_suggestions")[0] | |||||
| ).toBeUndefined() | |||||
| ); | |||||
| }); | |||||
| it("Should render mention list after entering @ inside our mention input", async () => { | |||||
| const { container } = render(cont); | |||||
| const input = container | |||||
| .getElementsByClassName("comment-input")[0] | |||||
| .querySelector("textarea"); | |||||
| waitFor(() => { | |||||
| fireEvent.change(input, { target: { value: "@" } }); | |||||
| expect( | |||||
| container | |||||
| .getElementsByClassName("comment-input")[0] | |||||
| .getElementsByClassName("comment-input_suggestions")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| }); | |||||
| it("Should render first button for sending commment because width of screen is greater than 361", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("comment-send-btn")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Clicking button for sending comment should dispatch function", async () => { | |||||
| const { container } = render(cont); | |||||
| const input = container | |||||
| .getElementsByClassName("comment-input")[0] | |||||
| .querySelector("textarea"); | |||||
| fireEvent.change(input, { target: { value: "some value" } }); | |||||
| fireEvent.click(container.getElementsByClassName("comment-send-btn")[0]); | |||||
| await waitFor(() => expect(mockDispatch).toBeCalledTimes(3)); | |||||
| }); | |||||
| it("Should not render second button for sending commment because width of screen is greater than 361", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("comment-send-btn-responsive")[0] | |||||
| ).toBeUndefined(); | |||||
| }); | |||||
| it("Should render button for downloading CV", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("applicant-cv-button")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("should not render responsive right and left arrow because screen width is greater than 361", () => { | |||||
| render(cont); | |||||
| expect(screen.queryByTestId("candidate-ad-responsive-arrows")).toBeNull(); | |||||
| }); | |||||
| it("Should render two ads for candidate", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("applicant-add").length).toBe(2); | |||||
| }); | |||||
| it("Should render three comments", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("comment-sub-container").length | |||||
| ).toBe(3); | |||||
| }); | |||||
| it("Should render page with all candidates", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("applicant-ads-back-button")[0] | |||||
| ); | |||||
| const arg = { pathname: "/candidates" }; | |||||
| expect(props.history.push).toHaveBeenCalledWith(arg); | |||||
| }); | |||||
| }); |
| import { fireEvent, render, screen, waitFor } from "@testing-library/react"; | |||||
| 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 ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import CandidateFilters from "../../components/Candidates/CandidateFilters"; | |||||
| describe("Add ad modals ui tests", () => { | |||||
| const props = { | |||||
| open: true, | |||||
| handleClose: jest.fn(), | |||||
| pageSize: 3, | |||||
| currentPage: 1, | |||||
| isTableView: false, | |||||
| technologies: [ | |||||
| { | |||||
| technologyId: 1, | |||||
| name: ".NET", | |||||
| technologyType: "Backend", | |||||
| isChecked: true, | |||||
| }, | |||||
| ], | |||||
| startingDate: "", | |||||
| endingDate: "", | |||||
| typesOfEmployments: [], | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <CandidateFilters {...props} /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should check checkbox", async () => { | |||||
| const { container } = render(cont); | |||||
| const a = container.getElementsByClassName( | |||||
| "ad-filters-technologies-checkboxes-checkbox" | |||||
| )[0]; | |||||
| waitFor(() => { | |||||
| fireEvent.click(a); | |||||
| expect(a).toBeDefined(); | |||||
| }); | |||||
| }); | |||||
| it("Should click type of employment button", async () => { | |||||
| const { container } = render(cont); | |||||
| const btn = container.getElementsByClassName("type-of-employment-btn"); | |||||
| waitFor(() => { | |||||
| fireEvent.click(btn[1]); | |||||
| expect(btn).toBeDefined(); | |||||
| }); | |||||
| }); | |||||
| }); |
| import { render, screen, fireEvent, waitFor } from "@testing-library/react"; | |||||
| import * as redux from "react-redux"; | |||||
| import CandidatesPage from "../../pages/CandidatesPage/CandidatesPage"; | |||||
| import store from "../../store"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import history from "../../store/utils/history"; | |||||
| import mediaQuery from "css-mediaquery"; | |||||
| function createMatchMedia(width) { | |||||
| return (query) => ({ | |||||
| matches: mediaQuery.match(query, { width }), | |||||
| addListener: () => {}, | |||||
| removeListener: () => {}, | |||||
| }); | |||||
| } | |||||
| describe("CandidatesPage render tests", () => { | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <CandidatesPage /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| window.matchMedia = createMatchMedia(601); | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce(mockState.technologies.technologies); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render first header because width of screen is greater than 600", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("candidates-header1")).toBeDefined(); | |||||
| }); | |||||
| it("Should render second header because width of screen is greater than 600", () => { | |||||
| render(cont); | |||||
| expect(screen.queryByTestId("candidates-header2")).toBeNull(); | |||||
| }); | |||||
| it("Should render", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("candidates-page")).toBeDefined(); | |||||
| }); | |||||
| it("Should render first button responsible for showing different components inside page because width of screen is greater than 600", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("all-white-btn")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should not render second button responsible for showing different components inside page because width of screen is greater than 600", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("candidate-btn-view-2")[0] | |||||
| ).toBeUndefined(); | |||||
| }); | |||||
| it("should be rendered button which is used for showing input responsible for searching by name", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("candidate-btn")[1]).toBeDefined(); | |||||
| }); | |||||
| it("Should render first filter button because width is greater than 600", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("candidate-btn-filters1")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should not render second filter button because width is greater than 600", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("candidate-btn-filters2")[0] | |||||
| ).toBeUndefined(); | |||||
| }); | |||||
| it("input for searching by name should not be shown when component is initialy rendered", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("proba")[0].style.visibility).toBe( | |||||
| "hidden" | |||||
| ); | |||||
| }); | |||||
| // it("input for searching by name should be shown after clicking button for first time", async () => { | |||||
| // const { container } = render(cont); | |||||
| // const button = container.getElementsByClassName("candidate-btn")[1]; | |||||
| // const a = button.innerHTML; | |||||
| // await waitFor(() => { | |||||
| // fireEvent.click(button); | |||||
| // expect( | |||||
| // container.getElementsByClassName("proba")[0].style.visibility | |||||
| // ).toBe("visible"); | |||||
| // }); | |||||
| // }); | |||||
| it("Should render TableViewPage component when page is initialy rendered", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("candidates-table")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| // it("should render AdsCandidatesPage component when button for switching to another view is clicked for the first time", async () => { | |||||
| // const { container } = render(cont); | |||||
| // fireEvent.click(container.getElementsByClassName("candidate-btn")[0]); | |||||
| // await waitFor(() => | |||||
| // expect( | |||||
| // container.getElementsByClassName("ads-candidates-container")[0] | |||||
| // ).toBeDefined() | |||||
| // ); | |||||
| // }); | |||||
| }); |
| import { render, screen, fireEvent } from "@testing-library/react"; | |||||
| import * as redux from "react-redux"; | |||||
| import CreateAdPage from "../../pages/AdsPage/CreateAdPage"; | |||||
| import store from "../../store"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import history from "../../store/utils/history"; | |||||
| import ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import CreateAdSecondStep from "../../pages/AdsPage/CreateAdSecondStep"; | |||||
| describe("CreateAdPage render tests", () => { | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <CreateAdPage /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValue([ | |||||
| { | |||||
| technologyId: 1, | |||||
| name: ".NET", | |||||
| technologyType: "Backend", | |||||
| isChecked: true, | |||||
| }, | |||||
| ]); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.resetAllMocks(); | |||||
| }); | |||||
| it("Should render create ad page", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("create-ad-page")).toBeDefined(); | |||||
| }); | |||||
| it("Should render go back button", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("create-ad-buttons-back")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render go forward button", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("create-ad-buttons-forward")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render create ad first step form", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("create-ad-first-step-form")).toBeDefined(); | |||||
| }); | |||||
| it("Should render sercond step form", () => { | |||||
| const { container } = render(cont); | |||||
| const formControls = container.getElementsByClassName( | |||||
| "create-ad-form-control-first-step-input" | |||||
| ); | |||||
| fireEvent.change(formControls[0], { target: { value: ".NET DEVELOPER" } }); | |||||
| fireEvent.change(formControls[1], { target: { value: "2020-05-24" } }); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("create-ad-buttons-forward")[0] | |||||
| ); | |||||
| fireEvent.click(container.getElementsByClassName("create-ad-second-step-checkbox")[0]) | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("create-ad-buttons-forward")[0] | |||||
| ); | |||||
| expect(screen.getByTestId("create-ad-third-step-form")).toBeDefined(); | |||||
| }); | |||||
| }); |
| 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); | |||||
| }); | |||||
| }); |
| import * as redux from "react-redux"; | |||||
| import store from "../../store"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { render, screen, fireEvent } from "@testing-library/react"; | |||||
| import history from "../../store/utils/history"; | |||||
| import DayDetailsComponent from "../../components/Schedules/DayDetailsComponent"; | |||||
| import ColorModeProvider from "../../context/ColorModeContext"; | |||||
| const setCurrentlySelected = jest.fn(); | |||||
| const setCurrentlySelectedDay = jest.fn(); | |||||
| const props = { | |||||
| selectedDate: "20.12.2023", | |||||
| selectionProcesses: mockState.schedule.schedule, | |||||
| open: jest.fn(), | |||||
| onClose: jest.fn(), | |||||
| setCurrentlySelected: setCurrentlySelected, | |||||
| setCurrentlySelectedDay: setCurrentlySelectedDay, | |||||
| currentlySelectedDay: 20, | |||||
| numberOfDaysInMonth: 31, | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/schedule", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| 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 render left arrow as enabled because currenlty selected day is not 1", () => { | |||||
| render(cont); | |||||
| expect(screen.getAllByTestId("day-details-left-arrow")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render right arrow as enabled because currently selected day is not 31", () => { | |||||
| render(cont); | |||||
| expect(screen.getAllByTestId("day-details-right-arrow")[0]).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 | |||||
| ); | |||||
| }); | |||||
| it("Should render candidate details page after clicking on candidate name", () => { | |||||
| render(cont); | |||||
| fireEvent.click(screen.getAllByTestId("day-details-applicant")[0]); | |||||
| const arg = { pathname: "/candidates/1" }; | |||||
| expect(props.history.push).toHaveBeenCalledWith(arg); | |||||
| }); | |||||
| it("Should call function when we press right arrow", () => { | |||||
| render(cont); | |||||
| fireEvent.click(screen.getAllByTestId("day-details-right-arrow")[0]); | |||||
| expect(setCurrentlySelected.mock.calls).toHaveLength(1); | |||||
| expect(setCurrentlySelectedDay.mock.calls).toHaveLength(1); | |||||
| }); | |||||
| it("Should call function when we press right arrow", () => { | |||||
| render(cont); | |||||
| fireEvent.click(screen.getAllByTestId("day-details-left-arrow")[0]); | |||||
| expect(setCurrentlySelected.mock.calls).toHaveLength(1); | |||||
| expect(setCurrentlySelectedDay.mock.calls).toHaveLength(1); | |||||
| }); | |||||
| }); |
| import { | |||||
| render, | |||||
| screen, | |||||
| fireEvent, | |||||
| waitFor, | |||||
| findByTestId, | |||||
| } 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 ColorModeProvider from "../../context/ColorModeContext"; | |||||
| import PatternDetailsPage from "../../pages/PatternsPage/PatternDetailsPage"; | |||||
| describe("PatternDetailsPage render tests", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/patterns/1", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <ColorModeProvider> | |||||
| <PatternDetailsPage {...props} /> | |||||
| </ColorModeProvider> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValue(mockState.patterns.patterns[0]) | |||||
| .mockReturnValue([ | |||||
| { | |||||
| applicantId: 21359, | |||||
| firstName: "Jelena", | |||||
| lastName: "Zivkovic", | |||||
| email: "jelena.d.zivkovic@gmail.com", | |||||
| }, | |||||
| ]) | |||||
| .mockReturnValue(null); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render PatternDetaisPage", async () => { | |||||
| render(cont); | |||||
| waitFor(() => { | |||||
| expect(screen.getByTestId("pattern-details")).toBeDefined(); | |||||
| }); | |||||
| }); | |||||
| it("Should render select input for choosing candidate", async () => { | |||||
| render(cont); | |||||
| waitFor(() => { | |||||
| expect(screen.getByTestId("pattern-details-select")).toBeDefined(); | |||||
| }); | |||||
| }); | |||||
| it("Should render add candidate button for choosing email", async () => { | |||||
| render(cont); | |||||
| waitFor(() => { | |||||
| expect(screen.getByTestId("pattern-details-plus")).toBeDefined(); | |||||
| }); | |||||
| }); | |||||
| it("Should render go back button", async () => { | |||||
| const { container } = render(cont); | |||||
| waitFor(() => { | |||||
| expect( | |||||
| container.getElementsByClassName("ad-details-buttons-link")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| }); | |||||
| it("Should go to patterns page when click go back button", async () => { | |||||
| const { container } = render(cont); | |||||
| waitFor(() => { | |||||
| fireEvent.click(screen.getByTestId("ad-details-buttons-link")); | |||||
| expect(props.history.push).toHaveBeenCalledWith("/patterns"); | |||||
| }); | |||||
| }); | |||||
| it("Should render send email button", () => { | |||||
| render(cont); | |||||
| waitFor(() => { | |||||
| expect(screen.getByTestId("pattern-details-send-email")).toBeDefined(); | |||||
| }); | |||||
| }); | |||||
| it("Should render send email modal", () => { | |||||
| render(cont); | |||||
| waitFor(() => { | |||||
| fireEvent.change(screen.getByTestId("pattern-details-select"), { | |||||
| target: { value: "jelena.d.zivkovic@gmail.com" }, | |||||
| }); | |||||
| fireEvent.click(screen.getByTestId("pattern-details-plus")); | |||||
| fireEvent.click(screen.getByTestId("pattern-details-send-email")); | |||||
| expect(props.history.push).toHaveBeenCalledWith("/patterns"); | |||||
| }); | |||||
| }); | |||||
| }); |
| import { render, screen, fireEvent, waitFor } from "@testing-library/react"; | |||||
| import * as redux from "react-redux"; | |||||
| import PatternsPage from "../../pages/PatternsPage/PatternsPage"; | |||||
| import store from "../../store"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import history from "../../store/utils/history"; | |||||
| describe("PatternsPage render tests", () => { | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <PatternsPage /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValue(mockState.patterns.patterns); | |||||
| // .mockReturnValueOnce([ | |||||
| // { | |||||
| // id: 1, | |||||
| // name: "HR intervju", | |||||
| // selectionProcesses: [], | |||||
| // }, | |||||
| // ]); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.resetAllMocks(); | |||||
| }); | |||||
| it("Should render patterns page", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("patterns-page")).toBeDefined(); | |||||
| }); | |||||
| it("Should render edit mode button", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("editEnableBtn")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render edit mode button on card", () => { | |||||
| const { container } = render(cont); | |||||
| var btn = container.getElementsByClassName("c-icon-button")[0]; | |||||
| fireEvent.click(btn); | |||||
| var btn1 = container.getElementsByClassName("c-icon-button")[1]; | |||||
| expect(btn1).toBeDefined(); | |||||
| }); | |||||
| it("Should render add pattern button", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("add-ad-btn")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render add pattern modal", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(container.getElementsByClassName("add-pattern-btn")[0]); | |||||
| expect( | |||||
| container.getElementsByClassName("add-pattern-btn")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render edit pattern modal when click on edit pattern button", () => { | |||||
| const { container } = render(cont); | |||||
| var btn = container.getElementsByClassName("c-icon-button")[0]; | |||||
| fireEvent.click(btn); | |||||
| var btn1 = container.getElementsByClassName("c-icon-button")[1]; | |||||
| fireEvent.click(btn1); | |||||
| var modal = screen.getByTestId("custom-modal-test-id"); | |||||
| expect(modal).toBeDefined(); | |||||
| }); | |||||
| it("Should render filter button", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("custom-filter-button") | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render filters", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("custom-filter-button")[0] | |||||
| ); | |||||
| expect(screen.getByTestId("pattern-filters")).toBeDefined(); | |||||
| }); | |||||
| it("Should render pattern cards", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("pattern-card-parent").length | |||||
| ).toBeGreaterThan(0); | |||||
| }); | |||||
| it("Should submit filters handler", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("custom-filter-button")[0] | |||||
| ); | |||||
| waitFor(() => { | |||||
| fireEvent.click( | |||||
| container.getElementsByClassName("pattern-filters-checkbox")[0] | |||||
| ); | |||||
| fireEvent.change( | |||||
| container.getElementsByClassName( | |||||
| "custom-drawer-sub-card-content-input-1" | |||||
| )[0], | |||||
| { target: { value: "2024-05-05" } } | |||||
| ); | |||||
| fireEvent.change( | |||||
| container.getElementsByClassName( | |||||
| "custom-drawer-sub-card-content-input-2" | |||||
| )[0], | |||||
| { target: { value: "2025-05-05" } } | |||||
| ); | |||||
| const searchBtn = screen.getByTestId("custom-drawer-submit-search"); | |||||
| fireEvent.click(searchBtn); | |||||
| expect(searchBtn).toBeDefined(); | |||||
| }); | |||||
| }); | |||||
| }); |
| import { render, fireEvent, screen, waitFor } 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) | |||||
| .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(); | |||||
| }); | |||||
| }); |
| import { fireEvent, render, screen, waitFor } from "@testing-library/react"; | |||||
| import * as redux from "react-redux"; | |||||
| import SelectionProcessPage from "../../pages/selectionProcessPage/selectionProcessPage"; | |||||
| import store from "../../store"; | |||||
| import "../../i18n"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import history from "../../store/utils/history"; | |||||
| import { SelectionProvider } from "../../context/SelectionContext"; | |||||
| describe("SelectionProcessPage render tests", () => { | |||||
| var props = { | |||||
| history: { | |||||
| replace: jest.fn(), | |||||
| push: jest.fn(), | |||||
| location: { | |||||
| pathname: "/selectionFlow", | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <SelectionProvider> | |||||
| <Router history={history}> | |||||
| <SelectionProcessPage {...props} /> | |||||
| </Router> | |||||
| </SelectionProvider> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| // Mock useSelector hook | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.selections) | |||||
| .mockReturnValueOnce(mockState.selections.processes) | |||||
| .mockReturnValueOnce(mockState.selections.statuses); | |||||
| // MOZDA VRATITI KANDIDATE i korisnike? | |||||
| // spyOnUseSelector.mockReturnValue(mockState.selections); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("selections-page")).toBeDefined(); | |||||
| }); | |||||
| it("Should render a card foreach mocked level", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("selection-card").length).toBe(4); | |||||
| }); | |||||
| // it("Should render a button with specific class for an enabled user", () => { | |||||
| // const { container } = render(cont); | |||||
| // expect(container.getElementsByClassName("td-btn").length).toBe(0); | |||||
| // }); | |||||
| it("Should render filter button", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("userPageBtn").length).toBe(1); | |||||
| }); | |||||
| it("Should render date if process is scheduled", () => { | |||||
| render(cont); | |||||
| expect(screen.getAllByTestId("process-date")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render scheduler if process is scheduled", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("sel-item-scheduler")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render interviewBtn", () => { | |||||
| render(cont); | |||||
| expect(screen.getByTestId("interview-image")).toBeDefined(); | |||||
| }); | |||||
| // it("Should render interview dailog when clicked on", () => { | |||||
| // render(cont); | |||||
| // fireEvent.click(screen.getByTestId("interview-image")); | |||||
| // waitFor(() => expect(screen.getByTestId("interview-dialog")).toBeDefined()); | |||||
| // }); | |||||
| it("Should render selection card if process failed", () => { | |||||
| render(cont); | |||||
| expect( | |||||
| screen.getByRole("button", { | |||||
| name: /neuspešno/i, | |||||
| }) | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should navigate to applicant selection when status is clicked if status is 'failed'", () => { | |||||
| render(cont); | |||||
| var statusBtn = screen.getByRole("button", { | |||||
| name: /neuspešno/i, | |||||
| }); | |||||
| fireEvent.click(statusBtn); | |||||
| // 21364 is the id of the applicant in mockState | |||||
| expect(props.history.push).toHaveBeenCalledWith("/selectionFlow/21364"); | |||||
| }); | |||||
| it("Should navigate to applicant selection when status is clicked if status is 'done'", () => { | |||||
| render(cont); | |||||
| var statusBtn = screen.getAllByRole("button", { | |||||
| name: /zakazan/i, | |||||
| })[0]; | |||||
| fireEvent.click(statusBtn); | |||||
| expect(screen.getByTestId("status-select")).toBeDefined(); | |||||
| }); | |||||
| it("Should not render selection card if process is done", () => { | |||||
| render(cont); | |||||
| expect( | |||||
| screen.queryByRole("button", { | |||||
| name: /odrađen/i, | |||||
| }) | |||||
| ).toBe(null); | |||||
| }); | |||||
| it("Drag and drop", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.drop(container.getElementsByClassName("selection-card")[0], { | |||||
| dataTransfer: { | |||||
| getData: (type) => | |||||
| '{"id":32,"name":"random","status":"Kandidat primljen","date":null,"link":"link","applicant":{"applicantId":6,"firstName":"Safet","lastName":"Purkovic","position":"React Developer","dateOfApplication":"2021-05-05T00:00:00","cv":"dasdas","email":"safet@gmail.com","phoneNumber":"2313123","linkedlnLink":"sda","githubLink":null,"bitBucketLink":null,"experience":2,"applicationChannel":null,"typeOfEmployment":"Posao","technologyApplicants":[],"comments":[],"ads":[],"selectionProcesses":[{"status":"Kandidat primljen","date":null,"link":"link","scheduler":{"id":7,"firstName":"Safet","lastName":"Purkovic","email":"safet.purkovic@dilig.net","isEnabled":true},"selectionLevel":{"id":4,"name":"Konacna odluka"}}]},"selectionLevelId":4}', | |||||
| }, | |||||
| }); | |||||
| }); | |||||
| }); |
| import * as redux from "react-redux"; | |||||
| import store from "../../store"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import { render } from "@testing-library/react"; | |||||
| import history from "../../store/utils/history"; | |||||
| import StatsAd from "../../components/Ads/StatsAd"; | |||||
| describe("StatsAd render tests", () => { | |||||
| var props = { | |||||
| className: "some class", | |||||
| count: 2, | |||||
| title: ".NET", | |||||
| minimumExperience: 1, | |||||
| createdAt: "20.12.2023", | |||||
| expiredAt: "28.12.2023", | |||||
| onShowAdDetails: jest.fn(), | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <StatsAd {...props} /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("stats-ad")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render title", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("archive-ad-title")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render date", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("archive-ad-date")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should render that experience is required because minimumExperience is greater than 0", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container | |||||
| .getElementsByClassName("archive-ad-experience")[0] | |||||
| .getElementsByTagName("p")[0].textContent | |||||
| ).toBe("1+ common.experience"); | |||||
| }); | |||||
| }); |
| import * as redux from "react-redux"; | |||||
| import store from "../../store"; | |||||
| import { Router } from "react-router-dom"; | |||||
| import { mockState } from "../../mockState"; | |||||
| import { render, screen, fireEvent, waitFor } from "@testing-library/react"; | |||||
| import history from "../../store/utils/history"; | |||||
| import StatsPage from "../../pages/StatsPage/StatsPage"; | |||||
| describe("StatsPage render tests", () => { | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <StatsPage /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector.mockReturnValueOnce(mockState); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("stats-section")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render 4 levels for selection process section", () => { | |||||
| render(cont); | |||||
| expect(screen.getAllByTestId("stats-item").length).toBe(4); | |||||
| }); | |||||
| it("Should render 4 levels for relationship section", () => { | |||||
| render(cont); | |||||
| expect(screen.getAllByTestId("stats-item2").length).toBe(4); | |||||
| }); | |||||
| it("Should render ads because there is more than 0 ads", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("archived-ads")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render only one right arrow and that depends on screen size", () => { | |||||
| render(cont); | |||||
| expect(screen.getAllByTestId("right-arrow").length).toBe(1); | |||||
| }); | |||||
| it("Should render right arrow because there is more than 3 ads", () => { | |||||
| render(cont); | |||||
| expect(screen.getAllByTestId("right-arrow")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render only one left arrow and that depends on screen size", () => { | |||||
| render(cont); | |||||
| expect(screen.getAllByTestId("left-arrow").length).toBe(1); | |||||
| }); | |||||
| it("Should render all ads in slider", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("stats-ad").length).toBe( | |||||
| mockState.stats.ads.length | |||||
| ); | |||||
| }); | |||||
| it("Slider should represent 5 ads", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container | |||||
| .getElementsByClassName("slick-list")[0] | |||||
| .getElementsByClassName("slick-active").length | |||||
| ).toBe(5); | |||||
| }); | |||||
| it("After clicking on right arrow slider should represent ad number six as fifth ad in slider", async () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(screen.getAllByTestId("right-arrow")[0]); | |||||
| await waitFor(() => | |||||
| expect( | |||||
| container | |||||
| .getElementsByClassName("slick-list")[0] | |||||
| .getElementsByClassName("slick-active")[4] | |||||
| .getElementsByClassName("archive-ad-title")[0].textContent | |||||
| ).toBe("React") | |||||
| ); | |||||
| }); | |||||
| }); |
| import { render, screen, fireEvent, waitFor } 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 TableViewPage from "../../pages/CandidatesPage/TableViewPage"; | |||||
| import { PAGE_SIZE_CANDIDATES } from "../../constants/keyCodeConstants"; | |||||
| import { getCV } from "../../request/candidatesRequest"; | |||||
| 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, | |||||
| }; | |||||
| const cont = ( | |||||
| <redux.Provider store={store}> | |||||
| <Router history={history}> | |||||
| <TableViewPage search="" {...props} /> | |||||
| </Router> | |||||
| </redux.Provider> | |||||
| ); | |||||
| let spyOnUseSelector; | |||||
| let spyOnUseDispatch; | |||||
| let mockDispatch; | |||||
| beforeEach(() => { | |||||
| spyOnUseSelector = jest.spyOn(redux, "useSelector"); | |||||
| spyOnUseSelector | |||||
| .mockReturnValueOnce(mockState.candidates.candidates) | |||||
| .mockReturnValueOnce(mockState.candidates.pagination); | |||||
| spyOnUseDispatch = jest.spyOn(redux, "useDispatch"); | |||||
| mockDispatch = jest.fn(); | |||||
| spyOnUseDispatch.mockReturnValue(mockDispatch); | |||||
| }); | |||||
| afterEach(() => { | |||||
| jest.restoreAllMocks(); | |||||
| }); | |||||
| it("Should render", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("candidates-table")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Should dispatch function when component is rendered", async () => { | |||||
| render(cont); | |||||
| await waitFor(() => expect(mockDispatch).toBeCalledTimes(1)); | |||||
| }); | |||||
| it("Should render table", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("usersTable")[0]).toBeDefined(); | |||||
| }); | |||||
| it("Should render pagination component", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("candidates-pagination")[0] | |||||
| ).toBeDefined(); | |||||
| }); | |||||
| it("Here we check if our component is displaying as many pages as it should display", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container | |||||
| .getElementsByClassName("css-wjh20t-MuiPagination-ul")[0] | |||||
| .getElementsByTagName("li").length - 2 // we substract because list will contain left and right arrow | |||||
| ).toBe( | |||||
| parseInt(mockState.candidates.candidates.length) <= PAGE_SIZE_CANDIDATES | |||||
| ? 1 | |||||
| : Math.ceil( | |||||
| parseInt(mockState.candidates.candidates.length) / | |||||
| PAGE_SIZE_CANDIDATES | |||||
| ) | |||||
| ); | |||||
| }); | |||||
| it("The number of table rows should be equal to the number of candidates", () => { | |||||
| const { container } = render(cont); | |||||
| expect(container.getElementsByClassName("cadidate-row").length).toBe( | |||||
| mockState.candidates.candidates.length | |||||
| ); | |||||
| }); | |||||
| it("Should render candidate details page after clicking on table row", () => { | |||||
| const { container } = render(cont); | |||||
| fireEvent.click(container.getElementsByClassName("cadidate-row")[0]); | |||||
| const arg = { pathname: "/candidates/1" }; | |||||
| expect(props.history.push).toHaveBeenCalledWith(arg); | |||||
| }); | |||||
| it("Initially CV of candidate isn't displayed", () => { | |||||
| const { container } = render(cont); | |||||
| expect( | |||||
| container.getElementsByClassName("candidates-cv")[0].style.opacity | |||||
| ).toBe("0"); | |||||
| }); | |||||
| // 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 = "some base64 string"; | |||||
| getCV("name od pdf file") | |||||
| .then(() => basse64Pdf) | |||||
| .catch(catchFn); | |||||
| const { container } = render(cont); | |||||
| fireEvent.click( | |||||
| container | |||||
| .getElementsByClassName("cadidate-row")[0] | |||||
| .getElementsByTagName("td")[4] | |||||
| .getElementsByTagName("span")[0] | |||||
| ); | |||||
| waitFor(() => { | |||||
| expect( | |||||
| container.getElementsByClassName("candidates-cv")[0].style.opacity | |||||
| ).toBe("1"); | |||||
| }); | |||||
| }); | |||||
| }); |
| .candidate-card-container { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 36px; | |||||
| gap: 18px; | |||||
| isolation: isolate; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 18px; | |||||
| width: 354px; | |||||
| height: 238px; | |||||
| margin-right: 27px; | |||||
| } | |||||
| @media only screen and (max-width: 480px) { | |||||
| .candidate-card-container{ | |||||
| width: 300px; | |||||
| } | |||||
| } | |||||
| @media only screen and (max-width: 430px) { | |||||
| .candidate-card-container{ | |||||
| width: 240px; | |||||
| } | |||||
| } | |||||
| .candidate-card-container:active { | |||||
| animation-timing-function: ease-in-out; | |||||
| animation-duration: 300ms; | |||||
| } | |||||
| .candidate-card-container:hover{ | |||||
| cursor: pointer; | |||||
| } | |||||
| .candidate-card-tecnologies-container { | |||||
| display: flex; | |||||
| } | |||||
| .candidate-card-date { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 12px; | |||||
| font-weight: 400; | |||||
| line-height: 15px; | |||||
| letter-spacing: 0em; | |||||
| } | |||||
| .candidate-card-applicant-name { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 600; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| color: #226cb0; | |||||
| } | |||||
| .candidate-card-years { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #272727; | |||||
| } | |||||
| .candidate-card-techologies { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| gap: 18px; | |||||
| } |
| .main-candidate-container { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| margin-top: 36px; | |||||
| padding-right: 72px; | |||||
| } | |||||
| .top-candidate-container { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| margin-left: 144px; | |||||
| } | |||||
| .candidate-header { | |||||
| height: 36px; | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 36px; | |||||
| font-weight: 600; | |||||
| line-height: 36px; | |||||
| letter-spacing: 0.02em; | |||||
| text-align: left; | |||||
| color: #272727; | |||||
| } | |||||
| .separation-line { | |||||
| margin-left: 5px; | |||||
| margin-right: 5px; | |||||
| font-size: 20px; | |||||
| align-self: flex-end; | |||||
| } | |||||
| .candidate-lower-header { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 24px; | |||||
| font-weight: 600; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| text-align: left; | |||||
| color: #226cb0; | |||||
| align-self: flex-end; | |||||
| } | |||||
| .candidate-option-container { | |||||
| display: flex; | |||||
| height: 38px; | |||||
| } | |||||
| .content-candidate-container { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| margin-top: 14px; | |||||
| margin-left: 144px; | |||||
| } | |||||
| .technologies-candidate-container { | |||||
| display: flex; | |||||
| margin-top: 18px; | |||||
| } | |||||
| .technology-candidate-card { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 9px; | |||||
| gap: 10px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 9px; | |||||
| } | |||||
| .technology-candidate-card:not(:last-child) { | |||||
| margin-right: 18px; | |||||
| } | |||||
| .comment-container { | |||||
| width: 612px; | |||||
| height: 404px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 12px; | |||||
| margin-top: 16px; | |||||
| } | |||||
| .candidate-informations-container { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| } | |||||
| .candidate-informations-sub-container { | |||||
| margin-top: 36px; | |||||
| } | |||||
| .informations-candidate-header { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #272727; | |||||
| } | |||||
| .candidate-property-container { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| } | |||||
| .candidate-property { | |||||
| margin-top: 18px; | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 400; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| } | |||||
| .candidate-property-value { | |||||
| @extend .candidate-property; | |||||
| color: #1e92d0; | |||||
| } | |||||
| .candidate-informations-sub-container { | |||||
| display: flex; | |||||
| } | |||||
| .comment-container { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| padding-left: 36px; | |||||
| padding-right: 36px; | |||||
| padding-top: 36px; | |||||
| } | |||||
| .comment-sub-container { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| .comment-sub-container:not(:first-child) { | |||||
| margin-top: 36px; | |||||
| } | |||||
| .comment-sender { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| width: 40px; | |||||
| height: 40px; | |||||
| border-radius: 50%; | |||||
| box-sizing: border-box; | |||||
| border: 1px solid; | |||||
| border-color: #226cb0; | |||||
| } | |||||
| .comment-sender p { | |||||
| color: #226cb0; | |||||
| } | |||||
| .comment-message { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: center; | |||||
| align-items: flex-end; | |||||
| padding: 9px; | |||||
| gap: 9px; | |||||
| height: fit-content; | |||||
| background: #f4f4f4; | |||||
| border-radius: 12px; | |||||
| margin-left: 18px; | |||||
| max-width: 400px; | |||||
| } | |||||
| .comment-message-content { | |||||
| align-self: flex-start; | |||||
| height: 20px; | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| } | |||||
| .comment-message-date { | |||||
| align-self: flex-end; | |||||
| height: 15px; | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 12px; | |||||
| line-height: 15px; | |||||
| color: #272727; | |||||
| } | |||||
| .comment-separation-line { | |||||
| width: 100%; | |||||
| height: 0px; | |||||
| border: 1px solid #e4e4e4; | |||||
| background: #e4e4e4; | |||||
| } | |||||
| .send-comment-container { | |||||
| margin-top: 18px; | |||||
| } | |||||
| .send-comment-container p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #9d9d9d; | |||||
| } | |||||
| .send-comment-sub-container { | |||||
| display: flex; | |||||
| margin-top: 9px; | |||||
| height: 56px; | |||||
| margin-bottom: 36px; | |||||
| } | |||||
| .comment-send-btn { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 18px 36px; | |||||
| gap: 10px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #226cb0; | |||||
| border-radius: 9px; | |||||
| border: 1px solid #226cb0; | |||||
| width: 156px; | |||||
| margin-left: 18px; | |||||
| } | |||||
| .comment-send-btn-responsive { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| background: #ffffff; | |||||
| border: 1px solid #226cb0; | |||||
| border-radius: 9px; | |||||
| border: 1px solid #226cb0; | |||||
| margin-left: 18px; | |||||
| width: 54px; | |||||
| height: 54px; | |||||
| } | |||||
| .comment-send-btn:hover { | |||||
| cursor: pointer; | |||||
| } | |||||
| .comment-send-btn-responsive:hover { | |||||
| cursor: pointer; | |||||
| } | |||||
| .comment-send-btn-responsive img { | |||||
| margin: 0; | |||||
| } | |||||
| .comment-send-btn p { | |||||
| width: 62px; | |||||
| height: 15px; | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 12px; | |||||
| line-height: 15px; | |||||
| letter-spacing: 0.04em; | |||||
| text-transform: uppercase; | |||||
| color: #226cb0; | |||||
| flex: none; | |||||
| order: 1; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .comment-send-btn img { | |||||
| width: 12px; | |||||
| height: 12px; | |||||
| } | |||||
| .comment-send-btn-responsive img { | |||||
| width: 12px; | |||||
| height: 12px; | |||||
| } | |||||
| .candidate-users { | |||||
| background-color: #f4f4f4; | |||||
| } | |||||
| .candidate-user { | |||||
| color: #226cb0; | |||||
| } | |||||
| .applicant-ads-container { | |||||
| margin-top: 36px; | |||||
| } | |||||
| .applicant-ads-container > p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-weight: 600; | |||||
| font-size: 24px; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| color: #272727; | |||||
| } | |||||
| .applicant-ads-sub-container { | |||||
| margin-top: 18px; | |||||
| display: flex; | |||||
| margin-left: -20px; | |||||
| } | |||||
| .applicant-add { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| padding: 36px; | |||||
| gap: 18px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 12px; | |||||
| width: 247px; | |||||
| height: 238px; | |||||
| cursor: pointer; | |||||
| margin-left: 27px; | |||||
| } | |||||
| .applicant-add-date { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 12px; | |||||
| font-weight: 400; | |||||
| line-height: 15px; | |||||
| letter-spacing: 0em; | |||||
| } | |||||
| .applicant-add-title { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-weight: 600; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #226cb0; | |||||
| } | |||||
| .applicant-add-site { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| background: #ffffff; | |||||
| padding: 5px; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 8px; | |||||
| font-size: 16px; | |||||
| font-family: "Source Sans Pro"; | |||||
| font-weight: 400; | |||||
| color: #272727; | |||||
| } | |||||
| .applicant-ads-buttons-container { | |||||
| display: flex; | |||||
| align-self: flex-end; | |||||
| align-items: center; | |||||
| margin-bottom: 54px; | |||||
| margin-top: 18px; | |||||
| } | |||||
| .applicant-cv-button { | .applicant-cv-button { | ||||
| display: flex; | display: flex; | ||||
| cursor: pointer; | cursor: pointer; | ||||
| } | } | ||||
| .tagStyle { | |||||
| color: #226cb0; | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 600; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| } | |||||
| .comment-input { | |||||
| @extend .tagStyle; | |||||
| min-width: 368px; | |||||
| max-width: 368px; | |||||
| } | |||||
| .comment-input::placeholder { | |||||
| height: 20px; | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: italic; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #9d9d9d; | |||||
| flex: none; | |||||
| } | |||||
| .comment-input-list { | |||||
| @extend .tagStyle; | |||||
| } | |||||
| .comment-message-con { | |||||
| max-width: 400px; | |||||
| } | |||||
| .comment-container-header { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 18px; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| color: #272727; | |||||
| } | |||||
| .applicant-ads-container-2 { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-top: 18px; | |||||
| } | |||||
| @media only screen and (max-width: 930px) { | |||||
| .comment-container { | |||||
| width: 500px; | |||||
| } | |||||
| .comment-input { | |||||
| width: 250px; | |||||
| } | |||||
| .comment-message-con { | |||||
| max-width: 300px; | |||||
| } | |||||
| } | |||||
| @media only screen and (max-width: 820px) { | |||||
| .comment-container { | |||||
| width: 400px; | |||||
| } | |||||
| .comment-input { | |||||
| width: 170px; | |||||
| } | |||||
| .comment-message-con { | |||||
| max-width: 200px; | |||||
| } | |||||
| .comment-send-btn { | |||||
| width: 90; | |||||
| padding: 10px 20px; | |||||
| } | |||||
| .send-comment-sub-container { | |||||
| height: 45px; | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| .comment-input ::placeholder { | |||||
| font-size: 14px; | |||||
| line-height: 18px; | |||||
| padding-top: 2px; | |||||
| } | |||||
| } | |||||
| @media only screen and (max-width: 700px) { | |||||
| .comment-container { | |||||
| width: 380px; | |||||
| } | |||||
| .comment-message-con { | |||||
| max-width: 180px; | |||||
| } | |||||
| .comment-send-btn { | |||||
| width: 110; | |||||
| padding: 10px 20px; | |||||
| } | |||||
| } | |||||
| @media only screen and (max-width: 680px) { | |||||
| .content-candidate-container { | |||||
| flex-direction: column; | |||||
| } | |||||
| .comment-container { | |||||
| margin-top: 30px; | |||||
| } | |||||
| } | |||||
| @media only screen and (max-width: 540px) { | @media only screen and (max-width: 540px) { | ||||
| .candidate-header { | |||||
| height: 30px; | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 30px; | |||||
| line-height: 30px; | |||||
| } | |||||
| .candidate-lower-header { | |||||
| font-size: 18px; | |||||
| line-height: 26px; | |||||
| } | |||||
| .applicant-cv-button { | .applicant-cv-button { | ||||
| padding: 10px 52px; | padding: 10px 52px; | ||||
| gap: 7px; | gap: 7px; | ||||
| } | } | ||||
| } | } | ||||
| @media only screen and (max-width: 480px) { | |||||
| .comment-container { | |||||
| width: 297px; | |||||
| } | |||||
| .comment-input { | |||||
| width: 100px; | |||||
| } | |||||
| .comment-input::placeholder { | |||||
| font-size: 12px; | |||||
| line-height: 15px; | |||||
| padding-top: -2px; | |||||
| } | |||||
| .comment-message-con { | |||||
| max-width: 130px; | |||||
| } | |||||
| .comment-send-btn { | |||||
| padding: 5px 5px; | |||||
| } | |||||
| .comment-container { | |||||
| padding: 20px; | |||||
| } | |||||
| .candidate-header { | |||||
| height: 20x; | |||||
| font-size: 20px; | |||||
| line-height: 20px; | |||||
| } | |||||
| .candidate-lower-header { | |||||
| font-size: 17px; | |||||
| line-height: 17px; | |||||
| } | |||||
| } | |||||
| @media only screen and (max-width: 361px) { | @media only screen and (max-width: 361px) { | ||||
| .main-candidate-container{ | |||||
| padding-right: 36px; | |||||
| } | |||||
| .top-candidate-container { | |||||
| margin-left: 36px; | |||||
| } | |||||
| .content-candidate-container { | |||||
| margin-left: 36px; | |||||
| } | |||||
| .comment-input { | |||||
| @extend .tagStyle; | |||||
| min-width: 195px; | |||||
| max-width: 195px; | |||||
| height: 54px; | |||||
| } | |||||
| .comment-send-btn { | |||||
| width: fit-content; | |||||
| } | |||||
| .comment-input::placeholder { | |||||
| font-size: 10px; | |||||
| line-height: 12px; | |||||
| padding: 14px; | |||||
| } | |||||
| .comment-container { | |||||
| width: 300px; | |||||
| padding-left: 18px; | |||||
| } | |||||
| .content-candidate-container { | |||||
| justify-content: initial; | |||||
| } | |||||
| .applicant-ads-container-2 { | |||||
| flex-direction: column-reverse; | |||||
| align-items: flex-start; | |||||
| } | |||||
| .slick-list { | |||||
| padding-left: 0 !important; | |||||
| } | |||||
| .applicant-ads-back-button { | .applicant-ads-back-button { | ||||
| font-size: 14px; | font-size: 14px; | ||||
| line-height: 18px; | line-height: 18px; | ||||
| line-height: 15px; | line-height: 15px; | ||||
| letter-spacing: 0.04em; | letter-spacing: 0.04em; | ||||
| } | } | ||||
| .active-ads-ads-arrows { | |||||
| margin-left: -0.75rem; | |||||
| } | |||||
| .applicant-ads-buttons-container{ | |||||
| margin-left: 36px; | |||||
| } | |||||
| } | } |
| .main-candidates-container { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| margin-bottom: 36px; | |||||
| margin-top: 36px; | |||||
| padding-left: 72px; | |||||
| } | |||||
| .top-candidates-container { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| margin-left: 72px; | |||||
| margin-right: 72px; | |||||
| } | |||||
| .candidate-btn { | .candidate-btn { | ||||
| margin-left: 20px; | margin-left: 20px; | ||||
| font-family: "Source Sans Pro"; | font-family: "Source Sans Pro"; | ||||
| text-transform: none; | text-transform: none; | ||||
| } | } | ||||
| .all-white-btn { | |||||
| background: linear-gradient(0deg, #e8f7ff, #e8f7ff), | |||||
| linear-gradient(0deg, #226cb0, #226cb0); | |||||
| } | |||||
| .candidate-btn-mobile { | |||||
| @extend .candidate-btn; | |||||
| // overrride style from candidate-btn class | |||||
| margin-left: 10px; | |||||
| } | |||||
| .invite-btn { | .invite-btn { | ||||
| padding: 18px 72px; | padding: 18px 72px; | ||||
| gap: 10px; | gap: 10px; | ||||
| margin-bottom: 36px; | margin-bottom: 36px; | ||||
| } | } | ||||
| .candidates-options-container { | |||||
| display: flex; | |||||
| } | |||||
| .candidates-header { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 36px; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| color: #272727; | |||||
| } | |||||
| .candidates-table { | |||||
| margin-top: 30px; | |||||
| width: 100%; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| min-height: 70vh; | |||||
| align-items: space-between; | |||||
| } | |||||
| .candidates-image { | .candidates-image { | ||||
| height: 14px; | height: 14px; | ||||
| width: 16px; | width: 16px; | ||||
| margin-left: 10px; | margin-left: 10px; | ||||
| } | } | ||||
| .candidate-image-mobile { | |||||
| position: "relative"; | |||||
| top: -0.25; | |||||
| } | |||||
| .invite-btn-color { | |||||
| color: #fff; | |||||
| background-color: #226cb0; | |||||
| } | |||||
| .ads-candidates-container { | |||||
| max-height: 837px; | |||||
| overflow-y: auto; | |||||
| overflow-x: hidden; | |||||
| } | |||||
| .ads-candidates-slider { | |||||
| display: flex; | |||||
| margin-top: 31px; | |||||
| } | |||||
| .ads-candidates-slider .slick-track { | |||||
| margin: 0 !important; | |||||
| } | |||||
| .ads-candidates-slider .slick-slider { | |||||
| width: 100% !important; | |||||
| } | |||||
| .ads-candidates-top-container { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-left: 72px; | |||||
| } | |||||
| .ads-candidates-title { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 24px; | |||||
| font-weight: 600; | |||||
| letter-spacing: 0.02em; | |||||
| margin-left: 18px; | |||||
| } | |||||
| .ads-candidates-numberOfApplicants { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 600; | |||||
| letter-spacing: 0em; | |||||
| color: #226cb0; | |||||
| margin-left: 5px; | |||||
| } | |||||
| .ads-candidates-image { | |||||
| width: 49px; | |||||
| height: 39px; | |||||
| } | |||||
| .top-cnd { | |||||
| margin-top: 39px; | |||||
| } | |||||
| .top-cnd > div:not(:first-child) { | |||||
| margin-top: 79px; | |||||
| } | |||||
| .filter-date-container { | |||||
| border: none; | |||||
| box-sizing: border-box; | |||||
| outline: 0; | |||||
| position: relative; | |||||
| width: 100%; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| margin-top: 10px; | |||||
| } | |||||
| .filter-date-container input[type="date"]::-webkit-calendar-picker-indicator { | |||||
| background: transparent; | |||||
| bottom: 0; | |||||
| color: transparent; | |||||
| cursor: pointer; | |||||
| height: auto; | |||||
| left: 0; | |||||
| position: absolute; | |||||
| right: 0; | |||||
| top: 0; | |||||
| width: auto; | |||||
| } | |||||
| .filter-date-container input { | |||||
| border: 1px solid gray; | |||||
| border-radius: 4px; | |||||
| height: 40px; | |||||
| padding-left: 12px; | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-style: italic; | |||||
| font-weight: 400; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| color: #9d9d9d; | |||||
| margin-top: 5px; | |||||
| } | |||||
| .left-move-candidateAd { | |||||
| margin-left: -0.75rem !important; | |||||
| } | |||||
| .left-move-candidateAd-page { | |||||
| margin-left: 16px; | |||||
| } | |||||
| .left-move-candidateAd-page-2 { | |||||
| margin-left: 42px; | |||||
| } | |||||
| // .ads-search-field-responsive { | |||||
| // min-width: 350px; | |||||
| // border: 1px solid #226cb0; | |||||
| // border-radius: 10px; | |||||
| // padding: 20px; | |||||
| // background-color: white; | |||||
| // position: absolute; | |||||
| // top: 100px; | |||||
| // right: 9px; | |||||
| // z-index: 1000; | |||||
| // &.smaller { | |||||
| // min-width: 250px !important; | |||||
| // } | |||||
| // } | |||||
| .ads-search-field-responsive2 { | .ads-search-field-responsive2 { | ||||
| border: 1px solid #226cb0; | border: 1px solid #226cb0; | ||||
| border-radius: 10px; | border-radius: 10px; | ||||
| font-style: italic; | font-style: italic; | ||||
| } | } | ||||
| .cls1 .slick-track { | |||||
| margin-left: 35px !important; | |||||
| } | |||||
| .cls2 .slick-track { | |||||
| margin-left: 20px !important; | |||||
| } | |||||
| .cls3 .slick-track { | |||||
| margin-left: 0px !important; | |||||
| } | |||||
| .cls4 .slick-track { | |||||
| margin-left: 45px !important; | |||||
| } | |||||
| .candidates-pagination { | .candidates-pagination { | ||||
| margin-top: 20px; | margin-top: 20px; | ||||
| align-self: center; | align-self: center; | ||||
| padding-bottom: 20px; | padding-bottom: 20px; | ||||
| } | } | ||||
| .candidates-cv { | |||||
| width: 500px; | |||||
| height: 610px; | |||||
| margin-right: 72px; | |||||
| } | |||||
| @media only screen and (max-width: 600px) { | |||||
| .ads-candidates-title { | |||||
| font-size: 18px; | |||||
| margin-left: 10px; | |||||
| } | |||||
| .ads-candidates-image { | |||||
| width: 40px; | |||||
| height: 30px; | |||||
| } | |||||
| .ads-candidates-numberOfApplicants { | |||||
| font-size: 14px; | |||||
| } | |||||
| } | |||||
| @media only screen and (max-width: 361px) { | |||||
| .ads-candidates-slider { | |||||
| flex-direction: column-reverse; | |||||
| } | |||||
| .main-candidates-container { | |||||
| padding-left: 0px; | |||||
| } | |||||
| .top-candidates-container { | |||||
| margin-left: 36px; | |||||
| margin-right: 29px; | |||||
| } | |||||
| .candidates-textField { | |||||
| margin-left: 36px; | |||||
| } | |||||
| .ads-candidates-top-container { | |||||
| margin-left: 36px; | |||||
| } | |||||
| .left-move-candidateAd-page { | |||||
| margin-left: -12px; | |||||
| } | |||||
| } |
| .day-component-container { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| height: 143px; | |||||
| width: 178px; | |||||
| border: 1px solid #f4f4f4; | |||||
| padding: 17px; | |||||
| transition: 0.5s; | |||||
| } | |||||
| .day-component-container:hover{ | |||||
| cursor: pointer; | |||||
| scale: 1.02; | |||||
| animation-timing-function: ease-in-out; | |||||
| animation-duration: 300ms; | |||||
| } | |||||
| .day-component-container:hover { | |||||
| height: 151px; | |||||
| width: 184px; | |||||
| left: 489px; | |||||
| top: 244px; | |||||
| border-radius: 12px; | |||||
| background: linear-gradient(0deg, #e8f7ff, #e8f7ff), | |||||
| linear-gradient(0deg, #226cb0, #226cb0); | |||||
| border: 1px solid #226cb0; | |||||
| } | |||||
| .day-component-day-informations-container { | |||||
| display: flex; | |||||
| height: fit-content; | |||||
| margin-bottom: 5px; | |||||
| } | |||||
| .day-component-day-number { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 600; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| color: linear-gradient(0deg, #353535, #353535), | |||||
| linear-gradient(0deg, #272727, #272727); | |||||
| } | |||||
| .day-component-day-name { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 12px; | |||||
| font-weight: 400; | |||||
| line-height: 15px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| align-self: flex-end; | |||||
| margin-left: 3px; | |||||
| } | |||||
| .day-component-interviews-container { | |||||
| display: flex; | |||||
| } | |||||
| .day-component-interviews-time { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 12px; | |||||
| font-weight: 400; | |||||
| line-height: 15px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| align-self: flex-end; | |||||
| } | |||||
| .day-component-interviews-name { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 600; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| color: #353535; | |||||
| margin-left: 3px; | |||||
| } | |||||
| .day-component-more { | |||||
| height: 15px; | |||||
| width: fit-content; | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 12px; | |||||
| font-weight: 400; | |||||
| line-height: 15px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| color: #226CB0; | |||||
| font-style: normal; | |||||
| text-decoration-line: underline; | |||||
| cursor: pointer; | |||||
| margin-top: 21px; | |||||
| } |
| .day-details-sub-container { | |||||
| padding-top: 46px; | |||||
| padding-left: 36px; | |||||
| padding-right: 36px; | |||||
| padding-bottom: 36px; | |||||
| } | |||||
| .day-datails-title-container { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| height: fit-content; | |||||
| } | |||||
| .day-details-calendar-image { | |||||
| width: 15.75px; | |||||
| height: 18px; | |||||
| } | |||||
| .day-details-main-header { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 24px; | |||||
| font-weight: 600; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| text-align: left; | |||||
| margin-left: 9.25px; | |||||
| } | |||||
| .day-details-header { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 600; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| color: #226cb0; | |||||
| margin-left: 5px; | |||||
| align-self: flex-end; | |||||
| } | |||||
| .day-details-close-btn { | |||||
| margin-left: 208px; | |||||
| cursor: pointer; | |||||
| } | |||||
| .day-details-time { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 400; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| border: 1px solid #f4f4f4; | |||||
| padding: 8px; | |||||
| border-radius: 10px; | |||||
| } | |||||
| .day-details-line { | |||||
| height: 1px; | |||||
| width: 100%; | |||||
| background-color: #f4f4f4; | |||||
| margin-top: 19px; | |||||
| margin-bottom: 19px; | |||||
| } | |||||
| .day-details-name { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 400; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| color: #272727; | |||||
| margin-left: 6px; | |||||
| width: 111px; | |||||
| } | |||||
| .day-details-applicant { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 600; | |||||
| line-height: 20px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| color: #226cb0; | |||||
| margin-left: 72px; | |||||
| width: 110px; | |||||
| cursor: pointer; | |||||
| text-decoration: none; | |||||
| } | |||||
| .day-details-link { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| gap: 10px; | |||||
| height: 36px; | |||||
| width: 120px; | |||||
| border-radius: 9px; | |||||
| padding: 18px 36px 18px 36px; | |||||
| color: linear-gradient(0deg, #226cb0, #226cb0), | |||||
| linear-gradient(0deg, #ffffff, #ffffff); | |||||
| border: 1px solid #226cb0; | |||||
| margin-left: 28px; | |||||
| cursor: pointer; | |||||
| text-decoration: none; | |||||
| } | |||||
| .day-details-link span { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 12px; | |||||
| font-weight: 600; | |||||
| line-height: 15px; | |||||
| letter-spacing: 0.04em; | |||||
| text-align: left; | |||||
| color: #226cb0; | |||||
| text-transform: uppercase; | |||||
| } | |||||
| .day-details-content-sub-container > div:first-child { | |||||
| margin-top: 37px; | |||||
| } | |||||
| .day-details-arrow-container { | |||||
| display: flex; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 7px; | |||||
| width: 36px; | |||||
| height: 36px; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| cursor: pointer; | |||||
| } | |||||
| .day-details-arrow-container-p { | |||||
| display: flex; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 7px; | |||||
| width: 36px; | |||||
| height: 36px; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| cursor: pointer; | |||||
| transform: rotate(-180deg); | |||||
| } | |||||
| @media only screen and (max-width: 361px) { | |||||
| .day-details-applicant { | |||||
| margin-left: 10px; | |||||
| } | |||||
| .day-details-sub-container { | |||||
| padding: 32px; | |||||
| } | |||||
| .day-details-link { | |||||
| width: 36px; | |||||
| height: 36px; | |||||
| gap: 0px; | |||||
| padding: 11px; | |||||
| margin-left: 20px; | |||||
| } | |||||
| .day-details-name { | |||||
| width: 66px; | |||||
| } | |||||
| .day-details-applicant { | |||||
| width: 97px; | |||||
| } | |||||
| .day-details-close-btn { | |||||
| margin-left: 12px; | |||||
| } | |||||
| .day-details-main-header { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 16px; | |||||
| font-weight: 600; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| text-align: left; | |||||
| } | |||||
| .day-details-header{ | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 12px; | |||||
| font-weight: 600; | |||||
| line-height: 18px; | |||||
| letter-spacing: 0em; | |||||
| text-align: left; | |||||
| } | |||||
| .day-details-header{ | |||||
| align-self: center; | |||||
| } | |||||
| } | |||||
| .css-ypiqx9-MuiDialogContent-root{ | |||||
| .css-ypiqx9-MuiDialogContent-root { | |||||
| padding: 0px !important; | padding: 0px !important; | ||||
| } | } | ||||
| .css-bdhsul-MuiTypography-root-MuiDialogTitle-root{ | |||||
| .css-bdhsul-MuiTypography-root-MuiDialogTitle-root { | |||||
| padding: 0px !important; | padding: 0px !important; | ||||
| } | |||||
| } |
| .patterns { | |||||
| padding: 0 72px; | |||||
| @include media-below($bp-xl) { | |||||
| padding: 0 18px; | |||||
| } | |||||
| } | |||||
| .patterns-header { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| margin-top: 16px; | |||||
| padding-left: calc(144px - 72px); | |||||
| margin-bottom: 18px !important; | |||||
| @include media-below($bp-xl) { | |||||
| padding-left: 18px; | |||||
| } | |||||
| } | |||||
| .pattern-header-active-button { | |||||
| background-color: $mainBlueLight !important; | |||||
| } | |||||
| .patterns-header button { | |||||
| margin-left: 14px; | |||||
| } | |||||
| .patterns-cards { | |||||
| padding: 0 calc(138px - 72px) 0 calc(144px - 72px); | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| width: 100% !important; | |||||
| margin-bottom: 18px !important; | |||||
| @include media-below($bp-xl) { | |||||
| padding: 0 18px !important; | |||||
| flex-direction: column !important; | |||||
| } | |||||
| } | |||||
| .pattern-card-parent { | |||||
| width: calc(100% / 3) !important; | |||||
| margin-bottom: 36px; | |||||
| padding-right: 36px; | |||||
| @include media-below($bp-xl) { | |||||
| width: 100% !important; | |||||
| padding: 0 !important; | |||||
| } | |||||
| } | |||||
| /* PATTERN CARD */ | |||||
| .pattern-card-with-icon { | |||||
| position: relative; | |||||
| } | |||||
| .pattern-card { | |||||
| position: relative; | |||||
| box-sizing: border-box; | |||||
| padding: 72px !important; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| gap: 18px; | |||||
| isolation: isolate; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 18px; | |||||
| width: 100% !important; | |||||
| transition: 0.3s; | |||||
| cursor: pointer; | |||||
| } | |||||
| .pattern-card:hover { | |||||
| scale: 1.05; | |||||
| border-color: $mainBlue !important; | |||||
| background-color: $mainBlueLight !important; | |||||
| } | |||||
| .pattern-card-edit { | |||||
| position: absolute; | |||||
| top: 9px !important; | |||||
| right: 9px !important; | |||||
| border-radius: 50% !important; | |||||
| width: 40px !important; | |||||
| height: 40px !important; | |||||
| z-index: 100; | |||||
| } | |||||
| .pattern-card-date p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 12px; | |||||
| line-height: 15px; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| z-index: 0; | |||||
| } | |||||
| .pattern-card-title p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 24px; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| color: $mainBlue; | |||||
| flex: none; | |||||
| order: 1; | |||||
| flex-grow: 0; | |||||
| z-index: 1; | |||||
| } | |||||
| .pattern-card-selection-proccess { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 9px; | |||||
| gap: 10px; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 9px; | |||||
| flex: none; | |||||
| order: 2; | |||||
| flex-grow: 0; | |||||
| z-index: 2; | |||||
| } | |||||
| .pattern-card-date, | |||||
| .pattern-card-title, | |||||
| .pattern-card-selection-proccess { | |||||
| display: flex !important; | |||||
| justify-content: center !important; | |||||
| } | |||||
| .patterns-button { | |||||
| padding-bottom: 18px; | |||||
| display: flex; | |||||
| justify-content: flex-end; | |||||
| } | |||||
| /* AD DETAILS */ | |||||
| .pattern-details { | |||||
| padding: 42px 36px 72px 36px !important; | |||||
| @include media-below($bp-xl) { | |||||
| margin-top: 9px; | |||||
| } | |||||
| } | |||||
| .pattern-details-header { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-end; | |||||
| @include media-below($bp-xl) { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 14px; | |||||
| justify-content: flex-start; | |||||
| } | |||||
| } | |||||
| .pattern-details-header p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| text-align: right; | |||||
| } | |||||
| .pattern-details-header p span { | |||||
| color: #9d9d9d; | |||||
| } | |||||
| .pattern-details-card { | |||||
| margin: 41px auto 0 auto !important; | |||||
| padding: 0 405px !important; | |||||
| @include media-below($bp-xl) { | |||||
| margin: 9px auto 0 auto !important; | |||||
| padding: 0 !important; | |||||
| } | |||||
| } | |||||
| .pattern-details-card-title { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-bottom: 7px; | |||||
| @include media-below($bp-xl) { | |||||
| margin-top: 9px; | |||||
| } | |||||
| } | |||||
| .pattern-details-card-title-title h1 { | |||||
| font-size: 36px; | |||||
| margin-right: 4px; | |||||
| @include media-below($bp-xl) { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 18px; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| } | |||||
| } | |||||
| .pattern-details-card-title-sub { | |||||
| font-size: 24px; | |||||
| color: $mainBlue; | |||||
| font-weight: 600; | |||||
| @include media-below($bp-xl) { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 18px; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| } | |||||
| } | |||||
| .pattern-details-card-sub-card { | |||||
| margin-bottom: 18px; | |||||
| } | |||||
| .pattern-details-card-sub-card-title { | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| .pattern-details-card-screening-title p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #272727; | |||||
| } | |||||
| .pattern-details-card-sub-card-emails { | |||||
| display: flex; | |||||
| flex-wrap: wrap; | |||||
| } | |||||
| .pattern-details-card-sub-card-emails > div { | |||||
| margin-right: 9px; | |||||
| margin-bottom: 4px; | |||||
| } | |||||
| .pattern-details-card-sub-card-emails-email { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 9px; | |||||
| gap: 10px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 9px; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .pattern-details-card-sub-card-add-email { | |||||
| display: flex; | |||||
| } | |||||
| .pattern-details-card-sub-card-add-email input, | |||||
| .pattern-details-card-sub-card-add-email select { | |||||
| margin-right: 18px; | |||||
| flex: 50; | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: center; | |||||
| padding: 18px; | |||||
| gap: 10px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 7px; | |||||
| outline: none; | |||||
| } | |||||
| .pattern-details-card-sub-card-add-email button { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 18px; | |||||
| gap: 10px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #226cb0; | |||||
| border-radius: 9px; | |||||
| flex: 1; | |||||
| cursor: pointer; | |||||
| transition: 0.3s; | |||||
| } | |||||
| .pattern-details-card-sub-card-add-email button:hover { | |||||
| background-color: $mainBlueLight; | |||||
| } | |||||
| .pattern-details-card-sub-card-add-email button img { | |||||
| width: 12px; | |||||
| height: 12px; | |||||
| } | |||||
| .pattern-details-card-sub-card-message-pattern { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| height: 256px !important; | |||||
| border: 2px solid#ccc !important; | |||||
| background: rgb(224, 224, 224) !important; | |||||
| border-radius: 6px; | |||||
| padding: 1rem; | |||||
| } | |||||
| .pattern-details-card-sub-card-message-pattern ul { | |||||
| list-style: disc; | |||||
| padding: 1rem 2rem; | |||||
| } | |||||
| .pattern-details-card-sub-card-message-pattern textarea { | |||||
| resize: none; | |||||
| width: 100%; | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: flex-start; | |||||
| padding: 18px; | |||||
| gap: 10px; | |||||
| background: #f4f4f4; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 7px; | |||||
| min-height: 256px; | |||||
| } | |||||
| .pattern-details-card-buttons { | |||||
| display: flex; | |||||
| justify-content: flex-end; | |||||
| align-items: center; | |||||
| } | |||||
| .pattern-details-card-buttons > * { | |||||
| margin-left: 18px !important; | |||||
| } | |||||
| .custom-modal { | .custom-modal { | ||||
| padding: 36px !important; | padding: 36px !important; | ||||
| cursor: pointer; | cursor: pointer; | ||||
| } | } | ||||
| .edit-pattern-modal { | |||||
| width: 512px; | |||||
| min-height: 618px; | |||||
| } | |||||
| .edit-pattern-modal-header { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| margin-bottom: 18px; | |||||
| } | |||||
| .edit-pattern-modal-header-title { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| .edit-pattern-modal-header-title > * { | |||||
| margin-right: 4px; | |||||
| } | |||||
| .edit-pattern-modal-header-title-image img { | |||||
| width: 18px; | |||||
| height: 18px; | |||||
| } | |||||
| .edit-pattern-modal-header-title-title p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 24px; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| color: #272727; | |||||
| } | |||||
| .edit-pattern-modal-header-title-sub sub { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| line-height: 32px; | |||||
| font-size: 18px; | |||||
| letter-spacing: 0.02em; | |||||
| color: $mainBlue; | |||||
| } | |||||
| .edit-pattern-modal-header-close img { | |||||
| width: 9px; | |||||
| height: 10.5px; | |||||
| cursor: pointer; | |||||
| } | |||||
| .edit-pattern-modal-form-control { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| margin-bottom: 9px; | |||||
| } | |||||
| .edit-pattern-modal-form-control .tox { | |||||
| height: 300px !important; | |||||
| } | |||||
| .edit-pattern-modal-form-control label { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #272727; | |||||
| margin-bottom: 4.5px; | |||||
| } | |||||
| .edit-pattern-modal-form-control input, | |||||
| .edit-pattern-modal-form-control select, | |||||
| .edit-pattern-modal-form-control textarea { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: center; | |||||
| padding: 18px; | |||||
| gap: 10px; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 7px; | |||||
| outline: none; | |||||
| } | |||||
| .edit-pattern-modal-form-control textarea { | |||||
| resize: none; | |||||
| } | |||||
| .edit-pattern-modal-form-control input[type="submit"] { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 18px 72px; | |||||
| gap: 10px; | |||||
| background: #226cb0; | |||||
| color: white; | |||||
| border-radius: 9px; | |||||
| cursor: pointer; | |||||
| } | |||||
| /* CUSTOM-FILTER-DRAWER */ | |||||
| .custom-drawer { | |||||
| display: flex; | |||||
| height: 100% !important; | |||||
| flex-direction: column; | |||||
| justify-content: space-between; | |||||
| } | |||||
| .custom-filter-drawer-header-container { | .custom-filter-drawer-header-container { | ||||
| display: flex; | display: flex; | ||||
| justify-content: space-between; | justify-content: space-between; |
| .schedule-page-container { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| padding-bottom: 46px; | |||||
| overflow-x: auto; | |||||
| } | |||||
| .schedule-page-main-header { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 36px; | |||||
| font-weight: 600; | |||||
| line-height: 36px; | |||||
| letter-spacing: 0.02em; | |||||
| text-align: left; | |||||
| } | |||||
| .schedule-page-header { | |||||
| font-family: Source Sans Pro; | |||||
| font-size: 24px; | |||||
| font-weight: 600; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| text-align: left; | |||||
| color: #226cb0; | |||||
| align-self: flex-end; | |||||
| margin-left: 5px; | |||||
| } | |||||
| .schedule-page-arrows-container { | |||||
| display: flex; | |||||
| gap: 18px; | |||||
| margin-top: 32px; | |||||
| } | |||||
| .schedule-page-arrow-container { | |||||
| display: flex; | |||||
| height: 45px; | |||||
| width: 45px; | |||||
| border-radius: 9px; | |||||
| border: 1px solid #e4e4e4; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| cursor: pointer; | |||||
| } | |||||
| .schedule-page-content-container { | |||||
| display: grid; | |||||
| grid-template-columns: auto auto auto auto auto auto auto; | |||||
| padding-top: 18px; | |||||
| padding-right: 59px; | |||||
| padding-bottom: 10px; | |||||
| grid-gap: 0px; | |||||
| width: 1305px; | |||||
| } | |||||
| @media only screen and (max-width: 361px) { | |||||
| .schedule-page-main-header { | |||||
| font-size: 18px; | |||||
| } | |||||
| .schedule-page-header{ | |||||
| font-size: 14px; | |||||
| } | |||||
| .schedule-page-arrow-container{ | |||||
| width: 36px; | |||||
| height: 36px; | |||||
| } | |||||
| .schedule-page-content-container{ | |||||
| padding-right: 36px; | |||||
| width: 1250px; | |||||
| } | |||||
| } |
| .selections { | |||||
| padding-left: 153px; | |||||
| @include media-below($bp-xl) { | |||||
| padding-left: 36px !important; | |||||
| } | |||||
| } | |||||
| .level-header { | |||||
| padding-top: 72px; | |||||
| padding-bottom: 39px; | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| // background-color: red; | |||||
| @include media-below($bp-xl) { | |||||
| padding: 20px 0.75rem 39px 0.75em !important; | |||||
| } | |||||
| .userPageBtn { | |||||
| margin-right: 72px; | |||||
| @include media-below($bp-xl) { | |||||
| margin-right: 10px; | |||||
| } | |||||
| } | |||||
| } | |||||
| .selection-levels { | |||||
| overflow-x: scroll; | |||||
| padding-bottom: 100px; | |||||
| } | |||||
| .fixed-right { | |||||
| text-align: right; | |||||
| margin-left: auto; | |||||
| position: absolute; | |||||
| right: 100px; | |||||
| top: 123px; | |||||
| } | |||||
| .level-header-subheader { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 24px; | |||||
| line-height: 36px; | |||||
| padding-left: 0.3rem; | |||||
| color: #226cb0; | |||||
| letter-spacing: 0.02em; | |||||
| @include media-below($bp-xl) { | |||||
| font-size: 14px; | |||||
| } | |||||
| } | |||||
| h1, | h1, | ||||
| h3 { | h3 { | ||||
| @include media-below($bp-xl) { | @include media-below($bp-xl) { | ||||
| } | } | ||||
| } | } | ||||
| .level-header-spliter { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 24px; | |||||
| line-height: 36px; | |||||
| padding-left: 0.3rem; | |||||
| color: #272727; | |||||
| letter-spacing: 0.02em; | |||||
| @include media-below($bp-xl) { | |||||
| font-size: 18px; | |||||
| } | |||||
| } | |||||
| .selection-levels-processes { | |||||
| display: flex; | |||||
| position: relative; | |||||
| min-height: 53vh; | |||||
| } | |||||
| .selection-levels-processes-process { | |||||
| display: flex; | |||||
| @include media-below($bp-xl) { | |||||
| padding-left: 0; | |||||
| } | |||||
| } | |||||
| .selection-card { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: start; | |||||
| align-items: left; | |||||
| height: fit-content; | |||||
| padding: 36px; | |||||
| background: #f4f4f4; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 18px; | |||||
| gap: 18px; | |||||
| margin-right: 36px; | |||||
| transition: background-color 0.35s ease; | |||||
| @include media-below($bp-xl) { | |||||
| margin-right: 20px !important; | |||||
| padding: 18px !important; | |||||
| } | |||||
| &.over{ | |||||
| background-color: $mainBlueLight !important; | |||||
| transition: background-color 0.35s ease; | |||||
| } | |||||
| } | |||||
| .sel-item:hover { | |||||
| transition: .25s; | |||||
| scale: 1.05; | |||||
| border-color:$mainBlue; | |||||
| .sel-item-inner{ | |||||
| background-color: $mainBlueLight !important; | |||||
| transition: .25s; | |||||
| .status button{ | |||||
| transition: .25s; | |||||
| &.unsucc{ | |||||
| background: #FFEAEE !important; | |||||
| color: #D72228 !important; | |||||
| } | |||||
| background-color: $mainBlueLight !important; | |||||
| }} | |||||
| } | |||||
| .bg-danger { | |||||
| background-color: #272727; | |||||
| } | |||||
| .grey { | .grey { | ||||
| color: #e4e4e4; | color: #e4e4e4; | ||||
| } | } | ||||
| .selection-item { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: left; | |||||
| vertical-align: top; | |||||
| align-items: left; | |||||
| width: 400px; | |||||
| padding: 18px 36px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 18px; | |||||
| gap: 18px; | |||||
| margin-right: 36px; | |||||
| } | |||||
| .selection-item-date p { | |||||
| text-align: right; | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 15px; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| order: 4; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .selection-card-title { | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| img { | |||||
| width: 12px; | |||||
| } | |||||
| .c-btn { | |||||
| background-color: white !important; | |||||
| } | |||||
| h3 { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 32px; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| @include media-below($bp-xl) { | |||||
| font-size: 18px; | |||||
| } | |||||
| } | |||||
| } | |||||
| .selection-item-name, | |||||
| .selection-item-date { | |||||
| margin: auto 0 !important; | |||||
| } | |||||
| .selection-item-name p { | |||||
| height: 20px; | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| text-align: right; | |||||
| color: #226cb0; | |||||
| flex: none; | |||||
| order: 2; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .selection-item-buttons button { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| font-size: 16px; | |||||
| align-items: center; | |||||
| padding: 9px; | |||||
| gap: 10px; | |||||
| min-width: 76px; | |||||
| height: 38px; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 9px; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .sel-item{ | |||||
| border-radius: 18px; | |||||
| border: 1px solid #e4e4e4; | |||||
| overflow: hidden; | |||||
| transition: .25s; | |||||
| } | |||||
| .sel-item-scheduler{ | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| background: #E4E4E4; | |||||
| p{ | |||||
| padding: 12.5px 25px 12.5px 0px !important; | |||||
| font-family: 'Source Sans Pro'; | |||||
| font-style: italic; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| text-align: right; | |||||
| color: #272727; | |||||
| } | |||||
| } | |||||
| .sel-item-inner { | |||||
| transition: .25s; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: center; | |||||
| padding: 18px 36px; | |||||
| gap: 18px; | |||||
| cursor: pointer; | |||||
| width: 458px; | |||||
| background: #ffffff; | |||||
| // transition: 0.3s; | |||||
| @include media-below($bp-xl) { | |||||
| justify-content: space-between; | |||||
| padding: 18px; | |||||
| width: 303px; | |||||
| } | |||||
| .status button{ transition: .25s;} | |||||
| } | |||||
| .sel-item-inner-no-data { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: center; | |||||
| padding: 18px 36px; | |||||
| gap: 18px; | |||||
| width: 458px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 18px; | |||||
| transition: 0.3s; | |||||
| @include media-below($bp-xl) { | |||||
| justify-content: space-between; | |||||
| padding: 18px; | |||||
| width: 303px; | |||||
| } | |||||
| } | |||||
| .sel-item-inner .status { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| @include media-below($bp-xl) { | |||||
| font-size: 14px; | |||||
| order: 1; | |||||
| } | |||||
| } | |||||
| .sel-item-inner .date-name { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: flex-start; | |||||
| gap: 18px; | |||||
| cursor: pointer; | |||||
| width: 100%; | |||||
| order: 1; | |||||
| @include media-below($bp-xl) { | |||||
| flex-direction: column; | |||||
| font-size: 14px; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| gap: 4px; | |||||
| } | |||||
| } | |||||
| .sel-item-inner .date-name .date { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| font-size: 14px !important; | |||||
| order: 0; | |||||
| } | |||||
| .full-name { | |||||
| height: 20px; | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 16px; | |||||
| text-align: right; | |||||
| color: #226cb0; | |||||
| flex: 3 0 auto; | |||||
| order: 1; | |||||
| @include media-below($bp-xl) { | |||||
| text-align: left !important; | |||||
| font-size: 14px !important; | |||||
| } | |||||
| } | |||||
| .full-name p, | |||||
| .sel-item-inner .date-name .date p { | |||||
| @include media-below($bp-xl) { | |||||
| font-size: 14px !important; | |||||
| } | |||||
| } | |||||
| .sel-item-inner .status button { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| font-size: 16px; | |||||
| align-items: center; | |||||
| padding: 9px; | |||||
| gap: 10px; | |||||
| min-width: 76px; | |||||
| height: 38px; | |||||
| border: 1px solid #e4e4e4; | |||||
| background: white; | |||||
| border-radius: 9px; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| @include media-below($bp-xl) { | |||||
| font-size: 14px !important; | |||||
| } | |||||
| } | |||||
| .active-process { | |||||
| scale: 1.05; | |||||
| border-color: $mainBlue !important; | |||||
| background-color: $mainBlueLight !important; | |||||
| } | |||||
| .active-process-card { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: start; | |||||
| align-items: flex-start; | |||||
| padding: 18px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 18px; | |||||
| gap: 18px; | |||||
| margin-right: 36px; | |||||
| @include media-below($bp-xl) { | |||||
| margin-right: 20px !important; | |||||
| padding: 36px !important; | |||||
| } | |||||
| } | |||||
| .active-process-tip { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: start; | |||||
| align-items: flex-start; | |||||
| padding: 91.5px; | |||||
| width: 800px; | |||||
| background: #ffffff; | |||||
| gap: 18px; | |||||
| margin-right: 36px; | |||||
| @include media-below($bp-xl) { | |||||
| margin-right: 20px !important; | |||||
| padding: 36px !important; | |||||
| width: 100%; | |||||
| } | |||||
| } | |||||
| .active-process-tip h3 { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 16px; | |||||
| color: #272727; | |||||
| } | |||||
| .active-process-tip p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| color: #272727; | |||||
| } | |||||
| .active-process-card-header { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: space-between; | |||||
| width: 100%; | |||||
| align-items: center; | |||||
| padding: 0px; | |||||
| gap: 18px; | |||||
| flex-wrap: wrap; | |||||
| } | |||||
| .active-process-card-body { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: center; | |||||
| width: 100%; | |||||
| align-items: center; | |||||
| padding: 34px; | |||||
| gap: 18px; | |||||
| @include media-below($bp-xl) { | |||||
| margin-right: 20px !important; | |||||
| padding: 36px !important; | |||||
| } | |||||
| } | |||||
| .active-process-card-date p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| z-index: 0; | |||||
| } | |||||
| .active-process-card-number p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| text-align: left; | |||||
| background: conic-gradient( | |||||
| from 73.66deg at 50% 50%, | |||||
| #226cb0 0deg, | |||||
| #ba6fb9 106.88deg, | |||||
| #5e9fdb 228.75deg, | |||||
| #226cb0 360deg | |||||
| ); | |||||
| -webkit-background-clip: text; | |||||
| -webkit-text-fill-color: transparent; | |||||
| background-clip: text; | |||||
| text-fill-color: transparent; | |||||
| flex: none; | |||||
| order: 6; | |||||
| flex-grow: 0; | |||||
| z-index: 6; | |||||
| } | |||||
| .change-interbtn{ | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| padding-left: 35px; | |||||
| } | |||||
| .interbtn{ | |||||
| height: 27.5px; | |||||
| background-color: $mainBlue !important; | |||||
| color: white !important; | |||||
| font-size: 12px !important; | |||||
| border-radius: 7.5px !important; | |||||
| font-weight: 500 !important; | |||||
| text-transform: capitalize !important; | |||||
| } | |||||
| .unsucc{ | |||||
| background: #FFEAEE !important; | |||||
| color: #D72228 !important; | |||||
| } | |||||
| .active-process-card-buttons { | |||||
| overflow: hidden; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: flex-start; | |||||
| justify-content: center; | |||||
| padding: 0px; | |||||
| gap: 18px; | |||||
| flex: none; | |||||
| order: 4; | |||||
| flex-grow: 0; | |||||
| @include media-below($bp-xl) { | |||||
| gap: 9px !important; | |||||
| } | |||||
| } | |||||
| .active-process-card-buttons button { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 9px; | |||||
| gap: 10px; | |||||
| height: 38px; | |||||
| background: transparent; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 9px; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .active-process-card-link { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 12px; | |||||
| text-decoration-line: underline; | |||||
| color: #226cb0; | |||||
| flex: none; | |||||
| order: 4; | |||||
| flex-grow: 0; | |||||
| z-index: 4; | |||||
| } | |||||
| .active-process-card-logo img { | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .active-process-card-logo { | |||||
| margin-left: auto; | |||||
| flex: none; | |||||
| order: 1; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .modal-content.interviewDialog{ | |||||
| display: flex; | |||||
| gap: 15px; | |||||
| flex-direction: column; | |||||
| margin: 20px 0px 25px 0px; | |||||
| } | |||||
| .interview-btn{ | |||||
| .interview-btn { | |||||
| width: 220px !important; | width: 220px !important; | ||||
| } | } | ||||
| .css-11u53oe-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input.MuiSelect-select{ | |||||
| .css-11u53oe-MuiSelect-select-MuiInputBase-input-MuiOutlinedInput-input.MuiSelect-select { | |||||
| text-align: left; | text-align: left; | ||||
| padding-left: 20px; | padding-left: 20px; | ||||
| } | |||||
| } |
| .px36-heading { | |||||
| padding-top: 36px !important; | |||||
| padding-left: 144px; | |||||
| line-height: 32px; | |||||
| @include media-below($bp-xl) { | |||||
| padding-left: 36px !important; | |||||
| } | |||||
| } | |||||
| .section-header { | |||||
| padding-bottom: 27px !important; | |||||
| } | |||||
| .stats-section:not(:last-of-type) { | |||||
| padding-left: 144px; | |||||
| padding-right: 72px; | |||||
| margin-top: 83px; | |||||
| @include media-below($bp-xl) { | |||||
| padding: 20px 36px !important; | |||||
| } | |||||
| h3 { | |||||
| font-size: 24px; | |||||
| } | |||||
| .stats-items { | |||||
| display: flex; | |||||
| justify-content: flex-start; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 18px; | |||||
| width: 920px; | |||||
| overflow: hidden; | |||||
| .stats-item { | |||||
| width: 230px; | |||||
| position: relative; | |||||
| &:not(:last-of-type):after { | |||||
| content: ""; | |||||
| position: absolute; | |||||
| right: 0; | |||||
| bottom: 0; | |||||
| height: 60%; | |||||
| width: 1.75px; | |||||
| } | |||||
| &:first-of-type:after { | |||||
| background-color: #bfdbf5; | |||||
| } | |||||
| &:nth-of-type(2):after { | |||||
| background-color: #1e92d0; | |||||
| } | |||||
| &:nth-of-type(3):after { | |||||
| background-color: $mainBlue; | |||||
| } | |||||
| .stats-item-content { | |||||
| padding: 36px; | |||||
| background-color: white; | |||||
| p { | |||||
| margin-top: 9px; | |||||
| font-size: 16px; | |||||
| color: $mainBlue; | |||||
| font-weight: 600; | |||||
| } | |||||
| } | |||||
| .bottom-static { | |||||
| height: 35px; | |||||
| width: 100%; | |||||
| } | |||||
| &:first-of-type { | |||||
| .bottom-static { | |||||
| background-color: $mainBlueLight !important; | |||||
| } | |||||
| } | |||||
| &:nth-of-type(2) { | |||||
| .bottom-static { | |||||
| background-color: #bfdbf5 !important; | |||||
| } | |||||
| } | |||||
| &:nth-of-type(3) { | |||||
| .bottom-static { | |||||
| background-color: #1e92d0 !important; | |||||
| } | |||||
| } | |||||
| &:last-of-type { | |||||
| .bottom-static { | |||||
| background-color: $mainBlue !important; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .stats-items-dynamic { | |||||
| display: flex; | |||||
| justify-content: flex-start; | |||||
| // margin-top: 27px; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 18px; | |||||
| width: 1160px; | |||||
| overflow: hidden; | |||||
| .stats-item { | |||||
| width: 290px; | |||||
| position: relative; | |||||
| &:not(:last-of-type):after { | |||||
| content: ""; | |||||
| position: absolute; | |||||
| right: 0; | |||||
| bottom: 0; | |||||
| height: 60%; | |||||
| width: 1.75px; | |||||
| } | |||||
| &:first-of-type:after { | |||||
| background-color: #bfdbf5; | |||||
| } | |||||
| &:nth-of-type(2):after { | |||||
| background-color: #1e92d0; | |||||
| } | |||||
| &:nth-of-type(3):after { | |||||
| background-color: $mainBlue; | |||||
| } | |||||
| .stats-item-content { | |||||
| padding: 36px; | |||||
| background-color: white; | |||||
| p { | |||||
| margin-top: 9px; | |||||
| font-size: 16px; | |||||
| color: $mainBlue; | |||||
| font-weight: 600; | |||||
| } | |||||
| } | |||||
| .bottom-dynamic { | |||||
| height: 35px; | |||||
| width: 100%; | |||||
| } | |||||
| .bottom-dynamic { | |||||
| display: flex; | |||||
| background-color: $white; | |||||
| border-top: 1px solid #e4e4e4; | |||||
| .bottom-loader-indicator { | |||||
| // width: 85%; | |||||
| border-bottom-right-radius: 18px; | |||||
| } | |||||
| } | |||||
| &:first-of-type { | |||||
| .bottom-dynamic { | |||||
| .bottom-loader-indicator { | |||||
| background-color: $mainBlueLight !important; | |||||
| } | |||||
| } | |||||
| } | |||||
| &:nth-of-type(2) { | |||||
| .bottom-dynamic { | |||||
| .bottom-loader-indicator { | |||||
| background-color: #bfdbf5 !important; | |||||
| } | |||||
| } | |||||
| } | |||||
| &:nth-of-type(3) { | |||||
| .bottom-dynamic { | |||||
| .bottom-loader-indicator { | |||||
| background-color: #1e92d0 !important; | |||||
| } | |||||
| } | |||||
| } | |||||
| &:last-of-type { | |||||
| .bottom-dynamic { | |||||
| .bottom-loader-indicator { | |||||
| background-color: $mainBlue !important; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .stats-section:first-of-type { | |||||
| margin-top: 35px !important; | |||||
| } | |||||
| .stats-section { | |||||
| @include media-below($bp-xl) { | |||||
| margin-top: 20px !important; | |||||
| } | |||||
| } | |||||
| .stats-section:not(:last-of-type) { | |||||
| @include media-below($bp-xl) { | |||||
| overflow-x: auto; | |||||
| } | |||||
| } | |||||
| .stats-section:last-of-type { | |||||
| padding-bottom: 0px !important; | |||||
| margin-top: 83px; | |||||
| } | |||||
| .stats-section:last-of-type .section-header { | |||||
| padding: 0px !important; | |||||
| margin-bottom: 0px; | |||||
| padding-left: 144px; | |||||
| @include media-below($bp-xl) { | |||||
| padding: 20px 36px !important; | |||||
| } | |||||
| } | |||||
| .ad-count { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 9px; | |||||
| gap: 10px; | |||||
| width: 113px; | |||||
| height: 38px; | |||||
| /* Gray E4 */ | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 9px; | |||||
| /* Inside auto layout */ | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .stat-ads { | |||||
| margin-bottom: 0 !important; | |||||
| padding-bottom: 0 !important; | |||||
| } |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| // import logoReact from "../../assets/images/logo_react.png"; | |||||
| import { useTheme } from "@emotion/react"; | |||||
| import { useMediaQuery } from "@mui/material"; | |||||
| import linkedin from "../../assets/images/linkedin.png"; | |||||
| import facebook from "../../assets/images/facebook.png"; | |||||
| import instagram from "../../assets/images/instagram.png"; | |||||
| import { selectLogo } from "../../util/helpers/technologiesLogos"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const Ad = ({ | |||||
| title, | |||||
| minimumExperience, | |||||
| createdAt, | |||||
| expiredAt, | |||||
| onShowAdDetails, | |||||
| className, | |||||
| }) => { | |||||
| const theme = useTheme(); | |||||
| const matches = useMediaQuery(theme.breakpoints.down("sm")); | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <div className={`ad-card ${className}`} onClick={onShowAdDetails}> | |||||
| <div className="ad-card-date"> | |||||
| <p> | |||||
| {new Date(createdAt).toLocaleDateString()} -{" "} | |||||
| {new Date(expiredAt).toLocaleDateString()} | |||||
| </p> | |||||
| </div> | |||||
| <div className="ad-card-title"> | |||||
| <h3>{title}</h3> | |||||
| </div> | |||||
| <div className="ad-card-logo"> | |||||
| <img src={selectLogo(title)} alt="logo-react" /> | |||||
| </div> | |||||
| <div className="ad-card-experience"> | |||||
| <p> | |||||
| {minimumExperience}+ {t("common.experience")} | |||||
| </p> | |||||
| </div> | |||||
| {!matches && ( | |||||
| <div className="ad-card-buttons"> | |||||
| <button>LinkedIn</button> | |||||
| <button>Facebook</button> | |||||
| <button disabled>Instagram</button> | |||||
| </div> | |||||
| )} | |||||
| {matches && ( | |||||
| <div className="ad-card-buttons"> | |||||
| <button className="ad-card-buttons-button"> | |||||
| <img src={linkedin} /> | |||||
| </button> | |||||
| <button className="ad-card-buttons-button"> | |||||
| <img src={facebook} /> | |||||
| </button> | |||||
| <button disabled className="ad-card-buttons-button"> | |||||
| <img src={instagram} /> | |||||
| </button> | |||||
| </div> | |||||
| )} | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| Ad.propTypes = { | |||||
| id: PropTypes.number, | |||||
| title: PropTypes.string, | |||||
| minimumExperience: PropTypes.number, | |||||
| createdAt: PropTypes.any, | |||||
| expiredAt: PropTypes.any, | |||||
| onShowAdDetails: PropTypes.func, | |||||
| className: PropTypes.any, | |||||
| }; | |||||
| export default Ad; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { CANDIDATES_DETAILS_PAGE } from "../../constants/pages"; | |||||
| import { useHistory } from "react-router-dom"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const AdDetailsCandidateCard = ({ | |||||
| className, | |||||
| id, | |||||
| firstName, | |||||
| lastName, | |||||
| experience, | |||||
| cv, | |||||
| }) => { | |||||
| const history = useHistory(); | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <div | |||||
| data-testid="ad-details-candidate" | |||||
| className={`ad-details-candidate ${className}`} | |||||
| > | |||||
| <div className="ad-details-candidate-date"> | |||||
| <p>{new Date().toLocaleDateString()}</p> | |||||
| </div> | |||||
| <div className="ad-details-candidate-title"> | |||||
| <h3 | |||||
| data-testid="ad-details-candidate-title-link" | |||||
| onClick={() => | |||||
| history.push(CANDIDATES_DETAILS_PAGE.replace(":id", id)) | |||||
| } | |||||
| > | |||||
| {firstName} {lastName} | |||||
| </h3> | |||||
| </div> | |||||
| <div className="ad-details-candidate-experience"> | |||||
| {experience > 0 ? ( | |||||
| <p> | |||||
| {experience}+ {t("common.experience")} | |||||
| </p> | |||||
| ) : ( | |||||
| <p>{t("common.noExperience")}</p> | |||||
| )} | |||||
| </div> | |||||
| <div className="ad-details-candidate-buttons"> | |||||
| <button>React</button> | |||||
| <button>.NET</button> | |||||
| <button>Angular</button> | |||||
| </div> | |||||
| <div className="ad-details-candidate-cv"> | |||||
| <a href="#">{cv}</a> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| AdDetailsCandidateCard.propTypes = { | |||||
| className: PropTypes.any, | |||||
| id: PropTypes.number, | |||||
| firstName: PropTypes.string, | |||||
| lastName: PropTypes.string, | |||||
| experience: PropTypes.number, | |||||
| cv: PropTypes.string, | |||||
| }; | |||||
| export default AdDetailsCandidateCard; |
| import React, { useState } from "react"; | |||||
| import PropType from "prop-types"; | |||||
| import Box from "@mui/material/Box"; | |||||
| import Drawer from "@mui/material/Drawer"; | |||||
| import FormGroup from "@mui/material/FormGroup"; | |||||
| import FormControlLabel from "@mui/material/FormControlLabel"; | |||||
| import Checkbox from "@mui/material/Checkbox"; | |||||
| import Slider from "@mui/material/Slider"; | |||||
| import filterIcon from "../../assets/images/filter_vector.png"; | |||||
| import x from "../../assets/images/x.png"; | |||||
| import { changeIsCheckedValue } from "../../store/actions/technologies/technologiesActions"; | |||||
| import { useDispatch } from "react-redux"; | |||||
| import { setFilteredAdsReq } from "../../store/actions/ads/adsAction"; | |||||
| import { useHistory } from "react-router-dom"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const AdFilters = ({ open, handleClose, technologies }) => { | |||||
| const [sliderValue, setSliderValue] = useState([0, 10]); | |||||
| const [employmentType, setEmploymentType] = useState("Work"); | |||||
| const [workHour, setWorkHour] = useState("FullTime"); | |||||
| const dispatch = useDispatch(); | |||||
| const history = useHistory(); | |||||
| const { t } = useTranslation(); | |||||
| const handleSliderChange = (_, newValue) => { | |||||
| setSliderValue(newValue); | |||||
| }; | |||||
| const onSubmitFilters = () => { | |||||
| const tech = technologies | |||||
| .filter((tech) => tech.isChecked === true) | |||||
| .map((tech) => tech.name); | |||||
| dispatch( | |||||
| setFilteredAdsReq({ | |||||
| minExperience: sliderValue[0], | |||||
| maxExperience: sliderValue[1], | |||||
| technologies: tech, | |||||
| workHour, | |||||
| employmentType, | |||||
| }) | |||||
| ); | |||||
| let technologiesQuery = ""; | |||||
| for (let i = 0; i < tech.length; i++) { | |||||
| technologiesQuery += `technologies=${tech[i]}&`; | |||||
| } | |||||
| history.push({ | |||||
| pathname: "/ads", | |||||
| search: `?minExperience=${sliderValue[0]}&maxExperience=${sliderValue[1]}&workHour=${workHour}&employmentType=${employmentType}&${technologiesQuery}`, | |||||
| }); | |||||
| handleClose(); | |||||
| }; | |||||
| const handleCheckboxes = (e) => { | |||||
| const { value } = e.target; | |||||
| dispatch(changeIsCheckedValue(value)); | |||||
| }; | |||||
| const employmentTypeHandler = (type) => { | |||||
| setEmploymentType(type); | |||||
| }; | |||||
| const workHourHandler = (type) => { | |||||
| setWorkHour(type); | |||||
| }; | |||||
| const list = () => ( | |||||
| <Box | |||||
| sx={{ | |||||
| width: 360, | |||||
| height: "100%", | |||||
| borderRadius: "18px 0 0 18px", | |||||
| padding: "36px", | |||||
| }} | |||||
| role="presentation" | |||||
| // onClick={handleClose} | |||||
| onKeyDown={handleClose} | |||||
| > | |||||
| <div data-testid="ad-filters-drawer"> | |||||
| <div className="ad-filters-header-container"> | |||||
| <div className="ad-filters-header"> | |||||
| <img src={filterIcon} alt="filter_icon" /> | |||||
| <h3>{t("filters.filters")}</h3> | |||||
| <p> | |||||
| <sub>| {t("ads.ads")}</sub> | |||||
| </p> | |||||
| </div> | |||||
| <div className="ad-filters-header-close" onClick={handleClose}> | |||||
| <img src={x} alt="x" /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-experience"> | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>{t("filters.experience")}</p> | |||||
| </div> | |||||
| <div className="ad-filters-experience-slider"> | |||||
| <Slider | |||||
| getAriaLabel={() => "Temperature range"} | |||||
| value={sliderValue} | |||||
| onChange={handleSliderChange} | |||||
| valueLabelDisplay="auto" | |||||
| max={20} | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-technologies"> | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>{t("filters.tecnologies")}</p> | |||||
| </div> | |||||
| <div className="ad-filters-technologies-checkboxes"> | |||||
| <FormGroup> | |||||
| {technologies?.map((technology, index) => ( | |||||
| <FormControlLabel | |||||
| key={index} | |||||
| control={ | |||||
| <Checkbox | |||||
| onChange={handleCheckboxes} | |||||
| value={technology.name} | |||||
| checked={technology.isChecked} | |||||
| className="ad-filters-checkbox" | |||||
| /> | |||||
| } | |||||
| label={technology.name} | |||||
| /> | |||||
| ))} | |||||
| </FormGroup> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-technologies"> | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>{t("filters.employmentType")}</p> | |||||
| </div> | |||||
| <div className="ad-filters-employment-type"> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| employmentType === "Intership" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={employmentTypeHandler.bind(this, "Intership")} | |||||
| > | |||||
| {t("filters.internship")} | |||||
| </button> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| employmentType === "Work" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={employmentTypeHandler.bind(this, "Work")} | |||||
| > | |||||
| {t("filters.work")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-technologies"> | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>{t("filters.workHour")}</p> | |||||
| </div> | |||||
| <div className="ad-filters-employment-type"> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| workHour === "PartTime" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={workHourHandler.bind(this, "PartTime")} | |||||
| > | |||||
| {t("filters.partTime")} | |||||
| </button> | |||||
| <button | |||||
| className={`c-btn ${ | |||||
| workHour === "FullTime" | |||||
| ? "c-btn c-btn--primary" | |||||
| : "c-btn--primary-outlined" | |||||
| }`} | |||||
| onClick={workHourHandler.bind(this, "FullTime")} | |||||
| > | |||||
| {t("filters.fullTime")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-search"> | |||||
| <button | |||||
| onClick={onSubmitFilters} | |||||
| className="c-btn c-btn--primary" | |||||
| data-testid="ad-filters-submit" | |||||
| > | |||||
| {t("filters.search")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| </Box> | |||||
| ); | |||||
| return ( | |||||
| <div> | |||||
| <Drawer anchor="right" open={open} onClose={handleClose}> | |||||
| {list()} | |||||
| </Drawer> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| AdFilters.propTypes = { | |||||
| open: PropType.any, | |||||
| handleClose: PropType.func, | |||||
| technologies: PropType.any, | |||||
| }; | |||||
| export default AdFilters; |
| import React, { useState } from "react"; | |||||
| import ApplyForAdFirstStage from "./ApplyForAdFirstStage"; | |||||
| import PropTypes from "prop-types"; | |||||
| import briefcaseIcon from "../../assets/images/briefcase1.png"; | |||||
| import xIcon from "../../assets/images/x.png"; | |||||
| import CustomModal from "../UI/CustomModal"; | |||||
| import ApplyForAdSecondStage from "./ApplyForAdSecondStage"; | |||||
| import { setTechnologiesReq } from "../../store/actions/technologies/technologiesActions"; | |||||
| import { selectTechnologies } from "../../store/selectors/technologiesSelectors"; | |||||
| import { useDispatch, useSelector } from "react-redux"; | |||||
| import { useEffect } from "react"; | |||||
| import ApplyForAdThirdStage from "./ApplyForAdThirdStage"; | |||||
| import ApplyForAdFourthStage from "./ApplyForAdFourthStage"; | |||||
| import { applyForAdReq } from "../../store/actions/applyForAd/applyForAdActions"; | |||||
| import { useHistory } from "react-router-dom"; | |||||
| import { ADS_PAGE } from "../../constants/pages"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const ApplyForAd = ({ open, title, adId, onCloseModal }) => { | |||||
| const [stage, setStage] = useState(1); | |||||
| const [firstName, setFirstName] = useState(""); | |||||
| const [lastName, setLastName] = useState(""); | |||||
| const [gender, setGender] = useState(""); | |||||
| const [dateOfBirth, setDateOfBirth] = useState(""); | |||||
| const [phoneNumber, setPhoneNumber] = useState(""); | |||||
| const [mappedTechnologies, setMappedTechnologies] = useState([]); | |||||
| const [experience, setExperience] = useState(0); | |||||
| const [professionalQualification, setProfessionalQualification] = | |||||
| useState(""); | |||||
| const [linkedinLink, setLinkedinLink] = useState(""); | |||||
| const [githubLink, setGithubLink] = useState(""); | |||||
| const [email, setEmail] = useState(""); | |||||
| const [bitBucketLink, setBitBucketLink] = useState(""); | |||||
| const [coverLetter, setCoverLetter] = useState(""); | |||||
| const [pdfFile, setPdfFile] = useState(null); | |||||
| const technologies = useSelector(selectTechnologies); | |||||
| const dispatch = useDispatch(); | |||||
| const history = useHistory(); | |||||
| const { t } = useTranslation(); | |||||
| useEffect(() => { | |||||
| dispatch(setTechnologiesReq()); | |||||
| }, []); | |||||
| useEffect(() => { | |||||
| if (technologies && technologies.length > 0) { | |||||
| const tech = technologies.map((t) => ({ ...t, isChecked: false })); | |||||
| setMappedTechnologies(tech); | |||||
| } | |||||
| }, [technologies]); | |||||
| const increaseStageHandler = () => { | |||||
| setStage((oldValue) => oldValue + 1); | |||||
| }; | |||||
| const decreaseStageHandler = () => { | |||||
| setStage((oldValue) => oldValue - 1); | |||||
| }; | |||||
| const handleApiResponseSuccess = () => { | |||||
| onCloseModal(); | |||||
| history.push(ADS_PAGE); | |||||
| }; | |||||
| const finishedFourStagesHandler = () => { | |||||
| const technologiesIds = mappedTechnologies | |||||
| .filter((tech) => tech.isChecked === true) | |||||
| .map((x) => x.technologyId); | |||||
| dispatch( | |||||
| applyForAdReq({ | |||||
| adId, | |||||
| firstName, | |||||
| lastName, | |||||
| gender, | |||||
| dateOfBirth, | |||||
| phoneNumber, | |||||
| technologiesIds, | |||||
| experience, | |||||
| professionalQualification, | |||||
| linkedinLink, | |||||
| githubLink, | |||||
| bitBucketLink, | |||||
| email, | |||||
| coverLetter, | |||||
| pdfFile, | |||||
| handleApiResponseSuccess, | |||||
| }) | |||||
| ); | |||||
| }; | |||||
| return ( | |||||
| <CustomModal open={open} onCloseModal={onCloseModal} classes="apply-for-ad"> | |||||
| <div className="apply-for-ad-header"> | |||||
| <div className="apply-for-ad-header-left"> | |||||
| <div className="apply-for-ad-header-left-image"> | |||||
| <img src={briefcaseIcon} alt="plus" /> | |||||
| </div> | |||||
| <div className="apply-for-ad-header-left-image-title"> | |||||
| <p>{t("ads.signUp")}</p> | |||||
| </div> | |||||
| <div className="apply-for-ad-header-left-image-title-sub"> | |||||
| <sub> | {title}</sub> | |||||
| </div> | |||||
| </div> | |||||
| <div className="apply-for-ad-header-right"> | |||||
| <button onClick={onCloseModal}> | |||||
| <img src={xIcon} alt="x" /> | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| {stage === 1 && ( | |||||
| <ApplyForAdFirstStage | |||||
| onCloseModal={onCloseModal} | |||||
| firstName={firstName} | |||||
| setFirstName={setFirstName} | |||||
| lastName={lastName} | |||||
| setLastName={setLastName} | |||||
| gender={gender} | |||||
| setGender={setGender} | |||||
| dateOfBirth={dateOfBirth} | |||||
| setDateOfBirth={setDateOfBirth} | |||||
| phoneNumber={phoneNumber} | |||||
| setPhoneNumber={setPhoneNumber} | |||||
| onIncreaseStage={increaseStageHandler} | |||||
| /> | |||||
| )} | |||||
| {stage === 2 && ( | |||||
| <ApplyForAdSecondStage | |||||
| technologies={mappedTechnologies} | |||||
| setTechnologies={setMappedTechnologies} | |||||
| experience={experience} | |||||
| professionalQualification={professionalQualification} | |||||
| setProfessionalQualification={setProfessionalQualification} | |||||
| setExperience={setExperience} | |||||
| onIncreaseStage={increaseStageHandler} | |||||
| onDecreaseStage={decreaseStageHandler} | |||||
| /> | |||||
| )} | |||||
| {stage === 3 && ( | |||||
| <ApplyForAdThirdStage | |||||
| linkedinLink={linkedinLink} | |||||
| setLinkedinLink={setLinkedinLink} | |||||
| githubLink={githubLink} | |||||
| setGithubLink={setGithubLink} | |||||
| bitBucketLink={bitBucketLink} | |||||
| setBitBucketLink={setBitBucketLink} | |||||
| email={email} | |||||
| setEmail={setEmail} | |||||
| onIncreaseStage={increaseStageHandler} | |||||
| onDecreaseStage={decreaseStageHandler} | |||||
| /> | |||||
| )} | |||||
| {stage === 4 && ( | |||||
| <ApplyForAdFourthStage | |||||
| pdfFile={pdfFile} | |||||
| coverLetter={coverLetter} | |||||
| setCoverLetter={setCoverLetter} | |||||
| setPdfFile={setPdfFile} | |||||
| onDecreaseStage={decreaseStageHandler} | |||||
| onFinishedFourStages={finishedFourStagesHandler} | |||||
| /> | |||||
| )} | |||||
| </CustomModal> | |||||
| ); | |||||
| }; | |||||
| ApplyForAd.propTypes = { | |||||
| open: PropTypes.bool, | |||||
| title: PropTypes.string, | |||||
| adId: PropTypes.string, | |||||
| onCloseModal: PropTypes.func, | |||||
| }; | |||||
| export default ApplyForAd; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const ApplyForAdFirstStage = ({ | |||||
| firstName, | |||||
| setFirstName, | |||||
| lastName, | |||||
| gender, | |||||
| setGender, | |||||
| setLastName, | |||||
| dateOfBirth, | |||||
| setDateOfBirth, | |||||
| phoneNumber, | |||||
| setPhoneNumber, | |||||
| onIncreaseStage, | |||||
| }) => { | |||||
| const disabled = | |||||
| firstName.length === 0 || | |||||
| lastName.length === 0 || | |||||
| dateOfBirth === "" || | |||||
| phoneNumber.length === 0 || | |||||
| gender.length === 0; | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>{t("common.name")}</label> | |||||
| <input | |||||
| type="text" | |||||
| placeholder="ex. Petar" | |||||
| value={firstName} | |||||
| data-testid="apply-for-ad-modal-first-name-input" | |||||
| onChange={(e) => setFirstName(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>{t("common.lastName")}</label> | |||||
| <input | |||||
| type="text" | |||||
| placeholder="ex. Petrovic" | |||||
| value={lastName} | |||||
| data-testid="apply-for-ad-modal-last-name-input" | |||||
| onChange={(e) => setLastName(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>{t("common.gender")}</label> | |||||
| <div style={{ display: "flex" }}> | |||||
| <div style={{ display: "flex" }}> | |||||
| <input | |||||
| type="radio" | |||||
| name="gender" | |||||
| value="Muski" | |||||
| className="apply-for-ad-modal-gender-input" | |||||
| checked={gender === "Muski"} | |||||
| onChange={(e) => setGender(e.target.value)} | |||||
| /> | |||||
| <p style={{ marginLeft: "5px" }}>{t("common.male")}</p> | |||||
| </div> | |||||
| <div style={{ display: "flex", marginLeft: "50px" }}> | |||||
| <input | |||||
| type="radio" | |||||
| name="gender" | |||||
| value="Zenski" | |||||
| className="apply-for-ad-modal-gender-input" | |||||
| checked={gender === "Zenski"} | |||||
| onChange={(e) => setGender(e.target.value)} | |||||
| /> | |||||
| <p style={{ marginLeft: "5px" }}>{t("common.female")}</p> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>{t("common.dateOfBirth")}</label> | |||||
| <input | |||||
| type="date" | |||||
| placeholder="ex. Datum rodjenja" | |||||
| data-testid="apply-for-ad-modal-date-of-birth" | |||||
| value={dateOfBirth} | |||||
| onChange={(e) => setDateOfBirth(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>{t("common.phoneNumber")}</label> | |||||
| <input | |||||
| type="text" | |||||
| placeholder="ex. +381/60/000/0000" | |||||
| data-testid="apply-for-ad-modal-phone-number" | |||||
| value={phoneNumber} | |||||
| onChange={(e) => setPhoneNumber(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-buttons"> | |||||
| <button disabled>{t("common.back")}</button> | |||||
| <button | |||||
| disabled={disabled} | |||||
| data-testid="apply-for-ad-modal-go-forward-button" | |||||
| onClick={() => onIncreaseStage()} | |||||
| > | |||||
| {t("common.continue")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| ApplyForAdFirstStage.propTypes = { | |||||
| firstName: PropTypes.string, | |||||
| setFirstName: PropTypes.any, | |||||
| lastName: PropTypes.string, | |||||
| gender: PropTypes.string, | |||||
| setGender: PropTypes.func, | |||||
| setLastName: PropTypes.any, | |||||
| dateOfBirth: PropTypes.any, | |||||
| setDateOfBirth: PropTypes.any, | |||||
| phoneNumber: PropTypes.string, | |||||
| setPhoneNumber: PropTypes.any, | |||||
| onIncreaseStage: PropTypes.func, | |||||
| }; | |||||
| export default ApplyForAdFirstStage; |
| import React, { useState } from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import uploadIcon from "../../assets/images/upload.png"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const ApplyForAdFourthStage = ({ | |||||
| coverLetter, | |||||
| setCoverLetter, | |||||
| pdfFile, | |||||
| setPdfFile, | |||||
| onDecreaseStage, | |||||
| onFinishedFourStages, | |||||
| }) => { | |||||
| const [dropzoneActive, setDropzoneActive] = useState(false); | |||||
| const {t} = useTranslation() | |||||
| const disabled = pdfFile === null || coverLetter === ""; | |||||
| const handleDrop = (e) => { | |||||
| e.preventDefault(); | |||||
| setPdfFile(e.dataTransfer.files[0]); | |||||
| }; | |||||
| return ( | |||||
| <div data-testid="apply-for-ad-modal-fourth-stage"> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>CV</label> | |||||
| <div | |||||
| className="uploadCV-input" | |||||
| onDragOver={(e) => { | |||||
| setDropzoneActive(true); | |||||
| e.preventDefault(); | |||||
| }} | |||||
| onDragLeave={(e) => { | |||||
| setDropzoneActive(false); | |||||
| e.preventDefault(); | |||||
| }} | |||||
| onDrop={(e) => handleDrop(e)} | |||||
| style={{ | |||||
| backgroundColor: dropzoneActive ? "#F4F4F4" : "#ffffff", | |||||
| }} | |||||
| > | |||||
| <div className="uploadCV-input-sub-container"> | |||||
| <img src={uploadIcon} /> | |||||
| <div className="uploadCV-input-sub-container"> | |||||
| {pdfFile !== null ? ( | |||||
| <p>{pdfFile.name}</p> | |||||
| ) : ( | |||||
| <> | |||||
| <p> | |||||
| {t("ads.dragPdf1")} | |||||
| <label | |||||
| htmlFor="upload-file" | |||||
| style={{ | |||||
| cursor: "pointer", | |||||
| textDecoration: "underline", | |||||
| color: "#1E92D0", | |||||
| }} | |||||
| > | |||||
| {t("common.search")} | |||||
| </label> | |||||
| {t("ads.dragPdf2")} | |||||
| </p> | |||||
| <input | |||||
| type="file" | |||||
| name="photo" | |||||
| id="upload-file" | |||||
| style={{ display: "none", zIndex: -1 }} | |||||
| value={pdfFile} | |||||
| data-testid="apply-for-ad-modal-fourth-stage-pdf-input" | |||||
| onChange={(e) => { | |||||
| setPdfFile(e.target.files[0]); | |||||
| }} | |||||
| /> | |||||
| </> | |||||
| )} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>{t("ads.coverLetter")}</label> | |||||
| <textarea | |||||
| value={coverLetter} | |||||
| onChange={(e) => setCoverLetter(e.target.value)} | |||||
| data-testid="apply-for-ad-modal-fourth-stage-cover-letter-input" | |||||
| placeholder="ex. Kao student Elektronskog fakulteta u Nišu..." | |||||
| rows={5} | |||||
| ></textarea> | |||||
| </div> | |||||
| <div className="apply-for-ad-buttons"> | |||||
| <button | |||||
| onClick={onDecreaseStage} | |||||
| data-testid="apply-for-ad-modal-fourth-stage-go-back-button" | |||||
| > | |||||
| {t("common.back")} | |||||
| </button> | |||||
| <button | |||||
| disabled={disabled} | |||||
| data-testid="apply-for-ad-modal-fourth-stage-go-forward-button" | |||||
| onClick={onFinishedFourStages} | |||||
| > | |||||
| {t("ads.signUp")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| ApplyForAdFourthStage.propTypes = { | |||||
| coverLetter: PropTypes.string, | |||||
| setCoverLetter: PropTypes.any, | |||||
| pdfFile: PropTypes.any, | |||||
| setPdfFile: PropTypes.any, | |||||
| onDecreaseStage: PropTypes.func, | |||||
| onFinishedFourStages: PropTypes.func, | |||||
| }; | |||||
| export default ApplyForAdFourthStage; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { Checkbox, FormControlLabel } from "@mui/material"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const ApplyForAdSecondStage = ({ | |||||
| professionalQualification, | |||||
| setProfessionalQualification, | |||||
| technologies, | |||||
| setTechnologies, | |||||
| experience, | |||||
| setExperience, | |||||
| onIncreaseStage, | |||||
| onDecreaseStage, | |||||
| }) => { | |||||
| const {t} = useTranslation() | |||||
| let disabled = true; | |||||
| let isTechnologySelected = false; | |||||
| if (technologies.length > 0) { | |||||
| isTechnologySelected = technologies.some((x) => x.isChecked === true); | |||||
| } | |||||
| if (isTechnologySelected) { | |||||
| if (professionalQualification.length > 0) { | |||||
| disabled = false; | |||||
| } | |||||
| } | |||||
| const handleCheckboxes = (technologyId) => { | |||||
| const tmpTechnologies = technologies.map((tech) => | |||||
| tech.technologyId === technologyId | |||||
| ? { ...tech, isChecked: !tech.isChecked } | |||||
| : tech | |||||
| ); | |||||
| setTechnologies(tmpTechnologies); | |||||
| }; | |||||
| return ( | |||||
| <div data-testid="apply-for-ad-second-stage"> | |||||
| <div className="apply-for-ad-header-title"> | |||||
| <p>{t("ads.professionalQualification")}</p> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <input | |||||
| type="text" | |||||
| placeholder="ex. Elektrotehnicki fakultet" | |||||
| data-testid="apply-for-ad-second-stage-professional-qualification" | |||||
| value={professionalQualification} | |||||
| onChange={(e) => setProfessionalQualification(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-header-title"> | |||||
| <p>{t("ads.technologies")}</p> | |||||
| </div> | |||||
| <div className="apply-for-ad-header-sub"> | |||||
| <div className="apply-for-ad-header-sub-group"> | |||||
| <label>Back-End</label> | |||||
| <div className="apply-for-ad-header-sub-group-checkboxes"> | |||||
| {technologies | |||||
| .filter((x) => x.technologyType === "Backend") | |||||
| .map((x) => ( | |||||
| <FormControlLabel | |||||
| key={x.technologyId} | |||||
| control={ | |||||
| <Checkbox | |||||
| className="apply-for-ad-second-stage-checkbox" | |||||
| value={x.name} | |||||
| checked={x.isChecked} | |||||
| onChange={handleCheckboxes.bind(this, x.technologyId)} | |||||
| /> | |||||
| } | |||||
| label={x.name} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| </div> | |||||
| <div className="apply-for-ad-header-sub-group"> | |||||
| <label>Front-End</label> | |||||
| <div className="apply-for-ad-header-sub-group-checkboxes"> | |||||
| {technologies | |||||
| .filter((x) => x.technologyType === "Frontend") | |||||
| .map((x) => ( | |||||
| <FormControlLabel | |||||
| key={x.technologyId} | |||||
| control={ | |||||
| <Checkbox | |||||
| className="apply-for-ad-second-stage-checkbox" | |||||
| value={x.name} | |||||
| checked={x.isChecked} | |||||
| onChange={handleCheckboxes.bind(this, x.technologyId)} | |||||
| /> | |||||
| } | |||||
| label={x.name} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| </div> | |||||
| <div className="apply-for-ad-header-sub-group"> | |||||
| <label>{t("ads.others")}</label> | |||||
| <div className="apply-for-ad-header-sub-group-checkboxes"> | |||||
| {technologies | |||||
| .filter((x) => x.technologyType === "Other") | |||||
| .map((x) => ( | |||||
| <FormControlLabel | |||||
| key={x.technologyId} | |||||
| control={ | |||||
| <Checkbox | |||||
| className="apply-for-ad-second-stage-checkbox" | |||||
| value={x.name} | |||||
| checked={x.isChecked} | |||||
| onChange={handleCheckboxes.bind(this, x.technologyId)} | |||||
| /> | |||||
| } | |||||
| label={x.name} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>{t("filters.experience")}</label> | |||||
| <input | |||||
| type="number" | |||||
| placeholder="ex. 3 godine iskustva" | |||||
| value={experience} | |||||
| data-testid="apply-for-ad-second-stage-experience-input" | |||||
| onChange={(e) => setExperience(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-buttons"> | |||||
| <button onClick={onDecreaseStage}>{t("common.back")}</button> | |||||
| <button onClick={onIncreaseStage} disabled={disabled}> | |||||
| {t("common.continue")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| ApplyForAdSecondStage.propTypes = { | |||||
| professionalQualification: PropTypes.string, | |||||
| setProfessionalQualification: PropTypes.func, | |||||
| technologies: PropTypes.any, | |||||
| setTechnologies: PropTypes.any, | |||||
| experience: PropTypes.number, | |||||
| setExperience: PropTypes.any, | |||||
| onIncreaseStage: PropTypes.func, | |||||
| onDecreaseStage: PropTypes.func, | |||||
| }; | |||||
| export default ApplyForAdSecondStage; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const ApplyForAdThirdStage = ({ | |||||
| onIncreaseStage, | |||||
| onDecreaseStage, | |||||
| linkedinLink, | |||||
| setLinkedinLink, | |||||
| githubLink, | |||||
| setGithubLink, | |||||
| bitBucketLink, | |||||
| setBitBucketLink, | |||||
| email, | |||||
| setEmail, | |||||
| }) => { | |||||
| const disabled = | |||||
| linkedinLink.length === 0 || | |||||
| githubLink.length === 0 || | |||||
| bitBucketLink.length === 0; | |||||
| const {t} = useTranslation() | |||||
| return ( | |||||
| <div> | |||||
| <div className="apply-for-ad-header-title"> | |||||
| <p>{t("common.socialNetwork")}</p> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>LinkedIn</label> | |||||
| <input | |||||
| type="text" | |||||
| value={linkedinLink} | |||||
| data-testid="apply-for-ad-modal-third-stage-linkedin-input" | |||||
| onChange={(e) => setLinkedinLink(e.target.value)} | |||||
| placeholder="ex. https://www.linkedin.com/in/petar-petrovic" | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>GitHub</label> | |||||
| <input | |||||
| type="text" | |||||
| value={githubLink} | |||||
| data-testid="apply-for-ad-modal-third-stage-github-input" | |||||
| onChange={(e) => setGithubLink(e.target.value)} | |||||
| placeholder="ex. https://www.github.com/petarpetrovic" | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>BitBucket</label> | |||||
| <input | |||||
| type="text" | |||||
| value={bitBucketLink} | |||||
| data-testid="apply-for-ad-modal-third-stage-bitbucket-input" | |||||
| onChange={(e) => setBitBucketLink(e.target.value)} | |||||
| placeholder="ex. https://developer.atlassian.com/user/petarapetrovic" | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-modal-form-control"> | |||||
| <label>Email</label> | |||||
| <input | |||||
| type="email" | |||||
| value={email} | |||||
| data-testid="apply-for-ad-modal-third-stage-email-input" | |||||
| onChange={(e) => setEmail(e.target.value)} | |||||
| placeholder="ex. petar.petrovic@dilig.net" | |||||
| /> | |||||
| </div> | |||||
| <div className="apply-for-ad-buttons"> | |||||
| <button | |||||
| onClick={onDecreaseStage} | |||||
| data-testid="apply-for-ad-modal-third-stage-go-back-button" | |||||
| > | |||||
| {t("common.back")} | |||||
| </button> | |||||
| <button | |||||
| onClick={onIncreaseStage} | |||||
| disabled={disabled} | |||||
| data-testid="apply-for-ad-modal-third-stage-go-forward-button" | |||||
| > | |||||
| {t("common.continue")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| ApplyForAdThirdStage.propTypes = { | |||||
| linkedinLink: PropTypes.string, | |||||
| setLinkedinLink: PropTypes.any, | |||||
| githubLink: PropTypes.string, | |||||
| setGithubLink: PropTypes.any, | |||||
| bitBucketLink: PropTypes.string, | |||||
| setBitBucketLink: PropTypes.any, | |||||
| email: PropTypes.string, | |||||
| setEmail: PropTypes.any, | |||||
| onIncreaseStage: PropTypes.any, | |||||
| onDecreaseStage: PropTypes.any, | |||||
| }; | |||||
| export default ApplyForAdThirdStage; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { selectLogo } from "../../util/helpers/technologiesLogos"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const ArchiveAd = ({ | |||||
| className, | |||||
| title, | |||||
| minimumExperience, | |||||
| createdAt, | |||||
| expiredAt, | |||||
| onShowAdDetails, | |||||
| }) => { | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <div className={`archive-ad ${className}`} onClick={onShowAdDetails}> | |||||
| <div className="archive-ad-date"> | |||||
| <p> | |||||
| {new Date(createdAt).toLocaleDateString()} -{" "} | |||||
| {new Date(expiredAt).toLocaleDateString()} | |||||
| </p> | |||||
| </div> | |||||
| <div className="archive-ad-title"> | |||||
| <h3>{title}</h3> | |||||
| </div> | |||||
| <div className="archive-ad-image"> | |||||
| <img src={selectLogo(title)} alt=".net icon" /> | |||||
| </div> | |||||
| <div className="archive-ad-experience"> | |||||
| {minimumExperience > 0 ? ( | |||||
| <p> | |||||
| {minimumExperience}+ {t("common.experience")} | |||||
| </p> | |||||
| ) : ( | |||||
| <p>{t("ads.noExperience")}</p> | |||||
| )} | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| ArchiveAd.propTypes = { | |||||
| id: PropTypes.number, | |||||
| title: PropTypes.string, | |||||
| minimumExperience: PropTypes.number, | |||||
| createdAt: PropTypes.any, | |||||
| expiredAt: PropTypes.any, | |||||
| onShowAdDetails: PropTypes.func, | |||||
| className: PropTypes.any, | |||||
| }; | |||||
| export default ArchiveAd; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { selectLogo } from "../../util/helpers/technologiesLogos"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const StatsAd = ({ | |||||
| className, | |||||
| count, | |||||
| title, | |||||
| minimumExperience, | |||||
| createdAt, | |||||
| expiredAt, | |||||
| onShowAdDetails, | |||||
| }) => { | |||||
| const {t} = useTranslation() | |||||
| return ( | |||||
| <div className={`archive-ad stats-ad ${className}`} onClick={onShowAdDetails}> | |||||
| <div className="ad-count"> | |||||
| {count} {t("ads.registered")} | |||||
| </div> | |||||
| <div className="archive-ad-date"> | |||||
| <p> | |||||
| {new Date(createdAt).toLocaleDateString()} -{" "} | |||||
| {new Date(expiredAt).toLocaleDateString()} | |||||
| </p> | |||||
| </div> | |||||
| <div className="archive-ad-title"> | |||||
| <h3>{title}</h3> | |||||
| </div> | |||||
| <div className="archive-ad-image"> | |||||
| <img src={selectLogo(title)} alt=".net icon" /> | |||||
| </div> | |||||
| <div className="archive-ad-experience"> | |||||
| {minimumExperience > 0 ? ( | |||||
| <p>{minimumExperience}+ {t("common.experience")}</p> | |||||
| ) : ( | |||||
| <p>{t("ads.noExperience2")}</p> | |||||
| )} | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| StatsAd.propTypes = { | |||||
| id: PropTypes.number, | |||||
| count: PropTypes.number, | |||||
| title: PropTypes.string, | |||||
| minimumExperience: PropTypes.number, | |||||
| createdAt: PropTypes.any, | |||||
| expiredAt: PropTypes.any, | |||||
| onShowAdDetails: PropTypes.func, | |||||
| className: PropTypes.any, | |||||
| }; | |||||
| export default StatsAd; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { formatDate } from "../../util/helpers/dateHelpers"; | |||||
| import dotnetImage from "../../assets/images/.net_icon.png"; | |||||
| const CandidateAd = ({ add, className, onclick }) => { | |||||
| return add === undefined ? ( | |||||
| <p></p> | |||||
| ) : ( | |||||
| <div | |||||
| onClick={onclick} | |||||
| style={{ cursor: "pointer" }} | |||||
| className={`applicant-add ${className !== undefined ? className : ""}`} | |||||
| > | |||||
| <p className="applicant-add-date">{formatDate(add.createdAt)}</p> | |||||
| <p className="applicant-add-title">{add.title}</p> | |||||
| <img | |||||
| src={dotnetImage} | |||||
| alt="technology-image" | |||||
| className="applicant-add-technology-image" | |||||
| /> | |||||
| <div className="applicant-add-site">dilig.net</div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| CandidateAd.propTypes = { | |||||
| add: PropTypes.object, | |||||
| className: PropTypes.any, | |||||
| onclick: PropTypes.func, | |||||
| }; | |||||
| export default CandidateAd; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { formatDate } from "../../util/helpers/dateHelpers"; | |||||
| import { CANDIDATES_PAGE } from "../../constants/pages"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const CandidateCard = ({ candidate, className, history }) => { | |||||
| const { t } = useTranslation(); | |||||
| const navigateToDetailsPage = () => { | |||||
| history.push({ | |||||
| pathname: CANDIDATES_PAGE + "/" + candidate.applicantId, | |||||
| }); | |||||
| }; | |||||
| return candidate == null ? ( | |||||
| <p></p> | |||||
| ) : ( | |||||
| <div | |||||
| onClick={navigateToDetailsPage} | |||||
| className={`candidate-card-container ${ | |||||
| className !== undefined ? className : "" | |||||
| }`} | |||||
| > | |||||
| <p className="candidate-card-date"> | |||||
| {formatDate(candidate.dateOfApplication)} | |||||
| </p> | |||||
| <p className="candidate-card-applicant-name"> | |||||
| {candidate.firstName} {candidate.lastName} | |||||
| </p> | |||||
| <p className="candidate-card-years"> | |||||
| {candidate.experience === 0 | |||||
| ? t("common.noExperience") | |||||
| : candidate.experience + " " + t("common.experience")} | |||||
| </p> | |||||
| <div className="candidate-card-tecnologies-container"> | |||||
| {candidate.technologyApplicants.map((technology, index) => ( | |||||
| <p key={index}>{technology.name}</p> | |||||
| ))} | |||||
| </div> | |||||
| <div className="candidate-card-techologies"> | |||||
| {candidate.technologyApplicants.map((technology, index) => ( | |||||
| <div key={index} className="applicant-add-site"> | |||||
| {technology.technology.name} | |||||
| </div> | |||||
| ))} | |||||
| </div> | |||||
| <a className="cvLink"> | |||||
| CV {candidate.firstName} {candidate.lastName}.pdf | |||||
| </a> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| CandidateCard.propTypes = { | |||||
| candidate: PropTypes.object, | |||||
| className: PropTypes.any, | |||||
| history: PropTypes.shape({ | |||||
| replace: PropTypes.func, | |||||
| push: PropTypes.func, | |||||
| location: PropTypes.shape({ | |||||
| pathname: PropTypes.string, | |||||
| }), | |||||
| }), | |||||
| }; | |||||
| export default CandidateCard; |
| import React, { useEffect, useState } from "react"; | |||||
| import PropType from "prop-types"; | |||||
| import Box from "@mui/material/Box"; | |||||
| import Drawer from "@mui/material/Drawer"; | |||||
| import FormGroup from "@mui/material/FormGroup"; | |||||
| import FormControlLabel from "@mui/material/FormControlLabel"; | |||||
| import Checkbox from "@mui/material/Checkbox"; | |||||
| import Slider from "@mui/material/Slider"; | |||||
| import filterIcon from "../../assets/images/filter_vector.png"; | |||||
| import x from "../../assets/images/x.png"; | |||||
| import { | |||||
| filterCandidates, | |||||
| 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 { useTranslation } from "react-i18next"; | |||||
| const CandidateFilters = ({ | |||||
| open, | |||||
| handleClose, | |||||
| pageSize, | |||||
| currentPage, | |||||
| isTableView, | |||||
| technologies, | |||||
| sliderValue, | |||||
| startingDate, | |||||
| endingDate, | |||||
| typesOfEmployments, | |||||
| setSliderValue, | |||||
| setStartingDate, | |||||
| setEndingDate, | |||||
| setTypesOfEmployments, | |||||
| }) => { | |||||
| const dispatch = useDispatch(); | |||||
| const [isInitial, setIsInitial] = useState(true); | |||||
| const { t } = useTranslation(); | |||||
| useEffect(() => {}, [isTableView]); | |||||
| const handleSliderChange = (_, newValue) => { | |||||
| setSliderValue(newValue); | |||||
| }; | |||||
| const resetFilters = () => { | |||||
| setTypesOfEmployments([ | |||||
| { name: "Posao", isChecked: false }, | |||||
| { name: "Intership", isChecked: false }, | |||||
| ]); | |||||
| setSliderValue([0, 0]); | |||||
| setEndingDate(""); | |||||
| setStartingDate(""); | |||||
| }; | |||||
| useEffect(() => { | |||||
| if (isInitial) { | |||||
| setIsInitial(false); | |||||
| return; | |||||
| } | |||||
| dispatch(resetIsCheckedValue()); | |||||
| resetFilters(); | |||||
| }, [isTableView]); | |||||
| const updateTypeState = (name, value) => { | |||||
| const newState = typesOfEmployments.map((obj) => { | |||||
| if (obj.name === name) { | |||||
| return { ...obj, isChecked: value }; | |||||
| } else { | |||||
| return { ...obj, isChecked: false }; | |||||
| } | |||||
| }); | |||||
| setTypesOfEmployments(newState); | |||||
| }; | |||||
| const handleTechologiesChange = (e) => { | |||||
| const { name } = e.target; | |||||
| dispatch(changeIsCheckedValue(name)); | |||||
| }; | |||||
| const getSelectedEmploymentType = () => { | |||||
| return typesOfEmployments.filter((e) => e.isChecked === true); | |||||
| }; | |||||
| const handleChangeTypeOfEmployment = (name) => { | |||||
| updateTypeState(name, true); | |||||
| }; | |||||
| const handleApiResponseSuccess = () => { | |||||
| handleClose(); | |||||
| }; | |||||
| const isThereSelectedFilter = () => { | |||||
| 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; | |||||
| } | |||||
| if (sliderValue[0] !== 0 || sliderValue[1] !== 0) { | |||||
| return true; | |||||
| } | |||||
| if (startingDate !== "" || endingDate !== "") { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| }; | |||||
| const fiterItems = () => { | |||||
| const tech = technologies | |||||
| .filter((tech) => tech.isChecked === true) | |||||
| .map((tech) => tech.name); | |||||
| 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, | |||||
| }) | |||||
| ); | |||||
| }; | |||||
| const handleChangeStartingDate = (event) => { | |||||
| setStartingDate(event.target.value); | |||||
| }; | |||||
| const handleChangeEndingDate = (event) => { | |||||
| setEndingDate(event.target.value); | |||||
| }; | |||||
| const getDayBeforeToday = (date = new Date()) => { | |||||
| const previous = new Date(date.getTime()); | |||||
| previous.setDate(date.getDate() - 1); | |||||
| return previous; | |||||
| }; | |||||
| const list = () => ( | |||||
| <Box | |||||
| sx={{ | |||||
| width: 360, | |||||
| height: "100%", | |||||
| borderRadius: "18px 0 0 18px", | |||||
| padding: "36px", | |||||
| }} | |||||
| role="presentation" | |||||
| onKeyDown={handleClose} | |||||
| > | |||||
| <div> | |||||
| <div className="ad-filters-header-container"> | |||||
| <div className="ad-filters-header"> | |||||
| <img src={filterIcon} alt="filter_icon" /> | |||||
| <h3>{t("filters.filters")}</h3> | |||||
| <p> | |||||
| <sub>| {t("candidates.candidates")}</sub> | |||||
| </p> | |||||
| </div> | |||||
| <div className="ad-filters-header-close" onClick={handleClose}> | |||||
| <img src={x} alt="x" /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-experience"> | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>{t("filters.experience")}</p> | |||||
| </div> | |||||
| <div className="ad-filters-experience-slider"> | |||||
| <Slider | |||||
| getAriaLabel={() => "Temperature range"} | |||||
| value={sliderValue} | |||||
| onChange={handleSliderChange} | |||||
| valueLabelDisplay="auto" | |||||
| max={20} | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-technologies"> | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>{t("filters.technologies")}</p> | |||||
| </div> | |||||
| <div className="ad-filters-technologies-checkboxes"> | |||||
| <FormGroup> | |||||
| {technologies.map((technology, index) => ( | |||||
| <FormControlLabel | |||||
| key={index} | |||||
| control={ | |||||
| <Checkbox | |||||
| checked={technology.isChecked} | |||||
| name={technology.name} | |||||
| className="ad-filters-technologies-checkboxes-checkbox" | |||||
| onChange={handleTechologiesChange} | |||||
| /> | |||||
| } | |||||
| label={technology.name} | |||||
| /> | |||||
| ))} | |||||
| </FormGroup> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-technologies"> | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>{t("filters.employmentType")}</p> | |||||
| </div> | |||||
| <div className="ad-filters-employment-type"> | |||||
| {typesOfEmployments.map((type, index) => ( | |||||
| <button | |||||
| key={index} | |||||
| className={ | |||||
| type.isChecked === false | |||||
| ? "c-btn c-btn--primary-outlined type-of-employment-btn" | |||||
| : "c-btn c-btn--primary type-of-employment-btn" | |||||
| } | |||||
| onClick={() => handleChangeTypeOfEmployment(type.name)} | |||||
| > | |||||
| {type.name} | |||||
| </button> | |||||
| ))} | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-technologies" style={{ marginTop: "35px" }}> | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>{t("filters.dateOfApplication")}</p> | |||||
| <div className="filter-date-container"> | |||||
| <p>{t("common.from")}</p> | |||||
| <input | |||||
| type="date" | |||||
| id="start" | |||||
| max={formatDateInput(getDayBeforeToday())} | |||||
| value={startingDate} | |||||
| onChange={handleChangeStartingDate} | |||||
| /> | |||||
| </div> | |||||
| <div className="filter-date-container"> | |||||
| <p>{t("common.to")}</p> | |||||
| <input | |||||
| type="date" | |||||
| id="start" | |||||
| data-testid="filter-date-container-ending-date" | |||||
| max={formatDateInput(new Date())} | |||||
| value={endingDate} | |||||
| onChange={handleChangeEndingDate} | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-search" style={{ marginTop: "45px" }}> | |||||
| <button | |||||
| className="c-btn c-btn--primary" | |||||
| onClick={fiterItems} | |||||
| disabled={!isThereSelectedFilter()} | |||||
| > | |||||
| {t("common.search")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| </Box> | |||||
| ); | |||||
| return ( | |||||
| <div> | |||||
| <Drawer anchor="right" open={open} onClose={handleClose}> | |||||
| {list()} | |||||
| </Drawer> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| CandidateFilters.propTypes = { | |||||
| open: PropType.any, | |||||
| handleClose: PropType.func, | |||||
| candidates: PropType.array, | |||||
| currentPage: PropType.number, | |||||
| 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; |
| sx={{ | sx={{ | ||||
| flexGrow: 1, | flexGrow: 1, | ||||
| overflowY: "auto", | overflowY: "auto", | ||||
| zIndex: 100000, | |||||
| position: "relative", | position: "relative", | ||||
| }} | }} | ||||
| > | > |
| <div className="hr" style={{ width: "90%", marginTop: "18px" }}></div> | <div className="hr" style={{ width: "90%", marginTop: "18px" }}></div> | ||||
| </div> | </div> | ||||
| <List> | <List> | ||||
| {navItems.map((n) => ( | |||||
| {filterNavItems().map((n) => ( | |||||
| <ListItemButton key={n} onClick={handleToggleDrawer}> | <ListItemButton key={n} onClick={handleToggleDrawer}> | ||||
| <ListItemIcon> | <ListItemIcon> | ||||
| <ListItemText | <ListItemText |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import editIcon from "../../assets/images/edit.png"; | |||||
| import IconButton from "../IconButton/IconButton"; | |||||
| const PatternCard = ({ | |||||
| createdAt, | |||||
| title, | |||||
| selectionProcess, | |||||
| isShownEdit, | |||||
| onShowPatternDetails, | |||||
| onOpenEditModal, | |||||
| }) => { | |||||
| return ( | |||||
| <div className="pattern-card-with-icon"> | |||||
| {isShownEdit && ( | |||||
| <div className="pattern-card-edit"> | |||||
| <IconButton | |||||
| onClick={onOpenEditModal} | |||||
| className={`c-btn--primary-outlined c-btn pattern-card-edit`} | |||||
| > | |||||
| <img | |||||
| style={{ width: "16px !important", height: "16px !important" }} | |||||
| src={editIcon} | |||||
| /> | |||||
| </IconButton> | |||||
| </div> | |||||
| )} | |||||
| <div className="pattern-card" onClick={onShowPatternDetails}> | |||||
| <div className="pattern-card-date"> | |||||
| <p>{new Date(createdAt).toLocaleDateString()}</p> | |||||
| </div> | |||||
| <div className="pattern-card-title"> | |||||
| <p>{title}</p> | |||||
| </div> | |||||
| <div className="pattern-card-selection-proccess"> | |||||
| <p>{selectionProcess}</p> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| PatternCard.propTypes = { | |||||
| createdAt: PropTypes.any, | |||||
| title: PropTypes.string, | |||||
| selectionProcess: PropTypes.string, | |||||
| isShownEdit: PropTypes.bool, | |||||
| onShowPatternDetails: PropTypes.func, | |||||
| onOpenEditModal: PropTypes.func, | |||||
| }; | |||||
| export default PatternCard; |
| import React, { useState } from "react"; | |||||
| import CustomDrawer from "../UI/CustomDrawer"; | |||||
| import { Checkbox, FormControlLabel, FormGroup } from "@mui/material"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { useDispatch } from "react-redux"; | |||||
| import { setFilteredPatternsReq } from "../../store/actions/patterns/patternsActions"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const PatternFilters = ({ | |||||
| openFilterDrawer, | |||||
| handleClose, | |||||
| selectionLevelFilter, | |||||
| onChangeFilterCheckboxes, | |||||
| }) => { | |||||
| const [fromDate, setFromDate] = useState(""); | |||||
| const [toDate, setToDate] = useState(""); | |||||
| const dispatch = useDispatch(); | |||||
| const { t } = useTranslation(); | |||||
| const submitFiltersHandler = (e) => { | |||||
| e.preventDefault(); | |||||
| const selectionLevels = selectionLevelFilter | |||||
| .filter((level) => level.isChecked === true) | |||||
| .map((level) => level.id); | |||||
| dispatch( | |||||
| setFilteredPatternsReq({ | |||||
| fromDate: fromDate === "" ? null : fromDate, | |||||
| toDate: toDate === "" ? null : toDate, | |||||
| selectionLevels, | |||||
| handleApiResponseSuccess, | |||||
| }) | |||||
| ); | |||||
| }; | |||||
| const handleApiResponseSuccess = () => { | |||||
| handleClose(); | |||||
| }; | |||||
| const hasSelectedFilters = () => { | |||||
| const checked = selectionLevelFilter.filter( | |||||
| (level) => level.isChecked === true | |||||
| ); | |||||
| if (checked.length > 0) { | |||||
| return true; | |||||
| } | |||||
| if (fromDate !== "") { | |||||
| return true; | |||||
| } | |||||
| if (toDate !== "") { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| }; | |||||
| return ( | |||||
| <CustomDrawer | |||||
| title="Šabloni" | |||||
| open={openFilterDrawer} | |||||
| onCloseDrawer={handleClose} | |||||
| > | |||||
| <form onSubmit={submitFiltersHandler}> | |||||
| <div className="custom-drawer"> | |||||
| <div> | |||||
| <div className="custom-drawer-sub-card"> | |||||
| <div className="custom-drawer-sub-card-label"> | |||||
| <p>{t("filters.category")}</p> | |||||
| </div> | |||||
| <div className="custom-drawer-sub-card-content"> | |||||
| <FormGroup> | |||||
| {selectionLevelFilter.map((process) => ( | |||||
| <FormControlLabel | |||||
| key={process.id} | |||||
| control={ | |||||
| <Checkbox | |||||
| value={process.name} | |||||
| checked={process.isChecked} | |||||
| onChange={() => onChangeFilterCheckboxes(process.id)} | |||||
| className="pattern-filters-checkbox" | |||||
| /> | |||||
| } | |||||
| label={process.name} | |||||
| /> | |||||
| ))} | |||||
| </FormGroup> | |||||
| </div> | |||||
| </div> | |||||
| <div className="custom-drawer-sub-card"> | |||||
| <div className="custom-drawer-sub-card-label"> | |||||
| <p>{t("filters.creationDate")}</p> | |||||
| </div> | |||||
| <div className="custom-drawer-sub-card-content"> | |||||
| <FormGroup style={{ marginBottom: "9px" }}> | |||||
| <div className="custom-drawer-sub-card-content-sub"> | |||||
| <label className="custom-drawer-sub-card-content-sub-label"> | |||||
| {t("common.from")} | |||||
| </label> | |||||
| <input | |||||
| type="date" | |||||
| className="custom-drawer-sub-card-content-input-1" | |||||
| onChange={(e) => setFromDate(e.target.value)} | |||||
| value={fromDate} | |||||
| /> | |||||
| </div> | |||||
| </FormGroup> | |||||
| <FormGroup> | |||||
| <div className="custom-drawer-sub-card-content-sub"> | |||||
| <label className="custom-drawer-sub-card-content-sub-label"> | |||||
| {t("common.to")} | |||||
| </label> | |||||
| <input | |||||
| type="date" | |||||
| className="custom-drawer-sub-card-content-input-2" | |||||
| onChange={(e) => setToDate(e.target.value)} | |||||
| value={toDate} | |||||
| /> | |||||
| </div> | |||||
| </FormGroup> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="custom-drawer-submit"> | |||||
| <button | |||||
| className="c-btn c-btn--primary" | |||||
| data-testid="custom-drawer-submit-search" | |||||
| disabled={!hasSelectedFilters()} | |||||
| > | |||||
| {t("common.search")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| </form> | |||||
| </CustomDrawer> | |||||
| ); | |||||
| }; | |||||
| PatternFilters.propTypes = { | |||||
| openFilterDrawer: PropTypes.bool, | |||||
| handleClose: PropTypes.func, | |||||
| selectionLevelFilter: PropTypes.any, | |||||
| onChangeFilterCheckboxes: PropTypes.func, | |||||
| }; | |||||
| export default PatternFilters; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { formatTimeSrb } from "../../util/helpers/dateHelpers"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const DayComponent = ({ numberOfDay, nameOfDay, interviews, onClick }) => { | |||||
| const { t } = useTranslation(); | |||||
| 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> | |||||
| {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> | |||||
| </div> | |||||
| ))} | |||||
| {interviews && interviews.length > 2 && ( | |||||
| <span className="day-component-more"> | |||||
| +{interviews.length - 2} {t("schedule.items")} | |||||
| </span> | |||||
| )} | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| DayComponent.propTypes = { | |||||
| numberOfDay: PropTypes.number, | |||||
| nameOfDay: PropTypes.string, | |||||
| interviews: PropTypes.array, | |||||
| onClick: PropTypes.func, | |||||
| }; | |||||
| export default DayComponent; |
| import React, { useEffect, useState } from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { Dialog, DialogContent, DialogTitle } from "@mui/material"; | |||||
| import calendar from "../../../src/assets/images/calendar2.png"; | |||||
| import arrowLeftDisabled from "../../../src/assets/images/arrow_left.png"; | |||||
| import arrowLeft from "../../../src/assets/images/arrow_left2.png"; | |||||
| import arrowRight from "../../../src/assets/images/arrow_right.png"; | |||||
| import x from "../../../src/assets/images/x.png"; | |||||
| import meet from "../../../src/assets/images/meet.png"; | |||||
| import { formatTimeSrb } from "../../util/helpers/dateHelpers"; | |||||
| import { CANDIDATES_PAGE } from "../../constants/pages"; | |||||
| import { useTheme } from "@emotion/react"; | |||||
| import { useMediaQuery } from "@mui/material"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const DayDetailsComponent = ({ | |||||
| selectedDate, | |||||
| selectionProcesses, | |||||
| open, | |||||
| onClose, | |||||
| setCurrentlySelected, | |||||
| setCurrentlySelectedDay, | |||||
| currentlySelectedDay, | |||||
| numberOfDaysInMonth, | |||||
| history, | |||||
| }) => { | |||||
| const theme = useTheme(); | |||||
| const matches = useMediaQuery(theme.breakpoints.down("361")); | |||||
| const [isLeftArrowDisabled, setIsLeftArrowDisabled] = useState(false); | |||||
| const [isRightArrowDisabled, setIsRightArrowDisabled] = useState(false); | |||||
| const { t } = useTranslation(); | |||||
| const handleClose = () => { | |||||
| onClose(); | |||||
| }; | |||||
| useEffect(() => { | |||||
| setIsLeftArrowDisabled(currentlySelectedDay === 1 ? true : false); | |||||
| setIsRightArrowDisabled( | |||||
| currentlySelectedDay === numberOfDaysInMonth ? true : false | |||||
| ); | |||||
| }, [currentlySelectedDay, isLeftArrowDisabled, isRightArrowDisabled]); | |||||
| const goForwardOneDay = () => { | |||||
| const date = selectedDate.split("."); | |||||
| const day = date[0]; | |||||
| const month = date[1]; | |||||
| const year = date[2]; | |||||
| const newDay = parseInt(day) + 1; | |||||
| if (day === numberOfDaysInMonth) { | |||||
| setIsRightArrowDisabled(true); | |||||
| return; | |||||
| } | |||||
| setCurrentlySelected(newDay + "." + month + "." + year); | |||||
| setCurrentlySelectedDay(newDay); | |||||
| setIsLeftArrowDisabled(true); | |||||
| }; | |||||
| const goBackOneDay = () => { | |||||
| const date = selectedDate.split("."); | |||||
| const day = date[0]; | |||||
| const month = date[1]; | |||||
| const year = date[2]; | |||||
| if (day === 1) { | |||||
| setIsLeftArrowDisabled(true); | |||||
| return; | |||||
| } | |||||
| const newDay = parseInt(day) - 1; | |||||
| setCurrentlySelected(newDay + "." + month + "." + year); | |||||
| setCurrentlySelectedDay(newDay); | |||||
| }; | |||||
| const navigateToCandidateDetailsPage = (applicantId) => { | |||||
| history.push({ | |||||
| pathname: CANDIDATES_PAGE + "/" + applicantId, | |||||
| }); | |||||
| }; | |||||
| return ( | |||||
| <Dialog | |||||
| onClose={handleClose} | |||||
| open={open} | |||||
| maxWidth={!matches ? "549" : "339"} | |||||
| > | |||||
| <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">{t("schedule.planner")}</p> | |||||
| <p className="day-details-header">| {selectedDate}.</p> | |||||
| <img | |||||
| src={x} | |||||
| className="day-details-close-btn" | |||||
| onClick={handleClose} | |||||
| /> | |||||
| </DialogTitle> | |||||
| <DialogContent | |||||
| style={{ | |||||
| display: "flex", | |||||
| flexDirection: "column", | |||||
| alignItems: "center", | |||||
| }} | |||||
| > | |||||
| <div className="day-details-content-sub-container"> | |||||
| {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 | |||||
| </p> | |||||
| <div | |||||
| style={{ | |||||
| display: "flex", | |||||
| alignItems: !matches ? "center" : "flex-start", | |||||
| flexDirection: !matches ? "row" : "column", | |||||
| }} | |||||
| > | |||||
| <p className="day-details-name"> | |||||
| {selectionProcess.selectionLevel.name} | |||||
| </p> | |||||
| <p | |||||
| className="day-details-applicant" | |||||
| data-testid="day-details-applicant" | |||||
| onClick={() => | |||||
| navigateToCandidateDetailsPage( | |||||
| selectionProcess.applicant.applicantId | |||||
| ) | |||||
| } | |||||
| > | |||||
| {selectionProcess.applicant.firstName}{" "} | |||||
| {selectionProcess.applicant.lastName} | |||||
| </p> | |||||
| </div> | |||||
| <a | |||||
| className="day-details-link" | |||||
| href={selectionProcess.link} | |||||
| target="_blank" | |||||
| rel="noreferrer" | |||||
| > | |||||
| <img src={meet} /> | |||||
| {!matches && <span>Link</span>} | |||||
| </a> | |||||
| </div> | |||||
| <div className="day-details-line" /> | |||||
| </div> | |||||
| ))} | |||||
| </div> | |||||
| <div | |||||
| style={{ | |||||
| display: "flex", | |||||
| gap: "18px", | |||||
| marginTop: selectionProcesses.length === 0 ? "18px" : "0px", | |||||
| }} | |||||
| > | |||||
| {isLeftArrowDisabled === true ? ( | |||||
| <div className="day-details-arrow-container"> | |||||
| <img src={arrowLeftDisabled} /> | |||||
| </div> | |||||
| ) : ( | |||||
| <div | |||||
| className="day-details-arrow-container" | |||||
| data-testid="day-details-left-arrow" | |||||
| onClick={goBackOneDay} | |||||
| > | |||||
| <img src={arrowLeft} /> | |||||
| </div> | |||||
| )} | |||||
| {isRightArrowDisabled === true ? ( | |||||
| <div className="day-details-arrow-container-p"> | |||||
| <img src={arrowLeftDisabled} /> | |||||
| </div> | |||||
| ) : ( | |||||
| <div | |||||
| className="day-details-arrow-container" | |||||
| onClick={goForwardOneDay} | |||||
| data-testid="day-details-right-arrow" | |||||
| > | |||||
| <img src={arrowRight} /> | |||||
| </div> | |||||
| )} | |||||
| </div> | |||||
| </DialogContent> | |||||
| </div> | |||||
| </Dialog> | |||||
| ); | |||||
| }; | |||||
| DayDetailsComponent.propTypes = { | |||||
| selectedDate: PropTypes.string, | |||||
| selectionProcesses: PropTypes.array, | |||||
| open: PropTypes.bool, | |||||
| onClose: PropTypes.func, | |||||
| setCurrentlySelected: PropTypes.func, | |||||
| setCurrentlySelectedDay: PropTypes.func, | |||||
| currentlySelectedDay: PropTypes.number, | |||||
| numberOfDaysInMonth: PropTypes.number, | |||||
| history: PropTypes.shape({ | |||||
| replace: PropTypes.func, | |||||
| push: PropTypes.func, | |||||
| location: PropTypes.shape({ | |||||
| pathname: PropTypes.string, | |||||
| }), | |||||
| }), | |||||
| }; | |||||
| export default DayDetailsComponent; |
| import Navbar from "../../components/MUI/NavbarComponent"; | import Navbar from "../../components/MUI/NavbarComponent"; | ||||
| import { FormProvider } from "../../context/FormContext"; | import { FormProvider } from "../../context/FormContext"; | ||||
| import { SelectionProvider } from "../../context/SelectionContext"; | import { SelectionProvider } from "../../context/SelectionContext"; | ||||
| import { CREATE_AD_PAGE } from "../../constants/pages"; | |||||
| import { FILES_PAGE } from "../../constants/pages"; | |||||
| // import AppRoutes from "../../AppRoutes"; | // import AppRoutes from "../../AppRoutes"; | ||||
| const urls = [ | const urls = [ | ||||
| ) : ( | ) : ( | ||||
| <div className=""> | <div className=""> | ||||
| <Navbar /> | <Navbar /> | ||||
| <div className={pathname === CREATE_AD_PAGE ? "" : "h-withHeader"}> | |||||
| <div className={pathname === FILES_PAGE ? "" : "h-withHeader"}> | |||||
| {children} | {children} | ||||
| </div> | </div> | ||||
| </div> | </div> |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { formatDate } from "../../util/helpers/dateHelpers"; | |||||
| import { Link } from "react-router-dom"; | |||||
| import success from "../../assets/images/svg/success.svg"; | |||||
| import unsucc from "../../assets/images/unsucc.png"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const ApplicantSelection = ({ | |||||
| levelNumber, | |||||
| levelName, | |||||
| schedguler, | |||||
| link, | |||||
| date, | |||||
| status, | |||||
| id, | |||||
| onShowAdDetails, | |||||
| className, | |||||
| }) => { | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <div | |||||
| data-testid="appSelection" | |||||
| className={`active-process-card ${className}`} | |||||
| onClick={onShowAdDetails} | |||||
| > | |||||
| <div className="active-process-card-header"> | |||||
| <div className="active-process-card-number"> | |||||
| <p>{levelNumber}</p> | |||||
| </div> | |||||
| {status === "Odrađen" && ( | |||||
| <div className="active-process-card-logo"> | |||||
| <img src={success} alt="success-image" /> | |||||
| </div> | |||||
| )} | |||||
| {status === "Neuspešno" && ( | |||||
| <div className="active-process-card-logo"> | |||||
| <img src={unsucc} alt="success-image" /> | |||||
| </div> | |||||
| )} | |||||
| </div> | |||||
| <div className="active-process-card-body"> | |||||
| <div className="active-process-card-date"> | |||||
| <p>{date && date !== "" && formatDate(new Date(date))}</p> | |||||
| </div> | |||||
| <div className="ad-card-title"> | |||||
| <h3>{levelName}</h3> | |||||
| </div> | |||||
| <div className="active-process-card-date"> | |||||
| <p>{schedguler}</p> | |||||
| </div> | |||||
| <div className="active-process-card-buttons"> | |||||
| <button className={status === "Neuspešno" && "unsucc"}> | |||||
| {status} | |||||
| </button> | |||||
| </div> | |||||
| <div className="active-process-card-link"> | |||||
| {status === "Odrađen" && ( | |||||
| <Link className="ad-details-buttons-link" to={"/candidates/" + id}> | |||||
| {t("selection.report")} | |||||
| </Link> | |||||
| )} | |||||
| {link && status !== "Odrađen" && ( | |||||
| <a href={link} className="ad-details-buttons-link"> | |||||
| {t("selection.link")} | |||||
| </a> | |||||
| )} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| ApplicantSelection.propTypes = { | |||||
| id: PropTypes.string, | |||||
| levelNumber: PropTypes.number, | |||||
| levelName: PropTypes.string, | |||||
| schedguler: PropTypes.string, | |||||
| link: PropTypes.string, | |||||
| date: PropTypes.any, | |||||
| status: PropTypes.string, | |||||
| onShowAdDetails: PropTypes.func, | |||||
| className: PropTypes.any, | |||||
| }; | |||||
| export default ApplicantSelection; |
| import React, { useState } from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { selectDoneProcessError } from "../../store/selectors/processSelectors"; | |||||
| import { selectAuthUser } from "../../store/selectors/userSelectors"; | |||||
| import { setDoneProcessReq } from "../../store/actions/processes/processAction"; | |||||
| import { useDispatch, useSelector } from "react-redux"; | |||||
| // import { formatDateSrb, formatTimeSrb } from "../../util/helpers/dateHelpers"; | |||||
| import { SELECTION_PROCESS_OF_APPLICANT_PAGE } from "../../constants/pages"; | |||||
| import { PUT_PROCESS_LOADING } from "../../store/actions/processes/processesActionConstants"; | |||||
| import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||||
| import Backdrop from "../../components/MUI/BackdropComponent"; | |||||
| import { IconButton } from "@mui/material"; | |||||
| import plus from "../../assets/images/plus.png"; | |||||
| import SelectionCard from "./SelectionCard"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const Selection = (props) => { | |||||
| const [over, setOver] = useState(false); | |||||
| const allApplicants = props.selection.selectionProcesses; | |||||
| const errorMessage = useSelector(selectDoneProcessError); | |||||
| const dispatch = useDispatch(); | |||||
| const user = useSelector(selectAuthUser); | |||||
| const { t } = useTranslation(); | |||||
| const dropItem = (e, selId) => { | |||||
| setOver(false); | |||||
| var data = e.dataTransfer.getData("text/plain"); | |||||
| const selectionProcess = JSON.parse(data); | |||||
| if ( | |||||
| selectionProcess.selectionLevelId < selId && | |||||
| selectionProcess.status !== "Neuspešno" | |||||
| ) { | |||||
| dispatch( | |||||
| setDoneProcessReq({ | |||||
| id: selectionProcess.id, | |||||
| name: "Some random name", | |||||
| applicantId: selectionProcess.applicant.applicantId, | |||||
| schedulerId: user.id, | |||||
| }) | |||||
| ); | |||||
| } | |||||
| if (errorMessage) { | |||||
| console.log(errorMessage); | |||||
| } | |||||
| }; | |||||
| const dragStart = (e, applicant) => { | |||||
| e.dataTransfer.setData("text/plain", JSON.stringify(applicant)); | |||||
| }; | |||||
| const dragOver = (e) => { | |||||
| e.preventDefault(); | |||||
| setOver(true); | |||||
| }; | |||||
| const isLoading = useSelector( | |||||
| selectIsLoadingByActionType(PUT_PROCESS_LOADING) | |||||
| ); | |||||
| const handleOpenDetails = (id) => { | |||||
| props.history.push(SELECTION_PROCESS_OF_APPLICANT_PAGE.replace(":id", id)); | |||||
| }; | |||||
| const applicants = allApplicants?.filter( | |||||
| (a) => a.status !== "Odrađen" || a.selectionLevelId === 4 | |||||
| ); | |||||
| const renderList = applicants?.map((item, index) => { | |||||
| return ( | |||||
| <SelectionCard | |||||
| key={index} | |||||
| item={item} | |||||
| dragStart={(e) => dragStart(e, item)} | |||||
| click={() => handleOpenDetails(item.applicant.applicantId)} | |||||
| /> | |||||
| ); | |||||
| }); | |||||
| return ( | |||||
| <div | |||||
| data-testid="selection-level" | |||||
| dropppable="true" | |||||
| id={props.selection.id} | |||||
| className={`selection-card ${over ? "over" : ""}`} | |||||
| onDragOver={(e) => dragOver(e)} | |||||
| onDragLeave={() => setOver(false)} | |||||
| onDrop={(e) => dropItem(e, props.selection.id)} | |||||
| > | |||||
| <div className="selection-card-title"> | |||||
| <h3 style={{ marginRight: "50px" }}>{props.selection.name}</h3> | |||||
| {props.order === 0 ? ( | |||||
| <IconButton | |||||
| sx={{ marginRight: "35px" }} | |||||
| className={`c-btn--primary-outlined c-btn td-btn`} | |||||
| onClick={props.modalEvent} | |||||
| > | |||||
| <img | |||||
| style={{ | |||||
| position: "relative", | |||||
| }} | |||||
| src={plus} | |||||
| data-testid="interview-image" | |||||
| /> | |||||
| </IconButton> | |||||
| ) : ( | |||||
| "" | |||||
| )} | |||||
| </div> | |||||
| <Backdrop position="absolute" isLoading={isLoading} /> | |||||
| {applicants && | |||||
| applicants !== null && | |||||
| applicants?.length > 0 && | |||||
| renderList} | |||||
| {applicants && applicants !== null && applicants?.length === 0 && ( | |||||
| <div className="sel-item-no-data"> | |||||
| <div className="date"> | |||||
| <p data-testid="empty-selection" style={{ width: "240px" }}> | |||||
| {t("selection.noCandidates")} | |||||
| </p> | |||||
| </div> | |||||
| </div> | |||||
| )} | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| Selection.propTypes = { | |||||
| history: PropTypes.shape({ | |||||
| replace: PropTypes.func, | |||||
| push: PropTypes.func, | |||||
| location: PropTypes.shape({ | |||||
| pathname: PropTypes.string, | |||||
| }), | |||||
| }), | |||||
| order: PropTypes.number, | |||||
| modalEvent: PropTypes.func, | |||||
| selection: PropTypes.shape({ | |||||
| id: PropTypes.number, | |||||
| name: PropTypes.string, | |||||
| selectionProcesses: PropTypes.arrayOf( | |||||
| PropTypes.shape({ | |||||
| id: PropTypes.number, | |||||
| name: PropTypes.string, | |||||
| date: PropTypes.string, | |||||
| status: PropTypes.string, | |||||
| currentSelection: PropTypes.number, | |||||
| map: PropTypes.func, | |||||
| applicant: PropTypes.shape({ | |||||
| firstName: PropTypes.string, | |||||
| lastName: PropTypes.string, | |||||
| }), | |||||
| }) | |||||
| ), | |||||
| }), | |||||
| }; | |||||
| export default Selection; |
| import React, { useContext, useEffect, useState } from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { formatDateSrb, formatTimeSrb } from "../../util/helpers/dateHelpers"; | |||||
| import { | |||||
| Button, | |||||
| FormControl, | |||||
| InputLabel, | |||||
| MenuItem, | |||||
| Select, | |||||
| } from "@mui/material"; | |||||
| import { SelectionContext } from "../../context/SelectionContext"; | |||||
| import { useDispatch, useSelector } from "react-redux"; | |||||
| import { | |||||
| setDoneProcessReq, | |||||
| setUpdateStatusReq, | |||||
| } from "../../store/actions/processes/processAction"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| // import Button from "../Button/Button"; | |||||
| const options = ["Zakazan", "Odrađen", "Čeka na zakazivanje", "Neuspešno"]; | |||||
| const SelectionCard = (props) => { | |||||
| const [showForm, setShowForm] = useState(false); | |||||
| const [selected, setSelected] = useState(props.item.status); | |||||
| const { t } = useTranslation(); | |||||
| const { success } = useSelector((s) => s.statusUpdate); | |||||
| const { | |||||
| setActiveProcess, | |||||
| setActiveInterview, | |||||
| setActiveProcessUnsuccess, | |||||
| // activeProcessUnsuccess, | |||||
| } = useContext(SelectionContext); | |||||
| const dispatch = useDispatch(); | |||||
| const statusChange = (e) => { | |||||
| if (props.item.status !== "Odrađen") { | |||||
| e.stopPropagation(); | |||||
| setShowForm(true); | |||||
| } | |||||
| }; | |||||
| useEffect(() => { | |||||
| setShowForm(false); | |||||
| }, [success]); | |||||
| const select = (e) => { | |||||
| e.stopPropagation(); | |||||
| if (e.target.value === "Zakazan") { | |||||
| // setovanje context state-a | |||||
| setActiveProcess({ process: props.item, status: "Zakazan" }); | |||||
| } | |||||
| // poseban blok u slucaju da treba prikazati odredjeni modal kada je izabrano 'NEUSPESNO' | |||||
| else if (e.target.value === "Neuspešno") { | |||||
| setActiveProcessUnsuccess(props.item); | |||||
| } else if (e.target.value === "Odrađen") { | |||||
| // ukoliko nije zadnji nivo selekcije kreirati proces za sledeci nivo | |||||
| // u suprotnom samo promeniti status u odradjeno | |||||
| if (props.item.selectionLevelId !== 4) | |||||
| dispatch( | |||||
| setDoneProcessReq({ | |||||
| id: props.item.id, | |||||
| name: "Some random name", | |||||
| applicantId: props.item.applicant.applicantId, | |||||
| }) | |||||
| ); | |||||
| else { | |||||
| // pozvati nasu custom metodu za promenu statusa bez prebacivanja u veci nivo | |||||
| // promeni status u odradjeno | |||||
| dispatch( | |||||
| setUpdateStatusReq({ | |||||
| data: { | |||||
| newStatus: "Odrađen", | |||||
| processId: props.item.id, | |||||
| }, | |||||
| }) | |||||
| ); | |||||
| } | |||||
| } | |||||
| setSelected(e.target.value); | |||||
| }; | |||||
| const clickHandler = () => { | |||||
| if (showForm) { | |||||
| setSelected(props.item.status); | |||||
| setShowForm(false); | |||||
| } else props.click(); | |||||
| }; | |||||
| const changeInterviewerHandler = (e) => { | |||||
| e.stopPropagation(); | |||||
| setActiveInterview(props.item); | |||||
| }; | |||||
| return ( | |||||
| <div | |||||
| draggable | |||||
| className="sel-item" | |||||
| onDragStart={props.dragStart} | |||||
| onClick={clickHandler} | |||||
| data-testid="sel-card" | |||||
| > | |||||
| {" "} | |||||
| <div | |||||
| className={`sel-item-inner ${props.item.scheduler && "withScheduler"}`} | |||||
| > | |||||
| {showForm ? ( | |||||
| <form data-testid="status-select"> | |||||
| <FormControl> | |||||
| <InputLabel id="demo-simple-select-label">Status</InputLabel> | |||||
| <Select | |||||
| data-testid="status-select-drop" | |||||
| label="Status" | |||||
| onChange={(e) => { | |||||
| select(e); | |||||
| }} | |||||
| onClick={(e) => e.stopPropagation()} | |||||
| value={selected} | |||||
| sx={{ | |||||
| height: "40px", | |||||
| fontSize: "14px", | |||||
| paddingRight: "5px", | |||||
| }} | |||||
| > | |||||
| {options.map((n, index) => ( | |||||
| <MenuItem key={index} sx={{ textAlign: "left" }} value={n}> | |||||
| {n} | |||||
| </MenuItem> | |||||
| ))} | |||||
| </Select> | |||||
| </FormControl> | |||||
| </form> | |||||
| ) : ( | |||||
| <div | |||||
| className="status" | |||||
| onClick={(e) => { | |||||
| if (props.item.status !== "Neuspešno") statusChange(e); | |||||
| }} | |||||
| > | |||||
| <button | |||||
| data-testid="status-btn" | |||||
| className={props.item.status === "Neuspešno" ? "unsucc" : ""} | |||||
| > | |||||
| {props.item.status} | |||||
| </button> | |||||
| </div> | |||||
| )} | |||||
| <div className="date-name"> | |||||
| <div className="date"> | |||||
| {props.item.date !== null && props.item.date !== "" && ( | |||||
| <p data-testid="process-date"> | |||||
| {formatDateSrb(props.item.date)} <span className="grey">|</span>{" "} | |||||
| {formatTimeSrb(props.item.date)} | |||||
| </p> | |||||
| )} | |||||
| </div> | |||||
| <div className="full-name"> | |||||
| <p> | |||||
| {props.item.applicant.firstName + | |||||
| " " + | |||||
| props.item.applicant.lastName} | |||||
| </p> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {props.item.scheduler && | |||||
| props.item.status !== "Neuspešno" && | |||||
| props.item.status !== "Odrađen" ? ( | |||||
| <div className="sel-item-scheduler"> | |||||
| <div className="change-interbtn"> | |||||
| <Button | |||||
| className="interbtn" | |||||
| onClick={(e) => changeInterviewerHandler(e)} | |||||
| > | |||||
| {t("common.change")} | |||||
| </Button> | |||||
| </div> | |||||
| <p> | |||||
| {t("selection.interviewer")}: {props.item.scheduler.firstName}{" "} | |||||
| {props.item.scheduler.lastName} | |||||
| </p> | |||||
| </div> | |||||
| ) : ( | |||||
| "" | |||||
| )} | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| SelectionCard.propTypes = { | |||||
| item: PropTypes.any, | |||||
| click: PropTypes.func, | |||||
| dragStart: PropTypes.func, | |||||
| }; | |||||
| export default SelectionCard; |
| import React, { useState } from "react"; | |||||
| import PropType from "prop-types"; | |||||
| import Box from "@mui/material/Box"; | |||||
| import Drawer from "@mui/material/Drawer"; | |||||
| import FormGroup from "@mui/material/FormGroup"; | |||||
| import FormControlLabel from "@mui/material/FormControlLabel"; | |||||
| import Checkbox from "@mui/material/Checkbox"; | |||||
| import filterIcon from "../../assets/images/filter_vector.png"; | |||||
| import x from "../../assets/images/x.png"; | |||||
| import { changeStatusIsCheckedValue } from "../../store/actions/processes/statusAction"; | |||||
| import { useDispatch } from "react-redux"; | |||||
| import { setFilteredProcessesReq } from "../../store/actions/processes/processesAction"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const SelectionFilter = ({ open, handleClose, statuses }) => { | |||||
| const [startAt, setStartAt] = useState(""); | |||||
| const [endAt, setEndAt] = useState(""); | |||||
| const { t } = useTranslation(); | |||||
| const dispatch = useDispatch(); | |||||
| const onSubmitFilters = () => { | |||||
| const status = statuses | |||||
| .filter((status) => status.isChecked === true) | |||||
| .map((status) => status.name); | |||||
| dispatch( | |||||
| setFilteredProcessesReq({ | |||||
| statuses: status, | |||||
| startAt, | |||||
| endAt | |||||
| }) | |||||
| ); | |||||
| handleClose(); | |||||
| }; | |||||
| const handleCheckboxes = (e) => { | |||||
| const { value } = e.target; | |||||
| dispatch(changeStatusIsCheckedValue(value)); | |||||
| }; | |||||
| const list = () => ( | |||||
| <Box | |||||
| sx={{ | |||||
| width: 360, | |||||
| height: "100%", | |||||
| borderRadius: "18px 0 0 18px", | |||||
| padding: "36px", | |||||
| }} | |||||
| role="presentation" | |||||
| // onClick={handleClose} | |||||
| onKeyDown={handleClose} | |||||
| > | |||||
| <div> | |||||
| <div className="ad-filters-header-container"> | |||||
| <div className="ad-filters-header"> | |||||
| <img src={filterIcon} alt="filter_icon" /> | |||||
| <h3>{t("filters.filters")}</h3> | |||||
| <p> | |||||
| <sub>| {t("selection.title")}</sub> | |||||
| </p> | |||||
| </div> | |||||
| <div className="ad-filters-header-close" onClick={handleClose}> | |||||
| <img src={x} alt="x" /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-technologies"> | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>Status</p> | |||||
| </div> | |||||
| <div className="ad-filters-technologies-checkboxes"> | |||||
| <FormGroup> | |||||
| {statuses?.map((technology, index) => ( | |||||
| <FormControlLabel | |||||
| key={index} | |||||
| control={ | |||||
| <Checkbox | |||||
| onChange={handleCheckboxes} | |||||
| value={technology.name} | |||||
| checked={technology.isChecked} | |||||
| /> | |||||
| } | |||||
| label={technology.name} | |||||
| /> | |||||
| ))} | |||||
| </FormGroup> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-technologies"> | |||||
| {/* <div className="ad-filters-sub-title"> | |||||
| <p>Datum isteka oglasa</p> | |||||
| </div> | |||||
| <input | |||||
| type="date" | |||||
| placeholder="ex" | |||||
| value={expiredAt} | |||||
| onChange={(e) => setExpiredAt(e.target.value)} | |||||
| /> */} | |||||
| <div className="ad-filters-sub-title"> | |||||
| <p>{t("selection.filterDate")}</p> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card"> | |||||
| <label>{t("common.from")}</label> | |||||
| <input | |||||
| type="date" | |||||
| placeholder="ex" | |||||
| value={startAt} | |||||
| onChange={(e) => setStartAt(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| <div className="add-ad-modal-stage-sub-card"> | |||||
| <label>{t("common.to")}</label> | |||||
| <input | |||||
| type="date" | |||||
| placeholder="ex" | |||||
| value={endAt} | |||||
| onChange={(e) => setEndAt(e.target.value)} | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="ad-filters-search"> | |||||
| <button onClick={onSubmitFilters} className="c-btn c-btn--primary"> | |||||
| {t("common.search")} | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| </Box > | |||||
| ); | |||||
| return ( | |||||
| <div> | |||||
| <Drawer anchor="right" open={open} onClose={handleClose}> | |||||
| {list()} | |||||
| </Drawer> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| SelectionFilter.propTypes = { | |||||
| open: PropType.any, | |||||
| handleClose: PropType.func, | |||||
| statuses: PropType.any, | |||||
| }; | |||||
| export default SelectionFilter; |