Skip to content

Commit d2acc37

Browse files
diogofonteCarlosMealha
authored andcommitted
Merge branch 'feature/showHiddenToAdmin' of github.com:NIAEFEUP/nijobs-fe into feature/showHiddenToAdmin
2 parents 598f1ae + 695e803 commit d2acc37

File tree

10 files changed

+394
-273
lines changed

10 files changed

+394
-273
lines changed

package-lock.json

Lines changed: 216 additions & 249 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/actions/searchOffersActions.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ export const adminEnableOffer = (offerIdx) => ({
9494
offerIdx,
9595
});
9696

97+
export const setShowHidden = (showHidden) => ({
98+
type: OfferSearchTypes.SET_SHOW_HIDDEN,
99+
showHidden,
100+
});
101+
97102
export const resetAdvancedSearchFields = () => (dispatch) => {
98103
dispatch(setJobType(INITIAL_JOB_TYPE));
99104
dispatch(setShowJobDurationSlider(false));
@@ -102,8 +107,3 @@ export const resetAdvancedSearchFields = () => (dispatch) => {
102107
dispatch(setTechs([]));
103108
dispatch(setShowHidden(false));
104109
};
105-
106-
export const setShowHidden = (showHidden) => ({
107-
type: OfferSearchTypes.SET_SHOW_HIDDEN,
108-
showHidden,
109-
});

src/actions/searchOffersActions.spec.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
resetAdvancedSearchFields,
1313
setOffersFetchError,
1414
resetOffersFetchError,
15+
setShowHidden,
1516
} from "./searchOffersActions";
1617

1718
import { INITIAL_JOB_TYPE, INITIAL_JOB_DURATION } from "../reducers/searchOffersReducer";
@@ -54,6 +55,17 @@ describe("Search Offers actions", () => {
5455
expect(setSearchValue(value)).toEqual(expectedAction);
5556
});
5657

58+
it("should return Set Show Hidden action", () => {
59+
60+
const showHidden = true;
61+
const expectedAction = {
62+
type: OfferSearchTypes.SET_SHOW_HIDDEN,
63+
showHidden,
64+
};
65+
66+
expect(setShowHidden(showHidden)).toEqual(expectedAction);
67+
});
68+
5769
it("should return Set Job Duration action", () => {
5870

5971
const jobDuration = [1, 2];

src/components/HomePage/SearchArea/SearchArea.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ export const SearchArea = ({ onSubmit, searchValue,
186186
</form>
187187
<SubmitSearchButton
188188
onClick={submitForm}
189+
searchHasUserInput={
190+
(searchValue !== "" && searchValue !== undefined)
191+
|| advancedOptionsActive
192+
}
189193
/>
190194
</Paper>
191195
</ContextProvider>

src/components/HomePage/SearchArea/SearchArea.spec.js

Lines changed: 139 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import {
77
setFields,
88
setTechs,
99
setShowJobDurationSlider,
10+
setShowHidden,
1011
} from "../../../actions/searchOffersActions";
1112
import { createTheme } from "@material-ui/core";
1213
import { renderWithStoreAndTheme, screen, fireEvent, act } from "../../../test-utils";
13-
1414
import { MemoryRouter } from "react-router-dom";
1515

16+
import PropTypes from "prop-types";
17+
1618
import qs from "qs";
19+
import { INITIAL_JOB_TYPE } from "../../../reducers/searchOffersReducer";
1720

1821
// eslint-disable-next-line react/prop-types
1922
const RouteWrappedContent = ({ children, url = "/" }) => (
@@ -22,6 +25,49 @@ const RouteWrappedContent = ({ children, url = "/" }) => (
2225
</MemoryRouter>
2326
);
2427

28+
const SearchAreaWrapper = ({
29+
searchValue = "", jobType = INITIAL_JOB_TYPE, jobDuration = [null, null], filterJobDuration = false,
30+
showJobDurationSlider = false, fields = [], technologies = [], setShowJobDurationSlider = () => { },
31+
setTechs = () => { }, setJobDuration = () => { }, setFields = () => { }, setJobType = () => { },
32+
setSearchValue = () => { }, onSubmit = () => {}, setShowHidden = () => { },
33+
}) => (
34+
<SearchArea
35+
searchValue={searchValue}
36+
jobType={jobType}
37+
jobDuration={jobDuration}
38+
filterJobDuration={filterJobDuration}
39+
fields={fields}
40+
technologies={technologies}
41+
showJobDurationSlider={showJobDurationSlider}
42+
setShowJobDurationSlider={setShowJobDurationSlider}
43+
setTechs={setTechs}
44+
setJobDuration={setJobDuration}
45+
setFields={setFields}
46+
setJobType={setJobType}
47+
setSearchValue={setSearchValue}
48+
onSubmit={onSubmit}
49+
setShowHidden={setShowHidden}
50+
/>
51+
);
52+
53+
SearchAreaWrapper.propTypes = {
54+
onSubmit: PropTypes.func,
55+
searchValue: PropTypes.string.isRequired,
56+
jobType: PropTypes.string,
57+
setSearchValue: PropTypes.func.isRequired,
58+
setJobDuration: PropTypes.func.isRequired,
59+
setJobType: PropTypes.func.isRequired,
60+
fields: PropTypes.array.isRequired,
61+
technologies: PropTypes.array.isRequired,
62+
showJobDurationSlider: PropTypes.bool.isRequired,
63+
setFields: PropTypes.func.isRequired,
64+
setTechs: PropTypes.func.isRequired,
65+
setShowJobDurationSlider: PropTypes.func.isRequired,
66+
jobDuration: PropTypes.number,
67+
filterJobDuration: PropTypes.bool,
68+
setShowHidden: PropTypes.bool,
69+
};
70+
2571
describe("SearchArea", () => {
2672
let onSubmit;
2773
const theme = createTheme();
@@ -34,7 +80,7 @@ describe("SearchArea", () => {
3480
it("should render a Paper, a Form, a Search Bar, a Search Button and Advanced Options Button", () => {
3581
renderWithStoreAndTheme(
3682
<RouteWrappedContent>
37-
<SearchArea
83+
<SearchAreaWrapper
3884
onSubmit={onSubmit}
3985
fields={[]}
4086
technologies={[]}
@@ -44,6 +90,7 @@ describe("SearchArea", () => {
4490
setFields={() => { }}
4591
setJobType={() => { }}
4692
setSearchValue={() => { }}
93+
setShowHidden={() => { }}
4794
/>
4895
</RouteWrappedContent>,
4996
{ initialState, theme }
@@ -55,6 +102,88 @@ describe("SearchArea", () => {
55102
expect(screen.getByRole("button", { name: "Search" })).toBeInTheDocument();
56103
expect(screen.getByRole("button", { name: "Toggle Advanced Search" })).toBeInTheDocument();
57104
});
105+
it("should render a text='Show All' in the default state of searchArea", () => {
106+
const searchArea = renderWithStoreAndTheme(
107+
<RouteWrappedContent>
108+
<SearchAreaWrapper />
109+
</RouteWrappedContent>,
110+
{ initialState, theme }
111+
);
112+
113+
expect(searchArea.getByRole("button", { name: "Search" })).toHaveTextContent("Show All");
114+
});
115+
it("should render a text='Search' when search bar value != ''", () => {
116+
const searchArea = renderWithStoreAndTheme(
117+
<RouteWrappedContent>
118+
<SearchAreaWrapper
119+
searchValue={"somevalue"}
120+
/>
121+
</RouteWrappedContent>,
122+
{ initialState, theme }
123+
);
124+
125+
expect(searchArea.getByRole("button", { name: "Search" })).toHaveTextContent("Search");
126+
});
127+
it("should render a text='Show All' when search bar has undefined value", () => {
128+
const searchArea = renderWithStoreAndTheme(
129+
<RouteWrappedContent>
130+
<SearchAreaWrapper
131+
searchValue={undefined}
132+
/>
133+
</RouteWrappedContent>,
134+
{ initialState, theme }
135+
);
136+
137+
expect(searchArea.getByRole("button", { name: "Search" })).toHaveTextContent("Show All");
138+
});
139+
it("should render a text='Search' when fields != []", () => {
140+
const searchArea = renderWithStoreAndTheme(
141+
<RouteWrappedContent>
142+
<SearchAreaWrapper
143+
fields={["field1", "field2"]}
144+
/>
145+
</RouteWrappedContent>,
146+
{ initialState, theme }
147+
);
148+
149+
expect(searchArea.getByRole("button", { name: "Search" })).toHaveTextContent("Search");
150+
});
151+
it("should render a text='Search' when technologies != []", () => {
152+
const searchArea = renderWithStoreAndTheme(
153+
<RouteWrappedContent>
154+
<SearchAreaWrapper
155+
technologies={["tech1", "tech2"]}
156+
/>
157+
</RouteWrappedContent>,
158+
{ initialState, theme }
159+
);
160+
161+
expect(searchArea.getByRole("button", { name: "Search" })).toHaveTextContent("Search");
162+
});
163+
it("should render a text='Search' when jobType != INITIAL_JOB_TYPE", () => {
164+
const searchArea = renderWithStoreAndTheme(
165+
<RouteWrappedContent>
166+
<SearchAreaWrapper
167+
jobType={"JOB"}
168+
/>
169+
</RouteWrappedContent>,
170+
{ initialState, theme }
171+
);
172+
173+
expect(searchArea.getByRole("button", { name: "Search" })).toHaveTextContent("Search");
174+
});
175+
it("should render a text='Search' when showJobDurationSlider = true ", () => {
176+
const searchArea = renderWithStoreAndTheme(
177+
<RouteWrappedContent>
178+
<SearchAreaWrapper
179+
showJobDurationSlider={true}
180+
/>
181+
</RouteWrappedContent>,
182+
{ initialState, theme }
183+
);
184+
185+
expect(searchArea.getByRole("button", { name: "Search" })).toHaveTextContent("Search");
186+
});
58187
});
59188

60189
describe("interaction", () => {
@@ -80,6 +209,7 @@ describe("SearchArea", () => {
80209
setJobDuration={() => { }}
81210
setFields={() => { }}
82211
setJobType={() => { }}
212+
setShowHidden={() => { }}
83213
onSubmit={onSubmit}
84214
fields={[]}
85215
technologies={[]}
@@ -124,15 +254,13 @@ describe("SearchArea", () => {
124254

125255
renderWithStoreAndTheme(
126256
<RouteWrappedContent url={url}>
127-
<SearchArea
257+
<SearchAreaWrapper
128258
onSubmit={onSubmit}
129259
setSearchValue={setSearchValue}
130260
setJobType={setJobType}
131261
setJobDuration={setJobDuration}
132262
setShowJobDurationSlider={setShowJobDurationSlider}
133-
fields={[]}
134263
setFields={setFields}
135-
technologies={[]}
136264
setTechs={setTechs}
137265
/>
138266
</RouteWrappedContent>,
@@ -157,6 +285,7 @@ describe("SearchArea", () => {
157285
jobDuration: [1, 2],
158286
fields: ["field1", "field2"],
159287
technologies: ["tech1", "tech2"],
288+
showHidden: true,
160289
},
161290
};
162291
expect(mapStateToProps(mockState)).toEqual({
@@ -166,6 +295,7 @@ describe("SearchArea", () => {
166295
jobMaxDuration: 2,
167296
fields: ["field1", "field2"],
168297
technologies: ["tech1", "tech2"],
298+
showHidden: true,
169299
});
170300
});
171301

@@ -194,6 +324,10 @@ describe("SearchArea", () => {
194324
props.setShowJobDurationSlider(filterJobDuration);
195325
expect(dispatch).toHaveBeenCalledWith(setShowJobDurationSlider(false));
196326

327+
const showHidden = true;
328+
props.setShowHidden(showHidden);
329+
expect(dispatch).toHaveBeenCalledWith(setShowHidden(true));
330+
197331
dispatch.mockClear();
198332
props.resetAdvancedSearchFields();
199333
expect(dispatch).toHaveBeenCalled();

src/components/HomePage/SearchArea/SubmitSearchButton.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,32 @@ import React from "react";
22
import PropTypes from "prop-types";
33

44
import { Fab } from "@material-ui/core";
5-
import { Search } from "@material-ui/icons";
65

76
import useSearchAreaStyle from "./searchAreaStyle";
87

9-
const ShowAdvancedOptionsButton = ({ onClick }) => {
8+
const SubmitSearchButton = ({ onClick, searchHasUserInput }) => {
109
const classes = useSearchAreaStyle();
1110
return (
1211
<div className={classes.submitSearchButtonWrapper}>
1312
<Fab
1413
color="primary"
1514
aria-label="Search"
15+
variant="extended"
1616
onClick={onClick}
1717
>
18-
<Search />
18+
<span>
19+
{searchHasUserInput
20+
? "Search"
21+
: "Show All"}
22+
</span>
1923
</Fab>
2024
</div>
2125
);
2226
};
2327

24-
ShowAdvancedOptionsButton.propTypes = {
28+
SubmitSearchButton.propTypes = {
2529
onClick: PropTypes.func.isRequired,
30+
searchHasUserInput: PropTypes.bool.isRequired,
2631
};
2732

28-
export default ShowAdvancedOptionsButton;
33+
export default SubmitSearchButton;

src/components/HomePage/SearchArea/SubmitSearchButton.spec.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React from "react";
2-
import { Search } from "@material-ui/icons";
32
import { Fab } from "@material-ui/core";
43
import SubmitSearchButton from "./SubmitSearchButton";
54

@@ -11,9 +10,6 @@ describe("SubmitSearchButton", () => {
1110
.find(Fab).exists()
1211
).toBe(true);
1312
});
14-
it("should render 'search' icon", () => {
15-
expect(shallow(<SubmitSearchButton />).find(Search).exists()).toBe(true);
16-
});
1713
});
1814

1915
describe("interaction", () => {

src/components/HomePage/SearchResultsArea/SearchResultsWidget/SearchResultsDesktop.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const OffersList = ({
1515
showSearchFilters, toggleShowSearchFilters, offers, moreOffersLoading, loadMoreOffers, searchQueryToken,
1616
}) => (
1717
<Grid item md={4} id="offer_list" className={classes.fullHeight}>
18-
<Grid container className={classes.fullHeight}>
18+
<Grid container className={classes.heightOffersList}>
1919
<div className={classes.offerItemsContainer}>
2020
{noOffers ?
2121
<div className={classes.noOffersColumn}>
@@ -51,6 +51,7 @@ OffersList.propTypes = {
5151
classes: PropTypes.shape({
5252
divider: PropTypes.string.isRequired,
5353
fullHeight: PropTypes.string.isRequired,
54+
heightOffersList: PropTypes.string.isRequired,
5455
offerItemsContainer: PropTypes.string.isRequired,
5556
noOffersColumn: PropTypes.string.isRequired,
5657
errorLoadingOffersIcon: PropTypes.string.isRequired,
@@ -139,6 +140,7 @@ const SearchResultsDesktop = () => {
139140

140141
const offersListClasses = {
141142
fullHeight: classes.fullHeight,
143+
heightOffersList: classes.heightOffersList,
142144
noOffersColumn: classes.noOffersColumn,
143145
errorLoadingOffersIcon: classes.errorLoadingOffersIcon,
144146
divider: classes.divider,

src/components/HomePage/SearchResultsArea/SearchResultsWidget/searchResultsWidgetStyles.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ export default makeStyles((theme) => ({
1313
fullWidth: {
1414
width: "100%",
1515
},
16+
heightOffersList: {
17+
height: "100%",
18+
overflow: "auto",
19+
},
1620
searchResults: {
1721
boxSizing: "border-box",
1822
height: "100vh",
@@ -58,8 +62,6 @@ export default makeStyles((theme) => ({
5862
display: "flex",
5963
justifyContent: "space-between",
6064
width: "100%",
61-
height: "100%",
62-
overflow: "auto",
6365
},
6466
offerBodyContainer: {
6567
height: "100%",
@@ -69,7 +71,6 @@ export default makeStyles((theme) => ({
6971
offerHeader: {
7072
marginBottom: theme.spacing(1),
7173
alignItems: "flex-start",
72-
7374
},
7475
verticalDivider: {
7576
"&&": {

src/hooks/useComponentController.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from "react";
33
export const DefaultContext = React.createContext();
44

55
/**
6-
* This is based on the pattern described here: https://angeloteixeira.me/blog/reactive-controller-pattern
6+
* This is based on the pattern described here: https://angeloteixeira.eu/blog/reactive-controller-pattern
77
* With it, components can abstract logic common to different view layouts (such as desktop/mobile) and both can read from the given Context
88
*
99
* @param controller - A function (can be a React Hook) that handles some logic.

0 commit comments

Comments
 (0)