Skip to content

Commit

Permalink
Merge pull request #135 from kpi-ua/fix/preview-search
Browse files Browse the repository at this point in the history
Preview search upgrade
  • Loading branch information
ernado-x authored Jan 2, 2024
2 parents eadcd8f + f5765a1 commit b1f9d59
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 48 deletions.
3 changes: 2 additions & 1 deletion src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import axios from 'axios';
import { API_BASE_URL } from '../constants';

export const API_BASE_URL = 'https://api.campus.kpi.ua';

const Http = axios.create({
baseURL: API_BASE_URL + '/intellect/',
Expand Down
7 changes: 5 additions & 2 deletions src/api/subdivision.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import Http from './index';
import { API_BASE_URL } from '../constants';
import Http, { API_BASE_URL } from './index';

export const getFaculties = (): Promise<{ name: string }[]> => {
return Http.get(API_BASE_URL + '/subdivision/faculty/');
};

export const getByQueryString = (q: string): Promise<string[]> => {
return Http.get('/subdivision?q=' + q);
};
60 changes: 26 additions & 34 deletions src/components/I-TeacherSearch/I-TeacherSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,41 @@ import ITab from '@/components/I-Tab/I-Tab';
import InputField from '@/components/InputField/InputField';
import Alphabet from '@/components/Alphabet/Alphabet';

type Tab = {
label: string;
type: Intellect.SearchMode;
placeholder?: string;
};
import { tabs } from '@/constants';

const ITeacherSearch: React.FC = () => {
const [activeTab, setActiveTab] = useState('overall' as Intellect.SearchMode);
const router = useRouter();

const tabs = [
{
label: 'Загальний пошук спiвробiтникiв',
type: 'overall',
placeholder: 'Введіть ПІБ особи.. (наприклад: Петров Петро Петрович)',
},
{ label: 'Алфавітний покажчик', type: 'alphabetic' },
{
label: 'За кафедрами та факультетами',
type: 'subdivision',
placeholder: 'Введіть кафедру або факультет.. (наприклад: ФІОТ)',
},
{
label: 'За інтересами',
type: 'interests',
placeholder: 'Введіть можливі інтереси.. (наприклад: програмування)',
},
] as Tab[];
const handleSearch = (input: string, alphabetic?: boolean) => {
const state_input = alphabetic ? `startsWith:${input}` : input;

const handleSearch = (input: string) => {
router.push({
pathname: '/search',
query: { state_input: input, mode: activeTab },
query: { state_input, mode: activeTab },
});
};

const renderInputField = (): React.ReactNode => {
const currentTab = tabs.find((tab) => tab.type === activeTab);

if (!currentTab) return null;

return (
<InputField
keyField={currentTab.label}
buttonText="Пошук"
buttonClass="xs:flex hidden p-4 h-40 items-center"
icon="search"
tipsFetchFunction={currentTab?.searchFetchFunction}
tips={!!currentTab?.searchFetchFunction}
fieldClass="text-black flex-1 max-h-6 overflow-auto"
placeholder={currentTab?.placeholder}
onSubmit={handleSearch}
/>
);
};

return (
<>
<div className="flex gap-3 text-xs text-primary mb-3 xs:m-0 overflow-x-auto xs:overflow-x-hidden">
Expand All @@ -57,16 +56,9 @@ const ITeacherSearch: React.FC = () => {
}
>
{activeTab === 'alphabetic' ? (
<Alphabet onLetterSelected={handleSearch} />
<Alphabet onLetterSelected={(e) => handleSearch(e, true)} />
) : (
<InputField
buttonText="Пошук"
buttonClass="xs:flex hidden p-4 h-40 items-center"
icon="search"
fieldClass="text-black flex-1 max-h-6 overflow-auto"
placeholder={tabs.find((tab) => tab.type === activeTab)?.placeholder}
onSubmit={handleSearch}
/>
renderInputField()
)}
</div>
</>
Expand Down
19 changes: 15 additions & 4 deletions src/components/InputField/InputField.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import feather from 'feather-icons';

import FeatherIcon from '@/components/FeatherIcon/FeatherIcon';
Expand All @@ -8,6 +8,7 @@ import { searchStringParams } from '@/constants';
import { debounce } from '@/utils';

interface Props {
keyField: string;
onInput?: (a: React.SyntheticEvent<HTMLInputElement>) => void;
onSubmit?: (payload: string) => void;
buttonText: string;
Expand All @@ -24,6 +25,7 @@ interface Props {
let handleTipsDebounced: (param: string) => void | undefined;

const InputField: React.FC<Props> = ({
keyField,
onInput,
onSubmit,
buttonText,
Expand All @@ -40,22 +42,31 @@ const InputField: React.FC<Props> = ({
const [showTips, setShowTips] = useState(false);
const [tipOptions, setTipOptions] = useState<string[]>([]);

let tipsMemoizedFunction: null | ((q: string) => Promise<string[]>) = null;
if (tipsFetchFunction) {
tipsMemoizedFunction = useCallback((q: string) => tipsFetchFunction(q), [keyField]);
}

useEffect(() => {
setUserInput(value);
}, [value]);

useEffect(() => {
setUserInput('');
}, [keyField]);

useEffect(() => {
if (handleTips) {
handleTipsDebounced = debounce<string>(handleTips, 1000);
}
}, []);
}, [tipsMemoizedFunction]);

const handleTips = async (value: string | undefined) => {
setShowTips(false);

if (tipsFetchFunction && value) {
if (tipsMemoizedFunction && value) {
try {
const tipOptions = (await tipsFetchFunction(value)) as [];
const tipOptions = (await tipsMemoizedFunction(value)) as [];
setTipOptions(tipOptions);
} catch (e) {
console.error(e);
Expand Down
2 changes: 1 addition & 1 deletion src/components/TabList/TabList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';

type Props = {
children: React.ReactNode;
tabs: { [key in Intellect.ExperienceType]: string };
tabs: Record<Intellect.ExperienceType, string>;
selectTab?: (a: any) => void;
className: string;
tabActive: any;
Expand Down
36 changes: 33 additions & 3 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
export const experienceTabs: { [key in Intellect.ExperienceType]: string } = {
import { getByQueryString as searchTeachers } from '@/api/teacher';
import { getByQueryString as searchDivision } from '@/api/subdivision';

type Tab = {
label: string;
type: Intellect.SearchMode;
placeholder?: string;
searchFetchFunction?: (q: string) => Promise<string[]>;
};

export const experienceTabs: Record<Intellect.ExperienceType, string> = {
profile: 'Профіль',
publications: 'Публікації',
exploration: 'Виконання науково-дослідних та дослідно-конструкторських робіт',
Expand All @@ -12,7 +22,7 @@ export const searchStringParams = {
INTERESTS: 'interests:',
};

export const profileTabs: { [key in string]: { field: keyof Intellect.Teacher; label: string }[] } = {
export const profileTabs: Record<string, { field: keyof Intellect.Teacher; label: string }[]> = {
'Загальна інформація': [
{
field: 'scientificInterest' as keyof Intellect.Teacher,
Expand All @@ -30,4 +40,24 @@ export const profileTabs: { [key in string]: { field: keyof Intellect.Teacher; l
};

// export const API_BASE_URL = 'https://dev-api.campus.cloud.kpi.ua';
export const API_BASE_URL = 'https://api.campus.kpi.ua';

export const tabs = [
{
label: 'Загальний пошук спiвробiтникiв',
type: 'overall',
placeholder: 'Введіть ПІБ особи.. (наприклад: Петров Петро Петрович)',
searchFetchFunction: (searchField: string) => searchTeachers(searchField),
},
{ label: 'Алфавітний покажчик', type: 'alphabetic' },
{
label: 'За кафедрами та факультетами',
type: 'subdivision',
placeholder: 'Введіть кафедру або факультет.. (наприклад: ФІОТ)',
searchFetchFunction: (searchField: string) => searchDivision(searchField),
},
{
label: 'За інтересами',
type: 'interests',
placeholder: 'Введіть можливі інтереси.. (наприклад: програмування)',
},
] as Tab[];
4 changes: 2 additions & 2 deletions src/pages/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ const Search: React.FC = () => {

const [pagingOptions, setPagingOptions] = useState<ECampus.PaginationModel | null>(null);

const { invalidateCache, cacheSlice, setCache } =
useRuntimeCache<{ [key in number]: Intellect.Teacher[] }>(CACHE_KEY);
const { invalidateCache, cacheSlice, setCache } = useRuntimeCache<Record<number, Intellect.Teacher[]>>(CACHE_KEY);

const [loading, setLoading] = useState(false);

Expand Down Expand Up @@ -149,6 +148,7 @@ const Search: React.FC = () => {
<div className="mt-4">
<Alphabet onLetterSelected={(e) => onSubmit(searchStringParams.STARTS_WITH + e, true, false)} />
<InputField
keyField=""
syntheticRef={inputRef}
tips={true}
onSubmit={(e) => onSubmit(e, true, false)}
Expand Down
2 changes: 1 addition & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const decodeHtmlCharCodes = (str: string): string => {
return str.replace(/(&#(\d+);)/g, (match, capture, charCode) => String.fromCharCode(charCode));
};

export const parseSearchParams = (searchString: string): { [key in Intellect.SearchParams]: string } => {
export const parseSearchParams = (searchString: string): Record<Intellect.SearchParams, string> => {
const paramsObject: { [key in Intellect.SearchParams]: string } = {
startsWith: '',
subdivision: '',
Expand Down

0 comments on commit b1f9d59

Please sign in to comment.