2024-09-13 18:52:33 -05:00
|
|
|
import React, { useState, useRef, useEffect } from 'react';
|
2024-09-13 16:17:19 -05:00
|
|
|
import { InputText } from 'primereact/inputtext';
|
|
|
|
import { InputIcon } from 'primereact/inputicon';
|
|
|
|
import { IconField } from 'primereact/iconfield';
|
|
|
|
import { Dropdown } from 'primereact/dropdown';
|
2024-09-13 18:52:33 -05:00
|
|
|
import { OverlayPanel } from 'primereact/overlaypanel';
|
|
|
|
import ContentDropdownItem from '@/components/content/dropdowns/ContentDropdownItem';
|
|
|
|
import MessageDropdownItem from '@/components/content/dropdowns/MessageDropdownItem';
|
|
|
|
import { useContentSearch } from '@/hooks/useContentSearch';
|
|
|
|
import { useCommunitySearch } from '@/hooks/useCommunitySearch';
|
|
|
|
import { useRouter } from 'next/router';
|
2024-09-14 18:05:59 -05:00
|
|
|
import useWindowWidth from '@/hooks/useWindowWidth';
|
2024-09-13 16:17:19 -05:00
|
|
|
import styles from './searchbar.module.css';
|
|
|
|
|
|
|
|
const SearchBar = () => {
|
2024-09-13 18:52:33 -05:00
|
|
|
const { searchContent, searchResults: contentResults } = useContentSearch();
|
|
|
|
const { searchCommunity, searchResults: communityResults } = useCommunitySearch();
|
|
|
|
const router = useRouter();
|
2024-09-14 18:05:59 -05:00
|
|
|
const windowWidth = useWindowWidth();
|
2024-09-13 16:17:19 -05:00
|
|
|
const [selectedSearchOption, setSelectedSearchOption] = useState({ name: 'Content', code: 'content', icon: 'pi pi-video' });
|
|
|
|
const searchOptions = [
|
|
|
|
{ name: 'Content', code: 'content', icon: 'pi pi-video' },
|
|
|
|
{ name: 'Community', code: 'community', icon: 'pi pi-users' },
|
|
|
|
];
|
2024-09-13 18:52:33 -05:00
|
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
|
|
const [searchResults, setSearchResults] = useState([]);
|
|
|
|
const op = useRef(null);
|
2024-09-13 16:17:19 -05:00
|
|
|
|
|
|
|
const selectedOptionTemplate = (option, props) => {
|
|
|
|
if (!props?.placeholder) {
|
|
|
|
return (
|
|
|
|
<div className="flex items-center">
|
|
|
|
<i className={option.icon + ' mr-2'}></i>
|
|
|
|
<span>{option.code}</span>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return <i className={option.icon + ' text-transparent text-xs'} />
|
|
|
|
};
|
|
|
|
|
2024-09-13 18:52:33 -05:00
|
|
|
const handleSearch = (e) => {
|
|
|
|
const term = e.target.value;
|
|
|
|
setSearchTerm(term);
|
|
|
|
|
|
|
|
if (selectedSearchOption.code === 'content') {
|
|
|
|
searchContent(term);
|
|
|
|
setSearchResults(contentResults);
|
|
|
|
} else if (selectedSearchOption.code === 'community') {
|
|
|
|
searchCommunity(term);
|
|
|
|
setSearchResults(communityResults);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (term.length > 2) {
|
|
|
|
op.current.show(e);
|
|
|
|
} else {
|
|
|
|
op.current.hide();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (selectedSearchOption.code === 'content') {
|
|
|
|
setSearchResults(contentResults);
|
|
|
|
} else if (selectedSearchOption.code === 'community') {
|
|
|
|
setSearchResults(communityResults);
|
|
|
|
}
|
|
|
|
}, [selectedSearchOption, contentResults, communityResults]);
|
|
|
|
|
|
|
|
const handleContentSelect = (content) => {
|
2024-10-05 19:35:04 -05:00
|
|
|
if (content?.type === 'course') {
|
|
|
|
router.push(`/course/${content.id}`);
|
|
|
|
} else {
|
|
|
|
router.push(`/details/${content.id}`);
|
|
|
|
}
|
2024-09-13 18:52:33 -05:00
|
|
|
setSearchTerm('');
|
|
|
|
searchContent('');
|
|
|
|
op.current.hide();
|
|
|
|
}
|
|
|
|
|
2024-09-13 16:17:19 -05:00
|
|
|
return (
|
2024-09-14 18:05:59 -05:00
|
|
|
<div className={`absolute ${windowWidth < 700 ? "left-[40%]" : "left-[50%]"} transform -translate-x-[50%]`}>
|
2024-09-13 16:17:19 -05:00
|
|
|
<IconField iconPosition="left">
|
|
|
|
<InputIcon className="pi pi-search"> </InputIcon>
|
2024-09-13 18:52:33 -05:00
|
|
|
<InputText
|
2024-09-14 18:05:59 -05:00
|
|
|
className={`${windowWidth > 845 ? 'w-[300px]' : 'w-[160px]'}`}
|
2024-09-13 18:52:33 -05:00
|
|
|
value={searchTerm}
|
|
|
|
onChange={handleSearch}
|
|
|
|
placeholder={`Search ${selectedSearchOption.name.toLowerCase()}`}
|
|
|
|
pt={{
|
|
|
|
root: {
|
|
|
|
className: 'border-none rounded-tr-none rounded-br-none focus:border-none focus:ring-0 pr-0'
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
2024-09-13 16:17:19 -05:00
|
|
|
|
|
|
|
<Dropdown
|
|
|
|
pt={{
|
|
|
|
root: {
|
|
|
|
className: 'border-none rounded-tl-none rounded-bl-none bg-gray-900/55 hover:bg-gray-900/30'
|
|
|
|
},
|
|
|
|
input: {
|
|
|
|
className: 'mx-0 px-0 shadow-lg'
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
className={styles.dropdown}
|
|
|
|
value={selectedSearchOption}
|
|
|
|
onChange={(e) => setSelectedSearchOption(e.value)}
|
|
|
|
options={searchOptions}
|
|
|
|
optionLabel="name"
|
|
|
|
placeholder="Search"
|
|
|
|
dropdownIcon={
|
|
|
|
<div className='w-full pr-2 flex flex-row items-center justify-between'>
|
|
|
|
<i className={selectedSearchOption.icon + " text-white"} />
|
|
|
|
<i className="pi pi-chevron-down" />
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
valueTemplate={selectedOptionTemplate}
|
|
|
|
itemTemplate={selectedOptionTemplate}
|
|
|
|
required
|
|
|
|
/>
|
|
|
|
</IconField>
|
2024-09-13 18:52:33 -05:00
|
|
|
|
|
|
|
<OverlayPanel ref={op} className="w-[600px] max-h-[70vh] overflow-y-auto">
|
|
|
|
{searchResults.map((item, index) => (
|
|
|
|
item.type === 'discord' || item.type === 'nostr' || item.type === 'stackernews' ? (
|
|
|
|
<MessageDropdownItem
|
|
|
|
key={index}
|
|
|
|
message={item}
|
|
|
|
onSelect={handleContentSelect}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<ContentDropdownItem
|
|
|
|
key={index}
|
|
|
|
content={item}
|
|
|
|
onSelect={handleContentSelect}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
))}
|
|
|
|
{searchResults.length === 0 && searchTerm.length > 2 && (
|
|
|
|
<div className="p-4 text-center">No results found</div>
|
|
|
|
)}
|
|
|
|
</OverlayPanel>
|
2024-09-13 16:17:19 -05:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default SearchBar;
|