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

feat: add auto suggestion for achievement filter #626

Merged
merged 1 commit into from
Aug 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 45 additions & 36 deletions client/src/components/FiltersSideMenu/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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
Expand All @@ -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();

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -319,25 +327,26 @@ export default function SearchTabFilters({ achievements }) {
)}
{search.isFilterActive(FILTERS.ACHIEVEMENTS) && (
<div className={utilityStyles.mt32}>
<Collapsible
title="Achievements"
onCollapsed={(isCollapsed) =>
filterData("", achievements, "name", setAchievementsData)
}
>
<SearchBox
<Collapsible title="Achievements">
<SuggestionBox
placeholder="Search for an achievement"
name={"achievements search"}
onChange={(q) =>
filterData(q.trim(), achievements, "name", setAchievementsData)
}
/>
<TagList
tags={achievementsData}
selected={search.selectedAchievements}
selector={"selectAchievements"}
noResultsText={"No achievement found"}
purpose="achievements"
onSelect={addAchievementToFilter}
/>
{search.selectedAchievements.length > 0 && (
<div className={utilityStyles.mt16}>
{search.selectedAchievements.map((achievement) => {
return (
<Pill
key={achievement.id}
name={achievement.name}
removable={true}
onRemove={() => removeAchievementFromFilter(achievement)}
/>
);
})}
</div>
)}
</Collapsible>
</div>
)}
Expand Down
7 changes: 1 addition & 6 deletions client/src/components/FiltersSideMenu/index.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import React from "react";
import PT from "prop-types";

import style from "./style.module.scss";
import SearchTabFilters from "./filters";

export default function FiltersSideMenu({ achievements }) {
return (
<div className={style.container}>
<SearchTabFilters achievements={achievements} />
<SearchTabFilters />
</div>
);
}

FiltersSideMenu.propTypes = {
achievements: PT.array.isRequired,
};
24 changes: 24 additions & 0 deletions client/src/components/SuggestionBox/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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);
Expand Down
26 changes: 26 additions & 0 deletions client/src/lib/achievements.js
Original file line number Diff line number Diff line change
@@ -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;
}
28 changes: 4 additions & 24 deletions client/src/pages/Search/Global.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -312,7 +292,7 @@ export default function SearchGlobal({ keyword }) {
return (
<>
<div className={style.sideMenu}>
<FiltersSideMenu achievements={achievements} />
<FiltersSideMenu />
</div>
{!isSearching && users.length > 0 && (
<div className={style.rightSide}>
Expand Down
13 changes: 0 additions & 13 deletions client/src/services/static-data.js

This file was deleted.