Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit cda61fd

Browse files
Merge branch 'issue-15' into develop
2 parents ee4604a + 9087d32 commit cda61fd

File tree

7 files changed

+104
-80
lines changed

7 files changed

+104
-80
lines changed

client/src/components/FiltersSideMenu/filters.js

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ import utilityStyles from "../../styles/utility.module.css";
1818

1919
/**
2020
* SearchTabFilters - component containing all the filters on the search tab page
21-
* locations: the values for the location filter options
2221
* achievements: the values for the achievements filter options
2322
*/
24-
export default function SearchTabFilters({ locations, achievements }) {
23+
export default function SearchTabFilters({ achievements }) {
2524
const search = useSearch();
26-
const [locationsData, setLocationsData] = useState(locations);
2725
const [achievementsData, setAchievementsData] = useState(achievements);
2826

2927
/**
@@ -49,9 +47,8 @@ export default function SearchTabFilters({ locations, achievements }) {
4947
};
5048

5149
useEffect(() => {
52-
setLocationsData(locations);
5350
setAchievementsData(achievements);
54-
}, [locations, achievements]);
51+
}, [achievements]);
5552

5653
const filterData = (query, initialValues, property, setState) => {
5754
const q = query.toLowerCase();
@@ -134,6 +131,32 @@ export default function SearchTabFilters({ locations, achievements }) {
134131
}
135132
};
136133

134+
const addLocationToFilter = (location) => {
135+
const locationFilters = JSON.parse(
136+
JSON.stringify(search.selectedLocations)
137+
);
138+
139+
if (locationFilters.findIndex((s) => s.id === location.id) !== -1) {
140+
return;
141+
}
142+
locationFilters.push({ name: location.value, id: location.id });
143+
search["selectLocations"](locationFilters);
144+
};
145+
146+
const removeLocationFromFilter = (location) => {
147+
const locationFilters = JSON.parse(
148+
JSON.stringify(search.selectedLocations)
149+
);
150+
const index = locationFilters.findIndex((s) => s.id === location.id);
151+
152+
if (index === -1) {
153+
return;
154+
}
155+
156+
locationFilters.splice(index, 1);
157+
search["selectLocations"](locationFilters);
158+
};
159+
137160
const addSkillToFilter = (skill) => {
138161
const skillFilters = JSON.parse(JSON.stringify(search.selectedSkills));
139162

@@ -230,27 +253,27 @@ export default function SearchTabFilters({ locations, achievements }) {
230253
/>
231254
{search.isFilterActive(FILTERS.LOCATIONS) && (
232255
<div className={utilityStyles.mt32}>
233-
<Collapsible
234-
onCollapsed={(isCollapsed) =>
235-
filterData("", locations, "name", setLocationsData)
236-
}
237-
title="Location"
238-
collapsed={false}
239-
>
240-
<SearchBox
241-
placeholder="Search for a location"
242-
name={"location search"}
243-
onChange={(q) =>
244-
filterData(q.trim(), locations, "name", setLocationsData)
245-
}
246-
/>
247-
<TagList
248-
key="l"
249-
tags={locationsData}
250-
selected={search.selectedLocations}
251-
selector={"selectLocations"}
252-
noResultsText={"No location found"}
256+
<Collapsible title="Location">
257+
<SuggestionBox
258+
placeholder={"Search for a location"}
259+
onSelect={addLocationToFilter}
260+
purpose="locations"
261+
companyAttrId={search.getAttributeId(FILTERS.LOCATIONS)}
253262
/>
263+
{search.selectedLocations.length > 0 && (
264+
<div className={utilityStyles.mt16}>
265+
{search.selectedLocations.map((location) => {
266+
return (
267+
<Pill
268+
key={location.id}
269+
name={location.name}
270+
removable={true}
271+
onRemove={() => removeLocationFromFilter(location)}
272+
/>
273+
);
274+
})}
275+
</div>
276+
)}
254277
</Collapsible>
255278
</div>
256279
)}
@@ -334,7 +357,6 @@ export default function SearchTabFilters({ locations, achievements }) {
334357
}
335358

336359
SearchTabFilters.propTypes = {
337-
locations: PT.array,
338360
achievements: PT.array,
339361
};
340362

client/src/components/FiltersSideMenu/index.jsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ import PT from "prop-types";
44
import style from "./style.module.scss";
55
import SearchTabFilters from "./filters";
66

7-
export default function FiltersSideMenu({ locations, achievements }) {
7+
export default function FiltersSideMenu({ achievements }) {
88
return (
99
<div className={style.container}>
10-
<SearchTabFilters locations={locations} achievements={achievements} />
10+
<SearchTabFilters achievements={achievements} />
1111
</div>
1212
);
1313
}
1414

1515
FiltersSideMenu.propTypes = {
16-
locations: PT.array.isRequired,
1716
achievements: PT.array.isRequired,
1817
};

client/src/components/SuggestionBox/index.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import config from "../../config";
44
import api from "../../services/api";
55
import style from "./style.module.scss";
66
import _ from "lodash";
7+
import { useSearch, FILTERS } from "../../lib/search";
78

89
const NO_RESULTS_FOUND = "no results found";
910
const DELAY_SEARCH = 300;
@@ -95,13 +96,19 @@ export default function SuggestionBox({
9596
placeholder,
9697
onSelect,
9798
}) {
99+
const search = useSearch();
98100
const apiClient = api();
99101
const [suggestions, setSuggestions] = React.useState([]);
100102
const [value, setValue] = React.useState("");
101103

102104
const onChange = (event, { newValue }) => setValue(newValue.trim());
103105

104106
const onSuggestionsFetchRequested = async ({ value }) => {
107+
if (purpose === "locations") {
108+
if (!companyAttrId) {
109+
companyAttrId = search.getAttributeId(FILTERS.LOCATIONS);
110+
}
111+
}
105112
if (purpose === "skills") {
106113
let data = await getSkillsSuggestions(apiClient, value);
107114

@@ -128,6 +135,8 @@ export default function SuggestionBox({
128135
const onSuggestionSelected = (event, { suggestion }) => {
129136
if (purpose === "skills") {
130137
if (suggestion.name !== NO_RESULTS_FOUND) onSelect(suggestion);
138+
} else if (purpose === "locations") {
139+
if (suggestion.name !== NO_RESULTS_FOUND) onSelect(suggestion);
131140
} else {
132141
if (suggestion.name !== NO_RESULTS_FOUND)
133142
onSelect(companyAttrId, suggestion);

client/src/lib/company-attributes.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ let primaryAttributeIds = [
1414
* Get the attributes associated with the company (organization)
1515
* @param {Object} apiClient The api client (you can get this from src/services/api and then call api() to get the apiClient)
1616
*/
17-
export async function getCompanyAttributes(apiClient, cancelToken) {
17+
export async function getAttributes(apiClient, cancelToken) {
1818
let response;
1919
let attributeGroups;
2020
let attributes = [];
@@ -29,7 +29,7 @@ export async function getCompanyAttributes(apiClient, cancelToken) {
2929
response = await apiClient.get(url, { cancelToken });
3030
} catch (error) {
3131
if (Axios.isCancel(error)) {
32-
return undefined;
32+
return [undefined, undefined];
3333
}
3434
console.log(error);
3535
alert(errorMessage);
@@ -52,7 +52,7 @@ export async function getCompanyAttributes(apiClient, cancelToken) {
5252
response = await apiClient.get(url, { cancelToken });
5353
} catch (error) {
5454
if (Axios.isCancel(error)) {
55-
return undefined;
55+
return [undefined, undefined];
5656
}
5757
console.log(error);
5858
alert(errorMessage);
@@ -70,14 +70,22 @@ export async function getCompanyAttributes(apiClient, cancelToken) {
7070
}
7171
}
7272

73-
// Finally, we only need the company attributes
74-
attributes = attributes.filter((attribute) => {
73+
// Finally, split 2 attribute types
74+
const companyAttrs = attributes.filter((attribute) => {
7575
if (primaryAttributeIds.includes(attribute.name)) {
7676
return false;
7777
}
7878

7979
return true;
8080
});
8181

82-
return attributes;
82+
const generalAttrs = attributes.filter((attribute) => {
83+
if (primaryAttributeIds.includes(attribute.name)) {
84+
return true;
85+
}
86+
87+
return false;
88+
});
89+
90+
return [companyAttrs, generalAttrs];
8391
}

client/src/lib/search.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ function useProvideSearch() {
6666
setPopupShown(true);
6767
};
6868

69+
const setFilter = (id, filter) => {
70+
return (filters[id] = filter);
71+
};
72+
73+
const getAttributeId = (filter) => {
74+
return filters[filter].id;
75+
};
76+
6977
const isFilterActive = (filter) => {
7078
return filters[filter].active;
7179
};
@@ -132,7 +140,9 @@ function useProvideSearch() {
132140
popupShown,
133141
showPopup,
134142
filters,
143+
setFilter,
135144
setFilters,
145+
getAttributeId,
136146
isFilterActive,
137147
activateFilter,
138148
deactivateFilter,

client/src/pages/Search/Global.jsx

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Pagination from "../../components/Pagination";
99

1010
import * as helper from "./helper";
1111
import { useAuth0 } from "../../react-auth0-spa";
12-
import { getCompanyAttributes } from "../../lib/company-attributes";
12+
import { getAttributes } from "../../lib/company-attributes";
1313
import { useSearch, FILTERS } from "../../lib/search";
1414
import { makeColorIterator, avatarColors } from "../../lib/colors";
1515
import config from "../../config";
@@ -50,7 +50,6 @@ export default function SearchGlobal({ keyword }) {
5050
const apiClient = api();
5151
const searchContext = useSearch();
5252
const [isSearching, setIsSearching] = React.useState(false);
53-
const [locations, setLocations] = React.useState([]);
5453
const [achievements, setAchievements] = React.useState([]);
5554
const [users, setUsers] = React.useState([]);
5655
const [page, setPage] = React.useState(1);
@@ -85,11 +84,9 @@ export default function SearchGlobal({ keyword }) {
8584
let isSubscribed = true;
8685

8786
(async () => {
88-
const locations = await staticData.getLocations();
8987
const achievements = await staticData.getAchievements();
9088

9189
if (isSubscribed) {
92-
setLocations(locations);
9390
setAchievements(achievements);
9491
}
9592
})();
@@ -107,7 +104,7 @@ export default function SearchGlobal({ keyword }) {
107104
let isSubscribed = true;
108105

109106
(async () => {
110-
const companyAttrs = await getCompanyAttributes(
107+
const [companyAttrs, generalAttrs] = await getAttributes(
111108
apiClient,
112109
cancelTokenSource.token
113110
);
@@ -125,6 +122,17 @@ export default function SearchGlobal({ keyword }) {
125122
searchContext.setFilters(filtersWithCompanyAttrs);
126123
}
127124
}
125+
if (generalAttrs) {
126+
generalAttrs.forEach((generalAttr) => {
127+
if (generalAttr.name === config.STANDARD_USER_ATTRIBUTES.location) {
128+
filtersWithCompanyAttrs[FILTERS.LOCATIONS].id = generalAttr.id;
129+
searchContext.setFilter(
130+
FILTERS.LOCATIONS,
131+
filtersWithCompanyAttrs[FILTERS.LOCATIONS]
132+
);
133+
}
134+
});
135+
}
128136
})();
129137

130138
return () => {
@@ -145,7 +153,7 @@ export default function SearchGlobal({ keyword }) {
145153
searchContext.filters[FILTERS.LOCATIONS].active &&
146154
searchContext.selectedLocations.length > 0
147155
) {
148-
criteria.locations = searchContext.selectedLocations;
156+
criteria.locations = searchContext.selectedLocations.map((l) => l.name);
149157
}
150158
if (
151159
searchContext.filters[FILTERS.SKILLS].active &&
@@ -209,10 +217,12 @@ export default function SearchGlobal({ keyword }) {
209217
pageChanged = true;
210218
}
211219

212-
if (_.isEqual(prevCriteria, criteria)
213-
&& prevKeyword === keyword
214-
&& prevOrderBy === orderBy
215-
&& pageChanged === false) {
220+
if (
221+
_.isEqual(prevCriteria, criteria) &&
222+
prevKeyword === keyword &&
223+
prevOrderBy === orderBy &&
224+
pageChanged === false
225+
) {
216226
return;
217227
} else {
218228
setPrevCriteria(criteria);
@@ -302,7 +312,7 @@ export default function SearchGlobal({ keyword }) {
302312
return (
303313
<>
304314
<div className={style.sideMenu}>
305-
<FiltersSideMenu locations={locations} achievements={achievements} />
315+
<FiltersSideMenu achievements={achievements} />
306316
</div>
307317
{!isSearching && users.length > 0 && (
308318
<div className={style.rightSide}>

client/src/services/static-data.js

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,3 @@
1-
async function getLocations() {
2-
const mockLocationTags = [
3-
{ name: "London" },
4-
{ name: "New York" },
5-
{ name: "East Carmen" },
6-
{ name: "Savanahville" },
7-
{ name: "Lake Audra" },
8-
{ name: "Elainaville" },
9-
{ name: "Howellstad" },
10-
{ name: "West Reneefort" },
11-
{ name: "Vanside" },
12-
{ name: "East Jonatan" },
13-
{ name: "Gottliebton" },
14-
{ name: "Ervinchester" },
15-
{ name: "Matteoburgh" },
16-
{ name: "Curtmouth" },
17-
{ name: "North Raphaelleton" },
18-
{ name: "Laishaside" },
19-
{ name: "West Trystanmouth" },
20-
{ name: "West Torrey" },
21-
{ name: "Abernathystad" },
22-
{ name: "Danland" },
23-
{ name: "Lednertown" },
24-
{ name: "Athenamouth" },
25-
{ name: "North Abagailport" },
26-
{ name: "North Andres" },
27-
{ name: "New Herbert" },
28-
{ name: "Bergstrombury" },
29-
{ name: "West Santinoside" },
30-
];
31-
return mockLocationTags;
32-
}
33-
341
async function getAchievements() {
352
const mockAchievementsTags = [
363
{ name: "Informatika" },
@@ -42,6 +9,5 @@ async function getAchievements() {
429
}
4310

4411
export default {
45-
getLocations,
4612
getAchievements,
4713
};

0 commit comments

Comments
 (0)