diff --git a/components/search/onesearch/onesearch.tsx b/components/search/onesearch/onesearch.tsx index 402f875..8a24671 100644 --- a/components/search/onesearch/onesearch.tsx +++ b/components/search/onesearch/onesearch.tsx @@ -1,16 +1,19 @@ import { useEffect, useState } from "react"; import SuggestionBox from "./suggestionBox"; -import Suggestion from "./suggestion"; import { useRecoilValue } from "recoil"; import { queryState } from "@/components/state/query"; -import { Suggestion as SuggestionType } from "search-engine-autocomplete"; import { useLocale, useTranslations } from "next-intl"; import { suggestionItem, suggestionsResponse } from "@/global"; import getSearchEngineName from "@/lib/getSearchEngineName"; +import PlainSearch from "./plainSearch"; export default function () { - const [suggestion, setSuggetsion] = useState([] as suggestionItem[]); + const [suggestion, setFinalSuggetsion] = useState([] as suggestionItem[]); + const [selected, setSelected] = useState(0); const [lastUpdate, setLastUpdate] = useState(0); + const [cloudLastUpdate, setCloudLastUpdate] = useState(0); + const [clientLastUpdate, setClientLastUpdate] = useState(0); + const devMode = true; const query = useRecoilValue(queryState); const engineName = getSearchEngineName(); const lang = useLocale(); @@ -18,18 +21,118 @@ export default function () { useEffect(() => { const time = new Date().getTime().toString(); + if (query.trim() === "") { + cleanSuggestion("QUERY", new Date().getTime()); + return; + } fetch(`/api/suggestion?q=${query}&l=${lang}&t=${time}`) .then((res) => res.json()) .then((data: suggestionsResponse) => { + let suggestionToUpdate: suggestionItem[] = data.suggestions; + if (data.verbatimRelevance) { + suggestionToUpdate.push({ + type: "default", + suggestion: query, + relevance: data.verbatimRelevance + }); + } + updateSuggestion(suggestionToUpdate, "cloud", data.time); }); - }, [query, engineName]); + }, [query]); + + function setSuggestion(data: suggestionItem[], source: "frontend" | "client" | "cloud", time?: number) { + let finalSuggestion = data.sort((a, b) => b.relevance - a.relevance); + finalSuggestion = finalSuggestion.filter( + (item, index, self) => index === self.findIndex((t) => t.suggestion === item.suggestion) + ); + setFinalSuggetsion(finalSuggestion); + const requestUpdateTime = time || new Date().getTime(); + const overwriteLastUpdate = requestUpdateTime > lastUpdate; + switch (source) { + case "frontend": + setLastUpdate(new Date().getTime()); + break; + case "client": + setClientLastUpdate(requestUpdateTime); + if (overwriteLastUpdate) setLastUpdate(new Date().getTime()); + case "cloud": + setCloudLastUpdate(requestUpdateTime); + if (overwriteLastUpdate) setLastUpdate(new Date().getTime()); + break; + default: + break; + } + } + + function updateSuggestion(data: suggestionItem[], source: "frontend" | "client" | "cloud", time?: number) { + let finalSuggestion = suggestion; + const types: string[] = []; + for (let sug of data) { + if (!types.includes(sug.type)) types.push(sug.type); + } + for (let type of types) { + finalSuggestion = finalSuggestion.filter((item) => { + return item.type !== type; + }); + } + finalSuggestion = finalSuggestion.concat(data); + setSuggestion(finalSuggestion, source, time); + } + + function cleanSuggestion(type: string, time?: number){ + let finalSuggestion = suggestion; + console.log("1",finalSuggestion); + finalSuggestion = finalSuggestion.filter((item) => { + return item.type !== type; + }); + console.log("2",finalSuggestion); + setSuggestion(finalSuggestion, "frontend", time); + } useEffect(() => { - setLastUpdate(new Date().getTime()); - }, [query]); + updateSuggestion( + [ + { + type: "default", + suggestion: query, + relevance: 2000 + } + ], + "frontend" + ); + }, [query, engineName]); return ( + {suggestion.map((s) => { + if (s.suggestion.trim() === "") return; + if (s.type === "default") { + return ( + + {s.suggestion}  + + {t("search-help-text", { engine: engineName })} + + {devMode && ( + +   Relevance: {s.relevance} + + )} + + ); + } else if (s.type === "QUERY") { + return ( + + {s.suggestion} + {devMode && ( + +   Relevance: {s.relevance} + + )} + + ); + } + })} ); } diff --git a/components/search/onesearch/plainSearch.tsx b/components/search/onesearch/plainSearch.tsx new file mode 100644 index 0000000..b545a43 --- /dev/null +++ b/components/search/onesearch/plainSearch.tsx @@ -0,0 +1,18 @@ +import search from "@/lib/search"; +import { settingsState } from "@/components/state/settings"; +import { useRecoilValue } from "recoil"; + +export default function (props: { children: React.ReactNode, query: string }) { + const settings = useRecoilValue(settingsState); + const engine = settings.searchEngines[settings.currentSearchEngine]; + const newTab = settings.searchInNewTab; + return ( +
{search(props.query, engine, newTab)}} + > + {props.children} +
+ ); +} diff --git a/components/state/settings.ts b/components/state/settings.ts index 44e7dfd..3eb45ab 100644 --- a/components/state/settings.ts +++ b/components/state/settings.ts @@ -1,35 +1,50 @@ +import { settingsType } from "@/global"; import isLocalStorageAvailable from "@/lib/isLocalStorageAvailable"; import { atom } from "recoil"; -const defaultSettings: settings = { - version: 1, - elementBackdrop: true, - bgBlur: true, - timeShowSecond: false, - currentSearchEngine: "google", - searchEngines: { - google: "https://www.google.com/search?q=%s", - bing: "https://www.bing.com/search?q=%s", - baidu: "https://www.baidu.com/s?wd=%s", - duckduckgo: "https://duckduckgo.com/?q=%s", - yandex: "https://yandex.com/search/?text=%s", - yahoo: "https://search.yahoo.com/search?p=%s", - ecosia: "https://www.ecosia.org/search?q=%s" +const defaultSettings: settingsType = { + "version": 2, + "elementBackdrop": true, + "bgBlur": true, + "timeShowSecond": false, + "currentSearchEngine": "google", + "searchInNewTab": true, + "searchEngines": { + "google": "https://www.google.com/search?q=%s", + "bing": "https://www.bing.com/search?q=%s", + "baidu": "https://www.baidu.com/s?wd=%s", + "duckduckgo": "https://duckduckgo.com/?q=%s", + "yandex": "https://yandex.com/search/?text=%s", + "yahoo": "https://search.yahoo.com/search?p=%s", + "ecosia": "https://www.ecosia.org/search?q=%s" } }; + const localStorageEffect = - (key: any) => + (key: string) => ({ setSelf, onSet }: any) => { if (isLocalStorageAvailable()===false){ return; } - const savedValue = localStorage.getItem(key); - if (savedValue != null) { - setSelf(JSON.parse(savedValue)); + if (localStorage.getItem(key) === null) { + localStorage.setItem(key, JSON.stringify(defaultSettings)); + return; } + let settings =JSON.parse(JSON.stringify(defaultSettings)); + const savedSettings = localStorage.getItem(key)!; + const parsedSettings = JSON.parse(savedSettings); + + Object.keys(settings).map((key) => { + if (parsedSettings[key] !== undefined && key !== "version"){ + settings[key] = parsedSettings[key]; + } + }) - onSet((newValue: settings) => { + setSelf(settings); + localStorage.setItem(key, JSON.stringify(settings)); + + onSet((newValue: settingsType) => { localStorage.setItem(key, JSON.stringify(newValue)); }); }; diff --git a/global.d.ts b/global.d.ts index 5718700..d575df9 100644 --- a/global.d.ts +++ b/global.d.ts @@ -1,17 +1,18 @@ import { Suggestion } from "search-engine-autocomplete"; -type settingsType = { - version: number; - elementBackdrop: boolean; - bgBlur: boolean; - timeShowSecond: boolean; - currentSearchEngine: string; - searchEngines: { - [key: string]: string, - }; +interface settingsType extends Object{ + "version": number, + "elementBackdrop": boolean, + "bgBlur": boolean, + "timeShowSecond": boolean, + "currentSearchEngine": string, + "searchInNewTab": boolean, + "searchEngines": { + [key: string]: string + }, }; -type suggestionsResponse = { +interface suggestionsResponse extends Object{ suggestions: Suggestion[], query: string, verbatimRelevance: number, @@ -21,6 +22,6 @@ type suggestionsResponse = { type suggestionItem = { suggestion: string, type: string, - relativeRelevance: number, - relevance?: number + relativeRelevance?: number, + relevance: number } \ No newline at end of file diff --git a/lib/search.ts b/lib/search.ts new file mode 100644 index 0000000..fee5d50 --- /dev/null +++ b/lib/search.ts @@ -0,0 +1,4 @@ +export default function(query: string, engine: string, newTab: boolean = true) { + if(newTab) window.open(engine.replace("%s", query)); + else window.location.href = engine.replace("%s", query); +} \ No newline at end of file