import { Group, type OptionsFilter, Overlay, Select, Stack, Text } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { HelpModal, WeatherModal } from 'components'; import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useEffect, useState } from 'react'; import * as fa6 from 'react-icons/fa6'; import * as si from 'react-icons/si'; import * as vsc from 'react-icons/vsc'; import { selectClasses } from 'styles'; import type { Application, CurrentWeather, ExtendedForecast, Provider, SearchHistoryItem, } from 'types'; import SearchSelectItem from './SearchSelectItem'; export default function Search({ current, extendedForecast, weatherModalOpened, closeWeatherModal, openWeatherModal, }: { current: CurrentWeather; extendedForecast: ExtendedForecast[]; weatherModalOpened: boolean; closeWeatherModal: () => void; openWeatherModal: () => void; }) { const allIcons: any = { ...fa6, ...vsc, ...si }; const { data: providerData, isFetched: providerDataIsFetched } = useQueryAPI({ endpoint: 'api/providers', }); const [providers, setProviders] = useState([]); const { data: applicationData, isFetching: isApplicationDataFetching } = useQueryAPI({ endpoint: 'api/enabledApplications', }); const [applications, setApplications] = useState([]); const searchEndpoint = 'api/searchHistory'; const { data: historyData, isFetched: historyDataIsFetched } = useQueryAPI({ endpoint: searchEndpoint, }); const [searchHistory, setSearchHistory] = useState([]); const [filteredHistory, setFilteredHistory] = useState([]); const { mutateAsync } = useMutationAPI(); const [providerModalOpened, { open: openProviderModal, close: closeProviderModal }] = useDisclosure(false); const [dropdownOpened, { open: openDropdown, close: closeDropdown }] = useDisclosure(); const [listIndex, setListIndex] = useState(0); const { isMobile, urlPattern, providerLabel, setProviderLabel, providerURL, setProviderURL, providerPrefix, setProviderPrefix, searchValue, setSearchValue, } = useCommonHooks(); const [placeholderValue, setPlaceholderValue] = useState(''); const [value, setValue] = useState(0); const handleSearchHistoryItem = ({ option }: { option: SearchHistoryItem }) => { const url = providerData.find((provider: Provider) => provider.prefix === option.prefix)?.url ?? 'https://www.google.com/search?q='; open(`${url}${option.searchTerm}`, '_self'); }; const handleAppLaunchItem = ({ option }: { option: any }) => { const validUrl = option.url.startsWith('http://') || option.url.startsWith('https://') ? option.url : `http://${option.url}`; open(validUrl, '_self'); }; const handleKeyPress = (item: any) => { let option = ''; let subtext = ''; if (item.target.value.startsWith('/')) { option = item.target.value.substr(1, item.target.value.indexOf(' ') - 1) ?? item.target.value.substr(1); subtext = item.target.value.substr(2 + option.length); } else if (item.target.value.startsWith('!')) { if (item.target.value.startsWith('!w')) { subtext = item.target.value.substr(2); } } else { subtext = item.target.value; } if (item.key === 'Enter') { if (providerLabel === 'Show help') { openProviderModal(); } else if (item.target.value.startsWith('/')) { mutateAsync({ method: 'POST', endpoint: searchEndpoint, body: { prefix: providerPrefix, provider: providerLabel, searchTerm: subtext }, }).then(() => { open(`${providerURL}${subtext}`, '_self'); }); } else if (providerLabel === 'Show weather') { openWeatherModal(); } else if (providerLabel.startsWith('Launch')) { const url = applications.find( (app: Application) => app.baseUrl.substring(1).toLowerCase() === item.target.value.substr(1), )?.url; const validUrl = url?.startsWith('http://') || url?.startsWith('https://') ? url : `http://${url}`; open(validUrl, '_self'); } else if (urlPattern.test(item.target.value)) { if (/^(https?:\/\/).*/i.test(item.target.value)) window.location = item.target.value; else open(`https://${item.target.value}`, '_self'); } else { mutateAsync({ method: 'POST', endpoint: searchEndpoint, body: { prefix: providerPrefix, provider: providerLabel, searchTerm: subtext }, }).then(() => { open(`${providerURL}${subtext}`, '_self'); }); } } }; const handleKeyUp = (item: any) => { if (item.code === 'Escape') { setListIndex(0); setSearchValue(''); setProviderLabel('Google Search'); setProviderPrefix('/g'); setPlaceholderValue(''); if (dropdownOpened) { closeDropdown(); } } if (item.code === 'ArrowDown' && !dropdownOpened) { setListIndex(0); openDropdown(); setPlaceholderValue( searchHistory.length > 0 ? `${searchHistory[listIndex].prefix} ${searchHistory[listIndex].searchTerm}` : '', ); } if (!providerLabel.startsWith('Invalid')) { handleKeyPress(item); } if (dropdownOpened) { if (searchValue === '') { if (item.code === 'ArrowUp') { if (listIndex === 0) { setListIndex(9); } else { setListIndex(listIndex - 1); } } else if (item.code === 'ArrowDown') { if (listIndex === 9) { setListIndex(0); } else { setListIndex(listIndex + 1); } } else if (item.code === 'ArrowRight' || item.code === 'Tab') { setSearchValue( searchHistory.length > 0 ? `${searchHistory[listIndex].prefix} ${searchHistory[listIndex].searchTerm}` : '', ); setValue(searchHistory[listIndex].id ?? 0); } } else if (searchValue !== '') { if (item.code === 'ArrowUp') { if (listIndex === 0) { setListIndex(filteredHistory.length - 1); } else if (listIndex >= filteredHistory.length) { setListIndex(filteredHistory.length - 1); } else { setListIndex(listIndex - 1); } } else if (item.code === 'ArrowDown') { if (listIndex >= filteredHistory.length - 1) { setListIndex(0); } else if (value === 0) { setListIndex(0); setValue(-1); } else { setListIndex(listIndex + 1); } } else if (item.code === 'ArrowRight' || item.code === 'Tab') { setSearchValue( `${filteredHistory[listIndex].prefix} ${filteredHistory[listIndex].searchTerm}`, ); setValue(filteredHistory[listIndex].id ?? 0); } } } }; const onInput = (item: any) => { openDropdown(); setSearchValue(item.currentTarget.value); if ( item.target.value === '/?' || item.target.value === '!help' || item.target.value === '/help' || item.target.value === '!h' || item.target.value === '/h' ) { setProviderLabel('Show help'); } else if (item.target.value.startsWith('/g')) { setProviderLabel('Google Search'); setProviderURL('https://www.google.com/search?q='); setProviderPrefix('/g'); } else if (item.target.value.startsWith('/')) { const provider = providers?.find( (p: Provider) => p.prefix === item.target.value.split(' ')[0], ); setProviderLabel(provider?.name ?? 'Invalid Search'); setProviderURL(provider?.url ?? ''); setProviderPrefix(provider?.prefix ?? ''); } else if (item.target.value.startsWith('!')) { if (item.target.value === '!w' || item.target.value === '!weather') { setProviderLabel('Show weather'); } else if ( applications?.find( (app: Application) => app.baseUrl.substring(1).toLowerCase() === item.target.value.substr(1), ) ) { setProviderLabel(`Launch ${item.target.value.substr(1)}`); } else { setProviderLabel('Invalid function'); } } else { setProviderLabel('Google Search'); setProviderURL('https://www.google.com/search?q='); setProviderPrefix('/g'); } }; const optionsFilter: OptionsFilter = ({ options, search }) => { const splittedSearch = search.toLowerCase().trim().split(' '); if (splittedSearch[0].startsWith('!')) { return applicationData .filter((app: Application) => app.name.toLowerCase().includes(splittedSearch[0].substring(1).toLowerCase()), ) .map((app: Application) => { return { label: app.name, value: app.baseUrl, ...app, }; }); } return options .filter((option: any) => { return splittedSearch.every((searchWord) => option.value .toLowerCase() .trim() .split(' ') .some((word: string) => word.includes(searchWord)), ); }) .slice(0, 10); }; useEffect(() => { if (providerData && providerDataIsFetched) { setProviders(providerData); } }, [providerData, providerDataIsFetched]); useEffect(() => { if (applicationData && !isApplicationDataFetching) { setApplications(applicationData); } }, [applicationData, isApplicationDataFetching]); useEffect(() => { if (historyData && historyDataIsFetched) { setSearchHistory(historyData); if (filteredHistory.length === 0) { setFilteredHistory(historyData.slice(0, 10)); } } }, [historyData, historyDataIsFetched]); useEffect(() => { if (dropdownOpened && listIndex >= 0) { setPlaceholderValue( searchHistory.length > 0 ? `${searchHistory[listIndex].prefix} ${searchHistory[listIndex].searchTerm}` : '', ); } }, [listIndex, dropdownOpened]); useEffect(() => { const splittedSearch = searchValue.toLowerCase().trim().split(' '); const filtered = searchHistory .filter((item: SearchHistoryItem) => { const option = `${item.prefix} ${item.searchTerm}`; const words = option.toLowerCase().trim().split(' '); return splittedSearch.every((searchWord) => words.some((word: string) => word.includes(searchWord)), ); }) .slice(0, 10); setFilteredHistory(filtered); }, [searchValue]); return ( <> {dropdownOpened && }