diff --git a/src/actions/searchOffersActions.js b/src/actions/searchOffersActions.js index 4b62d82d..b0f99d91 100644 --- a/src/actions/searchOffersActions.js +++ b/src/actions/searchOffersActions.js @@ -16,6 +16,7 @@ export const OfferSearchTypes = Object.freeze({ DISABLE_OFFER: "DISABLE_OFFER", COMPANY_ENABLE_OFFER: "COMPANY_ENABLE_OFFER", ADMIN_ENABLE_OFFER: "ADMIN_ENABLE_OFFER", + SET_SHOW_HIDDEN: "SET_SHOW_HIDDEN", }); export const setLoadingOffers = (loading) => ({ @@ -99,10 +100,16 @@ export const adminEnableOffer = (offerIdx) => ({ offerIdx, }); +export const setShowHidden = (showHidden) => ({ + type: OfferSearchTypes.SET_SHOW_HIDDEN, + showHidden, +}); + export const resetAdvancedSearchFields = () => (dispatch) => { dispatch(setJobType(INITIAL_JOB_TYPE)); dispatch(setShowJobDurationSlider(false)); dispatch(setJobDuration(INITIAL_JOB_DURATION, INITIAL_JOB_DURATION + 1)); dispatch(setFields([])); dispatch(setTechs([])); + dispatch(setShowHidden(false)); }; diff --git a/src/actions/searchOffersActions.spec.js b/src/actions/searchOffersActions.spec.js index fe87c2d6..f886bf09 100644 --- a/src/actions/searchOffersActions.spec.js +++ b/src/actions/searchOffersActions.spec.js @@ -12,6 +12,7 @@ import { resetAdvancedSearchFields, setOffersFetchError, resetOffersFetchError, + setShowHidden, } from "./searchOffersActions"; import { INITIAL_JOB_TYPE, INITIAL_JOB_DURATION } from "../reducers/searchOffersReducer"; @@ -54,6 +55,17 @@ describe("Search Offers actions", () => { expect(setSearchValue(value)).toEqual(expectedAction); }); + it("should return Set Show Hidden action", () => { + + const showHidden = true; + const expectedAction = { + type: OfferSearchTypes.SET_SHOW_HIDDEN, + showHidden, + }; + + expect(setShowHidden(showHidden)).toEqual(expectedAction); + }); + it("should return Set Job Duration action", () => { const jobDuration = [1, 2]; diff --git a/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchDesktop.js b/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchDesktop.js index 9f226ac6..daab3f98 100644 --- a/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchDesktop.js +++ b/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchDesktop.js @@ -11,6 +11,7 @@ import { FormHelperText, Button, } from "@material-ui/core"; +import useSession from "../../../../hooks/useSession"; import JobOptions from "../../../utils/offers/JobOptions"; import useSearchAreaStyles from "../searchAreaStyle"; @@ -40,11 +41,19 @@ JobDurationCollapse.propTypes = { const AdvancedSearchDesktop = () => { + const { data, + isValidating, + error, + isLoggedIn, + } = useSession(); + const sessionData = (!isValidating && !error && isLoggedIn) ? data : null; + const classes = useSearchAreaStyles(); const { advancedOptions, resetAdvancedSearch, FieldsSelectorProps, TechsSelectorProps, JobTypeSelectorProps, JobDurationSwitchProps, - ResetButtonProps, JobDurationSliderText, JobDurationCollapseProps, JobDurationSwitchLabel, JobDurationSliderProps, + ResetButtonProps, JobDurationSliderText, JobDurationCollapseProps, JobDurationSwitchLabel, ShowHiddenSwitchLabel, + JobDurationSliderProps, ShowHiddenSwitchProps, } = useContext(AdvancedSearchControllerContext); return ( @@ -94,8 +103,6 @@ const AdvancedSearchDesktop = () => { className: "chip-wrapper", }} /> - - {advancedOptions &&
- } + {sessionData?.isAdmin && + } + label={ShowHiddenSwitchLabel} + /> + } + ); }; diff --git a/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchDesktop.spec.js b/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchDesktop.spec.js index 55604f29..8a104013 100644 --- a/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchDesktop.spec.js +++ b/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchDesktop.spec.js @@ -10,9 +10,12 @@ import FieldOptions from "../../../utils/offers/FieldOptions"; import TechOptions from "../../../utils/offers/TechOptions"; import { INITIAL_JOB_DURATION, INITIAL_JOB_TYPE } from "../../../../reducers/searchOffersReducer"; import { createTheme } from "@material-ui/core/styles"; +import useSession from "../../../../hooks/useSession"; import { MemoryRouter } from "react-router-dom"; +jest.mock("../../../../hooks/useSession"); + const AdvancedSearchWrapper = ({ children, enableAdvancedSearchDefault, @@ -25,6 +28,8 @@ const AdvancedSearchWrapper = ({ setJobType = () => { }, fields = [], setFields = () => { }, + showHidden, + setShowHidden = () => { }, technologies = [], setTechs = () => { }, resetAdvancedSearchFields, @@ -43,6 +48,7 @@ const AdvancedSearchWrapper = ({ enableAdvancedSearchDefault, showJobDurationSlider, setShowJobDurationSlider, jobMinDuration, jobMaxDuration, setJobDuration, jobType, setJobType, fields, setFields, technologies, setTechs, resetAdvancedSearchFields, onSubmit, searchValue, searchOffers, onMobileClose, setSearchValue, + showHidden, setShowHidden, }, AdvancedSearchControllerContext ); @@ -67,6 +73,7 @@ describe("AdvancedSearchDesktop", () => { describe("render", () => { it("should render a job selector with all job types", () => { + useSession.mockImplementation(() => ({})); renderWithStoreAndTheme( @@ -92,6 +99,8 @@ describe("AdvancedSearchDesktop", () => { it("should toggle job duration slider (on)", () => { const setShowJobDurationSliderMock = jest.fn(); + useSession.mockImplementation(() => ({})); + renderWithStoreAndTheme( { it("should toggle job duration slider (off)", () => { const setShowJobDurationSliderMock = jest.fn(); + useSession.mockImplementation(() => ({})); + renderWithStoreAndTheme( { expect(setShowJobDurationSliderMock).toHaveBeenCalledWith(false); }); + + it("should toggle show hidden (on)", () => { + const setShowHiddenMock = jest.fn(); + useSession.mockImplementation(() => ({ isLoggedIn: true, data: { isAdmin: true } })); + + renderWithStoreAndTheme( + + + + + , + { initialState, theme } + ); + + fireEvent.click(screen.getByLabelText("Show Hidden Offers")); + expect(setShowHiddenMock).toHaveBeenCalledWith(true); + // Can't test that element is visible now (after toggling), since we can't emulate redux logic, wihtout having the whole tree, + // So, I'll just assert that when showJobDurationSlider=true, it shows correctly in the next test + }); + + it("should toggle show hidden (off)", () => { + const setShowHiddenMock = jest.fn(); + useSession.mockImplementation(() => ({ isLoggedIn: true, data: { isAdmin: true } })); + + renderWithStoreAndTheme( + + + + + , + { initialState, theme } + ); + + fireEvent.click(screen.getByLabelText("Show Hidden Offers")); + expect(setShowHiddenMock).toHaveBeenCalledWith(false); + // Can't test that element is visible now (after toggling), since we can't emulate redux logic, wihtout having the whole tree, + // So, I'll just assert that when showJobDurationSlider=true, it shows correctly in the next test + }); + + it("should render a fields selector with all field types", () => { renderWithStoreAndTheme( diff --git a/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchMobile.js b/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchMobile.js index fc512e09..9ce72962 100644 --- a/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchMobile.js +++ b/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchMobile.js @@ -24,6 +24,7 @@ import MultiOptionAutocomplete from "../../../utils/form/MultiOptionAutocomplete import JobOptions from "../../../utils/offers/JobOptions"; import useSearchAreaStyles from "../searchAreaStyle"; import { AdvancedSearchControllerContext } from "../SearchArea"; +import useSession from "../../../../hooks/useSession"; const JobDurationCollapse = ({ className, JobDurationCollapseProps, JobDurationSliderProps, sliderText }) => ( { const { advancedOptions, toggleAdvancedOptions, searchValue, submitForm, setSearchValue, FieldsSelectorProps, TechsSelectorProps, resetAdvancedSearch, JobDurationSliderText, ResetButtonProps, - JobTypeSelectorProps, JobDurationSwitchProps, JobDurationCollapseProps, JobDurationSwitchLabel, JobDurationSliderProps, - onMobileClose, + JobTypeSelectorProps, JobDurationSwitchProps, JobDurationCollapseProps, JobDurationSwitchLabel, ShowHiddenSwitchLabel, + JobDurationSliderProps, onMobileClose, ShowHiddenSwitchProps, } = useContext(AdvancedSearchControllerContext); const handleResetClick = (e) => { @@ -96,9 +97,15 @@ const AdvancedSearchMobile = () => { const handleExit = () => { if (shouldSubmitForm) submitForm(); if (onMobileClose) onMobileClose(); - }; + const { data, + isValidating, + error, + isLoggedIn, + } = useSession(); + const sessionData = (!isValidating && !error && isLoggedIn) ? data : null; + const classes = useSearchAreaStyles(); return ( @@ -151,6 +158,13 @@ const AdvancedSearchMobile = () => { JobDurationSliderProps={JobDurationSliderProps} sliderText={JobDurationSliderText} /> + {sessionData?.isAdmin && + } + label={ShowHiddenSwitchLabel} + /> + } @@ -190,6 +204,8 @@ AdvancedSearchMobile.propTypes = { JobDurationSwitchLabel: PropTypes.string, JobDurationSliderProps: PropTypes.object, onMobileClose: PropTypes.func, + ShowHiddenSwitchProps: PropTypes.object, + ShowHiddenSwitchLabel: PropTypes.string, }; export default AdvancedSearchMobile; diff --git a/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchMobile.spec.js b/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchMobile.spec.js index a5809382..38426174 100644 --- a/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchMobile.spec.js +++ b/src/components/HomePage/SearchArea/AdvancedSearch/AdvancedSearchMobile.spec.js @@ -34,6 +34,8 @@ const AdvancedSearchWrapper = ({ onMobileClose, setSearchValue = () => { }, submitForm, + showHidden, + setShowHidden = () => { }, }) => { const { ContextProvider, @@ -44,7 +46,7 @@ const AdvancedSearchWrapper = ({ enableAdvancedSearchDefault, showJobDurationSlider, setShowJobDurationSlider, jobMinDuration, jobMaxDuration, setJobDuration, jobType, setJobType, fields, setFields, technologies, setTechs, resetAdvancedSearchFields, onSubmit, searchValue, searchOffers, onMobileClose, setSearchValue, - submitForm, + submitForm, showHidden, setShowHidden, }, AdvancedSearchControllerContext ); diff --git a/src/components/HomePage/SearchArea/AdvancedSearch/useAdvancedSearch.js b/src/components/HomePage/SearchArea/AdvancedSearch/useAdvancedSearch.js index 7e2aca8f..f2f4b442 100644 --- a/src/components/HomePage/SearchArea/AdvancedSearch/useAdvancedSearch.js +++ b/src/components/HomePage/SearchArea/AdvancedSearch/useAdvancedSearch.js @@ -19,6 +19,8 @@ export default ({ technologies, setTechs, resetAdvancedSearchFields, + showHidden, + setShowHidden, }) => { const jobDuration = [jobMinDuration, jobMaxDuration]; @@ -30,6 +32,8 @@ export default ({ const JobDurationSwitchLabel = "Filter Job Duration"; + const ShowHiddenSwitchLabel = "Show Hidden Offers"; + const [advancedOptions, toggleAdvancedOptions] = useToggle(enableAdvancedSearchDefault); const JobTypeSelectorProps = { @@ -70,11 +74,21 @@ export default ({ const FieldsSelectorProps = useFieldSelector(fields, setFields); const TechsSelectorProps = useTechSelector(technologies, setTechs); + const toggleShowHidden = useCallback(() => { + setShowHidden(!showHidden); + }, [setShowHidden, showHidden]); + + const ShowHiddenSwitchProps = { + checked: showHidden, + onChange: toggleShowHidden, + value: "filterShowHiddenOffers", + }; const advancedOptionsActive = showJobDurationSlider || (jobType !== INITIAL_JOB_TYPE) || fields.length !== 0 - || technologies.length !== 0; + || technologies.length !== 0 + || showHidden; const ResetButtonProps = { disabled: !advancedOptionsActive, @@ -101,5 +115,7 @@ export default ({ JobDurationSliderProps, JobDurationSliderText, ResetButtonProps, + ShowHiddenSwitchProps, + ShowHiddenSwitchLabel, }; }; diff --git a/src/components/HomePage/SearchArea/AdvancedSearch/useAdvancedSearch.spec.js b/src/components/HomePage/SearchArea/AdvancedSearch/useAdvancedSearch.spec.js index 3c20b381..f217721d 100644 --- a/src/components/HomePage/SearchArea/AdvancedSearch/useAdvancedSearch.spec.js +++ b/src/components/HomePage/SearchArea/AdvancedSearch/useAdvancedSearch.spec.js @@ -10,6 +10,7 @@ describe("useAdvancedSearch", () => { it("should return the correct props for job duration", () => { const showJobDurationSlider = false; + const showHidden = false; const setShowJobDurationSlider = () => {}; const setJobDuration = jest.fn(); const jobMinDuration = 0; @@ -22,6 +23,7 @@ describe("useAdvancedSearch", () => { setJobDuration, showJobDurationSlider, setShowJobDurationSlider, + showHidden, }); }); @@ -105,6 +107,7 @@ describe("useAdvancedSearch", () => { it("should return the correct props for reset button", () => { const showJobDurationSlider = false; + const showHidden = false; const jobType = `${INITIAL_JOB_TYPE}a`; const fields = ["test"]; const technologies = ["test"]; @@ -115,6 +118,7 @@ describe("useAdvancedSearch", () => { jobType, fields, technologies, + showHidden, }); }); @@ -126,6 +130,7 @@ describe("useAdvancedSearch", () => { // Initial Values - if this test fails remind yourself of checking if these are accurate let showJobDurationSlider = false; + let showHidden = false; let jobType = INITIAL_JOB_TYPE; let fields = []; let technologies = []; @@ -136,6 +141,7 @@ describe("useAdvancedSearch", () => { jobType, fields, technologies, + showHidden, }); }); @@ -143,6 +149,7 @@ describe("useAdvancedSearch", () => { expect(advancedOptionsActive).toBe(false); showJobDurationSlider = true; + showHidden = false; jobType = INITIAL_JOB_TYPE; fields = []; technologies = []; @@ -153,6 +160,7 @@ describe("useAdvancedSearch", () => { jobType, fields, technologies, + showHidden, }); }); @@ -160,6 +168,26 @@ describe("useAdvancedSearch", () => { expect(advancedOptionsActive).toBe(true); showJobDurationSlider = false; + showHidden = true; + jobType = INITIAL_JOB_TYPE; + fields = []; + technologies = []; + + testHook(() => { + useAdvancedSearchProps = useAdvancedSearch({ + showJobDurationSlider, + jobType, + fields, + technologies, + showHidden, + }); + }); + + ({ advancedOptionsActive } = useAdvancedSearchProps); + expect(advancedOptionsActive).toBe(true); + + showJobDurationSlider = false; + showHidden = false; jobType = `${INITIAL_JOB_TYPE}a`; fields = []; technologies = []; @@ -170,6 +198,7 @@ describe("useAdvancedSearch", () => { jobType, fields, technologies, + showHidden, }); }); @@ -177,6 +206,7 @@ describe("useAdvancedSearch", () => { expect(advancedOptionsActive).toBe(true); showJobDurationSlider = false; + showHidden = false; jobType = INITIAL_JOB_TYPE; fields = ["test"]; technologies = []; @@ -187,6 +217,7 @@ describe("useAdvancedSearch", () => { jobType, fields, technologies, + showHidden, }); }); @@ -194,6 +225,7 @@ describe("useAdvancedSearch", () => { expect(advancedOptionsActive).toBe(true); showJobDurationSlider = false; + showHidden = false; jobType = INITIAL_JOB_TYPE; fields = []; technologies = ["test"]; @@ -204,6 +236,7 @@ describe("useAdvancedSearch", () => { jobType, fields, technologies, + showHidden, }); }); @@ -217,6 +250,7 @@ describe("useAdvancedSearch", () => { useAdvancedSearchProps = useAdvancedSearch({ setFields: () => {}, setTechs: () => {}, + setShowHidden: () => {}, resetAdvancedSearchFields, }); }); diff --git a/src/components/HomePage/SearchArea/SearchArea.js b/src/components/HomePage/SearchArea/SearchArea.js index 66a16970..368bb24f 100644 --- a/src/components/HomePage/SearchArea/SearchArea.js +++ b/src/components/HomePage/SearchArea/SearchArea.js @@ -12,6 +12,8 @@ import { setShowJobDurationSlider, setTechs, setLoadUrlFromFilters, + hideOffer, + setShowHidden, } from "../../../actions/searchOffersActions"; import { INITIAL_JOB_TYPE, INITIAL_JOB_DURATION } from "../../../reducers/searchOffersReducer"; @@ -38,7 +40,7 @@ export const AdvancedSearchController = ({ enableAdvancedSearchDefault, showJobDurationSlider, setShowJobDurationSlider, jobMinDuration, jobMaxDuration, setJobDuration, jobType, setJobType, fields, setFields, technologies, setTechs, resetAdvancedSearchFields, onSubmit, searchValue, setSearchValue, onMobileClose, - loadUrlFromFilters, setLoadUrlFromFilters, + loadUrlFromFilters, setLoadUrlFromFilters, showHidden, setShowHidden, }) => { const { @@ -51,6 +53,7 @@ export const AdvancedSearchController = ({ resetAdvancedSearchFields: actualResetAdvancedSearchFields, setSearchValue: setUrlSearchValue, setUrlFilters, + setShowHidden: actualSetShowHidden, } = useSearchParams({ setJobDuration, setShowJobDurationSlider, @@ -58,6 +61,7 @@ export const AdvancedSearchController = ({ setFields, setTechs, resetAdvancedSearchFields, + setShowHidden, }); const advancedSearchProps = useAdvancedSearch({ @@ -74,6 +78,9 @@ export const AdvancedSearchController = ({ technologies, setTechs: actualSetTechs, resetAdvancedSearchFields: actualResetAdvancedSearchFields, + hideOffer, + showHidden, + setShowHidden: actualSetShowHidden, }); const { search: searchOffers } = useOffersSearcher({ @@ -83,6 +90,7 @@ export const AdvancedSearchController = ({ jobType, fields, technologies, + showHidden, }); const submitForm = useCallback((e, updateUrl = true) => { @@ -102,6 +110,7 @@ export const AdvancedSearchController = ({ fields, technologies, jobType, + showHidden, searchValue, ); setLoadUrlFromFilters(false); @@ -119,6 +128,9 @@ export const AdvancedSearchController = ({ setSearchValue(queryParams.searchValue); } + setShowHidden(queryParams.showHidden); + + setSearchValue(queryParams.searchValue); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -141,7 +153,7 @@ export const SearchArea = ({ onSubmit, searchValue, jobMinDuration = INITIAL_JOB_DURATION, jobMaxDuration = INITIAL_JOB_DURATION + 1, jobType = INITIAL_JOB_TYPE, fields, technologies, showJobDurationSlider, setShowJobDurationSlider, advanced: enableAdvancedSearchDefault = false, setSearchValue, setJobDuration, setJobType, setFields, setTechs, resetAdvancedSearchFields, onMobileClose, - loadUrlFromFilters, setLoadUrlFromFilters }) => { + loadUrlFromFilters, setLoadUrlFromFilters, showHidden, setShowHidden }) => { const classes = useSearchAreaStyles(); const { @@ -157,7 +169,7 @@ export const SearchArea = ({ onSubmit, searchValue, enableAdvancedSearchDefault, showJobDurationSlider, setShowJobDurationSlider, jobMinDuration, jobMaxDuration, setJobDuration, jobType, setJobType, fields, setFields, technologies, setTechs, resetAdvancedSearchFields, onSubmit, searchValue, setSearchValue, onMobileClose, - loadUrlFromFilters, setLoadUrlFromFilters, + hideOffer, loadUrlFromFilters, setLoadUrlFromFilters, showHidden, setShowHidden, }, AdvancedSearchControllerContext ); @@ -224,6 +236,8 @@ SearchArea.propTypes = { setTechs: PropTypes.func.isRequired, setShowJobDurationSlider: PropTypes.func.isRequired, onMobileClose: PropTypes.func, + showHidden: PropTypes.bool, + setShowHidden: PropTypes.func, advanced: PropTypes.bool, }; @@ -236,6 +250,7 @@ export const mapStateToProps = ({ offerSearch }) => ({ technologies: offerSearch.technologies, showJobDurationSlider: offerSearch.filterJobDuration, loadUrlFromFilters: offerSearch.loadUrlFromFilters, + showHidden: offerSearch.showHidden, }); export const mapDispatchToProps = (dispatch) => ({ @@ -245,6 +260,7 @@ export const mapDispatchToProps = (dispatch) => ({ setFields: (fields) => dispatch(setFields(fields)), setTechs: (technologies) => dispatch(setTechs(technologies)), setShowJobDurationSlider: (val) => dispatch(setShowJobDurationSlider(val)), + setShowHidden: (val) => dispatch(setShowHidden(val)), resetAdvancedSearchFields: () => dispatch(resetAdvancedSearchFields()), setLoadUrlFromFilters: (value) => dispatch(setLoadUrlFromFilters(value)), }); diff --git a/src/components/HomePage/SearchArea/SearchArea.spec.js b/src/components/HomePage/SearchArea/SearchArea.spec.js index 0304242d..7b9979f1 100644 --- a/src/components/HomePage/SearchArea/SearchArea.spec.js +++ b/src/components/HomePage/SearchArea/SearchArea.spec.js @@ -7,6 +7,7 @@ import { setFields, setTechs, setShowJobDurationSlider, + setShowHidden, } from "../../../actions/searchOffersActions"; import { createTheme } from "@material-ui/core"; import { renderWithStoreAndTheme, screen, fireEvent, act } from "../../../test-utils"; @@ -28,7 +29,7 @@ const SearchAreaWrapper = ({ searchValue = "", jobType = INITIAL_JOB_TYPE, jobDuration = [null, null], filterJobDuration = false, showJobDurationSlider = false, fields = [], technologies = [], setShowJobDurationSlider = () => { }, setTechs = () => { }, setJobDuration = () => { }, setFields = () => { }, setJobType = () => { }, - setSearchValue = () => { }, onSubmit = () => {}, + setSearchValue = () => { }, onSubmit = () => {}, setShowHidden = () => { }, }) => ( ); @@ -63,6 +65,7 @@ SearchAreaWrapper.propTypes = { setShowJobDurationSlider: PropTypes.func.isRequired, jobDuration: PropTypes.number, filterJobDuration: PropTypes.bool, + setShowHidden: PropTypes.bool, }; describe("SearchArea", () => { @@ -79,6 +82,15 @@ describe("SearchArea", () => { { }} + setTechs={() => { }} + setJobDuration={() => { }} + setFields={() => { }} + setJobType={() => { }} + setSearchValue={() => { }} + setShowHidden={() => { }} /> , { initialState, theme } @@ -197,6 +209,7 @@ describe("SearchArea", () => { setJobDuration={() => { }} setFields={() => { }} setJobType={() => { }} + setShowHidden={() => { }} onSubmit={onSubmit} fields={[]} technologies={[]} @@ -237,6 +250,7 @@ describe("SearchArea", () => { setJobDuration={() => { }} setFields={() => { }} setJobType={() => { }} + setShowHidden={() => { }} onSubmit={onSubmit} fields={[]} technologies={[]} @@ -307,6 +321,7 @@ describe("SearchArea", () => { jobDuration: [1, 2], fields: ["field1", "field2"], technologies: ["tech1", "tech2"], + showHidden: true, }, }; expect(mapStateToProps(mockState)).toEqual({ @@ -316,6 +331,7 @@ describe("SearchArea", () => { jobMaxDuration: 2, fields: ["field1", "field2"], technologies: ["tech1", "tech2"], + showHidden: true, }); }); @@ -344,6 +360,10 @@ describe("SearchArea", () => { props.setShowJobDurationSlider(filterJobDuration); expect(dispatch).toHaveBeenCalledWith(setShowJobDurationSlider(false)); + const showHidden = true; + props.setShowHidden(showHidden); + expect(dispatch).toHaveBeenCalledWith(setShowHidden(true)); + dispatch.mockClear(); props.resetAdvancedSearchFields(); expect(dispatch).toHaveBeenCalled(); diff --git a/src/components/HomePage/SearchArea/searchAreaStyle.js b/src/components/HomePage/SearchArea/searchAreaStyle.js index ebc6d021..62fd8c34 100644 --- a/src/components/HomePage/SearchArea/searchAreaStyle.js +++ b/src/components/HomePage/SearchArea/searchAreaStyle.js @@ -19,12 +19,11 @@ export default makeStyles((theme) => ({ }, advancedSearchOuterWrapper: { gridColumn: "1 / span 2", - }, advancedSearchContainer: { display: "grid", gridTemplateColumns: "1fr 1fr", - gridTemplateRows: "1fr 0.7fr auto", + gridTemplateRows: "1fr 0.7fr 1fr 0.7fr", alignItems: "center", gridGap: "1em", }, @@ -82,10 +81,24 @@ export default makeStyles((theme) => ({ gridColumnStart: 2, }, resetBtnWrapper: { - display: "flex", + gridRowStart: 4, + gridColumnStart: 1, "& > *": { marginTop: theme.spacing(2), marginLeft: theme.spacing(-1), }, + "& .chip-wrapper": { + gridColumnStart: 2, + gridRowStart: 4, + }, + }, + showHiddenToggle: { + gridRowStart: 4, + gridColumnStart: 2, + }, + spaceBtwn: { + "& > *": { + justifyContent: "space-between", + }, }, })); diff --git a/src/components/HomePage/SearchArea/useUrlSearchParams.js b/src/components/HomePage/SearchArea/useUrlSearchParams.js index e499456e..6c328fd7 100644 --- a/src/components/HomePage/SearchArea/useUrlSearchParams.js +++ b/src/components/HomePage/SearchArea/useUrlSearchParams.js @@ -20,6 +20,7 @@ export default ({ setTechs, setSearchValue, resetAdvancedSearchFields, + setShowHidden, } = {}) => { const location = useLocation(); @@ -85,6 +86,18 @@ export default ({ }, [changeURLFilters, location, queryParams, setShowJobDurationSlider]); + const actualSetShowHidden = useCallback((showHiddenToggle) => { + + if (!showHiddenToggle) + changeURLFilters(location, queryParams, { showHidden: null }); + else + changeURLFilters(location, queryParams, { showHidden: showHiddenToggle }); + + if (setShowHidden) + setShowHidden(showHiddenToggle); + + }, [changeURLFilters, location, queryParams, setShowHidden]); + const actualSetFields = useCallback((fields) => { const sanitizedFields = ensureArray(fields); @@ -172,5 +185,6 @@ export default ({ setSearchValue: actualSetSearchValue, resetAdvancedSearchFields: actualResetAdvancedSearchFields, setUrlFilters, + setShowHidden: actualSetShowHidden, }; }; diff --git a/src/components/HomePage/SearchArea/useUrlSearchParams.spec.js b/src/components/HomePage/SearchArea/useUrlSearchParams.spec.js index bbf770ad..bab7c08a 100644 --- a/src/components/HomePage/SearchArea/useUrlSearchParams.spec.js +++ b/src/components/HomePage/SearchArea/useUrlSearchParams.spec.js @@ -37,6 +37,7 @@ describe("useUrlSearchParams", () => { it.each([ ["jobDuration", [1, 2], [1, 2]], + ["showHidden", true, true], ["jobType", { target: { value: "test-job-type" } }, "test-job-type"], ["searchValue", "test-search-value", "test-search-value"], ["fields", ["TEST-FIELD-1", "TEST-FIELD-2"], ["TEST-FIELD-1", "TEST-FIELD-2"]], @@ -83,10 +84,11 @@ describe("useUrlSearchParams", () => { "jobMinDuration": minDuration, "jobMaxDuration": maxDuration, }; - } else if (fieldName === "techs") + } else if (fieldName === "techs") { params = { "technologies": expectedValue, }; + } const expectedLocationSearch = `?${qs.stringify(params, { skipNulls: true, arrayFormat: "brackets" })}`; @@ -147,6 +149,7 @@ describe("useUrlSearchParams", () => { searchValue: "test-search-value", jobMinDuration: 2, jobMaxDuration: 9, + showHidden: true, fields: ["TEST-FIELD1", "TEST-FIELD2"], technologies: ["TEST-TECH"], jobType: "test-job-type", @@ -184,6 +187,7 @@ describe("useUrlSearchParams", () => { searchValue: "test-search-value", jobMinDuration: 2, jobMaxDuration: 9, + showHidden: true, fields: ["TEST-FIELD1", "TEST-FIELD2"], technologies: ["TEST-TECH"], jobType: "test-job-type", diff --git a/src/components/HomePage/SearchResultsArea/SearchResultsWidget/SearchResultsMobile.js b/src/components/HomePage/SearchResultsArea/SearchResultsWidget/SearchResultsMobile.js index d27d1497..0dd5072c 100644 --- a/src/components/HomePage/SearchResultsArea/SearchResultsWidget/SearchResultsMobile.js +++ b/src/components/HomePage/SearchResultsArea/SearchResultsWidget/SearchResultsMobile.js @@ -15,7 +15,7 @@ const OffersList = ({ toggleShowSearchFilters, offers, moreOffersLoading, loadMoreOffers, searchQueryToken, }) => ( - + {noOffers ?
@@ -45,6 +45,7 @@ OffersList.propTypes = { classes: PropTypes.shape({ reviseCriteriaErrorMessage: PropTypes.string.isRequired, fullHeight: PropTypes.string.isRequired, + heightOffersList: PropTypes.string.isRequired, errorLoadingOffersIcon: PropTypes.string.isRequired, noOffersColumn: PropTypes.string.isRequired, offerItemsContainer: PropTypes.string.isRequired, @@ -142,6 +143,7 @@ const SearchResultsMobile = () => { errorLoadingOffersIcon: classes.errorLoadingOffersIcon, reviseCriteriaErrorMessage: classes.reviseCriteriaErrorMessage, fullHeight: classes.fullHeight, + heightOffersList: classes.heightOffersList, offerItemsContainer: classes.offerItemsContainer, }; diff --git a/src/components/HomePage/URLSearchParamsParser.js b/src/components/HomePage/URLSearchParamsParser.js index 4d081344..1a8793c5 100644 --- a/src/components/HomePage/URLSearchParamsParser.js +++ b/src/components/HomePage/URLSearchParamsParser.js @@ -35,6 +35,7 @@ const URLSearchParamsParser = ({ showSearchResults }) => { jobType: queryParams.jobType, fields: ensureArray(queryParams.fields ?? []), technologies: ensureArray(queryParams.technologies ?? []), + showHidden: queryParams.showHidden, }); // we specifically want this to only run once to avoid infinite re-renders diff --git a/src/reducers/searchOffersReducer.js b/src/reducers/searchOffersReducer.js index 30afa317..1aed1d33 100644 --- a/src/reducers/searchOffersReducer.js +++ b/src/reducers/searchOffersReducer.js @@ -18,6 +18,7 @@ const initialState = { offers: [], loading: false, error: INITIAL_ERROR, + showHidden: false, }; export default (state = initialState, action) => { @@ -112,6 +113,11 @@ export default (state = initialState, action) => { new Offer({ ...offer, isHidden: false, hiddenReason: null, adminReason: null }) : offer ) }; + case OfferSearchTypes.SET_SHOW_HIDDEN: + return { + ...state, + showHidden: action.showHidden, + }; default: return state; } diff --git a/src/reducers/searchOffersReducer.spec.js b/src/reducers/searchOffersReducer.spec.js index f213ae62..f4378de4 100644 --- a/src/reducers/searchOffersReducer.spec.js +++ b/src/reducers/searchOffersReducer.spec.js @@ -14,6 +14,7 @@ import { disableOffer, companyEnableOffer, adminEnableOffer, + setShowHidden, } from "../actions/searchOffersActions"; describe("Search Offers Reducer", () => { @@ -26,8 +27,10 @@ describe("Search Offers Reducer", () => { offers: [], fields: [], technologies: [], + showHidden: false, loading: false, - error: null }); + error: null, + }); }); it("should set offers when setSearchOffers action is called", () => { @@ -111,6 +114,17 @@ describe("Search Offers Reducer", () => { expect(state.fields).toStrictEqual(["test1", "test2"]); }); + it("should set advanced search fields when setShowHidden action is called", () => { + const state = searchOffersState( + { + showHidden: false, + }, + setShowHidden(true) + ); + + expect(state.showHidden).toBe(true); + }); + it("should set advanced search technologies when setTechs action is called", () => { const state = searchOffersState( {