diff --git a/client/src/components/FiltersSideMenu/filters.js b/client/src/components/FiltersSideMenu/filters.js index 0361df0..f54d0d8 100644 --- a/client/src/components/FiltersSideMenu/filters.js +++ b/client/src/components/FiltersSideMenu/filters.js @@ -3,9 +3,7 @@ import PT from "prop-types"; import Button from "../Button"; import WideButton from "../wideButton"; import Collapsible from "../collapsible"; -import SearchBox from "../searchBox"; import Availability from "../availability"; -import TagList from "../tagList"; import EditFiltersPopup from "../editFiltersPopup"; import SuggestionBox from "../SuggestionBox"; import Pill from "../Pill"; @@ -20,9 +18,8 @@ import utilityStyles from "../../styles/utility.module.css"; * SearchTabFilters - component containing all the filters on the search tab page * achievements: the values for the achievements filter options */ -export default function SearchTabFilters({ achievements }) { +export default function SearchTabFilters() { const search = useSearch(); - const [achievementsData, setAchievementsData] = useState(achievements); /** * Component unmount trigger @@ -46,21 +43,6 @@ export default function SearchTabFilters({ achievements }) { search.changePageNumber(1); }; - useEffect(() => { - setAchievementsData(achievements); - }, [achievements]); - - const filterData = (query, initialValues, property, setState) => { - const q = query.toLowerCase(); - if (q.length >= 3) { - setState( - initialValues.filter((g) => g[property].toLowerCase().includes(q)) - ); - } else if (query.length === 0) { - setState(initialValues); - } - }; - const [numberOfFiltersApplied, setNumberOfFiltersApplied] = useState(); const modal = useModal(); @@ -180,6 +162,32 @@ export default function SearchTabFilters({ achievements }) { search["selectSkills"](skillFilters); }; + const addAchievementToFilter = (achievement) => { + const achievementFilters = JSON.parse( + JSON.stringify(search.selectedAchievements) + ); + + if (achievementFilters.findIndex((s) => s.id === achievement.id) !== -1) { + return; + } + achievementFilters.push(achievement); + search["selectAchievements"](achievementFilters); + }; + + const removeAchievementFromFilter = (achievement) => { + const achievementFilters = JSON.parse( + JSON.stringify(search.selectedAchievements) + ); + const index = achievementFilters.findIndex((s) => s.id === achievement.id); + + if (index === -1) { + return; + } + + achievementFilters.splice(index, 1); + search["selectAchievements"](achievementFilters); + }; + const addCompanyAttributeToFilter = (attrId, data) => { const companyAttrFilters = JSON.parse( JSON.stringify(search.selectedCompanyAttributes) @@ -319,25 +327,26 @@ export default function SearchTabFilters({ achievements }) { )} {search.isFilterActive(FILTERS.ACHIEVEMENTS) && (
- - filterData("", achievements, "name", setAchievementsData) - } - > - + - filterData(q.trim(), achievements, "name", setAchievementsData) - } - /> - + {search.selectedAchievements.length > 0 && ( +
+ {search.selectedAchievements.map((achievement) => { + return ( + removeAchievementFromFilter(achievement)} + /> + ); + })} +
+ )}
)} diff --git a/client/src/components/FiltersSideMenu/index.jsx b/client/src/components/FiltersSideMenu/index.jsx index 1932495..5307e47 100644 --- a/client/src/components/FiltersSideMenu/index.jsx +++ b/client/src/components/FiltersSideMenu/index.jsx @@ -1,5 +1,4 @@ import React from "react"; -import PT from "prop-types"; import style from "./style.module.scss"; import SearchTabFilters from "./filters"; @@ -7,11 +6,7 @@ import SearchTabFilters from "./filters"; export default function FiltersSideMenu({ achievements }) { return (
- +
); } - -FiltersSideMenu.propTypes = { - achievements: PT.array.isRequired, -}; diff --git a/client/src/components/SuggestionBox/index.jsx b/client/src/components/SuggestionBox/index.jsx index 1f12746..b1a79d3 100644 --- a/client/src/components/SuggestionBox/index.jsx +++ b/client/src/components/SuggestionBox/index.jsx @@ -5,6 +5,7 @@ import api from "../../services/api"; import style from "./style.module.scss"; import _ from "lodash"; import { useSearch, FILTERS } from "../../lib/search"; +import { getAchievements } from "../../lib/achievements"; const NO_RESULTS_FOUND = "no results found"; const DELAY_SEARCH = 300; @@ -66,6 +67,22 @@ const getSkillsSuggestions = async (apiClient, inputValue) => { return data.skills; }; +/** + * Returns the suggestions for achievements + * @param {Object} apiClient The api client to make the query + * @param {String} inputValue The search query + */ +const getAchievementSuggestions = async (apiClient, inputValue) => { + let term = inputValue.trim(); + if (term.length < 1) { + return []; + } + + term = encodeURIComponent(term); + const suggestions = await getAchievements(apiClient, term); + return suggestions; +}; + /** * Returns the suggestions for company attributes * @param {Object} apiClient The api client to make the query @@ -112,6 +129,11 @@ export default function SuggestionBox({ if (purpose === "skills") { let data = await getSkillsSuggestions(apiClient, value); + if (data.length < 1) data = [{ name: NO_RESULTS_FOUND }]; + setSuggestions(data); + } else if (purpose === "achievements") { + let data = await getAchievementSuggestions(apiClient, value); + if (data.length < 1) data = [{ name: NO_RESULTS_FOUND }]; setSuggestions(data); } else { @@ -137,6 +159,8 @@ export default function SuggestionBox({ if (suggestion.name !== NO_RESULTS_FOUND) onSelect(suggestion); } else if (purpose === "locations") { if (suggestion.name !== NO_RESULTS_FOUND) onSelect(suggestion); + } else if (purpose === "achievements") { + if (suggestion.name !== NO_RESULTS_FOUND) onSelect(suggestion); } else { if (suggestion.name !== NO_RESULTS_FOUND) onSelect(companyAttrId, suggestion); diff --git a/client/src/lib/achievements.js b/client/src/lib/achievements.js new file mode 100644 index 0000000..5c3b0ca --- /dev/null +++ b/client/src/lib/achievements.js @@ -0,0 +1,26 @@ +import config from "../config"; +import * as OrgService from "../services/user-org"; + +/** + * Returns achivement suggestions based on query + * @param {Object} apiClient The api client (you can get this from src/services/api and then call api() to get the apiClient) + * @param {String} query query to search for + */ +export async function getAchievements(apiClient, query) { + let response; + const organizationId = OrgService.getSingleOrg(); + let url = `${config.API_URL}/search/userAchievements?organizationId=${organizationId}&keyword=${query}`; + + try { + response = await apiClient.get(url); + } catch (error) { + console.log(error); + return []; + } + + if (!response.data || response.data.length < 1) { + return []; + } + + return response.data; +} diff --git a/client/src/pages/Search/Global.jsx b/client/src/pages/Search/Global.jsx index 899eac6..e7b154c 100644 --- a/client/src/pages/Search/Global.jsx +++ b/client/src/pages/Search/Global.jsx @@ -14,7 +14,6 @@ import { useSearch, FILTERS } from "../../lib/search"; import { makeColorIterator, avatarColors } from "../../lib/colors"; import config from "../../config"; import api from "../../services/api"; -import staticData from "../../services/static-data"; import style from "./style.module.scss"; import _ from "lodash"; @@ -50,7 +49,6 @@ export default function SearchGlobal({ keyword }) { const apiClient = api(); const searchContext = useSearch(); const [isSearching, setIsSearching] = React.useState(false); - const [achievements, setAchievements] = React.useState([]); const [users, setUsers] = React.useState([]); const [page, setPage] = React.useState(1); const [totalResults, setTotalResults] = React.useState(0); @@ -75,26 +73,6 @@ export default function SearchGlobal({ keyword }) { }; }); - // Static data only - React.useEffect(() => { - if (isLoading || !isAuthenticated) { - return; - } - - let isSubscribed = true; - - (async () => { - const achievements = await staticData.getAchievements(); - - if (isSubscribed) { - setAchievements(achievements); - } - })(); - - return () => (isSubscribed = false); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isLoading, isAuthenticated]); - // Non-static data and Non-user related data React.useEffect(() => { if (isLoading || !isAuthenticated) { @@ -165,7 +143,9 @@ export default function SearchGlobal({ keyword }) { searchContext.filters[FILTERS.ACHIEVEMENTS].active && searchContext.selectedAchievements.length > 0 ) { - criteria.achievements = searchContext.selectedAchievements; + criteria.achievements = searchContext.selectedAchievements.map( + (a) => a.name + ); } if (searchContext.filters[FILTERS.AVAILABILITY].active) { if ( @@ -312,7 +292,7 @@ export default function SearchGlobal({ keyword }) { return ( <>
- +
{!isSearching && users.length > 0 && (
diff --git a/client/src/services/static-data.js b/client/src/services/static-data.js deleted file mode 100644 index 68273c1..0000000 --- a/client/src/services/static-data.js +++ /dev/null @@ -1,13 +0,0 @@ -async function getAchievements() { - const mockAchievementsTags = [ - { name: "Informatika" }, - { name: "Upwork" }, - { name: "TopCoder" }, - ]; - - return mockAchievementsTags; -} - -export default { - getAchievements, -};