2023-08-27 15:39:49 +03:00
|
|
|
|
import { useCallback, useLayoutEffect, useState } from 'react';
|
2023-09-05 00:23:53 +03:00
|
|
|
|
import { useLocation } from 'react-router-dom';
|
2023-08-26 19:39:49 +03:00
|
|
|
|
|
|
|
|
|
import { MagnifyingGlassIcon } from '../../components/Icons';
|
|
|
|
|
import { useAuth } from '../../context/AuthContext';
|
2023-09-05 00:23:53 +03:00
|
|
|
|
import { useConceptNavigation } from '../../context/NagivationContext';
|
2023-09-02 01:11:27 +03:00
|
|
|
|
import useLocalStorage from '../../hooks/useLocalStorage';
|
2023-09-11 20:31:54 +03:00
|
|
|
|
import { ILibraryFilter } from '../../models/miscelanious';
|
|
|
|
|
import { LibraryFilterStrategy } from '../../models/miscelanious';
|
2023-08-27 15:39:49 +03:00
|
|
|
|
import PickerStrategy from './PickerStrategy';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function ApplyStrategy(strategy: LibraryFilterStrategy): ILibraryFilter {
|
|
|
|
|
switch (strategy) {
|
|
|
|
|
case LibraryFilterStrategy.MANUAL: return {};
|
|
|
|
|
case LibraryFilterStrategy.COMMON: return { is_common: true };
|
|
|
|
|
case LibraryFilterStrategy.CANONICAL: return { is_canonical: true };
|
|
|
|
|
case LibraryFilterStrategy.PERSONAL: return { is_personal: true };
|
|
|
|
|
case LibraryFilterStrategy.SUBSCRIBE: return { is_subscribed: true };
|
|
|
|
|
case LibraryFilterStrategy.OWNED: return { is_owned: true };
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-26 19:39:49 +03:00
|
|
|
|
|
|
|
|
|
interface SearchPanelProps {
|
2023-08-27 15:39:49 +03:00
|
|
|
|
total: number
|
|
|
|
|
filtered: number
|
2023-08-26 19:39:49 +03:00
|
|
|
|
setFilter: React.Dispatch<React.SetStateAction<ILibraryFilter>>
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-27 15:39:49 +03:00
|
|
|
|
function SearchPanel({ total, filtered, setFilter }: SearchPanelProps) {
|
2023-09-05 00:23:53 +03:00
|
|
|
|
const { navigateTo } = useConceptNavigation();
|
2023-08-26 19:39:49 +03:00
|
|
|
|
const search = useLocation().search;
|
|
|
|
|
const { user } = useAuth();
|
|
|
|
|
|
2023-08-27 00:19:19 +03:00
|
|
|
|
const [query, setQuery] = useState('');
|
2023-09-02 01:11:27 +03:00
|
|
|
|
const [strategy, setStrategy] = useLocalStorage<LibraryFilterStrategy>('search_strategy', LibraryFilterStrategy.MANUAL);
|
2023-08-27 00:19:19 +03:00
|
|
|
|
|
|
|
|
|
function handleChangeQuery(event: React.ChangeEvent<HTMLInputElement>) {
|
|
|
|
|
const newQuery = event.target.value;
|
|
|
|
|
setQuery(newQuery);
|
2023-09-09 20:36:55 +03:00
|
|
|
|
setFilter(prev => ({
|
|
|
|
|
query: newQuery,
|
|
|
|
|
is_owned: prev.is_owned,
|
|
|
|
|
is_common: prev.is_common,
|
|
|
|
|
is_canonical: prev.is_canonical,
|
|
|
|
|
is_subscribed: prev.is_subscribed,
|
|
|
|
|
is_personal: prev.is_personal
|
|
|
|
|
}));
|
2023-08-27 00:19:19 +03:00
|
|
|
|
}
|
2023-08-26 19:39:49 +03:00
|
|
|
|
|
|
|
|
|
useLayoutEffect(() => {
|
2023-08-27 15:39:49 +03:00
|
|
|
|
const searchFilter = new URLSearchParams(search).get('filter') as LibraryFilterStrategy | null;
|
2023-09-02 01:11:27 +03:00
|
|
|
|
if (searchFilter === null) {
|
2023-09-05 00:23:53 +03:00
|
|
|
|
navigateTo(`/library?filter=${strategy}`, { replace: true });
|
2023-09-02 01:11:27 +03:00
|
|
|
|
return;
|
|
|
|
|
}
|
2023-08-27 15:39:49 +03:00
|
|
|
|
const inputStrategy = searchFilter && Object.values(LibraryFilterStrategy).includes(searchFilter) ? searchFilter : LibraryFilterStrategy.MANUAL;
|
|
|
|
|
setQuery('')
|
|
|
|
|
setStrategy(inputStrategy)
|
|
|
|
|
setFilter(ApplyStrategy(inputStrategy));
|
2023-09-05 00:23:53 +03:00
|
|
|
|
}, [user, search, setQuery, setFilter, setStrategy, strategy, navigateTo]);
|
2023-08-26 19:39:49 +03:00
|
|
|
|
|
2023-08-27 15:39:49 +03:00
|
|
|
|
const handleChangeStrategy = useCallback(
|
|
|
|
|
(value: LibraryFilterStrategy) => {
|
|
|
|
|
if (value === strategy) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-09-05 00:23:53 +03:00
|
|
|
|
navigateTo(`/library?filter=${value}`)
|
|
|
|
|
}, [strategy, navigateTo]);
|
2023-08-27 15:39:49 +03:00
|
|
|
|
|
2023-08-26 19:39:49 +03:00
|
|
|
|
return (
|
2023-09-05 23:18:21 +03:00
|
|
|
|
<div className='sticky top-0 left-0 right-0 flex items-center justify-start w-full border-b clr-input'>
|
2023-08-27 15:39:49 +03:00
|
|
|
|
<div className='px-2 py-1 select-none whitespace-nowrap min-w-[10rem]'>
|
|
|
|
|
Фильтр
|
|
|
|
|
<span className='ml-2'>
|
2023-09-05 00:23:53 +03:00
|
|
|
|
{filtered} из {total}
|
2023-08-27 15:39:49 +03:00
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='flex items-center justify-center w-full pr-[10rem]'>
|
|
|
|
|
<PickerStrategy
|
|
|
|
|
value={strategy}
|
|
|
|
|
onChange={handleChangeStrategy}
|
2023-08-26 19:39:49 +03:00
|
|
|
|
/>
|
2023-09-10 20:17:18 +03:00
|
|
|
|
<div className='relative w-96 min-w-[10rem] select-none'>
|
2023-09-09 20:36:55 +03:00
|
|
|
|
<div className='absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-controls'>
|
2023-08-27 15:39:49 +03:00
|
|
|
|
<MagnifyingGlassIcon />
|
|
|
|
|
</div>
|
|
|
|
|
<input
|
|
|
|
|
type='text'
|
|
|
|
|
value={query}
|
|
|
|
|
className='w-full p-2 pl-10 text-sm outline-none clr-input'
|
|
|
|
|
placeholder='Поиск схемы...'
|
|
|
|
|
onChange={handleChangeQuery}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2023-08-26 19:39:49 +03:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default SearchPanel;
|