Extracted language selector logic into a custom hook
This commit is contained in:
parent
6f69aaf236
commit
85106d1735
@ -1,15 +1,17 @@
|
||||
import Chip from "components/Chip";
|
||||
import Img, { getAssetURL, ImageQuality } from "components/Img";
|
||||
import Img, {
|
||||
getAssetFilename,
|
||||
getAssetURL,
|
||||
ImageQuality,
|
||||
} from "components/Img";
|
||||
import Button from "components/Inputs/Button";
|
||||
import LanguageSwitcher from "components/Inputs/LanguageSwitcher";
|
||||
import RecorderChip from "components/RecorderChip";
|
||||
import ToolTip from "components/ToolTip";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { GetLibraryItemScansQuery } from "graphql/generated";
|
||||
import { useRouter } from "next/router";
|
||||
import useSmartLanguage from "hooks/useSmartLanguage";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getPreferredLanguage, getStatusDescription } from "queries/helpers";
|
||||
import { Dispatch, SetStateAction, useEffect, useMemo, useState } from "react";
|
||||
import { getStatusDescription, isInteger } from "queries/helpers";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
interface Props {
|
||||
setLightboxOpen: Dispatch<SetStateAction<boolean>>;
|
||||
@ -62,52 +64,28 @@ export default function ScanSet(props: Props): JSX.Element {
|
||||
langui,
|
||||
content,
|
||||
} = props;
|
||||
const appLayout = useAppLayout();
|
||||
const router = useRouter();
|
||||
|
||||
const [selectedScan, setSelectedScan] = useState<Props["scanSet"][number]>();
|
||||
const scanLocales: Map<string, number> = new Map();
|
||||
|
||||
const [selectedScanIndex, setSelectedScanIndex] = useState<
|
||||
number | undefined
|
||||
>();
|
||||
|
||||
scanSet.map((scan, index) => {
|
||||
if (scan?.language?.data?.attributes?.code) {
|
||||
scanLocales.set(scan.language.data.attributes.code, index);
|
||||
}
|
||||
});
|
||||
|
||||
useMemo(() => {
|
||||
setSelectedScanIndex(
|
||||
getPreferredLanguage(
|
||||
appLayout.preferredLanguages ?? [router.locale],
|
||||
scanLocales
|
||||
)
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [appLayout.preferredLanguages]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedScanIndex !== undefined) {
|
||||
const selectedScanSet = scanSet[selectedScanIndex];
|
||||
selectedScanSet?.pages?.data.sort((a, b) => {
|
||||
function isInteger(value: string): boolean {
|
||||
// eslint-disable-next-line require-unicode-regexp
|
||||
return /^\d+$/.test(value);
|
||||
}
|
||||
function getFileName(path: string): string {
|
||||
let result = path.split("/");
|
||||
result = result[result.length - 1].split(".");
|
||||
result = result
|
||||
.splice(0, result.length - 1)
|
||||
.join(".")
|
||||
.split("_");
|
||||
return result[0];
|
||||
}
|
||||
const [selectedScan, LanguageSwitcher] = useSmartLanguage({
|
||||
items: scanSet,
|
||||
languages: languages,
|
||||
languageExtractor: (item) => item?.language?.data?.attributes?.code,
|
||||
transform: (item) => {
|
||||
item?.pages?.data.sort((a, b) => {
|
||||
if (a.attributes?.url && b.attributes?.url) {
|
||||
const aName = getFileName(a.attributes.url);
|
||||
const bName = getFileName(b.attributes.url);
|
||||
let aName = getAssetFilename(a.attributes.url);
|
||||
let bName = getAssetFilename(b.attributes.url);
|
||||
|
||||
/*
|
||||
* If the number is a succession of 0s, make the number
|
||||
* incrementally smaller than 0 (i.e: 00 becomes -1)
|
||||
*/
|
||||
if (aName.replaceAll("0", "").length === 0) {
|
||||
aName = (1 - aName.length).toString(10);
|
||||
}
|
||||
if (bName.replaceAll("0", "").length === 0) {
|
||||
bName = (1 - bName.length).toString(10);
|
||||
}
|
||||
|
||||
if (isInteger(aName) && isInteger(bName)) {
|
||||
return parseInt(aName, 10) - parseInt(bName, 10);
|
||||
}
|
||||
@ -115,10 +93,9 @@ export default function ScanSet(props: Props): JSX.Element {
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
setSelectedScan(selectedScanSet);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedScanIndex]);
|
||||
return item;
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -144,12 +121,7 @@ export default function ScanSet(props: Props): JSX.Element {
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<LanguageSwitcher
|
||||
languages={languages}
|
||||
locales={scanLocales}
|
||||
localesIndex={selectedScanIndex}
|
||||
setLocalesIndex={setSelectedScanIndex}
|
||||
/>
|
||||
<LanguageSwitcher />
|
||||
|
||||
<div className="grid place-items-center place-content-center">
|
||||
<p className="font-headers">{langui.status}:</p>
|
||||
|
@ -1,17 +1,15 @@
|
||||
import Chip from "components/Chip";
|
||||
import Img, { getAssetURL, ImageQuality } from "components/Img";
|
||||
import LanguageSwitcher from "components/Inputs/LanguageSwitcher";
|
||||
import RecorderChip from "components/RecorderChip";
|
||||
import ToolTip from "components/ToolTip";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import {
|
||||
GetLibraryItemScansQuery,
|
||||
UploadImageFragment,
|
||||
} from "graphql/generated";
|
||||
import { useRouter } from "next/router";
|
||||
import useSmartLanguage from "hooks/useSmartLanguage";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getPreferredLanguage, getStatusDescription } from "queries/helpers";
|
||||
import { Dispatch, SetStateAction, useEffect, useMemo, useState } from "react";
|
||||
import { getStatusDescription } from "queries/helpers";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
interface Props {
|
||||
setLightboxOpen: Dispatch<SetStateAction<boolean>>;
|
||||
@ -40,38 +38,13 @@ export default function ScanSetCover(props: Props): JSX.Element {
|
||||
languages,
|
||||
langui,
|
||||
} = props;
|
||||
const appLayout = useAppLayout();
|
||||
const router = useRouter();
|
||||
|
||||
const [selectedScan, setSelectedScan] = useState<Props["images"][number]>();
|
||||
const scanLocales: Map<string, number> = new Map();
|
||||
|
||||
const [selectedScanIndex, setSelectedScanIndex] = useState<
|
||||
number | undefined
|
||||
>();
|
||||
|
||||
images.map((scan, index) => {
|
||||
if (scan?.language?.data?.attributes?.code) {
|
||||
scanLocales.set(scan.language.data.attributes.code, index);
|
||||
}
|
||||
const [selectedScan, LanguageSwitcher] = useSmartLanguage({
|
||||
items: images,
|
||||
languages: languages,
|
||||
languageExtractor: (item) => item?.language?.data?.attributes?.code,
|
||||
});
|
||||
|
||||
useMemo(() => {
|
||||
setSelectedScanIndex(
|
||||
getPreferredLanguage(
|
||||
appLayout.preferredLanguages ?? [router.locale],
|
||||
scanLocales
|
||||
)
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [appLayout.preferredLanguages]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedScanIndex !== undefined)
|
||||
setSelectedScan(images[selectedScanIndex]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedScanIndex]);
|
||||
|
||||
const coverImages: UploadImageFragment[] = [];
|
||||
if (selectedScan?.obi_belt?.full?.data?.attributes)
|
||||
coverImages.push(selectedScan.obi_belt.full.data.attributes);
|
||||
@ -105,12 +78,7 @@ export default function ScanSetCover(props: Props): JSX.Element {
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row flex-wrap gap-4 pb-6 place-items-center">
|
||||
<LanguageSwitcher
|
||||
languages={languages}
|
||||
locales={scanLocales}
|
||||
localesIndex={selectedScanIndex}
|
||||
setLocalesIndex={setSelectedScanIndex}
|
||||
/>
|
||||
<LanguageSwitcher />
|
||||
|
||||
<div className="grid place-items-center place-content-center">
|
||||
<p className="font-headers">{langui.status}:</p>
|
||||
|
@ -1,17 +1,10 @@
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { GetPostQuery } from "graphql/generated";
|
||||
import { useRouter } from "next/router";
|
||||
import useSmartLanguage from "hooks/useSmartLanguage";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import {
|
||||
getPreferredLanguage,
|
||||
getStatusDescription,
|
||||
prettySlug,
|
||||
} from "queries/helpers";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { getStatusDescription, prettySlug } from "queries/helpers";
|
||||
import AppLayout from "./AppLayout";
|
||||
import Chip from "./Chip";
|
||||
import HorizontalLine from "./HorizontalLine";
|
||||
import LanguageSwitcher from "./Inputs/LanguageSwitcher";
|
||||
import Markdawn from "./Markdown/Markdawn";
|
||||
import TOC from "./Markdown/TOC";
|
||||
import ReturnButton, { ReturnButtonType } from "./PanelComponents/ReturnButton";
|
||||
@ -23,9 +16,12 @@ import ToolTip from "./ToolTip";
|
||||
|
||||
interface Props {
|
||||
post: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
>;
|
||||
langui: AppStaticProps["langui"];
|
||||
languages: AppStaticProps["languages"];
|
||||
currencies: AppStaticProps["currencies"];
|
||||
@ -56,54 +52,18 @@ export default function Post(props: Props): JSX.Element {
|
||||
} = props;
|
||||
const displayTitle = props.displayTitle ?? true;
|
||||
|
||||
const appLayout = useAppLayout();
|
||||
const router = useRouter();
|
||||
|
||||
const [selectedTranslation, setSelectedTranslation] = useState<
|
||||
| Exclude<
|
||||
Exclude<Props["post"], null | undefined>["translations"],
|
||||
null | undefined
|
||||
>[number]
|
||||
>();
|
||||
const translationLocales: Map<string, number> = new Map();
|
||||
|
||||
const [selectedTranslationIndex, setSelectedTranslationIndex] = useState<
|
||||
number | undefined
|
||||
>();
|
||||
|
||||
if (post?.translations) {
|
||||
post.translations.map((translation, index) => {
|
||||
if (translation?.language?.data?.attributes?.code) {
|
||||
translationLocales.set(
|
||||
translation.language.data.attributes.code,
|
||||
index
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
useMemo(() => {
|
||||
setSelectedTranslationIndex(
|
||||
getPreferredLanguage(
|
||||
appLayout.preferredLanguages ?? [router.locale],
|
||||
translationLocales
|
||||
)
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [appLayout.preferredLanguages]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTranslationIndex !== undefined)
|
||||
setSelectedTranslation(post?.translations?.[selectedTranslationIndex]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedTranslationIndex]);
|
||||
const [selectedTranslation, LanguageSwitcher] = useSmartLanguage({
|
||||
items: post.translations,
|
||||
languages: languages,
|
||||
languageExtractor: (item) => item?.language?.data?.attributes?.code,
|
||||
});
|
||||
|
||||
const thumbnail =
|
||||
selectedTranslation?.thumbnail?.data?.attributes ??
|
||||
post?.thumbnail?.data?.attributes;
|
||||
post.thumbnail?.data?.attributes;
|
||||
|
||||
const body = selectedTranslation?.body ?? "";
|
||||
const title = selectedTranslation?.title ?? prettySlug(post?.slug);
|
||||
const title = selectedTranslation?.title ?? prettySlug(post.slug);
|
||||
const except = selectedTranslation?.excerpt ?? "";
|
||||
|
||||
const subPanel =
|
||||
@ -137,7 +97,7 @@ export default function Post(props: Props): JSX.Element {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{post?.authors && post.authors.data.length > 0 && (
|
||||
{post.authors && post.authors.data.length > 0 && (
|
||||
<div>
|
||||
<p className="font-headers">{"Authors"}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
@ -183,15 +143,8 @@ export default function Post(props: Props): JSX.Element {
|
||||
title={title}
|
||||
description={except}
|
||||
langui={langui}
|
||||
categories={post?.categories}
|
||||
languageSwitcher={
|
||||
<LanguageSwitcher
|
||||
languages={languages}
|
||||
locales={translationLocales}
|
||||
localesIndex={selectedTranslationIndex}
|
||||
setLocalesIndex={setSelectedTranslationIndex}
|
||||
/>
|
||||
}
|
||||
categories={post.categories}
|
||||
languageSwitcher={<LanguageSwitcher />}
|
||||
/>
|
||||
|
||||
<HorizontalLine />
|
||||
@ -200,12 +153,7 @@ export default function Post(props: Props): JSX.Element {
|
||||
<>
|
||||
{displayLanguageSwitcher && (
|
||||
<div className="grid place-content-end place-items-start">
|
||||
<LanguageSwitcher
|
||||
languages={languages}
|
||||
locales={translationLocales}
|
||||
localesIndex={selectedTranslationIndex}
|
||||
setLocalesIndex={setSelectedTranslationIndex}
|
||||
/>
|
||||
<LanguageSwitcher />
|
||||
</div>
|
||||
)}
|
||||
{displayTitle && (
|
||||
|
184
src/components/PostPage.tsx
Normal file
184
src/components/PostPage.tsx
Normal file
@ -0,0 +1,184 @@
|
||||
import { GetPostQuery } from "graphql/generated";
|
||||
import useSmartLanguage from "hooks/useSmartLanguage";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getStatusDescription, prettySlug } from "queries/helpers";
|
||||
import AppLayout from "./AppLayout";
|
||||
import Chip from "./Chip";
|
||||
import HorizontalLine from "./HorizontalLine";
|
||||
import Markdawn from "./Markdown/Markdawn";
|
||||
import TOC from "./Markdown/TOC";
|
||||
import ReturnButton, { ReturnButtonType } from "./PanelComponents/ReturnButton";
|
||||
import ContentPanel from "./Panels/ContentPanel";
|
||||
import SubPanel from "./Panels/SubPanel";
|
||||
import RecorderChip from "./RecorderChip";
|
||||
import ThumbnailHeader from "./ThumbnailHeader";
|
||||
import ToolTip from "./ToolTip";
|
||||
|
||||
export type Post = Exclude<
|
||||
Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>;
|
||||
|
||||
interface Props {
|
||||
post: Post;
|
||||
langui: AppStaticProps["langui"];
|
||||
languages: AppStaticProps["languages"];
|
||||
currencies: AppStaticProps["currencies"];
|
||||
returnHref?: string;
|
||||
returnTitle?: string | null | undefined;
|
||||
displayCredits?: boolean;
|
||||
displayToc?: boolean;
|
||||
displayThumbnailHeader?: boolean;
|
||||
displayTitle?: boolean;
|
||||
displayLanguageSwitcher?: boolean;
|
||||
prependBody?: JSX.Element;
|
||||
appendBody?: JSX.Element;
|
||||
}
|
||||
|
||||
export default function PostPage(props: Props): JSX.Element {
|
||||
const {
|
||||
post,
|
||||
langui,
|
||||
languages,
|
||||
returnHref,
|
||||
returnTitle,
|
||||
displayCredits,
|
||||
displayToc,
|
||||
displayThumbnailHeader,
|
||||
displayLanguageSwitcher,
|
||||
appendBody,
|
||||
prependBody,
|
||||
} = props;
|
||||
const displayTitle = props.displayTitle ?? true;
|
||||
|
||||
const [selectedTranslation, LanguageSwitcher] = useSmartLanguage({
|
||||
items: post.translations,
|
||||
languages: languages,
|
||||
languageExtractor: (item) => item?.language?.data?.attributes?.code,
|
||||
});
|
||||
|
||||
const thumbnail =
|
||||
selectedTranslation?.thumbnail?.data?.attributes ??
|
||||
post.thumbnail?.data?.attributes;
|
||||
|
||||
const body = selectedTranslation?.body ?? "";
|
||||
const title = selectedTranslation?.title ?? prettySlug(post.slug);
|
||||
const except = selectedTranslation?.excerpt ?? "";
|
||||
|
||||
const subPanel =
|
||||
returnHref || returnTitle || displayCredits || displayToc ? (
|
||||
<SubPanel>
|
||||
{returnHref && returnTitle && (
|
||||
<ReturnButton
|
||||
href={returnHref}
|
||||
title={returnTitle}
|
||||
langui={langui}
|
||||
displayOn={ReturnButtonType.desktop}
|
||||
horizontalLine
|
||||
/>
|
||||
)}
|
||||
|
||||
{displayCredits && (
|
||||
<>
|
||||
{selectedTranslation && (
|
||||
<div className="grid grid-flow-col place-items-center place-content-center gap-2">
|
||||
<p className="font-headers">{langui.status}:</p>
|
||||
|
||||
<ToolTip
|
||||
content={getStatusDescription(
|
||||
selectedTranslation.status,
|
||||
langui
|
||||
)}
|
||||
maxWidth={"20rem"}
|
||||
>
|
||||
<Chip>{selectedTranslation.status}</Chip>
|
||||
</ToolTip>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{post.authors && post.authors.data.length > 0 && (
|
||||
<div>
|
||||
<p className="font-headers">{"Authors"}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{post.authors.data.map((author) => (
|
||||
<>
|
||||
{author.attributes && (
|
||||
<RecorderChip
|
||||
key={author.id}
|
||||
langui={langui}
|
||||
recorder={author.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<HorizontalLine />
|
||||
</>
|
||||
)}
|
||||
|
||||
{displayToc && <TOC text={body} title={title} />}
|
||||
</SubPanel>
|
||||
) : undefined;
|
||||
|
||||
const contentPanel = (
|
||||
<ContentPanel>
|
||||
{returnHref && returnTitle && (
|
||||
<ReturnButton
|
||||
href={returnHref}
|
||||
title={returnTitle}
|
||||
langui={langui}
|
||||
displayOn={ReturnButtonType.mobile}
|
||||
horizontalLine
|
||||
/>
|
||||
)}
|
||||
|
||||
{displayThumbnailHeader ? (
|
||||
<>
|
||||
<ThumbnailHeader
|
||||
thumbnail={thumbnail}
|
||||
title={title}
|
||||
description={except}
|
||||
langui={langui}
|
||||
categories={post.categories}
|
||||
languageSwitcher={<LanguageSwitcher />}
|
||||
/>
|
||||
|
||||
<HorizontalLine />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{displayLanguageSwitcher && (
|
||||
<div className="grid place-content-end place-items-start">
|
||||
<LanguageSwitcher />
|
||||
</div>
|
||||
)}
|
||||
{displayTitle && (
|
||||
<h1 className="text-center flex gap-3 justify-center text-4xl my-16">
|
||||
{title}
|
||||
</h1>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{prependBody}
|
||||
<Markdawn text={body} />
|
||||
{appendBody}
|
||||
</ContentPanel>
|
||||
);
|
||||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={title}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
thumbnail={thumbnail ?? undefined}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
65
src/hooks/useSmartLanguage.tsx
Normal file
65
src/hooks/useSmartLanguage.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
import LanguageSwitcher from "components/Inputs/LanguageSwitcher";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getPreferredLanguage } from "queries/helpers";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
|
||||
interface Props<T> {
|
||||
items: T[];
|
||||
languages: AppStaticProps["languages"];
|
||||
languageExtractor: (item: T) => string | undefined;
|
||||
transform?: (item: T) => T;
|
||||
}
|
||||
|
||||
export default function useSmartLanguage<T>(
|
||||
props: Props<T>
|
||||
): [T | undefined, () => JSX.Element] {
|
||||
const {
|
||||
items,
|
||||
languageExtractor,
|
||||
languages,
|
||||
transform = (item) => item,
|
||||
} = props;
|
||||
const appLayout = useAppLayout();
|
||||
const router = useRouter();
|
||||
|
||||
const availableLocales: Map<string, number> = useMemo(() => new Map(), []);
|
||||
const [selectedTranslationIndex, setSelectedTranslationIndex] = useState<
|
||||
number | undefined
|
||||
>();
|
||||
const [selectedTranslation, setSelectedTranslation] = useState<T>();
|
||||
|
||||
useEffect(() => {
|
||||
items.map((elem, index) => {
|
||||
const result = languageExtractor(elem);
|
||||
if (result !== undefined) availableLocales.set(result, index);
|
||||
});
|
||||
}, [availableLocales, items, languageExtractor]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedTranslationIndex(
|
||||
getPreferredLanguage(
|
||||
appLayout.preferredLanguages ?? [router.locale],
|
||||
availableLocales
|
||||
)
|
||||
);
|
||||
}, [appLayout.preferredLanguages, availableLocales, router.locale]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTranslationIndex !== undefined)
|
||||
setSelectedTranslation(transform(items[selectedTranslationIndex]));
|
||||
}, [items, selectedTranslationIndex, transform]);
|
||||
|
||||
return [
|
||||
selectedTranslation,
|
||||
() => (
|
||||
<LanguageSwitcher
|
||||
languages={languages}
|
||||
locales={availableLocales}
|
||||
localesIndex={selectedTranslationIndex}
|
||||
setLocalesIndex={setSelectedTranslationIndex}
|
||||
/>
|
||||
),
|
||||
];
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
import AppLayout from "components/AppLayout";
|
||||
import Chip from "components/Chip";
|
||||
import HorizontalLine from "components/HorizontalLine";
|
||||
import LanguageSwitcher from "components/Inputs/LanguageSwitcher";
|
||||
import Markdawn from "components/Markdown/Markdawn";
|
||||
import TOC from "components/Markdown/TOC";
|
||||
import ReturnButton, {
|
||||
@ -13,25 +12,22 @@ import PreviewLine from "components/PreviewLine";
|
||||
import RecorderChip from "components/RecorderChip";
|
||||
import ThumbnailHeader from "components/ThumbnailHeader";
|
||||
import ToolTip from "components/ToolTip";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { GetContentTextQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { useMediaMobile } from "hooks/useMediaQuery";
|
||||
import useSmartLanguage from "hooks/useSmartLanguage";
|
||||
import {
|
||||
GetStaticPathsContext,
|
||||
GetStaticPathsResult,
|
||||
GetStaticPropsContext,
|
||||
} from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import {
|
||||
getPreferredLanguage,
|
||||
getStatusDescription,
|
||||
prettyinlineTitle,
|
||||
prettyLanguage,
|
||||
prettySlug,
|
||||
} from "queries/helpers";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
content: Exclude<
|
||||
@ -46,53 +42,15 @@ interface Props extends AppStaticProps {
|
||||
|
||||
export default function Content(props: Props): JSX.Element {
|
||||
const { langui, content, languages } = props;
|
||||
const router = useRouter();
|
||||
const appLayout = useAppLayout();
|
||||
|
||||
const isMobile = useMediaMobile();
|
||||
|
||||
const [selectedTextSet, setSelectedTextSet] = useState<
|
||||
| Exclude<
|
||||
Exclude<Props["content"], null | undefined>["text_set"],
|
||||
null | undefined
|
||||
>[number]
|
||||
>();
|
||||
const [selectedTitle, setSelectedTitle] = useState<
|
||||
| Exclude<
|
||||
Exclude<Props["content"], null | undefined>["titles"],
|
||||
null | undefined
|
||||
>[number]
|
||||
>();
|
||||
const textSetLocales: Map<string, number> = new Map();
|
||||
const [selectedTextSet, LanguageSwitcher] = useSmartLanguage({
|
||||
items: content?.text_set,
|
||||
languages: languages,
|
||||
languageExtractor: (item) => item?.language?.data?.attributes?.code,
|
||||
});
|
||||
|
||||
const [selectedTextSetIndex, setSelectedTextSetIndex] = useState<
|
||||
number | undefined
|
||||
>();
|
||||
|
||||
if (content?.text_set) {
|
||||
content.text_set.map((textSet, index) => {
|
||||
if (textSet?.language?.data?.attributes?.code && textSet.text) {
|
||||
textSetLocales.set(textSet.language.data.attributes.code, index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
useMemo(() => {
|
||||
setSelectedTextSetIndex(
|
||||
getPreferredLanguage(
|
||||
appLayout.preferredLanguages ?? [router.locale],
|
||||
textSetLocales
|
||||
)
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [appLayout.preferredLanguages]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTextSetIndex !== undefined) {
|
||||
setSelectedTextSet(content?.text_set?.[selectedTextSetIndex]);
|
||||
setSelectedTitle(content?.titles?.[selectedTextSetIndex]);
|
||||
}
|
||||
}, [content?.text_set, content?.titles, selectedTextSetIndex]);
|
||||
const selectedTitle = content?.titles?.[0];
|
||||
|
||||
const subPanel = (
|
||||
<SubPanel>
|
||||
@ -252,16 +210,7 @@ export default function Content(props: Props): JSX.Element {
|
||||
type={content.type}
|
||||
categories={content.categories}
|
||||
langui={langui}
|
||||
languageSwitcher={
|
||||
selectedTextSet ? (
|
||||
<LanguageSwitcher
|
||||
locales={textSetLocales}
|
||||
languages={props.languages}
|
||||
localesIndex={selectedTextSetIndex}
|
||||
setLocalesIndex={setSelectedTextSetIndex}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
languageSwitcher={<LanguageSwitcher />}
|
||||
/>
|
||||
|
||||
{content.previous_recommended?.data?.attributes && (
|
||||
|
@ -10,9 +10,12 @@ import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
post: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
>;
|
||||
postId: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
@ -45,7 +48,7 @@ export async function getStaticProps(
|
||||
slug: slug,
|
||||
language_code: context.locale ?? "en",
|
||||
});
|
||||
if (!post.posts?.data[0]) return { notFound: true };
|
||||
if (!post.posts?.data[0].attributes) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: post.posts.data[0].attributes,
|
||||
|
Loading…
x
Reference in New Issue
Block a user