Skip to content

Commit

Permalink
Merge pull request #283 from NIAEFEUP/feature/chip-search
Browse files Browse the repository at this point in the history
Add hook to allow the search trough the click of a chip
  • Loading branch information
DoStini authored Apr 11, 2023
2 parents d47281c + 83ec120 commit 014bd1d
Show file tree
Hide file tree
Showing 11 changed files with 493 additions and 14 deletions.
6 changes: 6 additions & 0 deletions src/actions/searchOffersActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const OfferSearchTypes = Object.freeze({
SET_JOB_TYPE: "SET_JOB_TYPE",
SET_JOB_FIELDS: "SET_JOB_FIELDS",
SET_JOB_TECHS: "SET_JOB_TECHS",
SET_LOAD_URL_FROM_FILTERS: "SET_LOAD_URL_FROM_FILTERS",
SET_OFFERS_SEARCH_RESULT: "SET_OFFERS_SEARCH_RESULT",
SET_SEARCH_QUERY_TOKEN: "SET_SEARCH_QUERY_TOKEN",
SET_OFFERS_LOADING: "SET_OFFERS_LOADING",
Expand Down Expand Up @@ -67,6 +68,11 @@ export const setTechs = (technologies) => ({
technologies,
});

export const setLoadUrlFromFilters = (value) => ({
type: OfferSearchTypes.SET_LOAD_URL_FROM_FILTERS,
value,
});

export const setShowJobDurationSlider = (filterJobDuration) => ({
type: OfferSearchTypes.SET_JOB_DURATION_TOGGLE,
filterJobDuration,
Expand Down
46 changes: 34 additions & 12 deletions src/components/HomePage/SearchArea/SearchArea.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
setFields,
setShowJobDurationSlider,
setTechs,
setLoadUrlFromFilters,
} from "../../../actions/searchOffersActions";
import { INITIAL_JOB_TYPE, INITIAL_JOB_DURATION } from "../../../reducers/searchOffersReducer";

Expand All @@ -37,6 +38,7 @@ export const AdvancedSearchController = ({
enableAdvancedSearchDefault, showJobDurationSlider, setShowJobDurationSlider, jobMinDuration,
jobMaxDuration, setJobDuration, jobType, setJobType, fields, setFields, technologies, setTechs,
resetAdvancedSearchFields, onSubmit, searchValue, setSearchValue, onMobileClose,
loadUrlFromFilters, setLoadUrlFromFilters,
}) => {

const {
Expand All @@ -48,6 +50,7 @@ export const AdvancedSearchController = ({
setTechs: actualSetTechs,
resetAdvancedSearchFields: actualResetAdvancedSearchFields,
setSearchValue: setUrlSearchValue,
setUrlFilters,
} = useSearchParams({
setJobDuration,
setShowJobDurationSlider,
Expand Down Expand Up @@ -92,17 +95,30 @@ export const AdvancedSearchController = ({
}, [onSubmit, searchOffers, searchValue, setUrlSearchValue]);

useEffect(() => {
setShowJobDurationSlider(!!queryParams.jobMinDuration && !!queryParams.jobMaxDuration);
setJobDuration(null, [
parseInt(queryParams.jobMinDuration, 10),
parseInt(queryParams.jobMaxDuration, 10),
]);

setJobType(queryParams.jobType);
setFields(ensureArray(queryParams.fields ?? []));
setTechs(ensureArray(queryParams.technologies ?? []));

setSearchValue(queryParams.searchValue);
if (loadUrlFromFilters) {
setUrlFilters(
jobMinDuration,
jobMaxDuration,
fields,
technologies,
jobType,
searchValue,
);
setLoadUrlFromFilters(false);
submitForm(null, false);
} else {
setShowJobDurationSlider(!!queryParams.jobMinDuration && !!queryParams.jobMaxDuration);
setJobDuration(null, [
parseInt(queryParams.jobMinDuration, 10),
parseInt(queryParams.jobMaxDuration, 10),
]);

setJobType(queryParams.jobType);
setFields(ensureArray(queryParams.fields ?? []));
setTechs(ensureArray(queryParams.technologies ?? []));

setSearchValue(queryParams.searchValue);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Expand All @@ -124,7 +140,8 @@ export const AdvancedSearchController = ({
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 }) => {
setSearchValue, setJobDuration, setJobType, setFields, setTechs, resetAdvancedSearchFields, onMobileClose,
loadUrlFromFilters, setLoadUrlFromFilters }) => {

const classes = useSearchAreaStyles();
const {
Expand All @@ -140,6 +157,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,
},
AdvancedSearchControllerContext
);
Expand Down Expand Up @@ -196,6 +214,8 @@ SearchArea.propTypes = {
setSearchValue: PropTypes.func.isRequired,
setJobDuration: PropTypes.func.isRequired,
setJobType: PropTypes.func.isRequired,
setLoadUrlFromFilters: PropTypes.func.isRequired,
loadUrlFromFilters: PropTypes.bool,
resetAdvancedSearchFields: PropTypes.func.isRequired,
fields: PropTypes.array.isRequired,
technologies: PropTypes.array.isRequired,
Expand All @@ -215,6 +235,7 @@ export const mapStateToProps = ({ offerSearch }) => ({
fields: offerSearch.fields,
technologies: offerSearch.technologies,
showJobDurationSlider: offerSearch.filterJobDuration,
loadUrlFromFilters: offerSearch.loadUrlFromFilters,
});

export const mapDispatchToProps = (dispatch) => ({
Expand All @@ -225,6 +246,7 @@ export const mapDispatchToProps = (dispatch) => ({
setTechs: (technologies) => dispatch(setTechs(technologies)),
setShowJobDurationSlider: (val) => dispatch(setShowJobDurationSlider(val)),
resetAdvancedSearchFields: () => dispatch(resetAdvancedSearchFields()),
setLoadUrlFromFilters: (value) => dispatch(setLoadUrlFromFilters(value)),
});

export default connect(mapStateToProps, mapDispatchToProps)(SearchArea);
35 changes: 35 additions & 0 deletions src/components/HomePage/SearchArea/SearchArea.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,41 @@ describe("SearchArea", () => {
expect(onSubmit).toHaveBeenCalledTimes(1);
});

it("should call onSubmit callback on search button click", () => {
const searchValue = "test";
const setSearchValue = () => { };

const onSubmit = jest.fn();
const addSnackbar = () => { };

// Simulate request success
fetch.mockResponse(JSON.stringify({ mockData: true }));

renderWithStoreAndTheme(
<RouteWrappedContent>
<SearchArea
searchValue={searchValue}
setSearchValue={setSearchValue}
addSnackbar={addSnackbar}
loadUrlFromFilters={true}
showJobDurationSlider={() => { }}
setShowJobDurationSlider={() => { }}
setTechs={() => { }}
setJobDuration={() => { }}
setFields={() => { }}
setJobType={() => { }}
onSubmit={onSubmit}
fields={[]}
technologies={[]}
setLoadUrlFromFilters={() => { }}
/>
</RouteWrappedContent>,
{ initialState, theme }
);

expect(onSubmit).toHaveBeenCalledTimes(1);
});

it("should fill in search filters if they are present in the URL", () => {

const urlParams = {
Expand Down
34 changes: 34 additions & 0 deletions src/components/HomePage/SearchArea/useUrlSearchParams.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,39 @@ export default ({

}, [clearURLFilters, location, resetAdvancedSearchFields]);

const setUrlFilters = useCallback((
jobMinDuration,
jobMaxDuration,
fields,
technologies,
jobType,
searchValue,
) => {
let currFilters = {};

if (jobMinDuration && jobMaxDuration) {
currFilters = { ...currFilters, jobMinDuration, jobMaxDuration };
}

if (fields) {
currFilters = { ...currFilters, fields };
}

if (technologies) {
currFilters = { ...currFilters, technologies };
}

if (jobType) {
currFilters = { ...currFilters, jobType };
}

if (searchValue) {
currFilters = { ...currFilters, searchValue };
}

changeURLFilters(location, {}, currFilters);
}, [changeURLFilters, location]);

return {
queryParams,
changeURLFilters,
Expand All @@ -138,5 +171,6 @@ export default ({
setTechs: actualSetTechs,
setSearchValue: actualSetSearchValue,
resetAdvancedSearchFields: actualResetAdvancedSearchFields,
setUrlFilters,
};
};
4 changes: 3 additions & 1 deletion src/components/HomePage/SearchResultsArea/Offer/ChipList.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const useStyles = makeStyles((theme) => ({
},
}));

const ChipList = ({ type, values, loading }) => {
const ChipList = ({ type, values, loading, onChipClick }) => {
const classes = useStyles();
if (loading)
return (
Expand All @@ -44,6 +44,7 @@ const ChipList = ({ type, values, loading }) => {
variant={type === "Technologies" ? "outlined" : "default"}
size="small"
className={classes.chip}
onClick={onChipClick ? () => onChipClick(value) : null}
/>
</li>
)}
Expand All @@ -57,6 +58,7 @@ ChipList.propTypes = {
type: PropTypes.string,
values: PropTypes.arrayOf(PropTypes.string),
loading: PropTypes.bool,
onChipClick: PropTypes.func,
};

export default ChipList;
28 changes: 28 additions & 0 deletions src/components/HomePage/SearchResultsArea/Offer/OfferDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import useSession from "../../../../hooks/useSession";
import useSearchResultsWidgetStyles from "../SearchResultsWidget/searchResultsWidgetStyles";
import { RouterLink } from "../../../../utils";
import { JOB_MAX_DURATION } from "../../../../reducers/searchOffersReducer";
import useChipsFieldSearch from "./useChipsFieldSearch";
import { useHistory } from "react-router-dom";

const defaultLogo = require("./default_icon.svg");

Expand Down Expand Up @@ -53,6 +55,30 @@ const OfferDetails = ({
+ "Please contact support for more information."
), [offer, sessionData]);

const { addField, addTech, addFieldWithUrl, addTechWithUrl, setLoadUrlFromFilters } = useChipsFieldSearch();

const handleChipSetFields = useCallback((values) => {
if (isPage) {
history.push("/");
addField(values);
setLoadUrlFromFilters(true);
} else {
addFieldWithUrl(values);
}
}, [history, isPage, addField, addFieldWithUrl, setLoadUrlFromFilters]);

const handleChipSetTechs = useCallback((values) => {
if (isPage) {
history.push("/");
addTech(values);
setLoadUrlFromFilters(true);
} else {
addTechWithUrl(values);
}
}, [history, isPage, setLoadUrlFromFilters, addTech, addTechWithUrl]);

const history = useHistory();

const getHiddenOfferMessage = useCallback(() => {
if (visibilityState.isDisabled)
return getDisabledOfferMessage();
Expand Down Expand Up @@ -248,11 +274,13 @@ const OfferDetails = ({
type="Technologies"
values={offer?.technologies}
loading={loading}
onChipClick={handleChipSetTechs}
/>
<ChipList
type="Fields"
values={offer?.fields}
loading={loading}
onChipClick={handleChipSetFields}
/>
</Grid>
</Grid>
Expand Down
Loading

0 comments on commit 014bd1d

Please sign in to comment.