2023-01-08 15:42:35 +01:00
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
import { useTranslation } from "react-i18next";
|
2023-04-24 17:41:54 +02:00
|
|
|
|
|
|
|
import { searchForMedia } from "@/backend/metadata/search";
|
2023-06-21 13:38:48 +02:00
|
|
|
import { MWMediaMeta, MWQuery } from "@/backend/metadata/types/mw";
|
2023-01-07 21:36:18 +01:00
|
|
|
import { IconPatch } from "@/components/buttons/IconPatch";
|
|
|
|
import { Icons } from "@/components/Icon";
|
|
|
|
import { SectionHeading } from "@/components/layout/SectionHeading";
|
2023-01-07 23:44:46 +01:00
|
|
|
import { MediaGrid } from "@/components/media/MediaGrid";
|
2023-01-07 21:36:18 +01:00
|
|
|
import { WatchedMediaCard } from "@/components/media/WatchedMediaCard";
|
|
|
|
import { useLoading } from "@/hooks/useLoading";
|
2023-08-20 18:45:07 +02:00
|
|
|
import { SearchLoadingPart } from "@/views/parts/search/SearchLoadingPart";
|
2023-01-07 21:36:18 +01:00
|
|
|
|
2023-01-10 22:43:27 +01:00
|
|
|
function SearchSuffix(props: { failed?: boolean; results?: number }) {
|
2023-01-07 21:36:18 +01:00
|
|
|
const { t } = useTranslation();
|
|
|
|
|
2023-01-10 22:43:27 +01:00
|
|
|
const icon: Icons = props.failed ? Icons.WARNING : Icons.EYE_SLASH;
|
2023-01-07 21:36:18 +01:00
|
|
|
|
|
|
|
return (
|
2023-04-27 20:54:36 +02:00
|
|
|
<div className="mb-24 mt-40 flex flex-col items-center justify-center space-y-3 text-center">
|
2023-01-07 21:36:18 +01:00
|
|
|
<IconPatch
|
|
|
|
icon={icon}
|
2023-01-10 22:43:27 +01:00
|
|
|
className={`text-xl ${props.failed ? "text-red-400" : "text-bink-600"}`}
|
2023-01-07 21:36:18 +01:00
|
|
|
/>
|
|
|
|
|
|
|
|
{/* standard suffix */}
|
2023-01-10 22:43:27 +01:00
|
|
|
{!props.failed ? (
|
2023-01-07 21:36:18 +01:00
|
|
|
<div>
|
2023-01-10 22:43:27 +01:00
|
|
|
{(props.results ?? 0) > 0 ? (
|
2023-01-07 21:36:18 +01:00
|
|
|
<p>{t("search.allResults")}</p>
|
|
|
|
) : (
|
|
|
|
<p>{t("search.noResults")}</p>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
) : null}
|
|
|
|
|
|
|
|
{/* Error result */}
|
2023-01-10 22:43:27 +01:00
|
|
|
{props.failed ? (
|
2023-01-07 21:36:18 +01:00
|
|
|
<div>
|
|
|
|
<p>{t("search.allFailed")}</p>
|
|
|
|
</div>
|
|
|
|
) : null}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function SearchResultsView({ searchQuery }: { searchQuery: MWQuery }) {
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
2023-01-12 22:04:28 +01:00
|
|
|
const [results, setResults] = useState<MWMediaMeta[]>([]);
|
2023-01-07 21:36:18 +01:00
|
|
|
const [runSearchQuery, loading, error] = useLoading((query: MWQuery) =>
|
2023-01-10 22:43:27 +01:00
|
|
|
searchForMedia(query)
|
2023-01-07 21:36:18 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
async function runSearch(query: MWQuery) {
|
|
|
|
const searchResults = await runSearchQuery(query);
|
|
|
|
if (!searchResults) return;
|
|
|
|
setResults(searchResults);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (searchQuery.searchQuery !== "") runSearch(searchQuery);
|
|
|
|
}, [searchQuery, runSearchQuery]);
|
|
|
|
|
2023-08-20 18:45:07 +02:00
|
|
|
if (loading) return <SearchLoadingPart />;
|
2023-01-10 22:43:27 +01:00
|
|
|
if (error) return <SearchSuffix failed />;
|
2023-01-07 21:36:18 +01:00
|
|
|
if (!results) return null;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
2023-01-10 22:43:27 +01:00
|
|
|
{results.length > 0 ? (
|
2023-01-19 22:29:56 +01:00
|
|
|
<div>
|
|
|
|
<SectionHeading
|
|
|
|
title={t("search.headingTitle") || "Search results"}
|
|
|
|
icon={Icons.SEARCH}
|
|
|
|
/>
|
2023-01-07 23:44:46 +01:00
|
|
|
<MediaGrid>
|
2023-01-10 22:43:27 +01:00
|
|
|
{results.map((v) => (
|
|
|
|
<WatchedMediaCard key={v.id.toString()} media={v} />
|
2023-01-07 23:44:46 +01:00
|
|
|
))}
|
|
|
|
</MediaGrid>
|
2023-01-19 22:29:56 +01:00
|
|
|
</div>
|
2023-01-07 21:36:18 +01:00
|
|
|
) : null}
|
|
|
|
|
2023-01-10 22:43:27 +01:00
|
|
|
<SearchSuffix results={results.length} />
|
2023-01-07 21:36:18 +01:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|