Files
lixiyu-net/pages/search.tsx

111 lines
4.0 KiB
TypeScript
Raw Normal View History

import { ContentContainer, Page } from "@/components/layouts";
2024-01-06 11:47:18 +08:00
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Toaster } from "@/components/ui/toaster";
import { useToast } from "@/components/ui/use-toast";
import { Footer } from "@/components/utils/Footer";
import { NavBar } from "@/components/utils/NavBar";
import { SEO } from "@/components/utils/SEO";
import { Config } from "@/data/config";
import { isEmptyString } from "@/lib/utils";
2024-01-06 11:47:18 +08:00
import { TSearchResultItem } from "@/types/search-result";
import axios from "axios";
import { nanoid } from "nanoid";
import Link from "next/link";
import { ChangeEvent, KeyboardEvent, useState } from "react";
import { useQuery } from "react-query";
export default function SearchPage() {
const [searchText, setSearchText] = useState<string>("");
const [searchResult, setSearchResult] = useState<TSearchResultItem[]>([]);
const { toast } = useToast();
const fetchSearchAPI = async (param: string) => {
2024-01-06 11:47:18 +08:00
const response = (await axios.get<TSearchResultItem[]>(`/api/search/${param}`)).data;
return response;
};
const querySearch = useQuery("searchData", () => fetchSearchAPI(searchText), {
2024-01-06 11:47:18 +08:00
enabled: false,
onSuccess: (data) => {
setSearchResult(data);
if (data.length === 0) {
toast({ title: "Empty Result", description: "No results were found for this keyword. Try another keyword." });
2024-01-06 11:47:18 +08:00
}
},
onError: () => {
toast({ title: "Network Error", description: "Please try it later." });
},
});
const handleInputSearchText = (event: ChangeEvent<HTMLInputElement>) => {
setSearchText(event.target.value);
};
const handleEnterKeySearch = (event: KeyboardEvent<HTMLInputElement>) => {
(event.key === "Go" || event.key === "Enter") && handleMakeSearch();
};
const handleMakeSearch = () => {
if (isEmptyString(searchText)) {
toast({ title: "Enter a Keyword", description: "Please enter one keyword at least." });
return;
}
if (searchText.length < 4) {
toast({ title: "Keywords too short", description: "Keyword length must be at least 5." });
return;
}
2024-01-06 11:47:18 +08:00
querySearch.refetch();
};
return (
<Page>
2024-04-03 22:08:27 +08:00
<SEO description={"Search the posts on your demand."} title={`${Config.SiteTitle} - Search`} />
2024-01-06 11:47:18 +08:00
<Toaster />
<NavBar />
2024-01-06 11:47:18 +08:00
<ContentContainer>
2024-04-03 22:08:27 +08:00
<h2 className={`my-10 flex justify-center text-2xl font-bold font-fang-zheng-xiao-biao-song`}>
2024-01-06 11:47:18 +08:00
{"SEARCH POSTS"}
</h2>
2024-04-03 22:08:27 +08:00
<div className="flex my-10">
2024-01-06 11:47:18 +08:00
<Input
className="my-auto py-0"
2024-04-03 22:08:27 +08:00
onChange={handleInputSearchText}
onKeyDown={handleEnterKeySearch}
2024-01-06 11:47:18 +08:00
placeholder="Input the keyword"
value={searchText}
/>
<Button className="mx-3 w-32 my-auto" disabled={querySearch.isLoading} onClick={handleMakeSearch}>
2024-01-08 18:18:21 +08:00
{querySearch.isFetching ? "Loading" : "Search"}
2024-01-06 11:47:18 +08:00
</Button>
</div>
<div className="flex flex-col justify-center">
2024-04-03 22:08:27 +08:00
<div className={`min-h-full flex flex-col font-source-serif-screen`}>
2024-01-06 11:47:18 +08:00
{querySearch.isSuccess &&
searchResult.map((item, index) => (
<Link
className={`py-2 px-5 border-t ${
index === searchResult.length - 1 && "border-b"
} hover:bg-gray-50 dark:hover:bg-gray-900 flex flex-col`}
href={`/blog/${item.id}`}
2024-04-03 22:08:27 +08:00
key={nanoid()}
2024-01-06 11:47:18 +08:00
target="_blank"
>
<div className="my-1 capitalize">{item.title}</div>
<div className="flex space-x-2 flex-wrap">
{item.tags?.map((tagitem) => (
<div className="text-sm text-gray-500 dark:text-gray-400" key={nanoid()}>
{tagitem}
</div>
))}
</div>
</Link>
))}
</div>
</div>
</ContentContainer>
<Footer />
</Page>
);
}