341 lines
11 KiB
TypeScript
341 lines
11 KiB
TypeScript
import { GetStaticProps, GetStaticPaths, GetStaticPathsResult } from "next";
|
|
import { useCallback, useMemo } from "react";
|
|
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
|
import { getReadySdk } from "graphql/sdk";
|
|
import { isDefined, filterHasAttributes } from "helpers/others";
|
|
import { ChronicleWithTranslations } from "helpers/types";
|
|
import { AppLayout, AppLayoutRequired } from "components/AppLayout";
|
|
import { useSmartLanguage } from "hooks/useSmartLanguage";
|
|
import { ContentPanel } from "components/Panels/ContentPanel";
|
|
import { Markdawn } from "components/Markdown/Markdawn";
|
|
import { SubPanel } from "components/Panels/SubPanel";
|
|
import { ThumbnailHeader } from "components/ThumbnailHeader";
|
|
import { HorizontalLine } from "components/HorizontalLine";
|
|
import { GetChroniclesChaptersQuery } from "graphql/generated";
|
|
import { prettyInlineTitle, prettySlug } from "helpers/formatters";
|
|
import {
|
|
ReturnButton,
|
|
ReturnButtonType,
|
|
} from "components/PanelComponents/ReturnButton";
|
|
import { TranslatedChroniclesList } from "components/Translated";
|
|
import { Icon } from "components/Ico";
|
|
import { getOpenGraph } from "helpers/openGraph";
|
|
import {
|
|
getDefaultPreferredLanguages,
|
|
staticSmartLanguage,
|
|
} from "helpers/locales";
|
|
import { getDescription } from "helpers/description";
|
|
|
|
/*
|
|
* ╭────────╮
|
|
* ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
|
|
*/
|
|
|
|
interface Props extends AppStaticProps, AppLayoutRequired {
|
|
chronicle: ChronicleWithTranslations;
|
|
chapters: NonNullable<
|
|
GetChroniclesChaptersQuery["chroniclesChapters"]
|
|
>["data"];
|
|
}
|
|
|
|
const Chronicle = ({
|
|
chronicle,
|
|
chapters,
|
|
langui,
|
|
languages,
|
|
...otherProps
|
|
}: Props): JSX.Element => {
|
|
const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] =
|
|
useSmartLanguage({
|
|
items: chronicle.translations,
|
|
languages: languages,
|
|
languageExtractor: useCallback(
|
|
(item: ChronicleWithTranslations["translations"][number]) =>
|
|
item?.language?.data?.attributes?.code,
|
|
[]
|
|
),
|
|
});
|
|
|
|
const primaryContent = useMemo<
|
|
NonNullable<
|
|
ChronicleWithTranslations["contents"]
|
|
>["data"][number]["attributes"]
|
|
>(
|
|
() =>
|
|
filterHasAttributes(chronicle.contents?.data, [
|
|
"attributes.translations",
|
|
] as const)[0]?.attributes,
|
|
[chronicle.contents?.data]
|
|
);
|
|
|
|
const [
|
|
selectedContentTranslation,
|
|
ContentLanguageSwitcher,
|
|
ContentLanguageSwitcherProps,
|
|
] = useSmartLanguage({
|
|
items: primaryContent?.translations ?? [],
|
|
languages: languages,
|
|
languageExtractor: useCallback(
|
|
(
|
|
item: NonNullable<
|
|
NonNullable<
|
|
NonNullable<
|
|
ChronicleWithTranslations["contents"]
|
|
>["data"][number]["attributes"]
|
|
>["translations"]
|
|
>[number]
|
|
) => item?.language?.data?.attributes?.code,
|
|
[]
|
|
),
|
|
});
|
|
|
|
const contentPanel = useMemo(
|
|
() => (
|
|
<ContentPanel>
|
|
<ReturnButton
|
|
displayOn={ReturnButtonType.Mobile}
|
|
href="/chronicles"
|
|
title={langui.chronicles}
|
|
langui={langui}
|
|
className="mb-10"
|
|
/>
|
|
|
|
{isDefined(selectedTranslation) ? (
|
|
<>
|
|
<h1 className="mb-16 text-center text-3xl">
|
|
{selectedTranslation.title}
|
|
</h1>
|
|
|
|
{languageSwitcherProps.locales.size > 1 && (
|
|
<LanguageSwitcher {...languageSwitcherProps} />
|
|
)}
|
|
|
|
{isDefined(selectedTranslation.body) && (
|
|
<Markdawn text={selectedTranslation.body.body} />
|
|
)}
|
|
</>
|
|
) : (
|
|
<>
|
|
{selectedContentTranslation && (
|
|
<>
|
|
<ThumbnailHeader
|
|
pre_title={selectedContentTranslation.pre_title}
|
|
title={selectedContentTranslation.title}
|
|
subtitle={selectedContentTranslation.subtitle}
|
|
languageSwitcher={
|
|
ContentLanguageSwitcherProps.locales.size > 1 ? (
|
|
<ContentLanguageSwitcher
|
|
{...ContentLanguageSwitcherProps}
|
|
/>
|
|
) : undefined
|
|
}
|
|
categories={primaryContent?.categories}
|
|
type={primaryContent?.type}
|
|
description={selectedContentTranslation.description}
|
|
thumbnail={primaryContent?.thumbnail?.data?.attributes}
|
|
langui={langui}
|
|
/>
|
|
|
|
<HorizontalLine />
|
|
|
|
{selectedContentTranslation.text_set?.text && (
|
|
<Markdawn text={selectedContentTranslation.text_set.text} />
|
|
)}
|
|
</>
|
|
)}
|
|
</>
|
|
)}
|
|
</ContentPanel>
|
|
),
|
|
[
|
|
selectedTranslation,
|
|
languageSwitcherProps,
|
|
LanguageSwitcher,
|
|
selectedContentTranslation,
|
|
ContentLanguageSwitcherProps,
|
|
ContentLanguageSwitcher,
|
|
primaryContent?.categories,
|
|
primaryContent?.type,
|
|
primaryContent?.thumbnail?.data?.attributes,
|
|
langui,
|
|
]
|
|
);
|
|
|
|
const subPanel = useMemo(
|
|
() => (
|
|
<SubPanel>
|
|
<ReturnButton
|
|
displayOn={ReturnButtonType.Desktop}
|
|
href="/chronicles"
|
|
title={langui.chronicles}
|
|
langui={langui}
|
|
horizontalLine
|
|
/>
|
|
<div className="grid gap-16">
|
|
{filterHasAttributes(chapters, [
|
|
"attributes.chronicles",
|
|
"id",
|
|
] as const).map((chapter) => (
|
|
<TranslatedChroniclesList
|
|
key={chapter.id}
|
|
chronicles={chapter.attributes.chronicles.data}
|
|
translations={filterHasAttributes(chapter.attributes.titles, [
|
|
"language.data.attributes.code",
|
|
] as const).map((translation) => ({
|
|
title: translation.title,
|
|
language: translation.language.data.attributes.code,
|
|
}))}
|
|
fallback={{ title: prettySlug(chapter.attributes.slug) }}
|
|
currentSlug={chronicle.slug}
|
|
/>
|
|
))}
|
|
</div>
|
|
</SubPanel>
|
|
),
|
|
[chapters, chronicle.slug, langui]
|
|
);
|
|
|
|
return (
|
|
<AppLayout
|
|
contentPanel={contentPanel}
|
|
subPanel={subPanel}
|
|
langui={langui}
|
|
languages={languages}
|
|
subPanelIcon={Icon.FormatListNumbered}
|
|
{...otherProps}
|
|
/>
|
|
);
|
|
};
|
|
export default Chronicle;
|
|
|
|
/*
|
|
* ╭──────────────────────╮
|
|
* ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
|
|
*/
|
|
|
|
export const getStaticProps: GetStaticProps = async (context) => {
|
|
const sdk = getReadySdk();
|
|
const slug =
|
|
context.params && isDefined(context.params.slug)
|
|
? context.params.slug.toString()
|
|
: "";
|
|
const chronicle = await sdk.getChronicle({
|
|
language_code: context.locale ?? "en",
|
|
slug: slug,
|
|
});
|
|
const chronicles = await sdk.getChroniclesChapters();
|
|
if (
|
|
!chronicle.chronicles?.data[0]?.attributes?.translations ||
|
|
!chronicles.chroniclesChapters?.data
|
|
)
|
|
return { notFound: true };
|
|
const appStaticProps = await getAppStaticProps(context);
|
|
|
|
const { title, description } = (() => {
|
|
if (context.locale && context.locales) {
|
|
if (
|
|
chronicle.chronicles.data[0].attributes.contents?.data[0]?.attributes
|
|
?.translations
|
|
) {
|
|
const selectedContentTranslation = staticSmartLanguage({
|
|
items:
|
|
chronicle.chronicles.data[0].attributes.contents.data[0].attributes
|
|
.translations,
|
|
languageExtractor: (item) => item.language?.data?.attributes?.code,
|
|
preferredLanguages: getDefaultPreferredLanguages(
|
|
context.locale,
|
|
context.locales
|
|
),
|
|
});
|
|
if (selectedContentTranslation) {
|
|
return {
|
|
title: prettyInlineTitle(
|
|
selectedContentTranslation.pre_title,
|
|
selectedContentTranslation.title,
|
|
selectedContentTranslation.subtitle
|
|
),
|
|
description: getDescription(
|
|
selectedContentTranslation.description,
|
|
{
|
|
[appStaticProps.langui.type ?? "Type"]: [
|
|
chronicle.chronicles.data[0].attributes.contents.data[0]
|
|
.attributes.type?.data?.attributes?.titles?.[0]?.title,
|
|
],
|
|
[appStaticProps.langui.categories ?? "Categories"]:
|
|
filterHasAttributes(
|
|
chronicle.chronicles.data[0].attributes.contents.data[0]
|
|
.attributes.categories?.data,
|
|
["attributes"] as const
|
|
).map((category) => category.attributes.short),
|
|
}
|
|
),
|
|
};
|
|
}
|
|
} else {
|
|
const selectedTranslation = staticSmartLanguage({
|
|
items: chronicle.chronicles.data[0].attributes.translations,
|
|
languageExtractor: (item) => item.language?.data?.attributes?.code,
|
|
preferredLanguages: getDefaultPreferredLanguages(
|
|
context.locale,
|
|
context.locales
|
|
),
|
|
});
|
|
if (selectedTranslation) {
|
|
return {
|
|
title: selectedTranslation.title,
|
|
description: selectedTranslation.summary,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
title: prettySlug(chronicle.chronicles.data[0].attributes.slug),
|
|
description: undefined,
|
|
};
|
|
})();
|
|
|
|
const thumbnail =
|
|
chronicle.chronicles.data[0].attributes.translations.length === 0
|
|
? chronicle.chronicles.data[0].attributes.contents?.data[0]?.attributes
|
|
?.thumbnail?.data?.attributes
|
|
: undefined;
|
|
|
|
const props: Props = {
|
|
...appStaticProps,
|
|
chronicle: chronicle.chronicles.data[0]
|
|
.attributes as ChronicleWithTranslations,
|
|
chapters: chronicles.chroniclesChapters.data,
|
|
openGraph: getOpenGraph(
|
|
appStaticProps.langui,
|
|
title,
|
|
description,
|
|
thumbnail
|
|
),
|
|
};
|
|
return {
|
|
props: props,
|
|
};
|
|
};
|
|
|
|
// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
|
|
|
export const getStaticPaths: GetStaticPaths = async (context) => {
|
|
const sdk = getReadySdk();
|
|
const contents = await sdk.getChroniclesSlugs();
|
|
const paths: GetStaticPathsResult["paths"] = [];
|
|
filterHasAttributes(contents.chronicles?.data, ["attributes"] as const).map(
|
|
(wikiPage) => {
|
|
context.locales?.map((local) =>
|
|
paths.push({
|
|
params: { slug: wikiPage.attributes.slug },
|
|
locale: local,
|
|
})
|
|
);
|
|
}
|
|
);
|
|
return {
|
|
paths,
|
|
fallback: "blocking",
|
|
};
|
|
};
|