Updated search params
This commit is contained in:
parent
0d112f192b
commit
cd7c163d6e
|
@ -1,4 +1,5 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { MaterialSymbol } from "material-symbols";
|
||||||
import { Popup } from "components/Containers/Popup";
|
import { Popup } from "components/Containers/Popup";
|
||||||
import { sendAnalytics } from "helpers/analytics";
|
import { sendAnalytics } from "helpers/analytics";
|
||||||
import { atoms } from "contexts/atoms";
|
import { atoms } from "contexts/atoms";
|
||||||
|
@ -46,16 +47,25 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
const fetchLibraryItems = async () => {
|
const fetchLibraryItems = async () => {
|
||||||
const searchResult = await meiliSearch(MeiliIndices.LIBRARY_ITEM, query, {
|
const searchResult = await meiliSearch(MeiliIndices.LIBRARY_ITEM, query, {
|
||||||
limit: SEARCH_LIMIT,
|
limit: SEARCH_LIMIT,
|
||||||
|
attributesToRetrieve: [
|
||||||
|
"title",
|
||||||
|
"subtitle",
|
||||||
|
"descriptions",
|
||||||
|
"id",
|
||||||
|
"slug",
|
||||||
|
"thumbnail",
|
||||||
|
"release_date",
|
||||||
|
"price",
|
||||||
|
"categories",
|
||||||
|
"metadata",
|
||||||
|
],
|
||||||
|
attributesToHighlight: ["title", "subtitle", "descriptions"],
|
||||||
attributesToCrop: ["descriptions"],
|
attributesToCrop: ["descriptions"],
|
||||||
});
|
});
|
||||||
searchResult.hits = searchResult.hits.map((item) => {
|
searchResult.hits = searchResult.hits.map((item) => {
|
||||||
if (
|
if (Object.keys(item._matchesPosition).some((match) => match.startsWith("descriptions"))) {
|
||||||
isDefined(item._formatted) &&
|
|
||||||
item._matchesPosition.descriptions &&
|
|
||||||
item._matchesPosition.descriptions.length > 0
|
|
||||||
) {
|
|
||||||
item._formatted.descriptions = filterDefined(item._formatted.descriptions).filter(
|
item._formatted.descriptions = filterDefined(item._formatted.descriptions).filter(
|
||||||
(description) => description.includes("</mark>")
|
(description) => containsHighlight(JSON.stringify(description))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
|
@ -65,16 +75,15 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
|
|
||||||
const fetchContents = async () => {
|
const fetchContents = async () => {
|
||||||
const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, {
|
const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, {
|
||||||
attributesToCrop: ["translations.description"],
|
|
||||||
limit: SEARCH_LIMIT,
|
limit: SEARCH_LIMIT,
|
||||||
|
attributesToRetrieve: ["translations", "id", "slug", "categories", "type", "thumbnail"],
|
||||||
|
attributesToHighlight: ["translations"],
|
||||||
|
attributesToCrop: ["translations.displayable_description"],
|
||||||
});
|
});
|
||||||
searchResult.hits = searchResult.hits.map((item) => {
|
searchResult.hits = searchResult.hits.map((item) => {
|
||||||
if (
|
if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) {
|
||||||
Object.keys(item._matchesPosition).filter((match) => match.startsWith("translations"))
|
|
||||||
.length > 0
|
|
||||||
) {
|
|
||||||
item._formatted.translations = filterDefined(item._formatted.translations).filter(
|
item._formatted.translations = filterDefined(item._formatted.translations).filter(
|
||||||
(translation) => JSON.stringify(translation).includes("</mark>")
|
(translation) => containsHighlight(JSON.stringify(translation))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
|
@ -94,8 +103,8 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
"duration",
|
"duration",
|
||||||
"description",
|
"description",
|
||||||
],
|
],
|
||||||
|
attributesToHighlight: ["title", "channel", "description"],
|
||||||
attributesToCrop: ["description"],
|
attributesToCrop: ["description"],
|
||||||
sort: ["sortable_published_date:desc"],
|
|
||||||
});
|
});
|
||||||
setVideos(searchResult);
|
setVideos(searchResult);
|
||||||
};
|
};
|
||||||
|
@ -106,9 +115,16 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
attributesToRetrieve: ["translations", "thumbnail", "slug", "date", "categories"],
|
attributesToRetrieve: ["translations", "thumbnail", "slug", "date", "categories"],
|
||||||
attributesToHighlight: ["translations.title", "translations.excerpt", "translations.body"],
|
attributesToHighlight: ["translations.title", "translations.excerpt", "translations.body"],
|
||||||
attributesToCrop: ["translations.body"],
|
attributesToCrop: ["translations.body"],
|
||||||
sort: ["sortable_date:desc"],
|
|
||||||
filter: ["hidden = false"],
|
filter: ["hidden = false"],
|
||||||
});
|
});
|
||||||
|
searchResult.hits = searchResult.hits.map((item) => {
|
||||||
|
if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) {
|
||||||
|
item._formatted.translations = filterDefined(item._formatted.translations).filter(
|
||||||
|
(translation) => JSON.stringify(translation).includes("</mark>")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
setPosts(searchResult);
|
setPosts(searchResult);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -123,6 +139,17 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
],
|
],
|
||||||
attributesToCrop: ["translations.displayable_description"],
|
attributesToCrop: ["translations.displayable_description"],
|
||||||
});
|
});
|
||||||
|
searchResult.hits = searchResult.hits.map((item) => {
|
||||||
|
if (
|
||||||
|
Object.keys(item._matchesPosition).filter((match) => match.startsWith("translations"))
|
||||||
|
.length > 0
|
||||||
|
) {
|
||||||
|
item._formatted.translations = filterDefined(item._formatted.translations).filter(
|
||||||
|
(translation) => JSON.stringify(translation).includes("</mark>")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
setWikiPages(searchResult);
|
setWikiPages(searchResult);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -159,22 +186,27 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
{isDefined(libraryItems) && (
|
{isDefined(libraryItems) && (
|
||||||
<SearchResultSection
|
<SearchResultSection
|
||||||
title={langui.library}
|
title={langui.library}
|
||||||
href={`/library?page=1&query=${query}&sort=0&primary=true&secondary=true&subitems=true&status=all`}
|
icon="auto_stories"
|
||||||
|
href={`/library?page=1&query=${query}\
|
||||||
|
&sort=0&primary=true&secondary=true&subitems=true&status=all`}
|
||||||
totalHits={libraryItems.estimatedTotalHits}>
|
totalHits={libraryItems.estimatedTotalHits}>
|
||||||
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
||||||
{libraryItems.hits.map((item) => (
|
{libraryItems.hits.map((item) => (
|
||||||
<PreviewCard
|
<TranslatedPreviewCard
|
||||||
key={item.id}
|
key={item.id}
|
||||||
className="w-52"
|
className="w-56"
|
||||||
href={`/library/${item.slug}`}
|
href={`/library/${item.slug}`}
|
||||||
title={item._formatted.title}
|
translations={filterHasAttributes(item._formatted.descriptions, [
|
||||||
subtitle={item._formatted.subtitle}
|
"language.data.attributes.code",
|
||||||
description={
|
] as const).map((translation) => ({
|
||||||
item._matchesPosition.descriptions &&
|
language: translation.language.data.attributes.code,
|
||||||
item._matchesPosition.descriptions.length > 0
|
title: item.title,
|
||||||
? item._formatted.descriptions?.[0]
|
subtitle: item.subtitle,
|
||||||
: undefined
|
description: containsHighlight(translation.description)
|
||||||
}
|
? translation.description
|
||||||
|
: undefined,
|
||||||
|
}))}
|
||||||
|
fallback={{ title: item._formatted.title, subtitle: item._formatted.subtitle }}
|
||||||
thumbnail={item.thumbnail?.data?.attributes}
|
thumbnail={item.thumbnail?.data?.attributes}
|
||||||
thumbnailAspectRatio="21/29.7"
|
thumbnailAspectRatio="21/29.7"
|
||||||
thumbnailRounded={false}
|
thumbnailRounded={false}
|
||||||
|
@ -201,18 +233,25 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
{isDefined(contents) && (
|
{isDefined(contents) && (
|
||||||
<SearchResultSection
|
<SearchResultSection
|
||||||
title={langui.contents}
|
title={langui.contents}
|
||||||
|
icon="workspaces"
|
||||||
href={`/contents/all?page=1&query=${query}&sort=0`}
|
href={`/contents/all?page=1&query=${query}&sort=0`}
|
||||||
totalHits={contents.estimatedTotalHits}>
|
totalHits={contents.estimatedTotalHits}>
|
||||||
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
||||||
{contents.hits.map((item) => (
|
{contents.hits.map((item) => (
|
||||||
<PreviewCard
|
<TranslatedPreviewCard
|
||||||
key={item.id}
|
key={item.id}
|
||||||
className="w-56"
|
className="w-56"
|
||||||
href={`/contents/${item.slug}`}
|
href={`/contents/${item.slug}`}
|
||||||
pre_title={item._formatted.translations?.[0]?.pre_title}
|
translations={filterHasAttributes(item._formatted.translations, [
|
||||||
title={item._formatted.translations?.[0]?.title}
|
"language.data.attributes.code",
|
||||||
subtitle={item._formatted.translations?.[0]?.subtitle}
|
] as const).map(({ displayable_description, language, ...otherAttributes }) => ({
|
||||||
description={item._formatted.translations?.[0]?.description}
|
...otherAttributes,
|
||||||
|
description: containsHighlight(displayable_description)
|
||||||
|
? displayable_description
|
||||||
|
: undefined,
|
||||||
|
language: language.data.attributes.code,
|
||||||
|
}))}
|
||||||
|
fallback={{ title: prettySlug(item.slug) }}
|
||||||
thumbnail={item.thumbnail?.data?.attributes}
|
thumbnail={item.thumbnail?.data?.attributes}
|
||||||
thumbnailAspectRatio="3/2"
|
thumbnailAspectRatio="3/2"
|
||||||
thumbnailForceAspectRatio
|
thumbnailForceAspectRatio
|
||||||
|
@ -238,7 +277,8 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
{isDefined(wikiPages) && (
|
{isDefined(wikiPages) && (
|
||||||
<SearchResultSection
|
<SearchResultSection
|
||||||
title={langui.wiki}
|
title={langui.wiki}
|
||||||
href={"/wiki"}
|
icon="travel_explore"
|
||||||
|
href={`/wiki?page=1&query=${query}`}
|
||||||
totalHits={wikiPages.estimatedTotalHits}>
|
totalHits={wikiPages.estimatedTotalHits}>
|
||||||
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
||||||
{wikiPages.hits.map((item) => (
|
{wikiPages.hits.map((item) => (
|
||||||
|
@ -288,6 +328,7 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
{isDefined(posts) && (
|
{isDefined(posts) && (
|
||||||
<SearchResultSection
|
<SearchResultSection
|
||||||
title={langui.news}
|
title={langui.news}
|
||||||
|
icon="newspaper"
|
||||||
href={`/news?page=1&query=${query}`}
|
href={`/news?page=1&query=${query}`}
|
||||||
totalHits={posts.estimatedTotalHits}>
|
totalHits={posts.estimatedTotalHits}>
|
||||||
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
||||||
|
@ -329,6 +370,7 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
{isDefined(videos) && (
|
{isDefined(videos) && (
|
||||||
<SearchResultSection
|
<SearchResultSection
|
||||||
title={langui.videos}
|
title={langui.videos}
|
||||||
|
icon="movie"
|
||||||
href={`/archives/videos?page=1&query=${query}&sort=1&gone=`}
|
href={`/archives/videos?page=1&query=${query}&sort=1&gone=`}
|
||||||
totalHits={videos.estimatedTotalHits}>
|
totalHits={videos.estimatedTotalHits}>
|
||||||
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
<div className="flex flex-wrap items-start gap-x-6 gap-y-8">
|
||||||
|
@ -370,21 +412,34 @@ export const SearchPopup = (): JSX.Element => {
|
||||||
|
|
||||||
interface SearchResultSectionProps {
|
interface SearchResultSectionProps {
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
|
icon: MaterialSymbol;
|
||||||
href: string;
|
href: string;
|
||||||
totalHits?: number;
|
totalHits?: number;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchResultSection = ({ title, href, totalHits, children }: SearchResultSectionProps) => (
|
const SearchResultSection = ({
|
||||||
|
title,
|
||||||
|
icon,
|
||||||
|
href,
|
||||||
|
totalHits,
|
||||||
|
children,
|
||||||
|
}: SearchResultSectionProps) => (
|
||||||
<>
|
<>
|
||||||
{isDefined(totalHits) && totalHits > 0 && (
|
{isDefined(totalHits) && totalHits > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-6 grid place-content-start">
|
<div className="mb-6 grid place-content-start">
|
||||||
<UpPressable className="px-6 py-4" href={href}>
|
<UpPressable
|
||||||
<p className="font-headers text-lg">{title}</p>
|
className="grid grid-cols-[auto_1fr] place-items-center gap-6 px-6 py-4"
|
||||||
{isDefined(totalHits) && totalHits > SEARCH_LIMIT && (
|
href={href}>
|
||||||
<p className="text-sm">{`(showing ${SEARCH_LIMIT} out of ${totalHits} results)`}</p>
|
<Ico icon={icon} className="!text-3xl" isFilled />
|
||||||
)}
|
<div>
|
||||||
|
<p className="font-headers text-lg">{title}</p>
|
||||||
|
{isDefined(totalHits) && totalHits > SEARCH_LIMIT && (
|
||||||
|
/* TODO: Langui */
|
||||||
|
<p className="text-sm">{`(showing ${SEARCH_LIMIT} out of ${totalHits} results)`}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</UpPressable>
|
</UpPressable>
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -123,8 +123,8 @@ const Channel = ({ channel, ...otherProps }: Props): JSX.Element => {
|
||||||
"duration",
|
"duration",
|
||||||
"description",
|
"description",
|
||||||
],
|
],
|
||||||
|
attributesToHighlight: ["title", "channel", "description"],
|
||||||
attributesToCrop: ["description"],
|
attributesToCrop: ["description"],
|
||||||
attributesToHighlight: ["*"],
|
|
||||||
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
|
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
|
||||||
filter: [onlyShowGone ? "gone = true" : "", `channel_uid = ${channel.uid}`],
|
filter: [onlyShowGone ? "gone = true" : "", `channel_uid = ${channel.uid}`],
|
||||||
});
|
});
|
||||||
|
@ -147,7 +147,6 @@ const Channel = ({ channel, ...otherProps }: Props): JSX.Element => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (router.isReady) {
|
if (router.isReady) {
|
||||||
console.log(router.query);
|
|
||||||
if (isDefined(router.query.page)) setPage(router.query.page);
|
if (isDefined(router.query.page)) setPage(router.query.page);
|
||||||
if (isDefined(router.query.query)) setQuery(router.query.query);
|
if (isDefined(router.query.query)) setQuery(router.query.query);
|
||||||
if (isDefined(router.query.sort)) setSortingMethod(router.query.sort);
|
if (isDefined(router.query.sort)) setSortingMethod(router.query.sort);
|
||||||
|
|
|
@ -117,8 +117,8 @@ const Videos = ({ ...otherProps }: Props): JSX.Element => {
|
||||||
"duration",
|
"duration",
|
||||||
"description",
|
"description",
|
||||||
],
|
],
|
||||||
|
attributesToHighlight: ["title", "channel", "description"],
|
||||||
attributesToCrop: ["description"],
|
attributesToCrop: ["description"],
|
||||||
attributesToHighlight: ["*"],
|
|
||||||
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
|
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
|
||||||
filter: onlyShowGone ? ["gone = true"] : undefined,
|
filter: onlyShowGone ? ["gone = true"] : undefined,
|
||||||
});
|
});
|
||||||
|
@ -141,7 +141,6 @@ const Videos = ({ ...otherProps }: Props): JSX.Element => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (router.isReady) {
|
if (router.isReady) {
|
||||||
console.log(router.query);
|
|
||||||
if (isDefined(router.query.page)) setPage(router.query.page);
|
if (isDefined(router.query.page)) setPage(router.query.page);
|
||||||
if (isDefined(router.query.query)) setQuery(router.query.query);
|
if (isDefined(router.query.query)) setQuery(router.query.query);
|
||||||
if (isDefined(router.query.sort)) setSortingMethod(router.query.sort);
|
if (isDefined(router.query.sort)) setSortingMethod(router.query.sort);
|
||||||
|
|
|
@ -109,7 +109,8 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
|
||||||
<h2 className="text-2xl">{langui.channel}</h2>
|
<h2 className="text-2xl">{langui.channel}</h2>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
href={`/archives/videos/c/${video.channel.data.attributes.uid}?page=1&query=&sort=1&gone=`}
|
href={`/archives/videos/c/${video.channel.data.attributes.uid}\
|
||||||
|
?page=1&query=&sort=1&gone=`}
|
||||||
text={video.channel.data.attributes.title}
|
text={video.channel.data.attributes.title}
|
||||||
/>
|
/>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -88,16 +88,15 @@ const Contents = (props: Props): JSX.Element => {
|
||||||
const fetchPosts = async () => {
|
const fetchPosts = async () => {
|
||||||
const currentSortingMethod = sortingMethods[sortingMethod];
|
const currentSortingMethod = sortingMethods[sortingMethod];
|
||||||
const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, {
|
const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, {
|
||||||
attributesToCrop: ["translations.description"],
|
attributesToRetrieve: ["translations", "id", "slug", "categories", "type", "thumbnail"],
|
||||||
|
attributesToHighlight: ["translations"],
|
||||||
|
attributesToCrop: ["translations.displayable_description"],
|
||||||
hitsPerPage: 25,
|
hitsPerPage: 25,
|
||||||
page,
|
page,
|
||||||
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
|
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
|
||||||
});
|
});
|
||||||
searchResult.hits = searchResult.hits.map((item) => {
|
searchResult.hits = searchResult.hits.map((item) => {
|
||||||
if (
|
if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) {
|
||||||
Object.keys(item._matchesPosition).filter((match) => match.startsWith("translations"))
|
|
||||||
.length > 0
|
|
||||||
) {
|
|
||||||
item._formatted.translations = filterDefined(item._formatted.translations).filter(
|
item._formatted.translations = filterDefined(item._formatted.translations).filter(
|
||||||
(translation) => containsHighlight(JSON.stringify(translation))
|
(translation) => containsHighlight(JSON.stringify(translation))
|
||||||
);
|
);
|
||||||
|
@ -212,9 +211,11 @@ const Contents = (props: Props): JSX.Element => {
|
||||||
href={`/contents/${item.slug}`}
|
href={`/contents/${item.slug}`}
|
||||||
translations={filterHasAttributes(item._formatted.translations, [
|
translations={filterHasAttributes(item._formatted.translations, [
|
||||||
"language.data.attributes.code",
|
"language.data.attributes.code",
|
||||||
] as const).map(({ description, language, ...otherAttributes }) => ({
|
] as const).map(({ displayable_description, language, ...otherAttributes }) => ({
|
||||||
...otherAttributes,
|
...otherAttributes,
|
||||||
description: containsHighlight(description) ? description : undefined,
|
description: containsHighlight(displayable_description)
|
||||||
|
? displayable_description
|
||||||
|
: undefined,
|
||||||
language: language.data.attributes.code,
|
language: language.data.attributes.code,
|
||||||
}))}
|
}))}
|
||||||
fallback={{ title: prettySlug(item.slug) }}
|
fallback={{ title: prettySlug(item.slug) }}
|
||||||
|
|
|
@ -14,17 +14,23 @@ import { TextInput } from "components/Inputs/TextInput";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
|
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
|
||||||
import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
||||||
import { filterDefined, isDefined, isDefinedAndNotEmpty, isUndefined } from "helpers/asserts";
|
import {
|
||||||
|
filterDefined,
|
||||||
|
filterHasAttributes,
|
||||||
|
isDefined,
|
||||||
|
isDefinedAndNotEmpty,
|
||||||
|
isUndefined,
|
||||||
|
} from "helpers/asserts";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
import { getLangui } from "graphql/fetchLocalData";
|
import { getLangui } from "graphql/fetchLocalData";
|
||||||
import { sendAnalytics } from "helpers/analytics";
|
import { sendAnalytics } from "helpers/analytics";
|
||||||
import { atoms } from "contexts/atoms";
|
import { atoms } from "contexts/atoms";
|
||||||
import { useAtomGetter } from "helpers/atoms";
|
import { useAtomGetter } from "helpers/atoms";
|
||||||
import { CustomSearchResponse, meiliSearch } from "helpers/search";
|
import { containsHighlight, CustomSearchResponse, meiliSearch } from "helpers/search";
|
||||||
import { MeiliIndices, MeiliLibraryItem } from "shared/meilisearch-graphql-typings/meiliTypes";
|
import { MeiliIndices, MeiliLibraryItem } from "shared/meilisearch-graphql-typings/meiliTypes";
|
||||||
import { useTypedRouter } from "hooks/useTypedRouter";
|
import { useTypedRouter } from "hooks/useTypedRouter";
|
||||||
import { PreviewCard } from "components/PreviewCard";
|
import { TranslatedPreviewCard } from "components/PreviewCard";
|
||||||
import { prettyItemSubType } from "helpers/formatters";
|
import { prettyItemSubType } from "helpers/formatters";
|
||||||
import { isUntangibleGroupItem } from "helpers/libraryItem";
|
import { isUntangibleGroupItem } from "helpers/libraryItem";
|
||||||
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
|
||||||
|
@ -156,18 +162,27 @@ const Library = (props: Props): JSX.Element => {
|
||||||
const searchResult = await meiliSearch(MeiliIndices.LIBRARY_ITEM, query, {
|
const searchResult = await meiliSearch(MeiliIndices.LIBRARY_ITEM, query, {
|
||||||
hitsPerPage: 25,
|
hitsPerPage: 25,
|
||||||
page,
|
page,
|
||||||
|
attributesToRetrieve: [
|
||||||
|
"title",
|
||||||
|
"subtitle",
|
||||||
|
"descriptions",
|
||||||
|
"id",
|
||||||
|
"slug",
|
||||||
|
"thumbnail",
|
||||||
|
"release_date",
|
||||||
|
"price",
|
||||||
|
"categories",
|
||||||
|
"metadata",
|
||||||
|
],
|
||||||
|
attributesToHighlight: ["title", "subtitle", "descriptions"],
|
||||||
attributesToCrop: ["descriptions"],
|
attributesToCrop: ["descriptions"],
|
||||||
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
|
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
|
||||||
filter,
|
filter,
|
||||||
});
|
});
|
||||||
searchResult.hits = searchResult.hits.map((item) => {
|
searchResult.hits = searchResult.hits.map((item) => {
|
||||||
if (
|
if (Object.keys(item._matchesPosition).some((match) => match.startsWith("descriptions"))) {
|
||||||
isDefined(item._formatted) &&
|
|
||||||
item._matchesPosition.descriptions &&
|
|
||||||
item._matchesPosition.descriptions.length > 0
|
|
||||||
) {
|
|
||||||
item._formatted.descriptions = filterDefined(item._formatted.descriptions).filter(
|
item._formatted.descriptions = filterDefined(item._formatted.descriptions).filter(
|
||||||
(description) => description.includes("</mark>")
|
(description) => containsHighlight(JSON.stringify(description))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
|
@ -188,16 +203,17 @@ const Library = (props: Props): JSX.Element => {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (router.isReady) console.log(router.query, filterUserStatus);
|
if (router.isReady) {
|
||||||
router.updateQuery({
|
router.updateQuery({
|
||||||
page,
|
page,
|
||||||
query,
|
query,
|
||||||
sort: sortingMethod,
|
sort: sortingMethod,
|
||||||
primary: showPrimaryItems,
|
primary: showPrimaryItems,
|
||||||
secondary: showSecondaryItems,
|
secondary: showSecondaryItems,
|
||||||
subitems: showSubitems,
|
subitems: showSubitems,
|
||||||
status: fromLibraryItemUserStatusToString(filterUserStatus),
|
status: fromLibraryItemUserStatusToString(filterUserStatus),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [
|
}, [
|
||||||
page,
|
page,
|
||||||
|
@ -212,7 +228,6 @@ const Library = (props: Props): JSX.Element => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (router.isReady) {
|
if (router.isReady) {
|
||||||
console.log(router.query);
|
|
||||||
if (isDefined(router.query.page)) setPage(router.query.page);
|
if (isDefined(router.query.page)) setPage(router.query.page);
|
||||||
if (isDefined(router.query.query)) setQuery(router.query.query);
|
if (isDefined(router.query.query)) setQuery(router.query.query);
|
||||||
if (isDefined(router.query.sort)) setSortingMethod(router.query.sort);
|
if (isDefined(router.query.sort)) setSortingMethod(router.query.sort);
|
||||||
|
@ -387,16 +402,20 @@ const Library = (props: Props): JSX.Element => {
|
||||||
className="grid grid-cols-[repeat(auto-fill,_minmax(12rem,1fr))] items-end
|
className="grid grid-cols-[repeat(auto-fill,_minmax(12rem,1fr))] items-end
|
||||||
gap-x-6 gap-y-8">
|
gap-x-6 gap-y-8">
|
||||||
{libraryItems?.hits.map((item) => (
|
{libraryItems?.hits.map((item) => (
|
||||||
<PreviewCard
|
<TranslatedPreviewCard
|
||||||
key={item.id}
|
key={item.id}
|
||||||
href={`/library/${item.slug}`}
|
href={`/library/${item.slug}`}
|
||||||
title={item._formatted.title}
|
translations={filterHasAttributes(item._formatted.descriptions, [
|
||||||
subtitle={item._formatted.subtitle}
|
"language.data.attributes.code",
|
||||||
description={
|
] as const).map((translation) => ({
|
||||||
item._matchesPosition.descriptions && item._matchesPosition.descriptions.length > 0
|
language: translation.language.data.attributes.code,
|
||||||
? item._formatted.descriptions?.[0]
|
title: item.title,
|
||||||
: undefined
|
subtitle: item.subtitle,
|
||||||
}
|
description: containsHighlight(translation.description)
|
||||||
|
? translation.description
|
||||||
|
: undefined,
|
||||||
|
}))}
|
||||||
|
fallback={{ title: item._formatted.title, subtitle: item._formatted.subtitle }}
|
||||||
thumbnail={item.thumbnail?.data?.attributes}
|
thumbnail={item.thumbnail?.data?.attributes}
|
||||||
thumbnailAspectRatio="21/29.7"
|
thumbnailAspectRatio="21/29.7"
|
||||||
thumbnailRounded={false}
|
thumbnailRounded={false}
|
||||||
|
|
|
@ -11,7 +11,12 @@ import { WithLabel } from "components/Inputs/WithLabel";
|
||||||
import { TextInput } from "components/Inputs/TextInput";
|
import { TextInput } from "components/Inputs/TextInput";
|
||||||
import { Button } from "components/Inputs/Button";
|
import { Button } from "components/Inputs/Button";
|
||||||
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
|
import { useDeviceSupportsHover } from "hooks/useMediaQuery";
|
||||||
import { filterHasAttributes, isDefined, isDefinedAndNotEmpty } from "helpers/asserts";
|
import {
|
||||||
|
filterDefined,
|
||||||
|
filterHasAttributes,
|
||||||
|
isDefined,
|
||||||
|
isDefinedAndNotEmpty,
|
||||||
|
} from "helpers/asserts";
|
||||||
import { getOpenGraph } from "helpers/openGraph";
|
import { getOpenGraph } from "helpers/openGraph";
|
||||||
import { TranslatedPreviewCard } from "components/PreviewCard";
|
import { TranslatedPreviewCard } from "components/PreviewCard";
|
||||||
import { HorizontalLine } from "components/HorizontalLine";
|
import { HorizontalLine } from "components/HorizontalLine";
|
||||||
|
@ -78,6 +83,14 @@ const News = ({ ...otherProps }: Props): JSX.Element => {
|
||||||
sort: ["sortable_date:desc"],
|
sort: ["sortable_date:desc"],
|
||||||
filter: ["hidden = false"],
|
filter: ["hidden = false"],
|
||||||
});
|
});
|
||||||
|
searchResult.hits = searchResult.hits.map((item) => {
|
||||||
|
if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) {
|
||||||
|
item._formatted.translations = filterDefined(item._formatted.translations).filter(
|
||||||
|
(translation) => JSON.stringify(translation).includes("</mark>")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
setPosts(searchResult);
|
setPosts(searchResult);
|
||||||
};
|
};
|
||||||
fetchPosts();
|
fetchPosts();
|
||||||
|
|
|
@ -11,9 +11,8 @@ import {
|
||||||
WikiPageAttributesFragment,
|
WikiPageAttributesFragment,
|
||||||
} from "./generated";
|
} from "./generated";
|
||||||
|
|
||||||
export interface MeiliLibraryItem extends Omit<LibraryItemAttributesFragment, "descriptions"> {
|
export interface MeiliLibraryItem extends LibraryItemAttributesFragment {
|
||||||
id: string;
|
id: string;
|
||||||
descriptions: string[];
|
|
||||||
sortable_name: string;
|
sortable_name: string;
|
||||||
sortable_price: number | undefined;
|
sortable_price: number | undefined;
|
||||||
sortable_date: number | undefined;
|
sortable_date: number | undefined;
|
||||||
|
@ -23,20 +22,12 @@ export interface MeiliLibraryItem extends Omit<LibraryItemAttributesFragment, "d
|
||||||
export interface MeiliContent
|
export interface MeiliContent
|
||||||
extends Omit<ContentAttributesFragment, "translations" | "updatedAt"> {
|
extends Omit<ContentAttributesFragment, "translations" | "updatedAt"> {
|
||||||
id: string;
|
id: string;
|
||||||
translations?: Array<{
|
translations: (Omit<
|
||||||
__typename?: "ComponentTranslationsTitle";
|
NonNullable<NonNullable<ContentAttributesFragment["translations"]>[number]>,
|
||||||
pre_title?: string | null;
|
"text_set" | "description"
|
||||||
title: string;
|
> & {
|
||||||
subtitle?: string | null;
|
displayable_description?: string | null;
|
||||||
description?: string | null;
|
})[];
|
||||||
language?: {
|
|
||||||
__typename?: "LanguageEntityResponse";
|
|
||||||
data?: {
|
|
||||||
__typename?: "LanguageEntity";
|
|
||||||
attributes?: { __typename?: "Language"; code: string } | null;
|
|
||||||
} | null;
|
|
||||||
} | null;
|
|
||||||
} | null> | null;
|
|
||||||
sortable_updated_date: number;
|
sortable_updated_date: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue