feat: implement site filter
This commit is contained in:
parent
0ad37ad433
commit
0c404bd3b1
|
@ -7,21 +7,14 @@ import React, {
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { ChevronDownIcon, ChevronRightIcon } from "@heroicons/react/24/outline"; // Assuming usage of Heroicons for icons
|
import { ChevronRightIcon } from "@heroicons/react/24/outline"; // Assuming usage of Heroicons for icons
|
||||||
import { flushSync } from "react-dom";
|
import { flushSync } from "react-dom";
|
||||||
import {
|
import { Link, useFetcher, useSearchParams } from "@remix-run/react";
|
||||||
Link,
|
import { FILTER_TIMES, formatDate } from "@/utils";
|
||||||
useFetcher,
|
|
||||||
useLocation,
|
|
||||||
useNavigate,
|
|
||||||
useSearchParams,
|
|
||||||
} from "@remix-run/react";
|
|
||||||
import { FILTER_TIMES, formatDate, getResults } from "@/utils";
|
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectLabel,
|
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "./ui/select";
|
} from "./ui/select";
|
||||||
|
@ -31,8 +24,6 @@ import { SearchResult, SiteList } from "@/types.js";
|
||||||
type Props = {};
|
type Props = {};
|
||||||
|
|
||||||
const SearchBar = ({ sites }: { sites: SiteList }) => {
|
const SearchBar = ({ sites }: { sites: SiteList }) => {
|
||||||
let navigate = useNavigate();
|
|
||||||
let { pathname } = useLocation();
|
|
||||||
let [searchParams] = useSearchParams();
|
let [searchParams] = useSearchParams();
|
||||||
const [query, setQuery] = useState(searchParams.get("q") ?? "");
|
const [query, setQuery] = useState(searchParams.get("q") ?? "");
|
||||||
const inputRef = useRef<HTMLInputElement>();
|
const inputRef = useRef<HTMLInputElement>();
|
||||||
|
@ -40,12 +31,19 @@ const SearchBar = ({ sites }: { sites: SiteList }) => {
|
||||||
const [activeInput, setActiveInput] = useState(true);
|
const [activeInput, setActiveInput] = useState(true);
|
||||||
const [dirtyInput, setDirtyInput] = useState(false);
|
const [dirtyInput, setDirtyInput] = useState(false);
|
||||||
const [results, setResults] = useState<SearchResult[]>([]);
|
const [results, setResults] = useState<SearchResult[]>([]);
|
||||||
|
const [selectedSite, setSelectedSite] = useState(null);
|
||||||
|
|
||||||
const fetcher = useFetcher();
|
const fetcher = useFetcher({ key: "seach" });
|
||||||
|
|
||||||
const handleSearch = useCallback(
|
const handleSearch = useCallback(
|
||||||
async (event: FormEvent<HTMLFormElement>) => {
|
(event: FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
doSearch();
|
||||||
|
},
|
||||||
|
[query, selectedSite]
|
||||||
|
);
|
||||||
|
|
||||||
|
function doSearch() {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
let newSearchParams = new URLSearchParams(searchParams.toString());
|
let newSearchParams = new URLSearchParams(searchParams.toString());
|
||||||
|
|
||||||
|
@ -56,12 +54,12 @@ const SearchBar = ({ sites }: { sites: SiteList }) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(`${pathname}?${newSearchParams.toString()}`);
|
if (selectedSite) {
|
||||||
|
newSearchParams.set("site", selectedSite);
|
||||||
|
}
|
||||||
|
|
||||||
fetcher.load(`/api/search?${newSearchParams}`);
|
fetcher.load(`/api/search?${newSearchParams}`);
|
||||||
},
|
}
|
||||||
[query, searchParams, navigate, pathname]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (fetcher.data) {
|
if (fetcher.data) {
|
||||||
|
@ -71,6 +69,10 @@ const SearchBar = ({ sites }: { sites: SiteList }) => {
|
||||||
}
|
}
|
||||||
}, [fetcher.data]);
|
}, [fetcher.data]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
doSearch();
|
||||||
|
}, [selectedSite]);
|
||||||
|
|
||||||
const isActive = results.length > 0 || dirtyInput;
|
const isActive = results.length > 0 || dirtyInput;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -155,7 +157,7 @@ const SearchBar = ({ sites }: { sites: SiteList }) => {
|
||||||
) : (
|
) : (
|
||||||
<div className="justify-self-end min-w-[220px] flex justify-end gap-2">
|
<div className="justify-self-end min-w-[220px] flex justify-end gap-2">
|
||||||
{/* Dropdown component should be here */}
|
{/* Dropdown component should be here */}
|
||||||
<SitesCombobox siteList={sites} />
|
<SitesCombobox siteList={sites} onSiteSelect={setSelectedSite} />
|
||||||
{/* Dropdown component should be here */}
|
{/* Dropdown component should be here */}
|
||||||
<Select defaultValue={"0"}>
|
<Select defaultValue={"0"}>
|
||||||
<SelectTrigger className="hover:bg-muted w-auto">
|
<SelectTrigger className="hover:bg-muted w-auto">
|
||||||
|
|
|
@ -17,8 +17,15 @@ import {
|
||||||
import { ChevronDownIcon } from "@heroicons/react/24/solid";
|
import { ChevronDownIcon } from "@heroicons/react/24/solid";
|
||||||
import { SelectOptions, SiteList } from "@/types.js";
|
import { SelectOptions, SiteList } from "@/types.js";
|
||||||
import slugify from "slugify";
|
import slugify from "slugify";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export function SitesCombobox({ siteList }: { siteList: SiteList }) {
|
export function SitesCombobox({
|
||||||
|
siteList,
|
||||||
|
onSiteSelect,
|
||||||
|
}: {
|
||||||
|
siteList: SiteList;
|
||||||
|
onSiteSelect: React.Dispatch<React.SetStateAction<any>>;
|
||||||
|
}) {
|
||||||
const sites = Object.entries(siteList).map((item) => {
|
const sites = Object.entries(siteList).map((item) => {
|
||||||
return {
|
return {
|
||||||
label: item[1].name,
|
label: item[1].name,
|
||||||
|
@ -30,6 +37,10 @@ export function SitesCombobox({ siteList }: { siteList: SiteList }) {
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onSiteSelect(selectedSite?.value as any);
|
||||||
|
}, [selectedSite]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex- items-center space-x-4">
|
<div className="flex flex- items-center space-x-4">
|
||||||
<Popover open={open} onOpenChange={setOpen}>
|
<Popover open={open} onOpenChange={setOpen}>
|
||||||
|
@ -55,8 +66,7 @@ export function SitesCombobox({ siteList }: { siteList: SiteList }) {
|
||||||
value={status.value}
|
value={status.value}
|
||||||
onSelect={(value) => {
|
onSelect={(value) => {
|
||||||
setSelectedSite(
|
setSelectedSite(
|
||||||
sites.find((priority) => priority.value === value) ||
|
sites.find((site) => site.value === value) || null
|
||||||
null
|
|
||||||
);
|
);
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -12,7 +12,11 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await search.index("articles").search(query);
|
const site = searchParams.get("site");
|
||||||
|
|
||||||
|
const results = await search.index("articles").search(query, {
|
||||||
|
filter: site ? `siteKey = ${site}` : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
return results.hits.map((item) => {
|
return results.hits.map((item) => {
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Reference in New Issue