Use graphql-codegen and replace all types from queries
This commit is contained in:
parent
acf92d6fc1
commit
125421de0f
|
@ -2,6 +2,9 @@
|
|||
|
||||
/testing_logs/*
|
||||
|
||||
# Generated content
|
||||
src/graphql/generated.ts
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
|
|
|
@ -25,9 +25,10 @@
|
|||
#### [Front](https://github.com/Accords-Library/accords-library.com) (this repository)
|
||||
|
||||
- Language: [TypeScript](https://www.typescriptlang.org/)
|
||||
- Queries: [GraphQL](https://graphql.org/)
|
||||
- [GraphQL Code Generator](https://www.graphql-code-generator.com/) to automatically generated types for the operations variables and responses
|
||||
- The operations are stored in a graphql file and then retrieved and wrap as an actual TypeScript function
|
||||
- Queries: [GraphQL Code Generator](https://www.graphql-code-generator.com/)
|
||||
- Fetch the GraphQL schema from the GraphQL back-end endpoint
|
||||
- Read the operations and fragments stored as graphql files in the `src/graphql` folder
|
||||
- Automatically generates a typesafe ready to use SDK using [graphql-request](https://www.npmjs.com/package/graphql-request) as the GraphQL client
|
||||
- Markdown: [markdown-to-jsx](https://www.npmjs.com/package/markdown-to-jsx)
|
||||
- Support for Arbitrary React Components and Component Props!
|
||||
- Autogenerated multi-level table of content and anchor links for the different headers
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
const { loadEnvConfig } = require("@next/env");
|
||||
loadEnvConfig(process.cwd());
|
||||
|
||||
module.exports = {
|
||||
overwrite: true,
|
||||
schema: {
|
||||
[process.env.URL_GRAPHQL]: {
|
||||
headers: { Authorization: `Bearer ${process.env.ACCESS_TOKEN}` },
|
||||
},
|
||||
},
|
||||
documents: ["src/graphql/operations/*.graphql", "src/graphql/fragments/*.graphql"],
|
||||
generates: {
|
||||
"src/graphql/generated.ts": {
|
||||
plugins: [
|
||||
"typescript",
|
||||
"typescript-operations",
|
||||
"typescript-graphql-request",
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,8 @@
|
|||
"build": "next build",
|
||||
"postbuild": "next-sitemap",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"generate": "graphql-codegen --config graphql-codegen.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/material-icons": "^4.5.4",
|
||||
|
@ -15,6 +16,7 @@
|
|||
"@fontsource/vollkorn": "^4.5.6",
|
||||
"@fontsource/zen-maru-gothic": "^4.5.8",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"graphql-request": "^4.2.0",
|
||||
"markdown-to-jsx": "^7.1.7",
|
||||
"next": "^12.1.2",
|
||||
"nodemailer": "^6.7.3",
|
||||
|
@ -25,6 +27,10 @@
|
|||
"turndown": "^7.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/cli": "^2.6.2",
|
||||
"@graphql-codegen/typescript": "2.4.8",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.4.4",
|
||||
"@graphql-codegen/typescript-operations": "^2.3.5",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@types/react": "17.0.43",
|
||||
|
@ -34,6 +40,7 @@
|
|||
"@typescript-eslint/parser": "^5.17.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-config-next": "12.1.2",
|
||||
"graphql": "^14.7.0",
|
||||
"next-sitemap": "^2.5.14",
|
||||
"prettier-plugin-organize-imports": "^2.3.4",
|
||||
"tailwindcss": "^3.0.23",
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
npx next build
|
||||
npm run generate
|
||||
npm run build
|
||||
npm run postbuild
|
|
@ -1,11 +1,16 @@
|
|||
import Button from "components/Button";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { StrapiImage } from "graphql/operations-types";
|
||||
import { UploadImageFragment } from "graphql/generated";
|
||||
import { useMediaMobile } from "hooks/useMediaQuery";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getOgImage, OgImage, prettyLanguage } from "queries/helpers";
|
||||
import {
|
||||
getOgImage,
|
||||
OgImage,
|
||||
prettyLanguage,
|
||||
prettySlug,
|
||||
} from "queries/helpers";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSwipeable } from "react-swipeable";
|
||||
import { ImageQuality } from "./Img";
|
||||
|
@ -18,8 +23,8 @@ interface AppLayoutProps extends AppStaticProps {
|
|||
subPanelIcon?: string;
|
||||
contentPanel?: React.ReactNode;
|
||||
title?: string;
|
||||
navTitle: string;
|
||||
thumbnail?: StrapiImage;
|
||||
navTitle: string | null | undefined;
|
||||
thumbnail?: UploadImageFragment;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
|
@ -61,11 +66,10 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
|
|||
height: 630,
|
||||
alt: "Accord's Library Logo",
|
||||
};
|
||||
const ogTitle = props.title ? props.title : props.navTitle;
|
||||
const ogTitle =
|
||||
props.title ?? props.navTitle ?? prettySlug(router.asPath.split("/").pop());
|
||||
|
||||
const metaDescription = props.description
|
||||
? props.description
|
||||
: langui.default_description;
|
||||
const metaDescription = props.description ?? langui.default_description ?? "";
|
||||
|
||||
useEffect(() => {
|
||||
document.getElementsByTagName("html")[0].style.fontSize = `${
|
||||
|
@ -73,9 +77,10 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
|
|||
}%`;
|
||||
}, [appLayout.fontSize]);
|
||||
|
||||
const currencyOptions = currencies.map(
|
||||
(currency) => currency.attributes.code
|
||||
);
|
||||
const currencyOptions: string[] = [];
|
||||
currencies.map((currency) => {
|
||||
if (currency.attributes?.code) currencyOptions.push(currency.attributes.code);
|
||||
});
|
||||
const [currencySelect, setCurrencySelect] = useState<number>(-1);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -127,7 +132,10 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
|
|||
></meta>
|
||||
|
||||
<meta name="description" content={metaDescription} />
|
||||
<meta name="twitter:description" content={metaDescription}></meta>
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content={metaDescription}
|
||||
></meta>
|
||||
|
||||
<meta property="og:image" content={metaImage.image}></meta>
|
||||
<meta property="og:image:secure_url" content={metaImage.image}></meta>
|
||||
|
@ -220,12 +228,12 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
|
|||
</span>
|
||||
<p
|
||||
className={`font-black font-headers text-center overflow-hidden ${
|
||||
props.navTitle?.length > 30
|
||||
ogTitle && ogTitle.length > 30
|
||||
? "text-xl max-h-14"
|
||||
: "text-2xl max-h-16"
|
||||
}`}
|
||||
>
|
||||
{props.navTitle}
|
||||
{ogTitle}
|
||||
</p>
|
||||
<span
|
||||
className="material-icons mt-[.1em] cursor-pointer"
|
||||
|
|
|
@ -3,14 +3,17 @@ import ToolTip from "components/ToolTip";
|
|||
import {
|
||||
Enum_Componenttranslationschronologyitem_Status,
|
||||
GetChronologyItemsQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
} from "graphql/operations-types";
|
||||
} from "graphql/generated";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getStatusDescription } from "queries/helpers";
|
||||
|
||||
export type ChronologyItemComponentProps = {
|
||||
item: GetChronologyItemsQuery["chronologyItems"]["data"][number];
|
||||
item: Exclude<
|
||||
GetChronologyItemsQuery["chronologyItems"],
|
||||
null | undefined
|
||||
>["data"][number];
|
||||
displayYear: boolean;
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||
langui: AppStaticProps["langui"];
|
||||
};
|
||||
|
||||
export default function ChronologyItemComponent(
|
||||
|
@ -18,22 +21,29 @@ export default function ChronologyItemComponent(
|
|||
): JSX.Element {
|
||||
const { langui } = props;
|
||||
|
||||
function generateAnchor(year: number, month: number, day: number): string {
|
||||
function generateAnchor(
|
||||
year: number | undefined,
|
||||
month: number | null | undefined,
|
||||
day: number | null | undefined
|
||||
): string {
|
||||
let result = "";
|
||||
result += year;
|
||||
if (year) result += year;
|
||||
if (month) result += `- ${month.toString().padStart(2, "0")}`;
|
||||
if (day) result += `- ${day.toString().padStart(2, "0")}`;
|
||||
return result;
|
||||
}
|
||||
|
||||
function generateYear(displayed_date: string, year: number): string {
|
||||
if (displayed_date) {
|
||||
return displayed_date;
|
||||
}
|
||||
return year.toString();
|
||||
function generateYear(
|
||||
displayed_date: string | null | undefined,
|
||||
year: number | undefined
|
||||
): string {
|
||||
return displayed_date ?? year?.toString() ?? "";
|
||||
}
|
||||
|
||||
function generateDate(month: number, day: number): string {
|
||||
function generateDate(
|
||||
month: number | null | undefined,
|
||||
day: number | null | undefined
|
||||
): string {
|
||||
const lut = [
|
||||
"Jan",
|
||||
"Feb",
|
||||
|
@ -50,7 +60,7 @@ export default function ChronologyItemComponent(
|
|||
];
|
||||
|
||||
let result = "";
|
||||
if (month) {
|
||||
if (month && month >= 1 && month <= 12) {
|
||||
result += lut[month - 1];
|
||||
if (day) {
|
||||
result += ` ${day}`;
|
||||
|
@ -60,6 +70,7 @@ export default function ChronologyItemComponent(
|
|||
return result;
|
||||
}
|
||||
|
||||
if (props.item.attributes) {
|
||||
return (
|
||||
<div
|
||||
className="grid place-content-start grid-rows-[auto_1fr] grid-cols-[4em] py-4 px-8 rounded-2xl target:bg-mid target:py-8 target:my-4"
|
||||
|
@ -83,26 +94,38 @@ export default function ChronologyItemComponent(
|
|||
</p>
|
||||
|
||||
<div className="col-start-2 row-start-1 row-span-2 grid gap-4">
|
||||
{props.item.attributes.events.map((event) => (
|
||||
{props.item.attributes.events?.map((event) => (
|
||||
<>
|
||||
{event && (
|
||||
<div className="m-0" key={event.id}>
|
||||
{event.translations.map((translation) => (
|
||||
{event.translations?.map((translation) => (
|
||||
<>
|
||||
{translation && (
|
||||
<>
|
||||
<div className="place-items-start place-content-start grid grid-flow-col gap-2">
|
||||
{translation.status !==
|
||||
Enum_Componenttranslationschronologyitem_Status.Done && (
|
||||
<ToolTip
|
||||
content={getStatusDescription(translation.status, langui)}
|
||||
content={getStatusDescription(
|
||||
translation.status,
|
||||
langui
|
||||
)}
|
||||
maxWidth={"20rem"}
|
||||
>
|
||||
<Chip>{translation.status}</Chip>
|
||||
</ToolTip>
|
||||
)}
|
||||
{translation.title ? <h3>{translation.title}</h3> : ""}
|
||||
{translation.title ? (
|
||||
<h3>{translation.title}</h3>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
|
||||
{translation.description && (
|
||||
<p
|
||||
className={
|
||||
event.translations &&
|
||||
event.translations.length > 1
|
||||
? "before:content-['-'] before:text-dark before:inline-block before:w-4 before:ml-[-1em] mt-2 whitespace-pre-line"
|
||||
: "whitespace-pre-line"
|
||||
|
@ -117,21 +140,28 @@ export default function ChronologyItemComponent(
|
|||
""
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
|
||||
<p className="text-dark text-xs grid place-self-start grid-flow-col gap-1 mt-1">
|
||||
{event.source.data ? (
|
||||
`(${event.source.data.attributes.name})`
|
||||
{event.source?.data ? (
|
||||
`(${event.source.data.attributes?.name})`
|
||||
) : (
|
||||
<>
|
||||
<span className="material-icons !text-sm">warning</span>No
|
||||
sources!
|
||||
<span className="material-icons !text-sm">warning</span>
|
||||
No sources!
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <></>;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import ChronologyItemComponent from "components/Chronology/ChronologyItemComponent";
|
||||
import {
|
||||
GetChronologyItemsQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
} from "graphql/operations-types";
|
||||
import { GetChronologyItemsQuery } from "graphql/generated";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
|
||||
type ChronologyYearComponentProps = {
|
||||
year: number;
|
||||
items: GetChronologyItemsQuery["chronologyItems"]["data"][number][];
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||
items: Exclude<
|
||||
GetChronologyItemsQuery["chronologyItems"],
|
||||
null | undefined
|
||||
>["data"][number][];
|
||||
langui: AppStaticProps["langui"];
|
||||
};
|
||||
|
||||
export default function ChronologyYearComponent(
|
||||
|
|
|
@ -1,21 +1,31 @@
|
|||
import Chip from "components/Chip";
|
||||
import Img, { ImageQuality } from "components/Img";
|
||||
import InsetBox from "components/InsetBox";
|
||||
import {
|
||||
GetContentQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
} from "graphql/operations-types";
|
||||
import { GetContentQuery, UploadImageFragment } from "graphql/generated";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { prettyinlineTitle, prettySlug, slugify } from "queries/helpers";
|
||||
|
||||
export type ThumbnailHeaderProps = {
|
||||
pre_title?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
description?: string;
|
||||
type?: GetContentQuery["contents"]["data"][number]["attributes"]["type"];
|
||||
categories?: GetContentQuery["contents"]["data"][number]["attributes"]["categories"];
|
||||
thumbnail?: GetContentQuery["contents"]["data"][number]["attributes"]["thumbnail"]["data"]["attributes"];
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||
pre_title?: string | null | undefined;
|
||||
title: string | null | undefined;
|
||||
subtitle?: string | null | undefined;
|
||||
description?: string | null | undefined;
|
||||
type?: Exclude<
|
||||
Exclude<
|
||||
GetContentQuery["contents"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>["type"];
|
||||
categories?: Exclude<
|
||||
Exclude<
|
||||
GetContentQuery["contents"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>["categories"];
|
||||
thumbnail?: UploadImageFragment | null | undefined;
|
||||
langui: AppStaticProps["langui"];
|
||||
};
|
||||
|
||||
export default function ThumbnailHeader(
|
||||
|
@ -60,13 +70,14 @@ export default function ThumbnailHeader(
|
|||
</div>
|
||||
|
||||
<div className="grid grid-flow-col gap-8">
|
||||
{type?.data && (
|
||||
{type?.data?.attributes && (
|
||||
<div className="flex flex-col place-items-center gap-2">
|
||||
<h3 className="text-xl">{langui.type}</h3>
|
||||
<div className="flex flex-row flex-wrap">
|
||||
<Chip>
|
||||
{type.data.attributes.titles.length > 0
|
||||
? type.data.attributes.titles[0].title
|
||||
{type.data.attributes.titles &&
|
||||
type.data.attributes.titles.length > 0
|
||||
? type.data.attributes.titles[0]?.title
|
||||
: prettySlug(type.data.attributes.slug)}
|
||||
</Chip>
|
||||
</div>
|
||||
|
@ -78,7 +89,7 @@ export default function ThumbnailHeader(
|
|||
<h3 className="text-xl">{langui.categories}</h3>
|
||||
<div className="flex flex-row flex-wrap place-content-center gap-2">
|
||||
{categories.data.map((category) => (
|
||||
<Chip key={category.id}>{category.attributes.name}</Chip>
|
||||
<Chip key={category.id}>{category.attributes?.name}</Chip>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { StrapiImage } from "graphql/operations-types";
|
||||
import { UploadImageFragment } from "graphql/generated";
|
||||
import Image, { ImageProps } from "next/image";
|
||||
|
||||
export enum ImageQuality {
|
||||
|
@ -51,7 +51,7 @@ export function getImgSizesByQuality(
|
|||
|
||||
type ImgProps = {
|
||||
className?: string;
|
||||
image?: StrapiImage;
|
||||
image?: UploadImageFragment;
|
||||
quality?: ImageQuality;
|
||||
alt?: ImageProps["alt"];
|
||||
layout?: ImageProps["layout"];
|
||||
|
@ -61,11 +61,11 @@ type ImgProps = {
|
|||
};
|
||||
|
||||
export default function Img(props: ImgProps): JSX.Element {
|
||||
if (props.image) {
|
||||
if (props.image?.width && props.image?.height) {
|
||||
const imgSize = getImgSizesByQuality(
|
||||
props.image.width,
|
||||
props.image.height,
|
||||
props.quality ? props.quality : ImageQuality.Small
|
||||
props.quality ?? ImageQuality.Small
|
||||
);
|
||||
|
||||
if (props.rawImg) {
|
||||
|
@ -75,9 +75,9 @@ export default function Img(props: ImgProps): JSX.Element {
|
|||
className={props.className}
|
||||
src={getAssetURL(
|
||||
props.image.url,
|
||||
props.quality ? props.quality : ImageQuality.Small
|
||||
props.quality ?? ImageQuality.Small
|
||||
)}
|
||||
alt={props.alt ? props.alt : props.image.alternativeText}
|
||||
alt={props.alt ?? props.image.alternativeText ?? ""}
|
||||
width={imgSize.width}
|
||||
height={imgSize.height}
|
||||
/>
|
||||
|
@ -90,7 +90,7 @@ export default function Img(props: ImgProps): JSX.Element {
|
|||
props.image.url,
|
||||
props.quality ? props.quality : ImageQuality.Small
|
||||
)}
|
||||
alt={props.alt ? props.alt : props.image.alternativeText}
|
||||
alt={props.alt ?? props.image.alternativeText ?? ""}
|
||||
width={props.layout === "fill" ? undefined : imgSize.width}
|
||||
height={props.layout === "fill" ? undefined : imgSize.height}
|
||||
layout={props.layout}
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
import {
|
||||
GetLanguagesQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
} from "graphql/operations-types";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { prettyLanguage } from "queries/helpers";
|
||||
import Button from "./Button";
|
||||
|
||||
type HorizontalLineProps = {
|
||||
className?: string;
|
||||
locales: string[];
|
||||
languages: GetLanguagesQuery["languages"]["data"];
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||
locales: (string | undefined)[];
|
||||
languages: AppStaticProps["languages"];
|
||||
langui: AppStaticProps["langui"];
|
||||
href?: string;
|
||||
};
|
||||
|
||||
|
@ -26,6 +23,8 @@ export default function HorizontalLine(
|
|||
<p>{langui.language_switch_message}</p>
|
||||
<div className="flex flex-wrap flex-row gap-2">
|
||||
{locales.map((locale, index) => (
|
||||
<>
|
||||
{locale && (
|
||||
<Button
|
||||
key={index}
|
||||
active={locale === router.locale}
|
||||
|
@ -34,6 +33,8 @@ export default function HorizontalLine(
|
|||
>
|
||||
{prettyLanguage(locale, props.languages)}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
import Button from "components/Button";
|
||||
import Chip from "components/Chip";
|
||||
import {
|
||||
GetLibraryItemQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
} from "graphql/operations-types";
|
||||
import { GetLibraryItemQuery } from "graphql/generated";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { prettyinlineTitle, prettySlug } from "queries/helpers";
|
||||
import { useState } from "react";
|
||||
|
||||
type ContentTOCLineProps = {
|
||||
content: GetLibraryItemQuery["libraryItems"]["data"][number]["attributes"]["contents"]["data"][number];
|
||||
content: Exclude<
|
||||
Exclude<
|
||||
Exclude<
|
||||
GetLibraryItemQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>["contents"],
|
||||
null | undefined
|
||||
>["data"][number];
|
||||
parentSlug: string;
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||
langui: AppStaticProps["langui"];
|
||||
};
|
||||
|
||||
export default function ContentTOCLine(
|
||||
|
@ -20,6 +27,7 @@ export default function ContentTOCLine(
|
|||
|
||||
const [opened, setOpened] = useState(false);
|
||||
|
||||
if (content.attributes) {
|
||||
return (
|
||||
<div
|
||||
className={`grid gap-2 px-4 rounded-lg ${
|
||||
|
@ -29,36 +37,40 @@ export default function ContentTOCLine(
|
|||
<div className="grid gap-4 place-items-center grid-cols-[auto_auto_1fr_auto_12ch] thin:grid-cols-[auto_auto_1fr_auto]">
|
||||
<a>
|
||||
<h3 className="cursor-pointer" onClick={() => setOpened(!opened)}>
|
||||
{content.attributes.content.data &&
|
||||
content.attributes.content.data.attributes.titles.length > 0
|
||||
{content.attributes.content?.data?.attributes?.titles?.[0]
|
||||
? prettyinlineTitle(
|
||||
content.attributes.content.data.attributes.titles[0]
|
||||
.pre_title,
|
||||
content.attributes.content.data.attributes.titles[0].title,
|
||||
content.attributes.content.data.attributes.titles[0].subtitle
|
||||
?.pre_title,
|
||||
content.attributes.content.data.attributes.titles[0]?.title,
|
||||
content.attributes.content.data.attributes.titles[0]
|
||||
?.subtitle
|
||||
)
|
||||
: prettySlug(content.attributes.slug, props.parentSlug)}
|
||||
</h3>
|
||||
</a>
|
||||
<div className="flex flex-row flex-wrap gap-1">
|
||||
{content.attributes.content.data?.attributes.categories.data.map(
|
||||
{content.attributes.content?.data?.attributes?.categories?.data.map(
|
||||
(category) => (
|
||||
<Chip key={category.id}>{category.attributes.short}</Chip>
|
||||
<Chip key={category.id}>{category.attributes?.short}</Chip>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
<p className="border-b-2 h-4 w-full border-black border-dotted opacity-30"></p>
|
||||
<p>
|
||||
{content.attributes.range[0].__typename === "ComponentRangePageRange"
|
||||
{content.attributes.range[0]?.__typename ===
|
||||
"ComponentRangePageRange"
|
||||
? content.attributes.range[0].starting_page
|
||||
: ""}
|
||||
</p>
|
||||
{content.attributes.content.data && (
|
||||
{content.attributes.content?.data?.attributes?.type?.data
|
||||
?.attributes && (
|
||||
<Chip className="justify-self-end thin:hidden">
|
||||
{content.attributes.content.data.attributes.type.data.attributes
|
||||
.titles &&
|
||||
content.attributes.content.data.attributes.type.data.attributes
|
||||
.titles.length > 0
|
||||
? content.attributes.content.data.attributes.type.data.attributes
|
||||
.titles[0].title
|
||||
? content.attributes.content.data.attributes.type.data
|
||||
.attributes.titles[0]?.title
|
||||
: prettySlug(
|
||||
content.attributes.content.data.attributes.type.data
|
||||
.attributes.slug
|
||||
|
@ -75,7 +87,8 @@ export default function ContentTOCLine(
|
|||
subdirectory_arrow_right
|
||||
</span>
|
||||
|
||||
{content.attributes.scan_set.length > 0 && (
|
||||
{content.attributes.scan_set &&
|
||||
content.attributes.scan_set.length > 0 && (
|
||||
<Button
|
||||
href={`/library/${parentSlug}/scans#${content.attributes.slug}`}
|
||||
>
|
||||
|
@ -83,19 +96,22 @@ export default function ContentTOCLine(
|
|||
</Button>
|
||||
)}
|
||||
|
||||
{content.attributes.content.data && (
|
||||
{content.attributes.content?.data && (
|
||||
<Button
|
||||
href={`/contents/${content.attributes.content.data.attributes.slug}`}
|
||||
href={`/contents/${content.attributes.content.data.attributes?.slug}`}
|
||||
>
|
||||
{langui.open_content}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{content.attributes.scan_set.length === 0 &&
|
||||
!content.attributes.content.data
|
||||
{content.attributes.scan_set &&
|
||||
content.attributes.scan_set.length === 0 &&
|
||||
!content.attributes.content?.data
|
||||
? "The content is not available"
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <></>;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
import Chip from "components/Chip";
|
||||
import Img, { ImageQuality } from "components/Img";
|
||||
import { GetContentsQuery } from "graphql/operations-types";
|
||||
import { GetContentsQuery } from "graphql/generated";
|
||||
import Link from "next/link";
|
||||
import { prettySlug } from "queries/helpers";
|
||||
|
||||
export type LibraryContentPreviewProps = {
|
||||
item: {
|
||||
slug: GetContentsQuery["contents"]["data"][number]["attributes"]["slug"];
|
||||
thumbnail: GetContentsQuery["contents"]["data"][number]["attributes"]["thumbnail"];
|
||||
titles: GetContentsQuery["contents"]["data"][number]["attributes"]["titles"];
|
||||
categories: GetContentsQuery["contents"]["data"][number]["attributes"]["categories"];
|
||||
type: GetContentsQuery["contents"]["data"][number]["attributes"]["type"];
|
||||
};
|
||||
item: Exclude<
|
||||
GetContentsQuery["contents"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
};
|
||||
|
||||
export default function LibraryContentPreview(
|
||||
|
@ -20,9 +17,9 @@ export default function LibraryContentPreview(
|
|||
const { item } = props;
|
||||
|
||||
return (
|
||||
<Link href={`/contents/${item.slug}`} passHref>
|
||||
<Link href={`/contents/${item?.slug}`} passHref>
|
||||
<div className="drop-shadow-shade-xl cursor-pointer grid items-end fine:[--cover-opacity:0] hover:[--cover-opacity:1] hover:scale-[1.02] transition-transform">
|
||||
{item.thumbnail.data ? (
|
||||
{item?.thumbnail?.data?.attributes ? (
|
||||
<Img
|
||||
className="rounded-md coarse:rounded-b-none"
|
||||
image={item.thumbnail.data.attributes}
|
||||
|
@ -33,29 +30,29 @@ export default function LibraryContentPreview(
|
|||
)}
|
||||
<div className="linearbg-obi fine:drop-shadow-shade-lg fine:absolute coarse:rounded-b-md bottom-2 -inset-x-0.5 opacity-[var(--cover-opacity)] transition-opacity z-20 grid p-4 gap-2">
|
||||
<div className="grid grid-flow-col gap-1 overflow-hidden place-content-start">
|
||||
{item.type.data && (
|
||||
{item?.type?.data?.attributes && (
|
||||
<Chip>
|
||||
{item.type.data.attributes.titles.length > 0
|
||||
? item.type.data.attributes.titles[0].title
|
||||
{item.type.data.attributes.titles?.[0]
|
||||
? item.type.data.attributes.titles[0]?.title
|
||||
: prettySlug(item.type.data.attributes.slug)}
|
||||
</Chip>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{item.titles.length > 0 ? (
|
||||
{item?.titles?.[0] ? (
|
||||
<>
|
||||
<p>{item.titles[0].pre_title}</p>
|
||||
<h1 className="text-lg">{item.titles[0].title}</h1>
|
||||
<h2>{item.titles[0].subtitle}</h2>
|
||||
</>
|
||||
) : (
|
||||
<h1 className="text-lg">{prettySlug(item.slug)}</h1>
|
||||
<h1 className="text-lg">{prettySlug(item?.slug)}</h1>
|
||||
)}
|
||||
</div>
|
||||
<div className="grid grid-flow-col gap-1 overflow-x-scroll webkit-scrollbar:w-0 [scrollbar-width:none] place-content-start">
|
||||
{item.categories.data.map((category) => (
|
||||
{item?.categories?.data.map((category) => (
|
||||
<Chip key={category.id} className="text-sm">
|
||||
{category.attributes.short}
|
||||
{category.attributes?.short}
|
||||
</Chip>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -2,25 +2,31 @@ import Chip from "components/Chip";
|
|||
import Img, { ImageQuality } from "components/Img";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import {
|
||||
GetCurrenciesQuery,
|
||||
GetLibraryItemQuery,
|
||||
GetLibraryItemsPreviewQuery,
|
||||
} from "graphql/operations-types";
|
||||
} from "graphql/generated";
|
||||
import Link from "next/link";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import { prettyDate, prettyItemSubType, prettyPrice } from "queries/helpers";
|
||||
|
||||
export type LibraryItemsPreviewProps = {
|
||||
className?: string;
|
||||
item: {
|
||||
slug: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["slug"];
|
||||
thumbnail: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["thumbnail"];
|
||||
title: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["title"];
|
||||
subtitle: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["subtitle"];
|
||||
price?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["price"];
|
||||
categories: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["categories"];
|
||||
release_date?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["release_date"];
|
||||
metadata?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"];
|
||||
};
|
||||
currencies?: GetCurrenciesQuery["currencies"]["data"];
|
||||
item:
|
||||
| Exclude<
|
||||
Exclude<
|
||||
Exclude<
|
||||
GetLibraryItemQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>["subitems"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"]
|
||||
| Exclude<
|
||||
GetLibraryItemsPreviewQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
currencies: AppStaticProps["currencies"];
|
||||
};
|
||||
|
||||
export default function LibraryItemsPreview(
|
||||
|
@ -30,11 +36,11 @@ export default function LibraryItemsPreview(
|
|||
const appLayout = useAppLayout();
|
||||
|
||||
return (
|
||||
<Link href={`/library/${item.slug}`} passHref>
|
||||
<Link href={`/library/${item?.slug}`} passHref>
|
||||
<div
|
||||
className={`drop-shadow-shade-xl cursor-pointer grid items-end hover:rounded-3xl fine:[--cover-opacity:0] hover:[--cover-opacity:1] hover:scale-[1.02] transition-transform ${props.className}`}
|
||||
>
|
||||
{item.thumbnail.data ? (
|
||||
{item?.thumbnail?.data?.attributes ? (
|
||||
<Img
|
||||
image={item.thumbnail.data.attributes}
|
||||
quality={ImageQuality.Small}
|
||||
|
@ -44,26 +50,26 @@ export default function LibraryItemsPreview(
|
|||
)}
|
||||
|
||||
<div className="linearbg-obi fine:drop-shadow-shade-lg fine:absolute place-items-start bottom-2 -inset-x-0.5 opacity-[var(--cover-opacity)] transition-opacity z-20 grid p-4 gap-2">
|
||||
{item.metadata && item.metadata.length > 0 && (
|
||||
{item?.metadata && item.metadata.length > 0 && item.metadata[0] && (
|
||||
<div className="flex flex-row gap-1">
|
||||
<Chip>{prettyItemSubType(item.metadata[0])}</Chip>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<h2 className="mobile:text-sm text-lg leading-5">{item.title}</h2>
|
||||
<h3 className="mobile:text-xs leading-3">{item.subtitle}</h3>
|
||||
<h2 className="mobile:text-sm text-lg leading-5">{item?.title}</h2>
|
||||
<h3 className="mobile:text-xs leading-3">{item?.subtitle}</h3>
|
||||
</div>
|
||||
|
||||
<div className="w-full grid grid-flow-col gap-1 overflow-x-scroll webkit-scrollbar:h-0 [scrollbar-width:none] place-content-start">
|
||||
{item.categories.data.map((category) => (
|
||||
{item?.categories?.data.map((category) => (
|
||||
<Chip key={category.id} className="text-sm">
|
||||
{category.attributes.short}
|
||||
{category.attributes?.short}
|
||||
</Chip>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{(item.release_date || item.price) && (
|
||||
{(item?.release_date || item?.price) && (
|
||||
<div className="grid grid-flow-col w-full">
|
||||
{item.release_date && (
|
||||
<p className="mobile:text-xs text-sm">
|
||||
|
@ -73,7 +79,7 @@ export default function LibraryItemsPreview(
|
|||
{prettyDate(item.release_date)}
|
||||
</p>
|
||||
)}
|
||||
{item.price && props.currencies && (
|
||||
{item.price && (
|
||||
<p className="mobile:text-xs text-sm justify-self-end">
|
||||
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
||||
shopping_cart
|
||||
|
|
|
@ -69,7 +69,7 @@ export type TOC = {
|
|||
export function getTocFromMarkdawn(text: string, title?: string): TOC {
|
||||
const toc: TOC = {
|
||||
title: title ?? "Return to top",
|
||||
slug: slugify(title) ?? "",
|
||||
slug: slugify(title),
|
||||
children: [],
|
||||
};
|
||||
let h2 = -1;
|
||||
|
|
|
@ -1,26 +1,23 @@
|
|||
import Chip from "components/Chip";
|
||||
import Img, { ImageQuality } from "components/Img";
|
||||
import { GetPostsPreviewQuery } from "graphql/operations-types";
|
||||
import { GetPostsPreviewQuery } from "graphql/generated";
|
||||
import Link from "next/link";
|
||||
import { prettyDate, prettySlug } from "queries/helpers";
|
||||
|
||||
export type PostPreviewProps = {
|
||||
post: {
|
||||
slug: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["slug"];
|
||||
thumbnail: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["thumbnail"];
|
||||
translations: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["translations"];
|
||||
categories: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["categories"];
|
||||
date: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["date"];
|
||||
};
|
||||
post: Exclude<
|
||||
GetPostsPreviewQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
};
|
||||
|
||||
export default function PostPreview(props: PostPreviewProps): JSX.Element {
|
||||
const { post } = props;
|
||||
|
||||
return (
|
||||
<Link href={`/news/${post.slug}`} passHref>
|
||||
<Link href={`/news/${post?.slug}`} passHref>
|
||||
<div className="drop-shadow-shade-xl cursor-pointer grid items-end hover:scale-[1.02] transition-transform">
|
||||
{post.thumbnail.data ? (
|
||||
{post?.thumbnail?.data?.attributes ? (
|
||||
<Img
|
||||
className="rounded-md rounded-b-none"
|
||||
image={post.thumbnail.data.attributes}
|
||||
|
@ -30,30 +27,31 @@ export default function PostPreview(props: PostPreviewProps): JSX.Element {
|
|||
<div className="w-full aspect-[3/2] bg-light rounded-lg"></div>
|
||||
)}
|
||||
<div className="linearbg-obi fine:drop-shadow-shade-lg rounded-b-md top-full transition-opacity z-20 grid p-4 gap-2">
|
||||
{post?.date && (
|
||||
<div className="grid grid-flow-col w-full">
|
||||
{post.date && (
|
||||
<p className="mobile:text-xs text-sm">
|
||||
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
||||
event
|
||||
</span>
|
||||
{prettyDate(post.date)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
{post.translations.length > 0 ? (
|
||||
{post?.translations?.[0] ? (
|
||||
<>
|
||||
<h1 className="text-xl">{post.translations[0].title}</h1>
|
||||
<p>{post.translations[0].excerpt}</p>
|
||||
</>
|
||||
) : (
|
||||
<h1 className="text-lg">{prettySlug(post.slug)}</h1>
|
||||
<h1 className="text-lg">{prettySlug(post?.slug)}</h1>
|
||||
)}
|
||||
</div>
|
||||
<div className="grid grid-flow-col gap-1 overflow-x-scroll webkit-scrollbar:w-0 [scrollbar-width:none] place-content-start">
|
||||
{post.categories.data.map((category) => (
|
||||
{post?.categories?.data.map((category) => (
|
||||
<Chip key={category.id} className="text-sm">
|
||||
{category.attributes.short}
|
||||
{category.attributes?.short}
|
||||
</Chip>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -5,8 +5,8 @@ import { MouseEventHandler } from "react";
|
|||
type NavOptionProps = {
|
||||
url: string;
|
||||
icon?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
title: string | null | undefined;
|
||||
subtitle?: string | null | undefined;
|
||||
border?: boolean;
|
||||
reduced?: boolean;
|
||||
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||
|
|
|
@ -2,8 +2,8 @@ import HorizontalLine from "components/HorizontalLine";
|
|||
|
||||
type PanelHeaderProps = {
|
||||
icon?: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
title: string | null | undefined;
|
||||
description?: string | null | undefined;
|
||||
};
|
||||
|
||||
export default function PanelHeader(props: PanelHeaderProps): JSX.Element {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import Button from "components/Button";
|
||||
import HorizontalLine from "components/HorizontalLine";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
|
||||
type ReturnButtonProps = {
|
||||
href: string;
|
||||
title: string;
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||
title: string | null | undefined;
|
||||
langui: AppStaticProps["langui"];
|
||||
displayOn: ReturnButtonType;
|
||||
horizontalLine?: boolean;
|
||||
className?: string;
|
||||
|
|
|
@ -3,14 +3,14 @@ import HorizontalLine from "components/HorizontalLine";
|
|||
import NavOption from "components/PanelComponents/NavOption";
|
||||
import ToolTip from "components/ToolTip";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
|
||||
import { useMediaDesktop } from "hooks/useMediaQuery";
|
||||
import Markdown from "markdown-to-jsx";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
|
||||
type MainPanelProps = {
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||
langui: AppStaticProps["langui"];
|
||||
};
|
||||
|
||||
export default function MainPanel(props: MainPanelProps): JSX.Element {
|
||||
|
|
|
@ -1,68 +1,67 @@
|
|||
import Chip from "components/Chip";
|
||||
import {
|
||||
GetContentTextQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
} from "graphql/operations-types";
|
||||
import { RecorderChipFragment } from "graphql/generated";
|
||||
import { AppStaticProps } from "queries/getAppStaticProps";
|
||||
import Button from "./Button";
|
||||
import Img, { ImageQuality } from "./Img";
|
||||
import ToolTip from "./ToolTip";
|
||||
|
||||
type RecorderChipProps = {
|
||||
className?: string;
|
||||
recorder: GetContentTextQuery["contents"]["data"][number]["attributes"]["text_set"][number]["transcribers"]["data"][number];
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||
recorder: RecorderChipFragment;
|
||||
langui: AppStaticProps["langui"];
|
||||
};
|
||||
|
||||
export default function RecorderChip(props: RecorderChipProps): JSX.Element {
|
||||
const { recorder, langui } = props;
|
||||
|
||||
return (
|
||||
<ToolTip
|
||||
content={
|
||||
<div className="text-left p-2 py-5 grid gap-8">
|
||||
<div className="grid grid-flow-col gap-6 place-items-center place-content-start">
|
||||
{recorder.attributes.avatar.data && (
|
||||
{recorder.avatar?.data?.attributes && (
|
||||
<Img
|
||||
className="w-20 rounded-full border-4 border-mid"
|
||||
image={recorder.attributes.avatar.data.attributes}
|
||||
image={recorder.avatar?.data.attributes}
|
||||
quality={ImageQuality.Small}
|
||||
rawImg
|
||||
/>
|
||||
)}
|
||||
<div className="grid gap-2">
|
||||
<h3 className=" text-2xl">{recorder.attributes.username}</h3>
|
||||
{recorder.attributes.languages.data.length > 0 && (
|
||||
<h3 className=" text-2xl">{recorder.username}</h3>
|
||||
{recorder.languages?.data && recorder.languages.data.length > 0 && (
|
||||
<div className="flex flex-row flex-wrap gap-1">
|
||||
<p>{langui.languages}:</p>
|
||||
{recorder.attributes.languages.data.map((language) => (
|
||||
{recorder.languages.data.map((language) => (
|
||||
<>
|
||||
{language.attributes && (
|
||||
<Chip key={language.attributes.code}>
|
||||
{language.attributes.code.toUpperCase()}
|
||||
</Chip>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{recorder.attributes.pronouns && (
|
||||
{recorder.pronouns && (
|
||||
<div className="flex flex-row flex-wrap gap-1">
|
||||
<p>{langui.pronouns}:</p>
|
||||
<Chip>{recorder.attributes.pronouns}</Chip>
|
||||
<Chip>{recorder.pronouns}</Chip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{recorder.attributes.bio.length > 0 && (
|
||||
<p>{recorder.attributes.bio[0].bio}</p>
|
||||
)}
|
||||
{recorder.bio?.[0] && <p>{recorder.bio[0].bio}</p>}
|
||||
|
||||
<Button className="cursor-not-allowed">View profile</Button>
|
||||
</div>
|
||||
}
|
||||
placement="top"
|
||||
>
|
||||
<Chip key={recorder.id}>
|
||||
{recorder.attributes.anonymize
|
||||
? `Recorder#${recorder.attributes.anonymous_code}`
|
||||
: recorder.attributes.username}
|
||||
<Chip key={recorder.anonymous_code}>
|
||||
{recorder.anonymize
|
||||
? `Recorder#${recorder.anonymous_code}`
|
||||
: recorder.username}
|
||||
</Chip>
|
||||
</ToolTip>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
fragment datePicker on ComponentBasicsDatepicker {
|
||||
year
|
||||
month
|
||||
day
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fragment pricePicker on ComponentBasicsPrice {
|
||||
amount
|
||||
currency {
|
||||
data {
|
||||
attributes {
|
||||
symbol
|
||||
code
|
||||
rate_to_usd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
fragment recorderChip on Recorder {
|
||||
username
|
||||
anonymize
|
||||
anonymous_code
|
||||
pronouns
|
||||
bio(filters: { language: { code: { eq: $language_code } } }) {
|
||||
bio
|
||||
}
|
||||
languages {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
}
|
||||
}
|
||||
}
|
||||
avatar {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
fragment uploadImage on UploadFile {
|
||||
name
|
||||
alternativeText
|
||||
caption
|
||||
width
|
||||
height
|
||||
url
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,178 +0,0 @@
|
|||
import { readFileSync } from "fs";
|
||||
import {
|
||||
GetChronologyItemsQuery,
|
||||
GetChronologyItemsQueryVariables,
|
||||
GetContentQuery,
|
||||
GetContentQueryVariables,
|
||||
GetContentsQuery,
|
||||
GetContentsQueryVariables,
|
||||
GetContentsSlugsQuery,
|
||||
GetContentsSlugsQueryVariables,
|
||||
GetContentTextQuery,
|
||||
GetContentTextQueryVariables,
|
||||
GetCurrenciesQuery,
|
||||
GetCurrenciesQueryVariables,
|
||||
GetErasQuery,
|
||||
GetErasQueryVariables,
|
||||
GetLanguagesQuery,
|
||||
GetLanguagesQueryVariables,
|
||||
GetLibraryItemQuery,
|
||||
GetLibraryItemQueryVariables,
|
||||
GetLibraryItemScansQuery,
|
||||
GetLibraryItemScansQueryVariables,
|
||||
GetLibraryItemsPreviewQuery,
|
||||
GetLibraryItemsPreviewQueryVariables,
|
||||
GetLibraryItemsSlugsQuery,
|
||||
GetLibraryItemsSlugsQueryVariables,
|
||||
GetPostQuery,
|
||||
GetPostQueryVariables,
|
||||
GetPostsPreviewQuery,
|
||||
GetPostsPreviewQueryVariables,
|
||||
GetPostsSlugsQuery,
|
||||
GetPostsSlugsQueryVariables,
|
||||
GetWebsiteInterfaceQuery,
|
||||
GetWebsiteInterfaceQueryVariables,
|
||||
} from "graphql/operations-types";
|
||||
|
||||
async function graphQL(query: string, variables?: string) {
|
||||
const res = await fetch(`${process.env.URL_GRAPHQL}`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
query: query,
|
||||
variables: variables,
|
||||
}),
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
|
||||
},
|
||||
});
|
||||
return (await res.json()).data;
|
||||
}
|
||||
|
||||
function getQueryFromOperations(queryName: string): string {
|
||||
const operations = readFileSync("./src/graphql/operation.graphql", "utf8");
|
||||
let startingIndex = -1;
|
||||
let endingIndex = -1;
|
||||
const lines = operations.split("\n");
|
||||
lines.map((line, index) => {
|
||||
if (startingIndex === -1) {
|
||||
if (line.startsWith(`query ${queryName}(`)) startingIndex = index;
|
||||
if (line.startsWith(`query ${queryName} {`)) startingIndex = index;
|
||||
} else if (endingIndex === -1) {
|
||||
if (line.startsWith("query")) endingIndex = index;
|
||||
}
|
||||
});
|
||||
return lines.slice(startingIndex, endingIndex).join("\n");
|
||||
}
|
||||
|
||||
export async function getWebsiteInterface(
|
||||
variables: GetWebsiteInterfaceQueryVariables
|
||||
): Promise<GetWebsiteInterfaceQuery> {
|
||||
const query = getQueryFromOperations("getWebsiteInterface");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getEras(
|
||||
variables: GetErasQueryVariables
|
||||
): Promise<GetErasQuery> {
|
||||
const query = getQueryFromOperations("getEras");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getChronologyItems(
|
||||
variables: GetChronologyItemsQueryVariables
|
||||
): Promise<GetChronologyItemsQuery> {
|
||||
const query = getQueryFromOperations("getChronologyItems");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getLibraryItemsPreview(
|
||||
variables: GetLibraryItemsPreviewQueryVariables
|
||||
): Promise<GetLibraryItemsPreviewQuery> {
|
||||
const query = getQueryFromOperations("getLibraryItemsPreview");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getLibraryItemsSlugs(
|
||||
variables: GetLibraryItemsSlugsQueryVariables
|
||||
): Promise<GetLibraryItemsSlugsQuery> {
|
||||
const query = getQueryFromOperations("getLibraryItemsSlugs");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getLibraryItem(
|
||||
variables: GetLibraryItemQueryVariables
|
||||
): Promise<GetLibraryItemQuery> {
|
||||
const query = getQueryFromOperations("getLibraryItem");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getContentsSlugs(
|
||||
variables: GetContentsSlugsQueryVariables
|
||||
): Promise<GetContentsSlugsQuery> {
|
||||
const query = getQueryFromOperations("getContentsSlugs");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getContents(
|
||||
variables: GetContentsQueryVariables
|
||||
): Promise<GetContentsQuery> {
|
||||
const query = getQueryFromOperations("getContents");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getContent(
|
||||
variables: GetContentQueryVariables
|
||||
): Promise<GetContentQuery> {
|
||||
const query = getQueryFromOperations("getContent");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getContentText(
|
||||
variables: GetContentTextQueryVariables
|
||||
): Promise<GetContentTextQuery> {
|
||||
const query = getQueryFromOperations("getContentText");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getCurrencies(
|
||||
variables: GetCurrenciesQueryVariables
|
||||
): Promise<GetCurrenciesQuery> {
|
||||
const query = getQueryFromOperations("getCurrencies");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getLanguages(
|
||||
variables: GetLanguagesQueryVariables
|
||||
): Promise<GetLanguagesQuery> {
|
||||
const query = getQueryFromOperations("getLanguages");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getPost(
|
||||
variables: GetPostQueryVariables
|
||||
): Promise<GetPostQuery> {
|
||||
const query = getQueryFromOperations("getPost");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getPostsSlugs(
|
||||
variables: GetPostsSlugsQueryVariables
|
||||
): Promise<GetPostsSlugsQuery> {
|
||||
const query = getQueryFromOperations("getPostsSlugs");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getPostsPreview(
|
||||
variables: GetPostsPreviewQueryVariables
|
||||
): Promise<GetPostsPreviewQuery> {
|
||||
const query = getQueryFromOperations("getPostsPreview");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
||||
|
||||
export async function getLibraryItemScans(
|
||||
variables: GetLibraryItemScansQueryVariables
|
||||
): Promise<GetLibraryItemScansQuery> {
|
||||
const query = getQueryFromOperations("getLibraryItemScans");
|
||||
return await graphQL(query, JSON.stringify(variables));
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
query getChronologyItems($language_code: String) {
|
||||
chronologyItems(
|
||||
pagination: { limit: -1 }
|
||||
sort: ["year:asc", "month:asc", "day:asc"]
|
||||
) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
year
|
||||
month
|
||||
day
|
||||
displayed_date
|
||||
events {
|
||||
id
|
||||
source {
|
||||
data {
|
||||
attributes {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
translations(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
description
|
||||
note
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
query getContent($slug: String, $language_code: String) {
|
||||
contents(filters: { slug: { eq: $slug } }) {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(filters: { language: { code: { eq: $language_code } } }) {
|
||||
pre_title
|
||||
title
|
||||
subtitle
|
||||
description
|
||||
}
|
||||
categories {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
name
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
type {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(filters: { language: { code: { eq: $language_code } } }) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ranged_contents {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
scan_set {
|
||||
id
|
||||
}
|
||||
library_item {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
title
|
||||
subtitle
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
text_set {
|
||||
id
|
||||
}
|
||||
video_set {
|
||||
id
|
||||
}
|
||||
audio_set {
|
||||
id
|
||||
}
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
query getContentText($slug: String, $language_code: String) {
|
||||
contents(filters: { slug: { eq: $slug } }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
titles(filters: { language: { code: { eq: $language_code } } }) {
|
||||
pre_title
|
||||
title
|
||||
subtitle
|
||||
description
|
||||
}
|
||||
categories {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
name
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
type {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(filters: { language: { code: { eq: $language_code } } }) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ranged_contents {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
scan_set {
|
||||
id
|
||||
}
|
||||
library_item {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
title
|
||||
subtitle
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
text_set_languages: text_set {
|
||||
language {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
text_set(filters: { language: { code: { eq: $language_code } } }) {
|
||||
status
|
||||
text
|
||||
source_language {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
}
|
||||
}
|
||||
}
|
||||
transcribers {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
...recorderChip
|
||||
}
|
||||
}
|
||||
}
|
||||
translators {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
...recorderChip
|
||||
}
|
||||
}
|
||||
}
|
||||
proofreaders {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
...recorderChip
|
||||
}
|
||||
}
|
||||
}
|
||||
notes
|
||||
}
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
query getContents($language_code: String) {
|
||||
contents(pagination: { limit: -1 }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
titles(filters: { language: { code: { eq: $language_code } } }) {
|
||||
pre_title
|
||||
title
|
||||
subtitle
|
||||
}
|
||||
categories {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
name
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
type {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(filters: { language: { code: { eq: $language_code } } }) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ranged_contents {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
scan_set {
|
||||
id
|
||||
}
|
||||
library_item {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
title
|
||||
subtitle
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
text_set {
|
||||
id
|
||||
}
|
||||
video_set {
|
||||
id
|
||||
}
|
||||
audio_set {
|
||||
id
|
||||
}
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
query getContentsSlugs {
|
||||
contents(pagination: { limit: -1 }) {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
query getCurrencies {
|
||||
currencies {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
code
|
||||
symbol
|
||||
rate_to_usd
|
||||
display_decimals
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
query getEras($language_code: String) {
|
||||
chronologyEras(sort: "starting_year") {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
starting_year
|
||||
ending_year
|
||||
title(filters: { language: { code: { eq: $language_code } } }) {
|
||||
title
|
||||
description
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
query getLanguages {
|
||||
languages {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
name
|
||||
code
|
||||
localized_name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,387 @@
|
|||
query getLibraryItem($slug: String, $language_code: String) {
|
||||
libraryItems(filters: { slug: { eq: $slug } }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
title
|
||||
subtitle
|
||||
slug
|
||||
root_item
|
||||
primary
|
||||
digital
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
gallery {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
release_date {
|
||||
...datePicker
|
||||
}
|
||||
price {
|
||||
...pricePicker
|
||||
}
|
||||
categories {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
name
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
size {
|
||||
width
|
||||
height
|
||||
thickness
|
||||
}
|
||||
descriptions(filters: { language: { code: { eq: $language_code } } }) {
|
||||
description
|
||||
}
|
||||
metadata {
|
||||
__typename
|
||||
... on ComponentMetadataBooks {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
binding_type
|
||||
page_count
|
||||
page_order
|
||||
languages {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataVideo {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataGame {
|
||||
platforms {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
audio_languages {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
sub_languages {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
interface_languages {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataAudio {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataGroup {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
subitems_type {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
subitem_of {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
title
|
||||
subtitle
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
subitems {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
title
|
||||
subtitle
|
||||
slug
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
release_date {
|
||||
...datePicker
|
||||
}
|
||||
price {
|
||||
...pricePicker
|
||||
}
|
||||
categories {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
name
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
metadata {
|
||||
__typename
|
||||
... on ComponentMetadataBooks {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: {
|
||||
language: { code: { eq: $language_code } }
|
||||
}
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataGame {
|
||||
platforms {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataVideo {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: {
|
||||
language: { code: { eq: $language_code } }
|
||||
}
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataAudio {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: {
|
||||
language: { code: { eq: $language_code } }
|
||||
}
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataGroup {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: {
|
||||
language: { code: { eq: $language_code } }
|
||||
}
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
subitems_type {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: {
|
||||
language: { code: { eq: $language_code } }
|
||||
}
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
submerchs {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
title
|
||||
subtitle
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
contents(pagination: { limit: -1 }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
range {
|
||||
__typename
|
||||
... on ComponentRangePageRange {
|
||||
starting_page
|
||||
ending_page
|
||||
}
|
||||
... on ComponentRangeTimeRange {
|
||||
starting_time
|
||||
ending_time
|
||||
}
|
||||
}
|
||||
scan_set {
|
||||
id
|
||||
}
|
||||
content {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
categories {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
name
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
type {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: {
|
||||
language: { code: { eq: $language_code } }
|
||||
}
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
pre_title
|
||||
title
|
||||
subtitle
|
||||
}
|
||||
text_set {
|
||||
id
|
||||
}
|
||||
video_set {
|
||||
id
|
||||
}
|
||||
audio_set {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
query getLibraryItemScans($slug: String, $language_code: String) {
|
||||
libraryItems(filters: { slug: { eq: $slug } }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
title
|
||||
subtitle
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
contents(pagination: { limit: -1 }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
range {
|
||||
__typename
|
||||
... on ComponentRangePageRange {
|
||||
starting_page
|
||||
ending_page
|
||||
}
|
||||
... on ComponentRangeTimeRange {
|
||||
starting_time
|
||||
ending_time
|
||||
}
|
||||
}
|
||||
scan_set_languages: scan_set {
|
||||
language {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scan_set(
|
||||
filters: {
|
||||
or: [
|
||||
{ language: { code: { eq: "xx" } } }
|
||||
{ language: { code: { eq: $language_code } } }
|
||||
]
|
||||
}
|
||||
) {
|
||||
status
|
||||
source_language {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
}
|
||||
}
|
||||
}
|
||||
scanners {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
...recorderChip
|
||||
}
|
||||
}
|
||||
}
|
||||
cleaners {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
...recorderChip
|
||||
}
|
||||
}
|
||||
}
|
||||
typesetters {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
...recorderChip
|
||||
}
|
||||
}
|
||||
}
|
||||
notes
|
||||
pages(pagination: { limit: -1 }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
query getLibraryItemsPreview($language_code: String) {
|
||||
libraryItems(pagination: { limit: -1 }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
title
|
||||
subtitle
|
||||
slug
|
||||
root_item
|
||||
primary
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
release_date {
|
||||
...datePicker
|
||||
}
|
||||
price {
|
||||
...pricePicker
|
||||
}
|
||||
categories {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
name
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
metadata {
|
||||
__typename
|
||||
... on ComponentMetadataBooks {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataGame {
|
||||
platforms {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataVideo {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataAudio {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
... on ComponentMetadataGroup {
|
||||
subtype {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
subitems_type {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
titles(
|
||||
filters: { language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
query getLibraryItemsSlugs {
|
||||
libraryItems(pagination: { limit: -1 }) {
|
||||
data {
|
||||
attributes {
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
query getPost($slug: String, $language_code: String) {
|
||||
posts(filters: { slug: { eq: $slug } }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
updatedAt
|
||||
date {
|
||||
...datePicker
|
||||
}
|
||||
authors {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
...recorderChip
|
||||
}
|
||||
}
|
||||
}
|
||||
categories {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
name
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
hidden
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
translations_languages: translations {
|
||||
language {
|
||||
data {
|
||||
attributes {
|
||||
code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
translations(filters: { language: { code: { eq: $language_code } } }) {
|
||||
status
|
||||
title
|
||||
excerpt
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
query getPostsPreview($language_code: String) {
|
||||
posts(filters: { hidden: { eq: false } }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
date {
|
||||
...datePicker
|
||||
}
|
||||
categories {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
short
|
||||
}
|
||||
}
|
||||
}
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
translations(filters: { language: { code: { eq: $language_code } } }) {
|
||||
title
|
||||
excerpt
|
||||
thumbnail {
|
||||
data {
|
||||
attributes {
|
||||
...uploadImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
query getPostsSlugs {
|
||||
posts(filters: { hidden: { eq: false } }) {
|
||||
data {
|
||||
id
|
||||
attributes {
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
query getWebsiteInterface($language_code: String) {
|
||||
websiteInterfaces(
|
||||
filters: { ui_language: { code: { eq: $language_code } } }
|
||||
) {
|
||||
data {
|
||||
attributes {
|
||||
library
|
||||
contents
|
||||
wiki
|
||||
chronicles
|
||||
library_short_description
|
||||
contents_short_description
|
||||
wiki_short_description
|
||||
chronicles_short_description
|
||||
news
|
||||
merch
|
||||
gallery
|
||||
archives
|
||||
about_us
|
||||
licensing_notice
|
||||
copyright_notice
|
||||
contents_description
|
||||
type
|
||||
category
|
||||
categories
|
||||
size
|
||||
release_date
|
||||
release_year
|
||||
details
|
||||
price
|
||||
width
|
||||
height
|
||||
thickness
|
||||
subitem
|
||||
subitems
|
||||
subitem_of
|
||||
variant
|
||||
variants
|
||||
variant_of
|
||||
summary
|
||||
audio
|
||||
video
|
||||
textual
|
||||
game
|
||||
other
|
||||
return_to
|
||||
left_to_right
|
||||
right_to_left
|
||||
page
|
||||
pages
|
||||
page_order
|
||||
binding
|
||||
type_information
|
||||
front_matter
|
||||
back_matter
|
||||
open_content
|
||||
read_content
|
||||
watch_content
|
||||
listen_content
|
||||
view_scans
|
||||
paperback
|
||||
hardcover
|
||||
languages
|
||||
select_language
|
||||
language
|
||||
library_description
|
||||
wiki_description
|
||||
chronicles_description
|
||||
news_description
|
||||
merch_description
|
||||
gallery_description
|
||||
archives_description
|
||||
about_us_description
|
||||
page_not_found
|
||||
default_description
|
||||
name
|
||||
show_subitems
|
||||
show_primary_items
|
||||
show_secondary_items
|
||||
no_type
|
||||
no_year
|
||||
order_by
|
||||
group_by
|
||||
select_option_sidebar
|
||||
group
|
||||
settings
|
||||
theme
|
||||
light
|
||||
auto
|
||||
dark
|
||||
font_size
|
||||
player_name
|
||||
currency
|
||||
font
|
||||
calculated
|
||||
status_incomplete
|
||||
status_draft
|
||||
status_review
|
||||
status_done
|
||||
incomplete
|
||||
draft
|
||||
review
|
||||
done
|
||||
status
|
||||
transcribers
|
||||
translators
|
||||
proofreaders
|
||||
transcript_notice
|
||||
translation_notice
|
||||
source_language
|
||||
pronouns
|
||||
no_category
|
||||
item
|
||||
items
|
||||
content
|
||||
result
|
||||
results
|
||||
language_switch_message
|
||||
open_settings
|
||||
change_language
|
||||
open_search
|
||||
chronology
|
||||
accords_handbook
|
||||
legality
|
||||
members
|
||||
sharing_policy
|
||||
contact_us
|
||||
email
|
||||
email_gdpr_notice
|
||||
message
|
||||
send
|
||||
response_invalid_code
|
||||
response_invalid_email
|
||||
response_email_success
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,9 @@
|
|||
import { GraphQLClient } from "graphql-request";
|
||||
import { getSdk, UploadFile } from "graphql/generated";
|
||||
|
||||
export function getReadySdk() {
|
||||
const client = new GraphQLClient(process.env.URL_GRAPHQL ?? "", {
|
||||
headers: { Authorization: `Bearer ${process.env.ACCESS_TOKEN}` },
|
||||
});
|
||||
return getSdk(client);
|
||||
}
|
|
@ -7,23 +7,27 @@ import ReturnButton, {
|
|||
} from "components/PanelComponents/ReturnButton";
|
||||
import ContentPanel from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import { getPost } from "graphql/operations";
|
||||
import { GetPostQuery } from "graphql/operations-types";
|
||||
import { GetPostQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getLocalesFromLanguages, prettySlug } from "queries/helpers";
|
||||
|
||||
interface AccordsHandbookProps extends AppStaticProps {
|
||||
post: GetPostQuery["posts"]["data"][number]["attributes"];
|
||||
interface Props extends AppStaticProps {
|
||||
post: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
}
|
||||
|
||||
export default function AccordsHandbook(
|
||||
props: AccordsHandbookProps
|
||||
): JSX.Element {
|
||||
export default function AccordsHandbook(props: Props): JSX.Element {
|
||||
const { langui, post } = props;
|
||||
const router = useRouter();
|
||||
const locales = getLocalesFromLanguages(post.translations_languages);
|
||||
const locales = getLocalesFromLanguages(post?.translations_languages);
|
||||
|
||||
const body = post?.translations?.[0]?.body ?? "";
|
||||
const title = post?.translations?.[0]?.title ?? prettySlug(post?.slug);
|
||||
|
||||
const subPanel = (
|
||||
<SubPanel>
|
||||
|
@ -34,12 +38,7 @@ export default function AccordsHandbook(
|
|||
title={langui.about_us}
|
||||
horizontalLine
|
||||
/>
|
||||
{post.translations.length > 0 && post.translations[0].body && (
|
||||
<TOC
|
||||
text={post.translations[0].body}
|
||||
title={post.translations[0].title}
|
||||
/>
|
||||
)}
|
||||
<TOC text={body} title={title} />
|
||||
</SubPanel>
|
||||
);
|
||||
|
||||
|
@ -53,7 +52,7 @@ export default function AccordsHandbook(
|
|||
className="mb-10"
|
||||
/>
|
||||
{locales.includes(router.locale ?? "en") ? (
|
||||
<Markdawn text={post.translations[0].body} />
|
||||
<Markdawn text={body} />
|
||||
) : (
|
||||
<LanguageSwitcher
|
||||
locales={locales}
|
||||
|
@ -66,11 +65,7 @@ export default function AccordsHandbook(
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={
|
||||
post.translations.length > 0
|
||||
? post.translations[0].title
|
||||
: prettySlug(post.slug)
|
||||
}
|
||||
navTitle={title}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
{...props}
|
||||
|
@ -80,16 +75,17 @@ export default function AccordsHandbook(
|
|||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: AccordsHandbookProps }> {
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const slug = "accords-handbook";
|
||||
const props: AccordsHandbookProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: (
|
||||
await getPost({
|
||||
const post = await sdk.getPost({
|
||||
slug: slug,
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).posts.data[0].attributes,
|
||||
});
|
||||
if (!post.posts) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: post.posts.data[0].attributes,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -8,31 +8,41 @@ import ReturnButton, {
|
|||
} from "components/PanelComponents/ReturnButton";
|
||||
import ContentPanel from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import { getPost } from "graphql/operations";
|
||||
import { GetPostQuery } from "graphql/operations-types";
|
||||
import { GetPostQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { RequestMailProps, ResponseMailProps } from "pages/api/mail";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getLocalesFromLanguages, randomInt } from "queries/helpers";
|
||||
import {
|
||||
getLocalesFromLanguages,
|
||||
prettySlug,
|
||||
randomInt,
|
||||
} from "queries/helpers";
|
||||
import { useState } from "react";
|
||||
|
||||
interface ContactProps extends AppStaticProps {
|
||||
post: GetPostQuery["posts"]["data"][number]["attributes"];
|
||||
interface Props extends AppStaticProps {
|
||||
post: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
}
|
||||
|
||||
export default function AboutUs(props: ContactProps): JSX.Element {
|
||||
export default function AboutUs(props: Props): JSX.Element {
|
||||
const { langui, post } = props;
|
||||
const router = useRouter();
|
||||
const [formResponse, setFormResponse] = useState("");
|
||||
const [formState, setFormState] = useState<"completed" | "ongoing" | "stale">(
|
||||
"stale"
|
||||
);
|
||||
const locales = getLocalesFromLanguages(post.translations_languages);
|
||||
const locales = getLocalesFromLanguages(post?.translations_languages);
|
||||
|
||||
const [randomNumber1, setRandomNumber1] = useState(randomInt(0, 10));
|
||||
const [randomNumber2, setRandomNumber2] = useState(randomInt(0, 10));
|
||||
|
||||
const body = post?.translations?.[0]?.body ?? "";
|
||||
const title = post?.translations?.[0]?.title ?? prettySlug(post?.slug);
|
||||
|
||||
const subPanel = (
|
||||
<SubPanel>
|
||||
<ReturnButton
|
||||
|
@ -42,12 +52,7 @@ export default function AboutUs(props: ContactProps): JSX.Element {
|
|||
title={langui.about_us}
|
||||
horizontalLine
|
||||
/>
|
||||
{post.translations.length > 0 && post.translations[0].body && (
|
||||
<TOC
|
||||
text={post.translations[0].body}
|
||||
title={post.translations[0].title}
|
||||
/>
|
||||
)}
|
||||
<TOC text={body} title={title} />
|
||||
</SubPanel>
|
||||
);
|
||||
|
||||
|
@ -61,7 +66,7 @@ export default function AboutUs(props: ContactProps): JSX.Element {
|
|||
className="mb-10"
|
||||
/>
|
||||
{locales.includes(router.locale ?? "en") ? (
|
||||
<Markdawn text={post.translations[0].body} />
|
||||
<Markdawn text={body} />
|
||||
) : (
|
||||
<LanguageSwitcher
|
||||
locales={locales}
|
||||
|
@ -110,13 +115,13 @@ export default function AboutUs(props: ContactProps): JSX.Element {
|
|||
.then((response: ResponseMailProps) => {
|
||||
switch (response.code) {
|
||||
case "OKAY":
|
||||
setFormResponse(langui.response_email_success);
|
||||
setFormResponse(langui.response_email_success ?? "");
|
||||
setFormState("completed");
|
||||
|
||||
break;
|
||||
|
||||
case "EENVELOPE":
|
||||
setFormResponse(langui.response_invalid_email);
|
||||
setFormResponse(langui.response_invalid_email ?? "");
|
||||
setFormState("stale");
|
||||
break;
|
||||
|
||||
|
@ -127,7 +132,7 @@ export default function AboutUs(props: ContactProps): JSX.Element {
|
|||
}
|
||||
});
|
||||
} else {
|
||||
setFormResponse(langui.response_invalid_code);
|
||||
setFormResponse(langui.response_invalid_code ?? "");
|
||||
setFormState("stale");
|
||||
setRandomNumber1(randomInt(0, 10));
|
||||
setRandomNumber2(randomInt(0, 10));
|
||||
|
@ -194,7 +199,7 @@ export default function AboutUs(props: ContactProps): JSX.Element {
|
|||
|
||||
<input
|
||||
type="submit"
|
||||
value={langui.send}
|
||||
value={langui.send ?? "Send"}
|
||||
className="w-min !px-6"
|
||||
disabled={formState !== "stale"}
|
||||
/>
|
||||
|
@ -224,16 +229,17 @@ export default function AboutUs(props: ContactProps): JSX.Element {
|
|||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: ContactProps }> {
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const slug = "contact";
|
||||
const props: ContactProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: (
|
||||
await getPost({
|
||||
const post = await sdk.getPost({
|
||||
slug: slug,
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).posts.data[0].attributes,
|
||||
});
|
||||
if (!post.posts) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: post.posts.data[0].attributes,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -5,9 +5,9 @@ import SubPanel from "components/Panels/SubPanel";
|
|||
import { GetStaticPropsContext } from "next";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
|
||||
interface AboutUsProps extends AppStaticProps {}
|
||||
interface Props extends AppStaticProps {}
|
||||
|
||||
export default function AboutUs(props: AboutUsProps): JSX.Element {
|
||||
export default function AboutUs(props: Props): JSX.Element {
|
||||
const { langui } = props;
|
||||
const subPanel = (
|
||||
<SubPanel>
|
||||
|
@ -38,8 +38,8 @@ export default function AboutUs(props: AboutUsProps): JSX.Element {
|
|||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: AboutUsProps }> {
|
||||
const props: AboutUsProps = {
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
};
|
||||
return {
|
||||
|
|
|
@ -7,21 +7,27 @@ import ReturnButton, {
|
|||
} from "components/PanelComponents/ReturnButton";
|
||||
import ContentPanel from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import { getPost } from "graphql/operations";
|
||||
import { GetPostQuery } from "graphql/operations-types";
|
||||
import { GetPostQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getLocalesFromLanguages, prettySlug } from "queries/helpers";
|
||||
|
||||
interface SiteInfoProps extends AppStaticProps {
|
||||
post: GetPostQuery["posts"]["data"][number]["attributes"];
|
||||
interface Props extends AppStaticProps {
|
||||
post: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
}
|
||||
|
||||
export default function SiteInformation(props: SiteInfoProps): JSX.Element {
|
||||
export default function SiteInformation(props: Props): JSX.Element {
|
||||
const { langui, post } = props;
|
||||
const router = useRouter();
|
||||
const locales = getLocalesFromLanguages(post.translations_languages);
|
||||
const locales = getLocalesFromLanguages(post?.translations_languages);
|
||||
|
||||
const body = post?.translations?.[0]?.body ?? "";
|
||||
const title = post?.translations?.[0]?.title ?? prettySlug(post?.slug);
|
||||
|
||||
const subPanel = (
|
||||
<SubPanel>
|
||||
|
@ -32,12 +38,7 @@ export default function SiteInformation(props: SiteInfoProps): JSX.Element {
|
|||
title={langui.about_us}
|
||||
horizontalLine
|
||||
/>
|
||||
{post.translations.length > 0 && post.translations[0].body && (
|
||||
<TOC
|
||||
text={post.translations[0].body}
|
||||
title={post.translations[0].title}
|
||||
/>
|
||||
)}
|
||||
<TOC text={body} title={title} />
|
||||
</SubPanel>
|
||||
);
|
||||
|
||||
|
@ -51,7 +52,7 @@ export default function SiteInformation(props: SiteInfoProps): JSX.Element {
|
|||
className="mb-10"
|
||||
/>
|
||||
{locales.includes(router.locale ?? "en") ? (
|
||||
<Markdawn text={post.translations[0].body} />
|
||||
<Markdawn text={body} />
|
||||
) : (
|
||||
<LanguageSwitcher
|
||||
locales={locales}
|
||||
|
@ -64,11 +65,7 @@ export default function SiteInformation(props: SiteInfoProps): JSX.Element {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={
|
||||
post.translations.length > 0
|
||||
? post.translations[0].title
|
||||
: prettySlug(post.slug)
|
||||
}
|
||||
navTitle={title}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
{...props}
|
||||
|
@ -78,16 +75,17 @@ export default function SiteInformation(props: SiteInfoProps): JSX.Element {
|
|||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: SiteInfoProps }> {
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const slug = "legality";
|
||||
const props: SiteInfoProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: (
|
||||
await getPost({
|
||||
const post = await sdk.getPost({
|
||||
slug: slug,
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).posts.data[0].attributes,
|
||||
});
|
||||
if (!post.posts) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: post.posts.data[0].attributes,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -7,22 +7,27 @@ import ReturnButton, {
|
|||
} from "components/PanelComponents/ReturnButton";
|
||||
import ContentPanel from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import { getPost } from "graphql/operations";
|
||||
import { GetPostQuery } from "graphql/operations-types";
|
||||
import { GetPostQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getLocalesFromLanguages, prettySlug } from "queries/helpers";
|
||||
|
||||
interface SharingPolicyProps extends AppStaticProps {
|
||||
post: GetPostQuery["posts"]["data"][number]["attributes"];
|
||||
interface Props extends AppStaticProps {
|
||||
post: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
}
|
||||
|
||||
export default function SharingPolicy(props: SharingPolicyProps): JSX.Element {
|
||||
export default function SharingPolicy(props: Props): JSX.Element {
|
||||
const { langui, post } = props;
|
||||
const locales = getLocalesFromLanguages(post.translations_languages);
|
||||
const locales = getLocalesFromLanguages(post?.translations_languages);
|
||||
const router = useRouter();
|
||||
|
||||
const body = post?.translations?.[0]?.body ?? "";
|
||||
const title = post?.translations?.[0]?.title ?? prettySlug(post?.slug);
|
||||
|
||||
const subPanel = (
|
||||
<SubPanel>
|
||||
<ReturnButton
|
||||
|
@ -32,12 +37,7 @@ export default function SharingPolicy(props: SharingPolicyProps): JSX.Element {
|
|||
title={langui.about_us}
|
||||
horizontalLine
|
||||
/>
|
||||
{post.translations.length > 0 && post.translations[0].body && (
|
||||
<TOC
|
||||
text={post.translations[0].body}
|
||||
title={post.translations[0].title}
|
||||
/>
|
||||
)}
|
||||
<TOC text={body} title={title} />
|
||||
</SubPanel>
|
||||
);
|
||||
|
||||
|
@ -51,7 +51,7 @@ export default function SharingPolicy(props: SharingPolicyProps): JSX.Element {
|
|||
className="mb-10"
|
||||
/>
|
||||
{locales.includes(router.locale ?? "en") ? (
|
||||
<Markdawn text={post.translations[0].body} />
|
||||
<Markdawn text={body} />
|
||||
) : (
|
||||
<LanguageSwitcher
|
||||
locales={locales}
|
||||
|
@ -64,11 +64,7 @@ export default function SharingPolicy(props: SharingPolicyProps): JSX.Element {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={
|
||||
post.translations.length > 0
|
||||
? post.translations[0].title
|
||||
: prettySlug(post.slug)
|
||||
}
|
||||
navTitle={title}
|
||||
subPanel={subPanel}
|
||||
contentPanel={contentPanel}
|
||||
{...props}
|
||||
|
@ -78,16 +74,17 @@ export default function SharingPolicy(props: SharingPolicyProps): JSX.Element {
|
|||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: SharingPolicyProps }> {
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const slug = "sharing-policy";
|
||||
const props: SharingPolicyProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: (
|
||||
await getPost({
|
||||
const post = await sdk.getPost({
|
||||
slug: slug,
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).posts.data[0].attributes,
|
||||
});
|
||||
if (!post.posts) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: post.posts.data[0].attributes,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -64,7 +64,6 @@ export default async function Mail(
|
|||
req: NextApiRequest,
|
||||
res: NextApiResponse<ResponseMailProps>
|
||||
) {
|
||||
console.log(req.body);
|
||||
const body = req.body as RequestProps;
|
||||
const { serverRuntimeConfig } = getConfig();
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ import ContentPanel from "components/Panels/ContentPanel";
|
|||
import SubPanel from "components/Panels/SubPanel";
|
||||
import RecorderChip from "components/RecorderChip";
|
||||
import ToolTip from "components/ToolTip";
|
||||
import { getContentsSlugs, getContentText } from "graphql/operations";
|
||||
import { GetContentTextQuery } from "graphql/operations-types";
|
||||
import { GetContentTextQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import {
|
||||
GetStaticPathsContext,
|
||||
GetStaticPathsResult,
|
||||
|
@ -33,15 +33,21 @@ import {
|
|||
} from "queries/helpers";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
content: GetContentTextQuery["contents"]["data"][number]["attributes"];
|
||||
contentId: GetContentTextQuery["contents"]["data"][number]["id"];
|
||||
content: Exclude<
|
||||
GetContentTextQuery["contents"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
contentId: Exclude<
|
||||
GetContentTextQuery["contents"],
|
||||
null | undefined
|
||||
>["data"][number]["id"];
|
||||
}
|
||||
|
||||
export default function Content(props: Props): JSX.Element {
|
||||
useTesting(props);
|
||||
const { langui, content, languages } = props;
|
||||
const router = useRouter();
|
||||
const locales = getLocalesFromLanguages(content.text_set_languages);
|
||||
const locales = getLocalesFromLanguages(content?.text_set_languages);
|
||||
|
||||
const subPanel = (
|
||||
<SubPanel>
|
||||
|
@ -53,7 +59,7 @@ export default function Content(props: Props): JSX.Element {
|
|||
horizontalLine
|
||||
/>
|
||||
|
||||
{content.text_set.length > 0 && content.text_set[0].source_language.data && (
|
||||
{content?.text_set?.[0]?.source_language?.data?.attributes && (
|
||||
<div className="grid gap-5">
|
||||
<h2 className="text-xl">
|
||||
{content.text_set[0].source_language.data.attributes.code ===
|
||||
|
@ -91,46 +97,61 @@ export default function Content(props: Props): JSX.Element {
|
|||
</ToolTip>
|
||||
</div>
|
||||
|
||||
{content.text_set[0].transcribers.data.length > 0 && (
|
||||
{content.text_set[0].transcribers &&
|
||||
content.text_set[0].transcribers.data.length > 0 && (
|
||||
<div>
|
||||
<p className="font-headers">{langui.transcribers}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{content.text_set[0].transcribers.data.map((recorder) => (
|
||||
<>
|
||||
{recorder.attributes && (
|
||||
<RecorderChip
|
||||
key={recorder.id}
|
||||
langui={langui}
|
||||
recorder={recorder}
|
||||
recorder={recorder.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{content.text_set[0].translators.data.length > 0 && (
|
||||
{content.text_set[0].translators &&
|
||||
content.text_set[0].translators.data.length > 0 && (
|
||||
<div>
|
||||
<p className="font-headers">{langui.translators}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{content.text_set[0].translators.data.map((recorder) => (
|
||||
<>
|
||||
{recorder.attributes && (
|
||||
<RecorderChip
|
||||
key={recorder.id}
|
||||
langui={langui}
|
||||
recorder={recorder}
|
||||
recorder={recorder.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{content.text_set[0].proofreaders.data.length > 0 && (
|
||||
{content.text_set[0].proofreaders &&
|
||||
content.text_set[0].proofreaders.data.length > 0 && (
|
||||
<div>
|
||||
<p className="font-headers">{langui.proofreaders}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{content.text_set[0].proofreaders.data.map((recorder) => (
|
||||
<>
|
||||
{recorder.attributes && (
|
||||
<RecorderChip
|
||||
key={recorder.id}
|
||||
langui={langui}
|
||||
recorder={recorder}
|
||||
recorder={recorder.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -138,13 +159,15 @@ export default function Content(props: Props): JSX.Element {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{content.text_set.length > 0 && content.text_set[0].text && (
|
||||
{content?.text_set &&
|
||||
content.text_set.length > 0 &&
|
||||
content.text_set[0]?.text && (
|
||||
<>
|
||||
<HorizontalLine />
|
||||
<TOC
|
||||
text={content.text_set[0].text}
|
||||
title={
|
||||
content.titles.length > 0
|
||||
content.titles && content.titles.length > 0 && content.titles[0]
|
||||
? prettyinlineTitle(
|
||||
content.titles[0].pre_title,
|
||||
content.titles[0].title,
|
||||
|
@ -160,29 +183,34 @@ export default function Content(props: Props): JSX.Element {
|
|||
const contentPanel = (
|
||||
<ContentPanel>
|
||||
<ReturnButton
|
||||
href={`/contents/${content.slug}`}
|
||||
href={`/contents/${content?.slug}`}
|
||||
title={langui.content}
|
||||
langui={langui}
|
||||
displayOn={ReturnButtonType.mobile}
|
||||
className="mb-10"
|
||||
/>
|
||||
{content && (
|
||||
<div className="grid place-items-center">
|
||||
<ThumbnailHeader
|
||||
thumbnail={content.thumbnail.data?.attributes}
|
||||
thumbnail={content.thumbnail?.data?.attributes}
|
||||
pre_title={
|
||||
content.titles.length > 0 ? content.titles[0].pre_title : undefined
|
||||
content.titles && content.titles.length > 0
|
||||
? content.titles[0]?.pre_title
|
||||
: undefined
|
||||
}
|
||||
title={
|
||||
content.titles.length > 0
|
||||
? content.titles[0].title
|
||||
content.titles && content.titles.length > 0
|
||||
? content.titles[0]?.title
|
||||
: prettySlug(content.slug)
|
||||
}
|
||||
subtitle={
|
||||
content.titles.length > 0 ? content.titles[0].subtitle : undefined
|
||||
content.titles && content.titles.length > 0
|
||||
? content.titles[0]?.subtitle
|
||||
: undefined
|
||||
}
|
||||
description={
|
||||
content.titles.length > 0
|
||||
? content.titles[0].description
|
||||
content.titles && content.titles.length > 0
|
||||
? content.titles[0]?.description
|
||||
: undefined
|
||||
}
|
||||
type={content.type}
|
||||
|
@ -193,7 +221,7 @@ export default function Content(props: Props): JSX.Element {
|
|||
<HorizontalLine />
|
||||
|
||||
{locales.includes(router.locale ?? "en") ? (
|
||||
<Markdawn text={content.text_set[0].text} />
|
||||
<Markdawn text={content.text_set?.[0]?.text ?? ""} />
|
||||
) : (
|
||||
<LanguageSwitcher
|
||||
locales={locales}
|
||||
|
@ -202,23 +230,24 @@ export default function Content(props: Props): JSX.Element {
|
|||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</ContentPanel>
|
||||
);
|
||||
|
||||
let description = "";
|
||||
if (content.type.data) {
|
||||
if (content?.type?.data) {
|
||||
description += `${langui.type}: `;
|
||||
if (content.type.data.attributes.titles.length > 0) {
|
||||
description += content.type.data.attributes.titles[0].title;
|
||||
} else {
|
||||
description += prettySlug(content.type.data.attributes.slug);
|
||||
}
|
||||
|
||||
description +=
|
||||
content.type.data.attributes?.titles?.[0]?.title ??
|
||||
prettySlug(content.type.data.attributes?.slug);
|
||||
|
||||
description += "\n";
|
||||
}
|
||||
if (content.categories.data.length > 0) {
|
||||
if (content?.categories?.data && content.categories.data.length > 0) {
|
||||
description += `${langui.categories}: `;
|
||||
description += content.categories.data
|
||||
.map((category) => category.attributes.short)
|
||||
.map((category) => category.attributes?.short)
|
||||
.join(" | ");
|
||||
description += "\n";
|
||||
}
|
||||
|
@ -226,15 +255,15 @@ export default function Content(props: Props): JSX.Element {
|
|||
return (
|
||||
<AppLayout
|
||||
navTitle={
|
||||
content.titles.length > 0
|
||||
content?.titles && content.titles.length > 0 && content.titles[0]
|
||||
? prettyinlineTitle(
|
||||
content.titles[0].pre_title,
|
||||
content.titles[0].title,
|
||||
content.titles[0].subtitle
|
||||
)
|
||||
: prettySlug(content.slug)
|
||||
: prettySlug(content?.slug)
|
||||
}
|
||||
thumbnail={content.thumbnail.data?.attributes}
|
||||
thumbnail={content?.thumbnail?.data?.attributes ?? undefined}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
description={description}
|
||||
|
@ -246,18 +275,19 @@ export default function Content(props: Props): JSX.Element {
|
|||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const slug = context.params?.slug?.toString() ?? "";
|
||||
const content = (
|
||||
await getContentText({
|
||||
const content = await sdk.getContentText({
|
||||
slug: slug,
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).contents.data[0];
|
||||
if (!content) return { notFound: true };
|
||||
});
|
||||
|
||||
if (!content.contents || content.contents.data.length === 0)
|
||||
return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
content: content.attributes,
|
||||
contentId: content.id,
|
||||
content: content.contents.data[0].attributes,
|
||||
contentId: content.contents.data[0].id,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
@ -267,10 +297,12 @@ export async function getStaticProps(
|
|||
export async function getStaticPaths(
|
||||
context: GetStaticPathsContext
|
||||
): Promise<GetStaticPathsResult> {
|
||||
const contents = await getContentsSlugs({});
|
||||
const sdk = getReadySdk();
|
||||
const contents = await sdk.getContentsSlugs();
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
contents.contents.data.map((item) => {
|
||||
contents.contents?.data.map((item) => {
|
||||
context.locales?.map((local) => {
|
||||
if (item.attributes)
|
||||
paths.push({ params: { slug: item.attributes.slug }, locale: local });
|
||||
});
|
||||
});
|
||||
|
@ -287,12 +319,12 @@ function useTesting(props: Props) {
|
|||
const contentURL = `/admin/content-manager/collectionType/api::content.content/${contentId}`;
|
||||
|
||||
if (router.locale === "en") {
|
||||
if (content.categories.data.length === 0) {
|
||||
if (content?.categories?.data.length === 0) {
|
||||
prettyTestError(router, "Missing categories", ["content"], contentURL);
|
||||
}
|
||||
}
|
||||
|
||||
if (content.ranged_contents.data.length === 0) {
|
||||
if (content?.ranged_contents?.data.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Unconnected to any source",
|
||||
|
@ -301,7 +333,7 @@ function useTesting(props: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
if (content.text_set.length === 0) {
|
||||
if (content?.text_set?.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Has no textset, nor audioset, nor videoset",
|
||||
|
@ -310,7 +342,7 @@ function useTesting(props: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
if (content.text_set.length > 1) {
|
||||
if (content?.text_set && content.text_set.length > 1) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"More than one textset for this language",
|
||||
|
@ -319,10 +351,10 @@ function useTesting(props: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
if (content.text_set.length === 1) {
|
||||
if (content?.text_set?.length === 1) {
|
||||
const textset = content.text_set[0];
|
||||
|
||||
if (!textset.text) {
|
||||
if (!textset?.text) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing text",
|
||||
|
@ -330,16 +362,18 @@ function useTesting(props: Props) {
|
|||
contentURL
|
||||
);
|
||||
}
|
||||
if (!textset.source_language.data) {
|
||||
if (!textset?.source_language?.data) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing source language",
|
||||
["content", "text_set"],
|
||||
contentURL
|
||||
);
|
||||
} else if (textset.source_language.data.attributes.code === router.locale) {
|
||||
} else if (
|
||||
textset.source_language.data.attributes?.code === router.locale
|
||||
) {
|
||||
// This is a transcript
|
||||
if (textset.transcribers.data.length === 0) {
|
||||
if (textset.transcribers?.data.length === 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing transcribers attribution",
|
||||
|
@ -347,7 +381,7 @@ function useTesting(props: Props) {
|
|||
contentURL
|
||||
);
|
||||
}
|
||||
if (textset.translators.data.length > 0) {
|
||||
if (textset.translators && textset.translators.data.length > 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Transcripts shouldn't have translators",
|
||||
|
@ -357,7 +391,7 @@ function useTesting(props: Props) {
|
|||
}
|
||||
} else {
|
||||
// This is a translation
|
||||
if (textset.translators.data.length === 0) {
|
||||
if (textset.translators?.data.length === 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing translators attribution",
|
||||
|
@ -365,7 +399,7 @@ function useTesting(props: Props) {
|
|||
contentURL
|
||||
);
|
||||
}
|
||||
if (textset.transcribers.data.length > 0) {
|
||||
if (textset.transcribers && textset.transcribers.data.length > 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Translations shouldn't have transcribers",
|
||||
|
|
|
@ -1,379 +0,0 @@
|
|||
import AppLayout from "components/AppLayout";
|
||||
import Button from "components/Button";
|
||||
import Chip from "components/Chip";
|
||||
import ThumbnailHeader from "components/Content/ThumbnailHeader";
|
||||
import HorizontalLine from "components/HorizontalLine";
|
||||
import LanguageSwitcher from "components/LanguageSwitcher";
|
||||
import Markdawn from "components/Markdown/Markdawn";
|
||||
import TOC from "components/Markdown/TOC";
|
||||
import ReturnButton, {
|
||||
ReturnButtonType,
|
||||
} from "components/PanelComponents/ReturnButton";
|
||||
import ContentPanel from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import RecorderChip from "components/RecorderChip";
|
||||
import ToolTip from "components/ToolTip";
|
||||
import { getContentsSlugs, getContentText } from "graphql/operations";
|
||||
import { GetContentTextQuery } from "graphql/operations-types";
|
||||
import {
|
||||
GetStaticPathsContext,
|
||||
GetStaticPathsResult,
|
||||
GetStaticPropsContext,
|
||||
} from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import {
|
||||
getLocalesFromLanguages,
|
||||
getStatusDescription,
|
||||
prettyinlineTitle,
|
||||
prettyLanguage,
|
||||
prettySlug,
|
||||
prettyTestError,
|
||||
prettyTestWarning,
|
||||
} from "queries/helpers";
|
||||
|
||||
interface ContentReadProps extends AppStaticProps {
|
||||
content: GetContentTextQuery["contents"]["data"][number]["attributes"];
|
||||
contentId: GetContentTextQuery["contents"]["data"][number]["id"];
|
||||
}
|
||||
|
||||
export default function ContentRead(props: ContentReadProps): JSX.Element {
|
||||
useTesting(props);
|
||||
const { langui, content, languages } = props;
|
||||
const router = useRouter();
|
||||
const locales = getLocalesFromLanguages(content.text_set_languages);
|
||||
|
||||
const subPanel = (
|
||||
<SubPanel>
|
||||
<ReturnButton
|
||||
href={`/contents/${content.slug}`}
|
||||
title={"Content"}
|
||||
langui={langui}
|
||||
displayOn={ReturnButtonType.desktop}
|
||||
horizontalLine
|
||||
/>
|
||||
|
||||
{content.text_set.length > 0 && content.text_set[0].source_language.data && (
|
||||
<div className="grid gap-5">
|
||||
<h2 className="text-xl">
|
||||
{content.text_set[0].source_language.data.attributes.code ===
|
||||
router.locale
|
||||
? langui.transcript_notice
|
||||
: langui.translation_notice}
|
||||
</h2>
|
||||
|
||||
{content.text_set[0].source_language.data.attributes.code !==
|
||||
router.locale && (
|
||||
<div className="grid place-items-center gap-2">
|
||||
<p className="font-headers">{langui.source_language}:</p>
|
||||
<Button
|
||||
href={router.asPath}
|
||||
locale={
|
||||
content.text_set[0].source_language.data.attributes.code
|
||||
}
|
||||
>
|
||||
{prettyLanguage(
|
||||
content.text_set[0].source_language.data.attributes.code,
|
||||
languages
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-flow-col place-items-center place-content-center gap-2">
|
||||
<p className="font-headers">{langui.status}:</p>
|
||||
|
||||
<ToolTip
|
||||
content={getStatusDescription(content.text_set[0].status, langui)}
|
||||
maxWidth={"20rem"}
|
||||
>
|
||||
<Chip>{content.text_set[0].status}</Chip>
|
||||
</ToolTip>
|
||||
</div>
|
||||
|
||||
{content.text_set[0].transcribers.data.length > 0 && (
|
||||
<div>
|
||||
<p className="font-headers">{langui.transcribers}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{content.text_set[0].transcribers.data.map((recorder) => (
|
||||
<RecorderChip
|
||||
key={recorder.id}
|
||||
langui={langui}
|
||||
recorder={recorder}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{content.text_set[0].translators.data.length > 0 && (
|
||||
<div>
|
||||
<p className="font-headers">{langui.translators}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{content.text_set[0].translators.data.map((recorder) => (
|
||||
<RecorderChip
|
||||
key={recorder.id}
|
||||
langui={langui}
|
||||
recorder={recorder}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{content.text_set[0].proofreaders.data.length > 0 && (
|
||||
<div>
|
||||
<p className="font-headers">{langui.proofreaders}:</p>
|
||||
<div className="grid place-items-center place-content-center gap-2">
|
||||
{content.text_set[0].proofreaders.data.map((recorder) => (
|
||||
<RecorderChip
|
||||
key={recorder.id}
|
||||
langui={langui}
|
||||
recorder={recorder}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{content.text_set.length > 0 && content.text_set[0].text && (
|
||||
<>
|
||||
<HorizontalLine />
|
||||
<TOC
|
||||
text={content.text_set[0].text}
|
||||
title={
|
||||
content.titles.length > 0
|
||||
? prettyinlineTitle(
|
||||
content.titles[0].pre_title,
|
||||
content.titles[0].title,
|
||||
content.titles[0].subtitle
|
||||
)
|
||||
: prettySlug(content.slug)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</SubPanel>
|
||||
);
|
||||
const contentPanel = (
|
||||
<ContentPanel>
|
||||
<ReturnButton
|
||||
href={`/contents/${content.slug}`}
|
||||
title={langui.content}
|
||||
langui={langui}
|
||||
displayOn={ReturnButtonType.mobile}
|
||||
className="mb-10"
|
||||
/>
|
||||
<div className="grid place-items-center">
|
||||
<ThumbnailHeader
|
||||
thumbnail={content.thumbnail.data?.attributes}
|
||||
pre_title={
|
||||
content.titles.length > 0 ? content.titles[0].pre_title : undefined
|
||||
}
|
||||
title={
|
||||
content.titles.length > 0
|
||||
? content.titles[0].title
|
||||
: prettySlug(content.slug)
|
||||
}
|
||||
subtitle={
|
||||
content.titles.length > 0 ? content.titles[0].subtitle : undefined
|
||||
}
|
||||
description={
|
||||
content.titles.length > 0
|
||||
? content.titles[0].description
|
||||
: undefined
|
||||
}
|
||||
type={content.type}
|
||||
categories={content.categories}
|
||||
langui={langui}
|
||||
/>
|
||||
|
||||
<HorizontalLine />
|
||||
|
||||
{locales.includes(router.locale ?? "en") ? (
|
||||
<Markdawn text={content.text_set[0].text} />
|
||||
) : (
|
||||
<LanguageSwitcher
|
||||
locales={locales}
|
||||
languages={props.languages}
|
||||
langui={props.langui}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ContentPanel>
|
||||
);
|
||||
|
||||
let description = "";
|
||||
if (content.type.data) {
|
||||
description += `${langui.type}: `;
|
||||
if (content.type.data.attributes.titles.length > 0) {
|
||||
description += content.type.data.attributes.titles[0].title;
|
||||
} else {
|
||||
description += prettySlug(content.type.data.attributes.slug);
|
||||
}
|
||||
description += "\n";
|
||||
}
|
||||
if (content.categories.data.length > 0) {
|
||||
description += `${langui.categories}: `;
|
||||
description += content.categories.data
|
||||
.map((category) => category.attributes.short)
|
||||
.join(" | ");
|
||||
description += "\n";
|
||||
}
|
||||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle="Contents"
|
||||
title={
|
||||
content.titles.length > 0
|
||||
? prettyinlineTitle(
|
||||
content.titles[0].pre_title,
|
||||
content.titles[0].title,
|
||||
content.titles[0].subtitle
|
||||
)
|
||||
: prettySlug(content.slug)
|
||||
}
|
||||
thumbnail={content.thumbnail.data?.attributes}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
description={description}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: ContentReadProps }> {
|
||||
const slug = context.params?.slug?.toString() ?? "";
|
||||
const content = (
|
||||
await getContentText({
|
||||
slug: slug,
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).contents.data[0];
|
||||
if (!content) return { notFound: true };
|
||||
const props: ContentReadProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
content: content.attributes,
|
||||
contentId: content.id,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getStaticPaths(
|
||||
context: GetStaticPathsContext
|
||||
): Promise<GetStaticPathsResult> {
|
||||
const contents = await getContentsSlugs({});
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
contents.contents.data.map((item) => {
|
||||
context.locales?.map((local) => {
|
||||
paths.push({ params: { slug: item.attributes.slug }, locale: local });
|
||||
});
|
||||
});
|
||||
return {
|
||||
paths,
|
||||
fallback: "blocking",
|
||||
};
|
||||
}
|
||||
|
||||
function useTesting(props: ContentReadProps) {
|
||||
const router = useRouter();
|
||||
const { content, contentId } = props;
|
||||
|
||||
const contentURL = `/admin/content-manager/collectionType/api::content.content/${contentId}`;
|
||||
|
||||
if (router.locale === "en") {
|
||||
if (content.categories.data.length === 0) {
|
||||
prettyTestError(router, "Missing categories", ["content"], contentURL);
|
||||
}
|
||||
}
|
||||
|
||||
if (content.ranged_contents.data.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Unconnected to any source",
|
||||
["content"],
|
||||
contentURL
|
||||
);
|
||||
}
|
||||
|
||||
if (content.text_set.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Has no textset, nor audioset, nor videoset",
|
||||
["content"],
|
||||
contentURL
|
||||
);
|
||||
}
|
||||
|
||||
if (content.text_set.length > 1) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"More than one textset for this language",
|
||||
["content", "text_set"],
|
||||
contentURL
|
||||
);
|
||||
}
|
||||
|
||||
if (content.text_set.length === 1) {
|
||||
const textset = content.text_set[0];
|
||||
|
||||
if (!textset.text) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing text",
|
||||
["content", "text_set"],
|
||||
contentURL
|
||||
);
|
||||
}
|
||||
if (!textset.source_language.data) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing source language",
|
||||
["content", "text_set"],
|
||||
contentURL
|
||||
);
|
||||
} else if (textset.source_language.data.attributes.code === router.locale) {
|
||||
// This is a transcript
|
||||
if (textset.transcribers.data.length === 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing transcribers attribution",
|
||||
["content", "text_set"],
|
||||
contentURL
|
||||
);
|
||||
}
|
||||
if (textset.translators.data.length > 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Transcripts shouldn't have translators",
|
||||
["content", "text_set"],
|
||||
contentURL
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// This is a translation
|
||||
if (textset.translators.data.length === 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing translators attribution",
|
||||
["content", "text_set"],
|
||||
contentURL
|
||||
);
|
||||
}
|
||||
if (textset.transcribers.data.length > 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Translations shouldn't have transcribers",
|
||||
["content", "text_set"],
|
||||
contentURL
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,21 +7,18 @@ import ContentPanel, {
|
|||
} from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import Select from "components/Select";
|
||||
import { getContents } from "graphql/operations";
|
||||
import {
|
||||
GetContentsQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
} from "graphql/operations-types";
|
||||
import { GetContentsQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import { prettyinlineTitle, prettySlug } from "queries/helpers";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface ContentsProps extends AppStaticProps {
|
||||
contents: GetContentsQuery["contents"]["data"];
|
||||
contents: Exclude<GetContentsQuery["contents"], null | undefined>["data"];
|
||||
}
|
||||
|
||||
type GroupContentItems = Map<string, GetContentsQuery["contents"]["data"]>;
|
||||
type GroupContentItems = Map<string, ContentsProps["contents"]>;
|
||||
|
||||
export default function Contents(props: ContentsProps): JSX.Element {
|
||||
const { langui, contents } = props;
|
||||
|
@ -48,7 +45,7 @@ export default function Contents(props: ContentsProps): JSX.Element {
|
|||
<p className="flex-shrink-0">{langui.group_by}:</p>
|
||||
<Select
|
||||
className="w-full"
|
||||
options={[langui.category, langui.type]}
|
||||
options={[langui.category ?? "", langui.type ?? ""]}
|
||||
state={groupingMethod}
|
||||
setState={setGroupingMethod}
|
||||
allowEmpty
|
||||
|
@ -70,8 +67,8 @@ export default function Contents(props: ContentsProps): JSX.Element {
|
|||
{name}
|
||||
<Chip>{`${items.length} ${
|
||||
items.length <= 1
|
||||
? langui.result.toLowerCase()
|
||||
: langui.results.toLowerCase()
|
||||
? langui.result?.toLowerCase() ?? ""
|
||||
: langui.results?.toLowerCase() ?? ""
|
||||
}`}</Chip>
|
||||
</h2>
|
||||
)}
|
||||
|
@ -80,7 +77,14 @@ export default function Contents(props: ContentsProps): JSX.Element {
|
|||
className="grid gap-8 items-end grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))]"
|
||||
>
|
||||
{items.map((item) => (
|
||||
<LibraryContentPreview key={item.id} item={item.attributes} />
|
||||
<>
|
||||
{item.attributes && (
|
||||
<LibraryContentPreview
|
||||
key={item.id}
|
||||
item={item.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
|
@ -102,35 +106,32 @@ export default function Contents(props: ContentsProps): JSX.Element {
|
|||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: ContentsProps }> {
|
||||
const contents = (
|
||||
await getContents({
|
||||
const sdk = getReadySdk();
|
||||
const contents = await sdk.getContents({
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).contents.data;
|
||||
|
||||
contents.sort((a, b) => {
|
||||
const titleA =
|
||||
a.attributes.titles.length > 0
|
||||
});
|
||||
if (!contents.contents) return { notFound: true };
|
||||
contents.contents.data.sort((a, b) => {
|
||||
const titleA = a.attributes?.titles?.[0]
|
||||
? prettyinlineTitle(
|
||||
a.attributes.titles[0].pre_title,
|
||||
a.attributes.titles[0].title,
|
||||
a.attributes.titles[0].subtitle
|
||||
)
|
||||
: a.attributes.slug;
|
||||
const titleB =
|
||||
b.attributes.titles.length > 0
|
||||
: a.attributes?.slug ?? "";
|
||||
const titleB = b.attributes?.titles?.[0]
|
||||
? prettyinlineTitle(
|
||||
b.attributes.titles[0].pre_title,
|
||||
b.attributes.titles[0].title,
|
||||
b.attributes.titles[0].subtitle
|
||||
)
|
||||
: b.attributes.slug;
|
||||
: b.attributes?.slug ?? "";
|
||||
return titleA.localeCompare(titleB);
|
||||
});
|
||||
|
||||
const props: ContentsProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
contents: contents,
|
||||
contents: contents.contents.data,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
@ -138,7 +139,7 @@ export async function getStaticProps(
|
|||
}
|
||||
|
||||
function getGroups(
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"],
|
||||
langui: AppStaticProps["langui"],
|
||||
groupByType: number,
|
||||
items: ContentsProps["contents"]
|
||||
): GroupContentItems {
|
||||
|
@ -165,11 +166,11 @@ function getGroups(
|
|||
group.set(langui.no_category, []);
|
||||
|
||||
items.map((item) => {
|
||||
if (item.attributes.categories.data.length === 0) {
|
||||
if (item.attributes?.categories?.data.length === 0) {
|
||||
group.get(langui.no_category)?.push(item);
|
||||
} else {
|
||||
item.attributes.categories.data.map((category) => {
|
||||
group.get(category.attributes.name)?.push(item);
|
||||
item.attributes?.categories?.data.map((category) => {
|
||||
group.get(category.attributes?.name)?.push(item);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -180,10 +181,8 @@ function getGroups(
|
|||
const group: GroupContentItems = new Map();
|
||||
items.map((item) => {
|
||||
const type =
|
||||
item.attributes.type.data.attributes.titles.length > 0
|
||||
? item.attributes.type.data.attributes.titles[0].title
|
||||
: prettySlug(item.attributes.type.data.attributes.slug);
|
||||
|
||||
item.attributes?.type?.data?.attributes?.titles?.[0]?.title ??
|
||||
prettySlug(item.attributes?.type?.data?.attributes?.slug);
|
||||
if (!group.has(type)) group.set(type, []);
|
||||
group.get(type)?.push(item);
|
||||
});
|
||||
|
|
|
@ -2,22 +2,28 @@ import AppLayout from "components/AppLayout";
|
|||
import LanguageSwitcher from "components/LanguageSwitcher";
|
||||
import Markdawn from "components/Markdown/Markdawn";
|
||||
import ContentPanel from "components/Panels/ContentPanel";
|
||||
import { getPost } from "graphql/operations";
|
||||
import { GetPostQuery } from "graphql/operations-types";
|
||||
import { GetPostQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import { getLocalesFromLanguages, prettySlug } from "queries/helpers";
|
||||
|
||||
interface HomeProps extends AppStaticProps {
|
||||
post: GetPostQuery["posts"]["data"][number]["attributes"];
|
||||
interface Props extends AppStaticProps {
|
||||
post: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
}
|
||||
|
||||
export default function Home(props: HomeProps): JSX.Element {
|
||||
export default function Home(props: Props): JSX.Element {
|
||||
const { post } = props;
|
||||
const locales = getLocalesFromLanguages(post.translations_languages);
|
||||
const locales = getLocalesFromLanguages(post?.translations_languages);
|
||||
const router = useRouter();
|
||||
|
||||
const body = post?.translations?.[0]?.body ?? "";
|
||||
const title = post?.translations?.[0]?.title ?? prettySlug(post?.slug);
|
||||
|
||||
const contentPanel = (
|
||||
<ContentPanel>
|
||||
<div className="grid place-items-center place-content-center w-full gap-5 text-center">
|
||||
|
@ -28,7 +34,7 @@ export default function Home(props: HomeProps): JSX.Element {
|
|||
</h2>
|
||||
</div>
|
||||
{locales.includes(router.locale ?? "en") ? (
|
||||
<Markdawn text={post.translations[0].body} />
|
||||
<Markdawn text={body} />
|
||||
) : (
|
||||
<LanguageSwitcher
|
||||
locales={locales}
|
||||
|
@ -39,31 +45,22 @@ export default function Home(props: HomeProps): JSX.Element {
|
|||
</ContentPanel>
|
||||
);
|
||||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={
|
||||
post.translations.length > 0
|
||||
? post.translations[0].title
|
||||
: prettySlug(post.slug)
|
||||
}
|
||||
contentPanel={contentPanel}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
return <AppLayout navTitle={title} contentPanel={contentPanel} {...props} />;
|
||||
}
|
||||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: HomeProps }> {
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const slug = "home";
|
||||
const props: HomeProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: (
|
||||
await getPost({
|
||||
const post = await sdk.getPost({
|
||||
slug: slug,
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).posts.data[0].attributes,
|
||||
});
|
||||
if (!post.posts) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: post.posts.data[0].attributes,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -15,12 +15,12 @@ import ContentPanel, {
|
|||
} from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { getLibraryItem, getLibraryItemsSlugs } from "graphql/operations";
|
||||
import {
|
||||
Enum_Componentmetadatabooks_Binding_Type,
|
||||
Enum_Componentmetadatabooks_Page_Order,
|
||||
GetLibraryItemQuery,
|
||||
} from "graphql/operations-types";
|
||||
} from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import {
|
||||
GetStaticPathsContext,
|
||||
GetStaticPathsResult,
|
||||
|
@ -41,22 +41,27 @@ import {
|
|||
} from "queries/helpers";
|
||||
import { useState } from "react";
|
||||
|
||||
interface LibrarySlugProps extends AppStaticProps {
|
||||
item: GetLibraryItemQuery["libraryItems"]["data"][number]["attributes"];
|
||||
itemId: GetLibraryItemQuery["libraryItems"]["data"][number]["id"];
|
||||
interface Props extends AppStaticProps {
|
||||
item: Exclude<
|
||||
GetLibraryItemQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
itemId: Exclude<
|
||||
GetLibraryItemQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"][number]["id"];
|
||||
}
|
||||
|
||||
export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
||||
export default function LibrarySlug(props: Props): JSX.Element {
|
||||
useTesting(props);
|
||||
const { item, langui, currencies } = props;
|
||||
const appLayout = useAppLayout();
|
||||
|
||||
const isVariantSet =
|
||||
item.metadata.length > 0 &&
|
||||
item.metadata[0].__typename === "ComponentMetadataGroup" &&
|
||||
item.metadata[0].subtype.data.attributes.slug === "variant-set";
|
||||
item?.metadata?.[0]?.__typename === "ComponentMetadataGroup" &&
|
||||
item.metadata[0].subtype?.data?.attributes?.slug === "variant-set";
|
||||
|
||||
sortContent(item.contents);
|
||||
sortContent(item?.contents);
|
||||
|
||||
const [lightboxOpen, setLightboxOpen] = useState(false);
|
||||
const [lightboxImages, setLightboxImages] = useState([""]);
|
||||
|
@ -80,7 +85,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
onClick={() => appLayout.setSubPanelOpen(false)}
|
||||
/>
|
||||
|
||||
{item.gallery.data.length > 0 && (
|
||||
{item?.gallery && item.gallery.data.length > 0 && (
|
||||
<NavOption
|
||||
title={langui.gallery}
|
||||
url="#gallery"
|
||||
|
@ -96,7 +101,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
onClick={() => appLayout.setSubPanelOpen(false)}
|
||||
/>
|
||||
|
||||
{item.subitems.data.length > 0 && (
|
||||
{item?.subitems && item.subitems.data.length > 0 && (
|
||||
<NavOption
|
||||
title={isVariantSet ? langui.variants : langui.subitems}
|
||||
url={isVariantSet ? "#variants" : "#subitems"}
|
||||
|
@ -105,7 +110,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
/>
|
||||
)}
|
||||
|
||||
{item.contents.data.length > 0 && (
|
||||
{item?.contents && item.contents.data.length > 0 && (
|
||||
<NavOption
|
||||
title={langui.contents}
|
||||
url="#contents"
|
||||
|
@ -138,6 +143,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
<div
|
||||
className="drop-shadow-shade-xl w-full h-[50vh] mobile:h-[60vh] desktop:mb-16 relative cursor-pointer"
|
||||
onClick={() => {
|
||||
if (item?.thumbnail?.data?.attributes) {
|
||||
setLightboxOpen(true);
|
||||
setLightboxImages([
|
||||
getAssetURL(
|
||||
|
@ -146,9 +152,10 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
),
|
||||
]);
|
||||
setLightboxIndex(0);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.thumbnail.data ? (
|
||||
{item?.thumbnail?.data?.attributes ? (
|
||||
<Img
|
||||
image={item.thumbnail.data.attributes}
|
||||
quality={ImageQuality.Large}
|
||||
|
@ -163,7 +170,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
|
||||
<InsetBox id="summary" className="grid place-items-center">
|
||||
<div className="w-[clamp(0px,100%,42rem)] grid place-items-center gap-8">
|
||||
{item.subitem_of.data.length > 0 && (
|
||||
{item?.subitem_of?.data[0]?.attributes && (
|
||||
<div className="grid place-items-center">
|
||||
<p>{langui.subitem_of}</p>
|
||||
<Button
|
||||
|
@ -178,31 +185,41 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
</div>
|
||||
)}
|
||||
<div className="grid place-items-center">
|
||||
<h1 className="text-3xl">{item.title}</h1>
|
||||
{item.subtitle && <h2 className="text-2xl">{item.subtitle}</h2>}
|
||||
<h1 className="text-3xl">{item?.title}</h1>
|
||||
{item?.subtitle && <h2 className="text-2xl">{item.subtitle}</h2>}
|
||||
</div>
|
||||
{item.descriptions.length > 0 && (
|
||||
{item?.descriptions?.[0] && (
|
||||
<p className="text-justify">{item.descriptions[0].description}</p>
|
||||
)}
|
||||
</div>
|
||||
</InsetBox>
|
||||
|
||||
{item.gallery.data.length > 0 && (
|
||||
{item?.gallery && item.gallery.data.length > 0 && (
|
||||
<div id="gallery" className="grid place-items-center gap-8 w-full">
|
||||
<h2 className="text-2xl">{langui.gallery}</h2>
|
||||
<div className="grid w-full gap-8 items-end grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))]">
|
||||
{item.gallery.data.map((galleryItem, index) => (
|
||||
<>
|
||||
{galleryItem.attributes && (
|
||||
<div
|
||||
key={galleryItem.id}
|
||||
className="relative aspect-square hover:scale-[1.02] transition-transform cursor-pointer"
|
||||
onClick={() => {
|
||||
setLightboxOpen(true);
|
||||
setLightboxImages(
|
||||
item.gallery.data.map((image) =>
|
||||
getAssetURL(image.attributes.url, ImageQuality.Large)
|
||||
if (item.gallery?.data) {
|
||||
const images: string[] = [];
|
||||
item.gallery.data.map((image) => {
|
||||
if (image.attributes)
|
||||
images.push(
|
||||
getAssetURL(
|
||||
image.attributes.url,
|
||||
ImageQuality.Large
|
||||
)
|
||||
);
|
||||
});
|
||||
setLightboxOpen(true);
|
||||
setLightboxImages(images);
|
||||
setLightboxIndex(index);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="bg-light absolute inset-0 rounded-lg drop-shadow-shade-md"></div>
|
||||
|
@ -213,6 +230,8 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
objectFit="cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -222,7 +241,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
<div className="w-[clamp(0px,100%,42rem)] grid place-items gap-8">
|
||||
<h2 className="text-2xl text-center">{langui.details}</h2>
|
||||
<div className="grid grid-flow-col w-full place-content-between">
|
||||
{item.metadata.length > 0 && (
|
||||
{item?.metadata?.[0] && (
|
||||
<div className="grid place-items-center place-content-start">
|
||||
<h3 className="text-xl">{langui.type}</h3>
|
||||
<div className="grid grid-flow-col gap-1">
|
||||
|
@ -233,24 +252,24 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{item.release_date && (
|
||||
{item?.release_date && (
|
||||
<div className="grid place-items-center place-content-start">
|
||||
<h3 className="text-xl">{langui.release_date}</h3>
|
||||
<p>{prettyDate(item.release_date)}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{item.price && (
|
||||
{item?.price && (
|
||||
<div className="grid place-items-center text-center place-content-start">
|
||||
<h3 className="text-xl">{langui.price}</h3>
|
||||
<p>
|
||||
{prettyPrice(
|
||||
item.price,
|
||||
currencies,
|
||||
item.price.currency.data.attributes.code
|
||||
item.price.currency?.data?.attributes?.code
|
||||
)}
|
||||
</p>
|
||||
{item.price.currency.data.attributes.code !==
|
||||
{item.price.currency?.data?.attributes?.code !==
|
||||
appLayout.currency && (
|
||||
<p>
|
||||
{prettyPrice(item.price, currencies, appLayout.currency)}{" "}
|
||||
|
@ -261,18 +280,18 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{item.categories.data.length > 0 && (
|
||||
{item?.categories && item.categories.data.length > 0 && (
|
||||
<div className="flex flex-col place-items-center gap-2">
|
||||
<h3 className="text-xl">{langui.categories}</h3>
|
||||
<div className="flex flex-row flex-wrap place-content-center gap-2">
|
||||
{item.categories.data.map((category) => (
|
||||
<Chip key={category.id}>{category.attributes.name}</Chip>
|
||||
<Chip key={category.id}>{category.attributes?.name}</Chip>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{item.size && (
|
||||
{item?.size && (
|
||||
<>
|
||||
<h3 className="text-xl">{langui.size}</h3>
|
||||
<div className="grid grid-flow-col w-full place-content-between">
|
||||
|
@ -303,13 +322,12 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
</>
|
||||
)}
|
||||
|
||||
{item.metadata.length > 0 &&
|
||||
item.metadata[0].__typename !== "ComponentMetadataGroup" &&
|
||||
item.metadata[0].__typename !== "ComponentMetadataOther" && (
|
||||
{item?.metadata?.[0]?.__typename !== "ComponentMetadataGroup" &&
|
||||
item?.metadata?.[0]?.__typename !== "ComponentMetadataOther" && (
|
||||
<>
|
||||
<h3 className="text-xl">{langui.type_information}</h3>
|
||||
<div className="grid grid-cols-2 w-full place-content-between">
|
||||
{item.metadata[0].__typename ===
|
||||
{item?.metadata?.[0]?.__typename ===
|
||||
"ComponentMetadataBooks" && (
|
||||
<>
|
||||
<div className="flex flex-row place-content-start gap-4">
|
||||
|
@ -336,18 +354,15 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
{item.metadata[0].page_order ===
|
||||
Enum_Componentmetadatabooks_Page_Order.LeftToRight
|
||||
? langui.left_to_right
|
||||
: item.metadata[0].page_order ===
|
||||
Enum_Componentmetadatabooks_Page_Order.RightToLeft
|
||||
? langui.right_to_left
|
||||
: ""}
|
||||
: langui.right_to_left}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row place-content-start gap-4">
|
||||
<p className="font-bold">{langui.languages}:</p>
|
||||
{item.metadata[0].languages.data.map((lang) => (
|
||||
<p key={lang.attributes.code}>
|
||||
{lang.attributes.name}
|
||||
{item.metadata[0]?.languages?.data.map((lang) => (
|
||||
<p key={lang.attributes?.code}>
|
||||
{lang.attributes?.name}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
|
@ -359,7 +374,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
</div>
|
||||
</InsetBox>
|
||||
|
||||
{item.subitems.data.length > 0 && (
|
||||
{item?.subitems && item.subitems.data.length > 0 && (
|
||||
<div
|
||||
id={isVariantSet ? "variants" : "subitems"}
|
||||
className="grid place-items-center gap-8 w-full"
|
||||
|
@ -372,13 +387,14 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
<LibraryItemsPreview
|
||||
key={subitem.id}
|
||||
item={subitem.attributes}
|
||||
currencies={props.currencies}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{item.contents.data.length > 0 && (
|
||||
{item?.contents && item.contents.data.length > 0 && (
|
||||
<div id="contents" className="w-full grid place-items-center gap-8">
|
||||
<h2 className="text-2xl">{langui.contents}</h2>
|
||||
<div className="grid gap-4 w-full">
|
||||
|
@ -399,15 +415,11 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={prettyinlineTitle("", item.title, item.subtitle)}
|
||||
navTitle={prettyinlineTitle("", item?.title, item?.subtitle)}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
thumbnail={item.thumbnail.data?.attributes}
|
||||
description={
|
||||
item.descriptions.length > 0
|
||||
? item.descriptions[0].description
|
||||
: undefined
|
||||
}
|
||||
thumbnail={item?.thumbnail?.data?.attributes ?? undefined}
|
||||
description={item?.descriptions?.[0]?.description ?? undefined}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
@ -415,18 +427,17 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
|||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: LibrarySlugProps }> {
|
||||
const item = (
|
||||
await getLibraryItem({
|
||||
slug: context.params?.slug?.toString() ?? "",
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const item = await sdk.getLibraryItem({
|
||||
slug: context.params?.slug ? context.params.slug.toString() : "",
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).libraryItems.data[0];
|
||||
if (!item) return { notFound: true };
|
||||
const props: LibrarySlugProps = {
|
||||
});
|
||||
if (!item.libraryItems) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
item: item.attributes,
|
||||
itemId: item.id,
|
||||
item: item.libraryItems.data[0].attributes,
|
||||
itemId: item.libraryItems.data[0].id,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
@ -436,29 +447,32 @@ export async function getStaticProps(
|
|||
export async function getStaticPaths(
|
||||
context: GetStaticPathsContext
|
||||
): Promise<GetStaticPathsResult> {
|
||||
const libraryItems = await getLibraryItemsSlugs({});
|
||||
const sdk = getReadySdk();
|
||||
const libraryItems = await sdk.getLibraryItemsSlugs();
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
if (libraryItems.libraryItems) {
|
||||
libraryItems.libraryItems.data.map((item) => {
|
||||
context.locales?.map((local) => {
|
||||
paths.push({ params: { slug: item.attributes.slug }, locale: local });
|
||||
paths.push({ params: { slug: item.attributes?.slug }, locale: local });
|
||||
});
|
||||
});
|
||||
}
|
||||
return {
|
||||
paths,
|
||||
fallback: "blocking",
|
||||
};
|
||||
}
|
||||
|
||||
function useTesting(props: LibrarySlugProps) {
|
||||
function useTesting(props: Props) {
|
||||
const { item, itemId } = props;
|
||||
const router = useRouter();
|
||||
|
||||
const libraryItemURL = `/admin/content-manager/collectionType/api::library-item.library-item/${itemId}`;
|
||||
|
||||
sortContent(item.contents);
|
||||
sortContent(item?.contents);
|
||||
|
||||
if (router.locale === "en") {
|
||||
if (!item.thumbnail.data) {
|
||||
if (!item?.thumbnail?.data) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing thumbnail",
|
||||
|
@ -466,7 +480,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
libraryItemURL
|
||||
);
|
||||
}
|
||||
if (item.metadata.length === 0) {
|
||||
if (item?.metadata?.length === 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing metadata",
|
||||
|
@ -474,9 +488,9 @@ function useTesting(props: LibrarySlugProps) {
|
|||
libraryItemURL
|
||||
);
|
||||
} else if (
|
||||
item.metadata[0].__typename === "ComponentMetadataGroup" &&
|
||||
(item.metadata[0].subtype.data.attributes.slug === "relation-set" ||
|
||||
item.metadata[0].subtype.data.attributes.slug === "variant-set")
|
||||
item?.metadata?.[0]?.__typename === "ComponentMetadataGroup" &&
|
||||
(item.metadata[0].subtype?.data?.attributes?.slug === "relation-set" ||
|
||||
item.metadata[0].subtype?.data?.attributes?.slug === "variant-set")
|
||||
) {
|
||||
// This is a group type item
|
||||
if (item.price) {
|
||||
|
@ -503,7 +517,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
libraryItemURL
|
||||
);
|
||||
}
|
||||
if (item.contents.data.length > 0) {
|
||||
if (item.contents && item.contents.data.length > 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Group-type items shouldn't have contents",
|
||||
|
@ -511,7 +525,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
libraryItemURL
|
||||
);
|
||||
}
|
||||
if (item.subitems.data.length === 0) {
|
||||
if (item.subitems && item.subitems.data.length === 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Group-type items should have subitems",
|
||||
|
@ -522,8 +536,8 @@ function useTesting(props: LibrarySlugProps) {
|
|||
} else {
|
||||
// This is a normal item
|
||||
|
||||
if (item.metadata[0].__typename === "ComponentMetadataGroup") {
|
||||
if (item.subitems.data.length === 0) {
|
||||
if (item?.metadata?.[0]?.__typename === "ComponentMetadataGroup") {
|
||||
if (item.subitems?.data.length === 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Group-type item should have subitems",
|
||||
|
@ -533,7 +547,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
}
|
||||
}
|
||||
|
||||
if (item.price) {
|
||||
if (item?.price) {
|
||||
if (!item.price.amount) {
|
||||
prettyTestError(
|
||||
router,
|
||||
|
@ -559,8 +573,8 @@ function useTesting(props: LibrarySlugProps) {
|
|||
);
|
||||
}
|
||||
|
||||
if (!item.digital) {
|
||||
if (item.size) {
|
||||
if (!item?.digital) {
|
||||
if (item?.size) {
|
||||
if (!item.size.width) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
|
@ -595,7 +609,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
}
|
||||
}
|
||||
|
||||
if (item.release_date) {
|
||||
if (item?.release_date) {
|
||||
if (!item.release_date.year) {
|
||||
prettyTestError(
|
||||
router,
|
||||
|
@ -629,7 +643,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
);
|
||||
}
|
||||
|
||||
if (item.contents.data.length === 0) {
|
||||
if (item?.contents?.data.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Missing contents",
|
||||
|
@ -638,26 +652,27 @@ function useTesting(props: LibrarySlugProps) {
|
|||
);
|
||||
} else {
|
||||
let currentRangePage = 0;
|
||||
item.contents.data.map((content) => {
|
||||
item?.contents?.data.map((content) => {
|
||||
const contentURL = `/admin/content-manager/collectionType/api::content.content/${content.id}`;
|
||||
|
||||
if (content.attributes.scan_set.length === 0) {
|
||||
if (content.attributes?.scan_set?.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Missing scan_set",
|
||||
["libraryItem", "content", content.id],
|
||||
["libraryItem", "content", content.id ?? ""],
|
||||
contentURL
|
||||
);
|
||||
}
|
||||
if (content.attributes.range.length === 0) {
|
||||
if (content.attributes?.range.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Missing range",
|
||||
["libraryItem", "content", content.id],
|
||||
["libraryItem", "content", content.id ?? ""],
|
||||
contentURL
|
||||
);
|
||||
} else if (
|
||||
content.attributes.range[0].__typename === "ComponentRangePageRange"
|
||||
content.attributes?.range[0]?.__typename ===
|
||||
"ComponentRangePageRange"
|
||||
) {
|
||||
if (
|
||||
content.attributes.range[0].starting_page <
|
||||
|
@ -666,7 +681,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
prettyTestError(
|
||||
router,
|
||||
`Overlapping pages ${content.attributes.range[0].starting_page} to ${currentRangePage}`,
|
||||
["libraryItem", "content", content.id, "range"],
|
||||
["libraryItem", "content", content.id ?? "", "range"],
|
||||
libraryItemURL
|
||||
);
|
||||
} else if (
|
||||
|
@ -678,16 +693,16 @@ function useTesting(props: LibrarySlugProps) {
|
|||
`Missing pages ${currentRangePage + 1} to ${
|
||||
content.attributes.range[0].starting_page - 1
|
||||
}`,
|
||||
["libraryItem", "content", content.id, "range"],
|
||||
["libraryItem", "content", content.id ?? "", "range"],
|
||||
libraryItemURL
|
||||
);
|
||||
}
|
||||
|
||||
if (!content.attributes.content.data) {
|
||||
if (!content.attributes.content?.data) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Missing content",
|
||||
["libraryItem", "content", content.id, "range"],
|
||||
["libraryItem", "content", content.id ?? "", "range"],
|
||||
libraryItemURL
|
||||
);
|
||||
}
|
||||
|
@ -696,7 +711,17 @@ function useTesting(props: LibrarySlugProps) {
|
|||
}
|
||||
});
|
||||
|
||||
if (item.metadata[0].__typename === "ComponentMetadataBooks") {
|
||||
if (item?.metadata?.[0]?.__typename === "ComponentMetadataBooks") {
|
||||
if (item.metadata[0].languages?.data.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Missing language",
|
||||
["libraryItem", "metadata"],
|
||||
libraryItemURL
|
||||
);
|
||||
}
|
||||
|
||||
if (item.metadata[0].page_count) {
|
||||
if (currentRangePage < item.metadata[0].page_count) {
|
||||
prettyTestError(
|
||||
router,
|
||||
|
@ -714,17 +739,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
libraryItemURL
|
||||
);
|
||||
}
|
||||
|
||||
if (item.metadata[0].languages.data.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Missing language",
|
||||
["libraryItem", "metadata"],
|
||||
libraryItemURL
|
||||
);
|
||||
}
|
||||
|
||||
if (!item.metadata[0].page_count) {
|
||||
} else {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Missing page_count",
|
||||
|
@ -736,7 +751,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!item.root_item && item.subitem_of.data.length === 0) {
|
||||
if (!item?.root_item && item?.subitem_of?.data.length === 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"This item is inaccessible (not root item and not subitem of another item)",
|
||||
|
@ -745,7 +760,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
);
|
||||
}
|
||||
|
||||
if (item.gallery.data.length === 0) {
|
||||
if (item?.gallery?.data.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Missing gallery",
|
||||
|
@ -755,7 +770,7 @@ function useTesting(props: LibrarySlugProps) {
|
|||
}
|
||||
}
|
||||
|
||||
if (item.descriptions.length === 0) {
|
||||
if (item?.descriptions?.length === 0) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"Missing description",
|
||||
|
|
|
@ -11,8 +11,8 @@ import ContentPanel, {
|
|||
} from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { getLibraryItemScans, getLibraryItemsSlugs } from "graphql/operations";
|
||||
import { GetLibraryItemScansQuery } from "graphql/operations-types";
|
||||
import { GetLibraryItemScansQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import {
|
||||
GetStaticPathsContext,
|
||||
GetStaticPathsResult,
|
||||
|
@ -23,15 +23,21 @@ import { prettyinlineTitle, prettySlug, sortContent } from "queries/helpers";
|
|||
import { useState } from "react";
|
||||
|
||||
interface Props extends AppStaticProps {
|
||||
item: GetLibraryItemScansQuery["libraryItems"]["data"][number]["attributes"];
|
||||
itemId: GetLibraryItemScansQuery["libraryItems"]["data"][number]["id"];
|
||||
item: Exclude<
|
||||
GetLibraryItemScansQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
itemId: Exclude<
|
||||
GetLibraryItemScansQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"][number]["id"];
|
||||
}
|
||||
|
||||
export default function LibrarySlug(props: Props): JSX.Element {
|
||||
const { item, langui } = props;
|
||||
const appLayout = useAppLayout();
|
||||
|
||||
sortContent(item.contents);
|
||||
sortContent(item?.contents);
|
||||
|
||||
const [lightboxOpen, setLightboxOpen] = useState(false);
|
||||
const [lightboxImages, setLightboxImages] = useState([""]);
|
||||
|
@ -40,21 +46,21 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
|||
const subPanel = (
|
||||
<SubPanel>
|
||||
<ReturnButton
|
||||
href={`/library/${item.slug}`}
|
||||
href={`/library/${item?.slug}`}
|
||||
title={langui.item}
|
||||
langui={langui}
|
||||
displayOn={ReturnButtonType.desktop}
|
||||
horizontalLine
|
||||
/>
|
||||
|
||||
{item.contents.data.map((content) => (
|
||||
{item?.contents?.data.map((content) => (
|
||||
<NavOption
|
||||
key={content.id}
|
||||
url={`#${content.attributes.slug}`}
|
||||
title={prettySlug(content.attributes.slug, item.slug)}
|
||||
url={`#${content.attributes?.slug}`}
|
||||
title={prettySlug(content.attributes?.slug, item.slug)}
|
||||
subtitle={
|
||||
content.attributes.range.length > 0 &&
|
||||
content.attributes.range[0].__typename === "ComponentRangePageRange"
|
||||
content.attributes?.range[0]?.__typename ===
|
||||
"ComponentRangePageRange"
|
||||
? `${content.attributes.range[0].starting_page} → ${content.attributes.range[0].ending_page}`
|
||||
: undefined
|
||||
}
|
||||
|
@ -76,55 +82,68 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
|||
/>
|
||||
|
||||
<ReturnButton
|
||||
href={`/library/${item.slug}`}
|
||||
href={`/library/${item?.slug}`}
|
||||
title={langui.item}
|
||||
langui={langui}
|
||||
displayOn={ReturnButtonType.mobile}
|
||||
className="mb-10"
|
||||
/>
|
||||
{item.contents.data.map((content) => (
|
||||
{item?.contents?.data.map((content) => (
|
||||
<>
|
||||
<h2
|
||||
id={content.attributes.slug}
|
||||
id={content.attributes?.slug}
|
||||
key={`h2${content.id}`}
|
||||
className="text-2xl pb-2 pt-10 first-of-type:pt-0 flex flex-row place-items-center gap-2"
|
||||
>
|
||||
{prettySlug(content.attributes.slug, item.slug)}
|
||||
{prettySlug(content.attributes?.slug, item.slug)}
|
||||
</h2>
|
||||
|
||||
{content.attributes.scan_set.length > 0 ? (
|
||||
{content.attributes?.scan_set?.[0] ? (
|
||||
<div
|
||||
key={`items${content.id}`}
|
||||
className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(10rem,1fr))] pb-12 border-b-[3px] border-dotted last-of-type:border-0"
|
||||
>
|
||||
{content.attributes.scan_set[0].pages.data.map((page, index) => (
|
||||
{content.attributes.scan_set[0].pages?.data.map((page, index) => (
|
||||
<div
|
||||
key={page.id}
|
||||
className="drop-shadow-shade-lg hover:scale-[1.02] cursor-pointer transition-transform"
|
||||
onClick={() => {
|
||||
setLightboxOpen(true);
|
||||
setLightboxImages(
|
||||
content.attributes.scan_set[0].pages.data.map((image) =>
|
||||
getAssetURL(image.attributes.url, ImageQuality.Large)
|
||||
if (content.attributes?.scan_set?.[0]?.pages) {
|
||||
const images: string[] = [];
|
||||
content.attributes.scan_set[0].pages.data.map((image) => {
|
||||
if (image.attributes?.url)
|
||||
images.push(
|
||||
getAssetURL(
|
||||
image.attributes.url,
|
||||
ImageQuality.Large
|
||||
)
|
||||
);
|
||||
});
|
||||
setLightboxImages(images);
|
||||
}
|
||||
|
||||
setLightboxIndex(index);
|
||||
}}
|
||||
>
|
||||
{page.attributes && (
|
||||
<Img image={page.attributes} quality={ImageQuality.Small} />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="pb-12 border-b-[3px] border-dotted last-of-type:border-0">
|
||||
{content.attributes?.scan_set_languages && (
|
||||
<LanguageSwitcher
|
||||
locales={content.attributes.scan_set_languages.map(
|
||||
(language) => language.language.data.attributes.code
|
||||
(language) => language?.language?.data?.attributes?.code
|
||||
)}
|
||||
languages={props.languages}
|
||||
langui={props.langui}
|
||||
href={`#${content.attributes.slug}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
@ -134,10 +153,10 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={prettyinlineTitle("", item.title, item.subtitle)}
|
||||
navTitle={prettyinlineTitle("", item?.title, item?.subtitle)}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
thumbnail={item.thumbnail.data?.attributes}
|
||||
thumbnail={item?.thumbnail?.data?.attributes ?? undefined}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
@ -146,17 +165,16 @@ export default function LibrarySlug(props: Props): JSX.Element {
|
|||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const item = (
|
||||
await getLibraryItemScans({
|
||||
const sdk = getReadySdk();
|
||||
const item = await sdk.getLibraryItemScans({
|
||||
slug: context.params?.slug?.toString() ?? "",
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).libraryItems.data[0];
|
||||
if (!item) return { notFound: true };
|
||||
});
|
||||
if (!item.libraryItems) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
item: item.attributes,
|
||||
itemId: item.id,
|
||||
item: item.libraryItems.data[0].attributes,
|
||||
itemId: item.libraryItems.data[0].id,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
@ -166,13 +184,17 @@ export async function getStaticProps(
|
|||
export async function getStaticPaths(
|
||||
context: GetStaticPathsContext
|
||||
): Promise<GetStaticPathsResult> {
|
||||
const libraryItems = await getLibraryItemsSlugs({});
|
||||
const sdk = getReadySdk();
|
||||
const libraryItems = await sdk.getLibraryItemsSlugs({});
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
if (libraryItems.libraryItems) {
|
||||
libraryItems.libraryItems.data.map((item) => {
|
||||
context.locales?.map((local) => {
|
||||
if (item.attributes)
|
||||
paths.push({ params: { slug: item.attributes.slug }, locale: local });
|
||||
});
|
||||
});
|
||||
}
|
||||
return {
|
||||
paths,
|
||||
fallback: "blocking",
|
||||
|
|
|
@ -8,27 +8,23 @@ import ContentPanel, {
|
|||
import SubPanel from "components/Panels/SubPanel";
|
||||
import Select from "components/Select";
|
||||
import Switch from "components/Switch";
|
||||
import { getLibraryItemsPreview } from "graphql/operations";
|
||||
import {
|
||||
GetCurrenciesQuery,
|
||||
GetLibraryItemsPreviewQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
} from "graphql/operations-types";
|
||||
import { GetLibraryItemsPreviewQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import { convertPrice, prettyDate, prettyinlineTitle } from "queries/helpers";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface LibraryProps extends AppStaticProps {
|
||||
items: GetLibraryItemsPreviewQuery["libraryItems"]["data"];
|
||||
interface Props extends AppStaticProps {
|
||||
items: Exclude<
|
||||
GetLibraryItemsPreviewQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"];
|
||||
}
|
||||
|
||||
type GroupLibraryItems = Map<
|
||||
string,
|
||||
GetLibraryItemsPreviewQuery["libraryItems"]["data"]
|
||||
>;
|
||||
type GroupLibraryItems = Map<string, Props["items"]>;
|
||||
|
||||
export default function Library(props: LibraryProps): JSX.Element {
|
||||
export default function Library(props: Props): JSX.Element {
|
||||
const { langui, items: libraryItems, currencies } = props;
|
||||
|
||||
const [showSubitems, setShowSubitems] = useState<boolean>(false);
|
||||
|
@ -37,7 +33,7 @@ export default function Library(props: LibraryProps): JSX.Element {
|
|||
const [sortingMethod, setSortingMethod] = useState<number>(0);
|
||||
const [groupingMethod, setGroupingMethod] = useState<number>(-1);
|
||||
|
||||
const [filteredItems, setFilteredItems] = useState<LibraryProps["items"]>(
|
||||
const [filteredItems, setFilteredItems] = useState<Props["items"]>(
|
||||
filterItems(
|
||||
showSubitems,
|
||||
showPrimaryItems,
|
||||
|
@ -46,7 +42,7 @@ export default function Library(props: LibraryProps): JSX.Element {
|
|||
)
|
||||
);
|
||||
|
||||
const [sortedItems, setSortedItem] = useState<LibraryProps["items"]>(
|
||||
const [sortedItems, setSortedItem] = useState<Props["items"]>(
|
||||
sortBy(groupingMethod, filteredItems, currencies)
|
||||
);
|
||||
|
||||
|
@ -85,7 +81,11 @@ export default function Library(props: LibraryProps): JSX.Element {
|
|||
<p className="flex-shrink-0">{langui.group_by}:</p>
|
||||
<Select
|
||||
className="w-full"
|
||||
options={[langui.category, langui.type, langui.release_year]}
|
||||
options={[
|
||||
langui.category ?? "Category",
|
||||
langui.type ?? "Type",
|
||||
langui.release_year ?? "Year",
|
||||
]}
|
||||
state={groupingMethod}
|
||||
setState={setGroupingMethod}
|
||||
allowEmpty
|
||||
|
@ -96,7 +96,11 @@ export default function Library(props: LibraryProps): JSX.Element {
|
|||
<p className="flex-shrink-0">{langui.order_by}:</p>
|
||||
<Select
|
||||
className="w-full"
|
||||
options={[langui.name, langui.price, langui.release_date]}
|
||||
options={[
|
||||
langui.name ?? "Name",
|
||||
langui.price ?? "Price",
|
||||
langui.release_date ?? "Release date",
|
||||
]}
|
||||
state={sortingMethod}
|
||||
setState={setSortingMethod}
|
||||
/>
|
||||
|
@ -132,8 +136,8 @@ export default function Library(props: LibraryProps): JSX.Element {
|
|||
{name}
|
||||
<Chip>{`${items.length} ${
|
||||
items.length <= 1
|
||||
? langui.result.toLowerCase()
|
||||
: langui.results.toLowerCase()
|
||||
? langui.result?.toLowerCase() ?? "result"
|
||||
: langui.results?.toLowerCase() ?? "results"
|
||||
}`}</Chip>
|
||||
</h2>
|
||||
)}
|
||||
|
@ -167,14 +171,15 @@ export default function Library(props: LibraryProps): JSX.Element {
|
|||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: LibraryProps }> {
|
||||
const props: LibraryProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
items: (
|
||||
await getLibraryItemsPreview({
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const items = await sdk.getLibraryItemsPreview({
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).libraryItems.data,
|
||||
});
|
||||
if (!items.libraryItems) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
items: items.libraryItems.data,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
@ -182,9 +187,9 @@ export async function getStaticProps(
|
|||
}
|
||||
|
||||
function getGroups(
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"],
|
||||
langui: AppStaticProps["langui"],
|
||||
groupByType: number,
|
||||
items: LibraryProps["items"]
|
||||
items: Props["items"]
|
||||
): GroupLibraryItems {
|
||||
switch (groupByType) {
|
||||
case 0: {
|
||||
|
@ -209,11 +214,11 @@ function getGroups(
|
|||
typeGroup.set(langui.no_category, []);
|
||||
|
||||
items.map((item) => {
|
||||
if (item.attributes.categories.data.length === 0) {
|
||||
if (item.attributes?.categories?.data.length === 0) {
|
||||
typeGroup.get(langui.no_category)?.push(item);
|
||||
} else {
|
||||
item.attributes.categories.data.map((category) => {
|
||||
typeGroup.get(category.attributes.name)?.push(item);
|
||||
item.attributes?.categories?.data.map((category) => {
|
||||
typeGroup.get(category.attributes?.name)?.push(item);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -223,49 +228,50 @@ function getGroups(
|
|||
|
||||
case 1: {
|
||||
const group: GroupLibraryItems = new Map();
|
||||
group.set(langui.audio, []);
|
||||
group.set(langui.game, []);
|
||||
group.set(langui.textual, []);
|
||||
group.set(langui.video, []);
|
||||
group.set(langui.other, []);
|
||||
group.set(langui.group, []);
|
||||
group.set(langui.no_type, []);
|
||||
group.set(langui.audio ?? "Audio", []);
|
||||
group.set(langui.game ?? "Game", []);
|
||||
group.set(langui.textual ?? "Textual", []);
|
||||
group.set(langui.video ?? "Video", []);
|
||||
group.set(langui.other ?? "Other", []);
|
||||
group.set(langui.group ?? "Group", []);
|
||||
group.set(langui.no_type ?? "No type", []);
|
||||
items.map((item) => {
|
||||
if (item.attributes.metadata.length > 0) {
|
||||
switch (item.attributes.metadata[0].__typename) {
|
||||
if (item.attributes?.metadata && item.attributes.metadata.length > 0) {
|
||||
switch (item.attributes.metadata[0]?.__typename) {
|
||||
case "ComponentMetadataAudio":
|
||||
group.get(langui.audio)?.push(item);
|
||||
group.get(langui.audio ?? "Audio")?.push(item);
|
||||
break;
|
||||
case "ComponentMetadataGame":
|
||||
group.get(langui.game)?.push(item);
|
||||
group.get(langui.game ?? "Game")?.push(item);
|
||||
break;
|
||||
case "ComponentMetadataBooks":
|
||||
group.get(langui.textual)?.push(item);
|
||||
group.get(langui.textual ?? "Textual")?.push(item);
|
||||
break;
|
||||
case "ComponentMetadataVideo":
|
||||
group.get(langui.video)?.push(item);
|
||||
group.get(langui.video ?? "Video")?.push(item);
|
||||
break;
|
||||
case "ComponentMetadataOther":
|
||||
group.get(langui.other)?.push(item);
|
||||
group.get(langui.other ?? "Other")?.push(item);
|
||||
break;
|
||||
case "ComponentMetadataGroup":
|
||||
switch (
|
||||
item.attributes.metadata[0].subitems_type.data.attributes.slug
|
||||
item.attributes.metadata[0]?.subitems_type?.data?.attributes
|
||||
?.slug
|
||||
) {
|
||||
case "audio":
|
||||
group.get(langui.audio)?.push(item);
|
||||
group.get(langui.audio ?? "Audio")?.push(item);
|
||||
break;
|
||||
case "video":
|
||||
group.get(langui.video)?.push(item);
|
||||
group.get(langui.video ?? "Video")?.push(item);
|
||||
break;
|
||||
case "game":
|
||||
group.get(langui.game)?.push(item);
|
||||
group.get(langui.game ?? "Game")?.push(item);
|
||||
break;
|
||||
case "textual":
|
||||
group.get(langui.textual)?.push(item);
|
||||
group.get(langui.textual ?? "Textual")?.push(item);
|
||||
break;
|
||||
case "mixed":
|
||||
group.get(langui.group)?.push(item);
|
||||
group.get(langui.group ?? "Group")?.push(item);
|
||||
break;
|
||||
default: {
|
||||
throw new Error(
|
||||
|
@ -279,7 +285,7 @@ function getGroups(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
group.get(langui.no_type)?.push(item);
|
||||
group.get(langui.no_type ?? "No type")?.push(item);
|
||||
}
|
||||
});
|
||||
return group;
|
||||
|
@ -288,7 +294,7 @@ function getGroups(
|
|||
case 2: {
|
||||
const years: number[] = [];
|
||||
items.map((item) => {
|
||||
if (item.attributes.release_date) {
|
||||
if (item.attributes?.release_date?.year) {
|
||||
if (!years.includes(item.attributes.release_date.year))
|
||||
years.push(item.attributes.release_date.year);
|
||||
}
|
||||
|
@ -298,12 +304,12 @@ function getGroups(
|
|||
years.map((year) => {
|
||||
group.set(year.toString(), []);
|
||||
});
|
||||
group.set(langui.no_year, []);
|
||||
group.set(langui.no_year || "No year", []);
|
||||
items.map((item) => {
|
||||
if (item.attributes.release_date) {
|
||||
if (item.attributes?.release_date?.year) {
|
||||
group.get(item.attributes.release_date.year.toString())?.push(item);
|
||||
} else {
|
||||
group.get(langui.no_year)?.push(item);
|
||||
group.get(langui.no_year || "No year")?.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -322,66 +328,63 @@ function filterItems(
|
|||
showSubitems: boolean,
|
||||
showPrimaryItems: boolean,
|
||||
showSecondaryItems: boolean,
|
||||
items: LibraryProps["items"]
|
||||
): LibraryProps["items"] {
|
||||
items: Props["items"]
|
||||
): Props["items"] {
|
||||
return [...items].filter((item) => {
|
||||
if (!showSubitems && !item.attributes.root_item) return false;
|
||||
if (!showSubitems && !item.attributes?.root_item) return false;
|
||||
if (
|
||||
showSubitems &&
|
||||
item.attributes.metadata.length > 0 &&
|
||||
item.attributes.metadata[0].__typename === "ComponentMetadataGroup" &&
|
||||
(item.attributes.metadata[0].subtype.data.attributes.slug ===
|
||||
item.attributes?.metadata?.[0]?.__typename === "ComponentMetadataGroup" &&
|
||||
(item.attributes.metadata[0].subtype?.data?.attributes?.slug ===
|
||||
"variant-set" ||
|
||||
item.attributes.metadata[0].subtype.data.attributes.slug ===
|
||||
item.attributes.metadata[0].subtype?.data?.attributes?.slug ===
|
||||
"relation-set")
|
||||
)
|
||||
return false;
|
||||
if (item.attributes.primary && !showPrimaryItems) return false;
|
||||
if (!item.attributes.primary && !showSecondaryItems) return false;
|
||||
if (item.attributes?.primary && !showPrimaryItems) return false;
|
||||
if (!item.attributes?.primary && !showSecondaryItems) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function sortBy(
|
||||
orderByType: number,
|
||||
items: LibraryProps["items"],
|
||||
currencies: GetCurrenciesQuery["currencies"]["data"]
|
||||
): LibraryProps["items"] {
|
||||
items: Props["items"],
|
||||
currencies: AppStaticProps["currencies"]
|
||||
): Props["items"] {
|
||||
switch (orderByType) {
|
||||
case 0:
|
||||
return [...items].sort((a, b) => {
|
||||
const titleA = prettyinlineTitle(
|
||||
"",
|
||||
a.attributes.title,
|
||||
a.attributes.subtitle
|
||||
a.attributes?.title,
|
||||
a.attributes?.subtitle
|
||||
);
|
||||
const titleB = prettyinlineTitle(
|
||||
"",
|
||||
b.attributes.title,
|
||||
b.attributes.subtitle
|
||||
b.attributes?.title,
|
||||
b.attributes?.subtitle
|
||||
);
|
||||
return titleA.localeCompare(titleB);
|
||||
});
|
||||
case 1:
|
||||
return [...items].sort((a, b) => {
|
||||
const priceA = a.attributes.price
|
||||
const priceA = a.attributes?.price
|
||||
? convertPrice(a.attributes.price, currencies[0])
|
||||
: 99999;
|
||||
const priceB = b.attributes.price
|
||||
const priceB = b.attributes?.price
|
||||
? convertPrice(b.attributes.price, currencies[0])
|
||||
: 99999;
|
||||
return priceA - priceB;
|
||||
});
|
||||
case 2:
|
||||
return [...items].sort((a, b) => {
|
||||
const dateA =
|
||||
a.attributes.release_date === null
|
||||
? "9999"
|
||||
: prettyDate(a.attributes.release_date);
|
||||
const dateB =
|
||||
b.attributes.release_date === null
|
||||
? "9999"
|
||||
: prettyDate(b.attributes.release_date);
|
||||
const dateA = a.attributes?.release_date
|
||||
? prettyDate(a.attributes.release_date)
|
||||
: "9999";
|
||||
const dateB = b.attributes?.release_date
|
||||
? prettyDate(b.attributes.release_date)
|
||||
: "9999";
|
||||
return dateA.localeCompare(dateB);
|
||||
});
|
||||
default:
|
||||
|
|
|
@ -17,7 +17,13 @@ export default function Merch(props: MerchProps): JSX.Element {
|
|||
</SubPanel>
|
||||
);
|
||||
|
||||
return <AppLayout navTitle={langui.merch} subPanel={subPanel} {...props} />;
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={langui.merch}
|
||||
subPanel={subPanel}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export async function getStaticProps(
|
||||
|
|
|
@ -12,8 +12,8 @@ import ContentPanel from "components/Panels/ContentPanel";
|
|||
import SubPanel from "components/Panels/SubPanel";
|
||||
import RecorderChip from "components/RecorderChip";
|
||||
import ToolTip from "components/ToolTip";
|
||||
import { getPost, getPostsSlugs } from "graphql/operations";
|
||||
import { GetPostQuery, StrapiImage } from "graphql/operations-types";
|
||||
import { GetPostQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import {
|
||||
GetStaticPathsContext,
|
||||
GetStaticPathsResult,
|
||||
|
@ -28,22 +28,31 @@ import {
|
|||
} from "queries/helpers";
|
||||
|
||||
interface PostProps extends AppStaticProps {
|
||||
post: GetPostQuery["posts"]["data"][number]["attributes"];
|
||||
postId: GetPostQuery["posts"]["data"][number]["id"];
|
||||
post: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"];
|
||||
postId: Exclude<
|
||||
GetPostQuery["posts"],
|
||||
null | undefined
|
||||
>["data"][number]["id"];
|
||||
}
|
||||
|
||||
export default function LibrarySlug(props: PostProps): JSX.Element {
|
||||
const { post, langui } = props;
|
||||
const locales = getLocalesFromLanguages(post.translations_languages);
|
||||
const locales = getLocalesFromLanguages(post?.translations_languages);
|
||||
const router = useRouter();
|
||||
|
||||
const thumbnail: StrapiImage | undefined =
|
||||
post.translations.length > 0 && post.translations[0].thumbnail.data
|
||||
const thumbnail = post?.translations?.[0]?.thumbnail?.data
|
||||
? post.translations[0].thumbnail.data.attributes
|
||||
: post.thumbnail.data
|
||||
: post?.thumbnail?.data
|
||||
? post.thumbnail.data.attributes
|
||||
: undefined;
|
||||
|
||||
const body = post?.translations?.[0]?.body ?? "";
|
||||
const title = post?.translations?.[0]?.title ?? prettySlug(post?.slug);
|
||||
const except = post?.translations?.[0]?.excerpt ?? "";
|
||||
|
||||
const subPanel = (
|
||||
<SubPanel>
|
||||
<ReturnButton
|
||||
|
@ -54,7 +63,7 @@ export default function LibrarySlug(props: PostProps): JSX.Element {
|
|||
horizontalLine
|
||||
/>
|
||||
|
||||
{post.translations.length > 0 && (
|
||||
{post?.translations?.[0] && (
|
||||
<div className="grid grid-flow-col place-items-center place-content-center gap-2">
|
||||
<p className="font-headers">{langui.status}:</p>
|
||||
|
||||
|
@ -67,12 +76,20 @@ export default function LibrarySlug(props: PostProps): JSX.Element {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{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">
|
||||
{post.authors.data.map((author) => (
|
||||
<RecorderChip key={author.id} langui={langui} recorder={author} />
|
||||
<>
|
||||
{author.attributes && (
|
||||
<RecorderChip
|
||||
key={author.id}
|
||||
langui={langui}
|
||||
recorder={author.attributes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -80,12 +97,7 @@ export default function LibrarySlug(props: PostProps): JSX.Element {
|
|||
|
||||
<HorizontalLine />
|
||||
|
||||
{post.translations.length > 0 && post.translations[0].body && (
|
||||
<TOC
|
||||
text={post.translations[0].body}
|
||||
title={post.translations[0].title}
|
||||
/>
|
||||
)}
|
||||
<TOC text={body} title={title} />
|
||||
</SubPanel>
|
||||
);
|
||||
const contentPanel = (
|
||||
|
@ -100,24 +112,16 @@ export default function LibrarySlug(props: PostProps): JSX.Element {
|
|||
|
||||
<ThumbnailHeader
|
||||
thumbnail={thumbnail}
|
||||
title={
|
||||
post.translations.length > 0
|
||||
? post.translations[0].title
|
||||
: prettySlug(post.slug)
|
||||
}
|
||||
description={
|
||||
post.translations.length > 0
|
||||
? post.translations[0].excerpt
|
||||
: undefined
|
||||
}
|
||||
title={title}
|
||||
description={except}
|
||||
langui={langui}
|
||||
categories={post.categories}
|
||||
categories={post?.categories}
|
||||
/>
|
||||
|
||||
<HorizontalLine />
|
||||
|
||||
{locales.includes(router.locale ?? "en") ? (
|
||||
<Markdawn text={post.translations[0].body} />
|
||||
<Markdawn text={body} />
|
||||
) : (
|
||||
<LanguageSwitcher
|
||||
locales={locales}
|
||||
|
@ -130,14 +134,10 @@ export default function LibrarySlug(props: PostProps): JSX.Element {
|
|||
|
||||
return (
|
||||
<AppLayout
|
||||
navTitle={
|
||||
post.translations.length > 0
|
||||
? post.translations[0].title
|
||||
: prettySlug(post.slug)
|
||||
}
|
||||
navTitle={title}
|
||||
contentPanel={contentPanel}
|
||||
subPanel={subPanel}
|
||||
thumbnail={thumbnail}
|
||||
thumbnail={thumbnail ?? undefined}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
@ -146,18 +146,17 @@ export default function LibrarySlug(props: PostProps): JSX.Element {
|
|||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: PostProps }> {
|
||||
const slug = context.params?.slug?.toString() ?? "";
|
||||
const post = (
|
||||
await getPost({
|
||||
const sdk = getReadySdk();
|
||||
const slug = context.params?.slug ? context.params.slug.toString() : "";
|
||||
const post = await sdk.getPost({
|
||||
slug: slug,
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).posts.data[0];
|
||||
if (!post) return { notFound: true };
|
||||
});
|
||||
if (!post.posts?.data[0]) return { notFound: true };
|
||||
const props: PostProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
post: post.attributes,
|
||||
postId: post.id,
|
||||
post: post.posts.data[0].attributes,
|
||||
postId: post.posts.data[0].id,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
@ -167,10 +166,13 @@ export async function getStaticProps(
|
|||
export async function getStaticPaths(
|
||||
context: GetStaticPathsContext
|
||||
): Promise<GetStaticPathsResult> {
|
||||
const posts = await getPostsSlugs({});
|
||||
const sdk = getReadySdk();
|
||||
const posts = await sdk.getPostsSlugs();
|
||||
const paths: GetStaticPathsResult["paths"] = [];
|
||||
if (posts.posts)
|
||||
posts.posts.data.map((item) => {
|
||||
context.locales?.map((local) => {
|
||||
if (item.attributes)
|
||||
paths.push({ params: { slug: item.attributes.slug }, locale: local });
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,25 +5,23 @@ import ContentPanel, {
|
|||
ContentPanelWidthSizes,
|
||||
} from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import { getPostsPreview } from "graphql/operations";
|
||||
import { GetPostsPreviewQuery } from "graphql/operations-types";
|
||||
import { GetPostsPreviewQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
import { prettyDate } from "queries/helpers";
|
||||
|
||||
interface NewsProps extends AppStaticProps {
|
||||
posts: GetPostsPreviewQuery["posts"]["data"];
|
||||
interface Props extends AppStaticProps {
|
||||
posts: Exclude<GetPostsPreviewQuery["posts"], null | undefined>["data"];
|
||||
}
|
||||
|
||||
export default function News(props: NewsProps): JSX.Element {
|
||||
export default function News(props: Props): JSX.Element {
|
||||
const { langui, posts } = props;
|
||||
|
||||
posts
|
||||
.sort((a, b) => {
|
||||
const dateA =
|
||||
a.attributes.date === null ? "9999" : prettyDate(a.attributes.date);
|
||||
const dateB =
|
||||
b.attributes.date === null ? "9999" : prettyDate(b.attributes.date);
|
||||
const dateA = a.attributes?.date ? prettyDate(a.attributes.date) : "9999";
|
||||
const dateB = b.attributes?.date ? prettyDate(b.attributes.date) : "9999";
|
||||
return dateA.localeCompare(dateB);
|
||||
})
|
||||
.reverse();
|
||||
|
@ -60,12 +58,15 @@ export default function News(props: NewsProps): JSX.Element {
|
|||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: NewsProps }> {
|
||||
const props: NewsProps = {
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const posts = await sdk.getPostsPreview({
|
||||
language_code: context.locale ?? "en",
|
||||
});
|
||||
if (!posts.posts) return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
posts: await (
|
||||
await getPostsPreview({ language_code: context.locale ?? "en" })
|
||||
).posts.data,
|
||||
posts: posts.posts.data,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
|
|
|
@ -8,11 +8,8 @@ import ReturnButton, {
|
|||
import ContentPanel from "components/Panels/ContentPanel";
|
||||
import SubPanel from "components/Panels/SubPanel";
|
||||
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||
import { getChronologyItems, getEras } from "graphql/operations";
|
||||
import {
|
||||
GetChronologyItemsQuery,
|
||||
GetErasQuery,
|
||||
} from "graphql/operations-types";
|
||||
import { GetChronologyItemsQuery, GetErasQuery } from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
|
||||
|
@ -22,19 +19,24 @@ import {
|
|||
prettyTestWarning,
|
||||
} from "queries/helpers";
|
||||
|
||||
interface ChronologyProps extends AppStaticProps {
|
||||
chronologyItems: GetChronologyItemsQuery["chronologyItems"]["data"];
|
||||
chronologyEras: GetErasQuery["chronologyEras"]["data"];
|
||||
interface Props extends AppStaticProps {
|
||||
chronologyItems: Exclude<
|
||||
GetChronologyItemsQuery["chronologyItems"],
|
||||
null | undefined
|
||||
>["data"];
|
||||
chronologyEras: Exclude<
|
||||
GetErasQuery["chronologyEras"],
|
||||
null | undefined
|
||||
>["data"];
|
||||
}
|
||||
|
||||
export default function Chronology(props: ChronologyProps): JSX.Element {
|
||||
export default function Chronology(props: Props): JSX.Element {
|
||||
useTesting(props);
|
||||
const { chronologyItems, chronologyEras, langui } = props;
|
||||
const appLayout = useAppLayout();
|
||||
|
||||
// Group by year the Chronology items
|
||||
const chronologyItemYearGroups: GetChronologyItemsQuery["chronologyItems"]["data"][number][][][] =
|
||||
[];
|
||||
const chronologyItemYearGroups: Props["chronologyItems"][number][][][] = [];
|
||||
|
||||
chronologyEras.map(() => {
|
||||
chronologyItemYearGroups.push([]);
|
||||
|
@ -42,9 +44,11 @@ export default function Chronology(props: ChronologyProps): JSX.Element {
|
|||
|
||||
let currentChronologyEraIndex = 0;
|
||||
chronologyItems.map((item) => {
|
||||
if (item.attributes) {
|
||||
if (
|
||||
item.attributes.year >
|
||||
chronologyEras[currentChronologyEraIndex].attributes.ending_year
|
||||
(chronologyEras[currentChronologyEraIndex].attributes?.ending_year ??
|
||||
999999)
|
||||
) {
|
||||
currentChronologyEraIndex += 1;
|
||||
}
|
||||
|
@ -62,6 +66,7 @@ export default function Chronology(props: ChronologyProps): JSX.Element {
|
|||
item.attributes.year
|
||||
] = [item];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const subPanel = (
|
||||
|
@ -75,11 +80,15 @@ export default function Chronology(props: ChronologyProps): JSX.Element {
|
|||
/>
|
||||
|
||||
{chronologyEras.map((era) => (
|
||||
<>
|
||||
{era.attributes && (
|
||||
<NavOption
|
||||
key={era.id}
|
||||
url={`#${era.attributes.slug}`}
|
||||
title={
|
||||
era.attributes.title.length > 0
|
||||
era.attributes.title &&
|
||||
era.attributes.title.length > 0 &&
|
||||
era.attributes.title[0]
|
||||
? era.attributes.title[0].title
|
||||
: prettySlug(era.attributes.slug)
|
||||
}
|
||||
|
@ -87,6 +96,8 @@ export default function Chronology(props: ChronologyProps): JSX.Element {
|
|||
border
|
||||
onClick={() => appLayout.setSubPanelOpen(false)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</SubPanel>
|
||||
);
|
||||
|
@ -104,27 +115,31 @@ export default function Chronology(props: ChronologyProps): JSX.Element {
|
|||
{chronologyItemYearGroups.map((era, eraIndex) => (
|
||||
<>
|
||||
<InsetBox
|
||||
id={chronologyEras[eraIndex].attributes.slug}
|
||||
id={chronologyEras[eraIndex].attributes?.slug}
|
||||
className="grid text-center my-8 gap-4"
|
||||
>
|
||||
<h2 className="text-2xl">
|
||||
{chronologyEras[eraIndex].attributes.title.length > 0
|
||||
? chronologyEras[eraIndex].attributes.title[0].title
|
||||
: prettySlug(chronologyEras[eraIndex].attributes.slug)}
|
||||
{chronologyEras[eraIndex].attributes?.title?.[0]
|
||||
? chronologyEras[eraIndex].attributes?.title?.[0]?.title
|
||||
: prettySlug(chronologyEras[eraIndex].attributes?.slug)}
|
||||
</h2>
|
||||
<p className="whitespace-pre-line ">
|
||||
{chronologyEras[eraIndex].attributes.title.length > 0
|
||||
? chronologyEras[eraIndex].attributes.title[0].description
|
||||
{chronologyEras[eraIndex].attributes?.title?.[0]
|
||||
? chronologyEras[eraIndex].attributes?.title?.[0]?.description
|
||||
: ""}
|
||||
</p>
|
||||
</InsetBox>
|
||||
{era.map((items, index) => (
|
||||
<>
|
||||
{items[0].attributes?.year && (
|
||||
<ChronologyYearComponent
|
||||
key={`${eraIndex}-${index}`}
|
||||
year={items[0].attributes.year}
|
||||
items={items}
|
||||
langui={langui}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</>
|
||||
))}
|
||||
|
@ -143,36 +158,40 @@ export default function Chronology(props: ChronologyProps): JSX.Element {
|
|||
|
||||
export async function getStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<{ notFound: boolean } | { props: ChronologyProps }> {
|
||||
const props: ChronologyProps = {
|
||||
...(await getAppStaticProps(context)),
|
||||
chronologyItems: (
|
||||
await getChronologyItems({
|
||||
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||
const sdk = getReadySdk();
|
||||
const chronologyItems = await sdk.getChronologyItems({
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).chronologyItems.data,
|
||||
chronologyEras: (await getEras({ language_code: context.locale ?? "en" }))
|
||||
.chronologyEras.data,
|
||||
});
|
||||
const chronologyEras = await sdk.getEras({
|
||||
language_code: context.locale ?? "en",
|
||||
});
|
||||
if (!chronologyItems.chronologyItems || !chronologyEras.chronologyEras)
|
||||
return { notFound: true };
|
||||
const props: Props = {
|
||||
...(await getAppStaticProps(context)),
|
||||
chronologyItems: chronologyItems.chronologyItems.data,
|
||||
chronologyEras: chronologyEras.chronologyEras.data,
|
||||
};
|
||||
return {
|
||||
props: props,
|
||||
};
|
||||
}
|
||||
|
||||
function useTesting(props: ChronologyProps) {
|
||||
function useTesting(props: Props) {
|
||||
const router = useRouter();
|
||||
const { chronologyItems, chronologyEras } = props;
|
||||
chronologyEras.map((era) => {
|
||||
const chronologyErasURL = `/admin/content-manager/collectionType/api::chronology-era.chronology-era/${chronologyItems[0].id}`;
|
||||
|
||||
if (era.attributes.title.length === 0) {
|
||||
if (era.attributes?.title?.length === 0) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing translation for title and description, using slug instead",
|
||||
["chronologyEras", era.attributes.slug],
|
||||
chronologyErasURL
|
||||
);
|
||||
} else if (era.attributes.title.length > 1) {
|
||||
} else if (era.attributes?.title && era.attributes.title.length > 1) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"More than one title and description",
|
||||
|
@ -180,18 +199,18 @@ function useTesting(props: ChronologyProps) {
|
|||
chronologyErasURL
|
||||
);
|
||||
} else {
|
||||
if (!era.attributes.title[0].title)
|
||||
if (!era.attributes?.title?.[0]?.title)
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing title, using slug instead",
|
||||
["chronologyEras", era.attributes.slug],
|
||||
["chronologyEras", era.attributes?.slug ?? ""],
|
||||
chronologyErasURL
|
||||
);
|
||||
if (!era.attributes.title[0].description)
|
||||
if (!era.attributes?.title?.[0]?.description)
|
||||
prettyTestError(
|
||||
router,
|
||||
"Missing description",
|
||||
["chronologyEras", era.attributes.slug],
|
||||
["chronologyEras", era.attributes?.slug ?? ""],
|
||||
chronologyErasURL
|
||||
);
|
||||
}
|
||||
|
@ -200,23 +219,23 @@ function useTesting(props: ChronologyProps) {
|
|||
chronologyItems.map((item) => {
|
||||
const chronologyItemsURL = `/admin/content-manager/collectionType/api::chronology-item.chronology-item/${chronologyItems[0].id}`;
|
||||
|
||||
const date = `${item.attributes.year}/${item.attributes.month}/${item.attributes.day}`;
|
||||
const date = `${item.attributes?.year}/${item.attributes?.month}/${item.attributes?.day}`;
|
||||
|
||||
if (item.attributes.events.length > 0) {
|
||||
if (item.attributes?.events && item.attributes.events.length > 0) {
|
||||
item.attributes.events.map((event) => {
|
||||
if (!event.source.data) {
|
||||
if (!event?.source?.data) {
|
||||
prettyTestError(
|
||||
router,
|
||||
"No source for this event",
|
||||
["chronologyItems", date, event.id],
|
||||
["chronologyItems", date, event?.id ?? ""],
|
||||
chronologyItemsURL
|
||||
);
|
||||
}
|
||||
if (!(event.translations.length > 0)) {
|
||||
if (!(event?.translations && event.translations.length > 0)) {
|
||||
prettyTestWarning(
|
||||
router,
|
||||
"No translation for this event",
|
||||
["chronologyItems", date, event.id],
|
||||
["chronologyItems", date, event?.id ?? ""],
|
||||
chronologyItemsURL
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,39 +1,58 @@
|
|||
import {
|
||||
getCurrencies,
|
||||
getLanguages,
|
||||
getWebsiteInterface,
|
||||
} from "graphql/operations";
|
||||
import {
|
||||
GetCurrenciesQuery,
|
||||
GetLanguagesQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
} from "graphql/operations-types";
|
||||
} from "graphql/generated";
|
||||
import { getReadySdk } from "graphql/sdk";
|
||||
import { GetStaticPropsContext } from "next";
|
||||
|
||||
export interface AppStaticProps {
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||
currencies: GetCurrenciesQuery["currencies"]["data"];
|
||||
languages: GetLanguagesQuery["languages"]["data"];
|
||||
langui: Exclude<
|
||||
Exclude<
|
||||
GetWebsiteInterfaceQuery["websiteInterfaces"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>;
|
||||
currencies: Exclude<
|
||||
GetCurrenciesQuery["currencies"],
|
||||
null | undefined
|
||||
>["data"];
|
||||
languages: Exclude<GetLanguagesQuery["languages"], null | undefined>["data"];
|
||||
}
|
||||
|
||||
export async function getAppStaticProps(
|
||||
context: GetStaticPropsContext
|
||||
): Promise<AppStaticProps> {
|
||||
const languages = (await getLanguages({})).languages.data;
|
||||
languages.sort((a, b) =>
|
||||
a.attributes.localized_name.localeCompare(b.attributes.localized_name)
|
||||
const sdk = getReadySdk();
|
||||
const languages = (await sdk.getLanguages()).languages;
|
||||
|
||||
if (languages?.data) {
|
||||
languages.data.sort((a, b) =>
|
||||
a.attributes && b.attributes
|
||||
? a.attributes.localized_name.localeCompare(b.attributes.localized_name)
|
||||
: 0
|
||||
);
|
||||
}
|
||||
|
||||
const currencies = (await getCurrencies({})).currencies.data;
|
||||
currencies.sort((a, b) => a.attributes.code.localeCompare(b.attributes.code));
|
||||
const currencies = (await sdk.getCurrencies()).currencies;
|
||||
if (currencies?.data) {
|
||||
currencies.data.sort((a, b) =>
|
||||
a.attributes && b.attributes
|
||||
? a.attributes.code.localeCompare(b.attributes.code)
|
||||
: 0
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
langui: (
|
||||
await getWebsiteInterface({
|
||||
const langui = (
|
||||
await sdk.getWebsiteInterface({
|
||||
language_code: context.locale ?? "en",
|
||||
})
|
||||
).websiteInterfaces.data[0].attributes,
|
||||
currencies: currencies,
|
||||
languages: languages,
|
||||
).websiteInterfaces?.data[0].attributes;
|
||||
|
||||
return {
|
||||
langui: langui ?? ({} as AppStaticProps["langui"]),
|
||||
currencies: currencies?.data ?? ({} as AppStaticProps["currencies"]),
|
||||
languages: languages?.data ?? ({} as AppStaticProps["languages"]),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,33 +4,36 @@ import {
|
|||
ImageQuality,
|
||||
} from "components/Img";
|
||||
import {
|
||||
DatePickerFragment,
|
||||
Enum_Componentsetstextset_Status,
|
||||
GetCurrenciesQuery,
|
||||
GetLanguagesQuery,
|
||||
GetLibraryItemQuery,
|
||||
GetLibraryItemsPreviewQuery,
|
||||
GetWebsiteInterfaceQuery,
|
||||
StrapiImage,
|
||||
} from "graphql/operations-types";
|
||||
GetLibraryItemScansQuery,
|
||||
PricePickerFragment,
|
||||
UploadImageFragment,
|
||||
} from "graphql/generated";
|
||||
import { NextRouter } from "next/router";
|
||||
import { AppStaticProps } from "./getAppStaticProps";
|
||||
|
||||
export function prettyDate(
|
||||
datePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["release_date"]
|
||||
): string {
|
||||
return `${datePicker.year}/${datePicker.month
|
||||
.toString()
|
||||
.padStart(2, "0")}/${datePicker.day.toString().padStart(2, "0")}`;
|
||||
export function prettyDate(datePicker: DatePickerFragment): string {
|
||||
let result = "";
|
||||
if (datePicker.year) result += datePicker.year.toString();
|
||||
if (datePicker.month)
|
||||
result += `/${datePicker.month.toString().padStart(2, "0")}`;
|
||||
if (datePicker.day)
|
||||
result += `/${datePicker.day.toString().padStart(2, "0")}`;
|
||||
return result;
|
||||
}
|
||||
|
||||
export function prettyPrice(
|
||||
pricePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["price"],
|
||||
currencies: GetCurrenciesQuery["currencies"]["data"],
|
||||
pricePicker: PricePickerFragment,
|
||||
currencies: AppStaticProps["currencies"],
|
||||
targetCurrencyCode?: string
|
||||
): string {
|
||||
if (!targetCurrencyCode) return "";
|
||||
let result = "";
|
||||
currencies.map((currency) => {
|
||||
if (currency.attributes.code === targetCurrencyCode) {
|
||||
if (currency?.attributes?.code === targetCurrencyCode) {
|
||||
const amountInTargetCurrency = convertPrice(pricePicker, currency);
|
||||
result =
|
||||
currency.attributes.symbol +
|
||||
|
@ -44,13 +47,22 @@ export function prettyPrice(
|
|||
}
|
||||
|
||||
export function convertPrice(
|
||||
pricePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["price"],
|
||||
targetCurrency: GetCurrenciesQuery["currencies"]["data"][number]
|
||||
pricePicker: PricePickerFragment,
|
||||
targetCurrency: Exclude<
|
||||
GetCurrenciesQuery["currencies"],
|
||||
null | undefined
|
||||
>["data"][number]
|
||||
): number {
|
||||
if (
|
||||
pricePicker.amount &&
|
||||
pricePicker.currency?.data?.attributes &&
|
||||
targetCurrency.attributes
|
||||
)
|
||||
return (
|
||||
(pricePicker.amount * pricePicker.currency.data.attributes.rate_to_usd) /
|
||||
targetCurrency.attributes.rate_to_usd
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function prettySlug(slug?: string, parentSlug?: string): string {
|
||||
|
@ -65,9 +77,9 @@ export function prettySlug(slug?: string, parentSlug?: string): string {
|
|||
}
|
||||
|
||||
export function prettyinlineTitle(
|
||||
pretitle: string,
|
||||
title: string,
|
||||
subtitle: string
|
||||
pretitle: string | undefined | null,
|
||||
title: string | undefined | null,
|
||||
subtitle: string | undefined | null
|
||||
): string {
|
||||
let result = "";
|
||||
if (pretitle) result += `${pretitle}: `;
|
||||
|
@ -77,11 +89,9 @@ export function prettyinlineTitle(
|
|||
}
|
||||
|
||||
export function prettyItemType(
|
||||
metadata: {
|
||||
__typename: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"][number]["__typename"];
|
||||
},
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"]
|
||||
): string {
|
||||
metadata: any,
|
||||
langui: AppStaticProps["langui"]
|
||||
): string | undefined | null {
|
||||
switch (metadata.__typename) {
|
||||
case "ComponentMetadataAudio":
|
||||
return langui.audio;
|
||||
|
@ -100,50 +110,132 @@ export function prettyItemType(
|
|||
}
|
||||
}
|
||||
|
||||
export function prettyItemSubType(metadata: {
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
__typename: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"][number]["__typename"];
|
||||
subtype?: any;
|
||||
platforms?: any;
|
||||
subitems_type?: any;
|
||||
}): string {
|
||||
export function prettyItemSubType(
|
||||
metadata:
|
||||
| {
|
||||
__typename: "ComponentMetadataAudio";
|
||||
subtype?: {
|
||||
data?: {
|
||||
attributes?: {
|
||||
slug: string;
|
||||
titles?: Array<{
|
||||
title: string;
|
||||
} | null> | null;
|
||||
} | null;
|
||||
} | null;
|
||||
} | null;
|
||||
}
|
||||
| {
|
||||
__typename: "ComponentMetadataBooks";
|
||||
subtype?: {
|
||||
data?: {
|
||||
attributes?: {
|
||||
slug: string;
|
||||
titles?: Array<{
|
||||
title: string;
|
||||
} | null> | null;
|
||||
} | null;
|
||||
} | null;
|
||||
} | null;
|
||||
}
|
||||
| {
|
||||
__typename: "ComponentMetadataGame";
|
||||
platforms?: {
|
||||
data: Array<{
|
||||
id?: string | null;
|
||||
attributes?: {
|
||||
short: string;
|
||||
} | null;
|
||||
}>;
|
||||
} | null;
|
||||
}
|
||||
| {
|
||||
__typename: "ComponentMetadataGroup";
|
||||
subtype?: {
|
||||
data?: {
|
||||
attributes?: {
|
||||
slug: string;
|
||||
titles?: Array<{
|
||||
title: string;
|
||||
} | null> | null;
|
||||
} | null;
|
||||
} | null;
|
||||
} | null;
|
||||
subitems_type?: {
|
||||
data?: {
|
||||
attributes?: {
|
||||
slug: string;
|
||||
titles?: Array<{
|
||||
title: string;
|
||||
} | null> | null;
|
||||
} | null;
|
||||
} | null;
|
||||
} | null;
|
||||
}
|
||||
| { __typename: "ComponentMetadataOther" }
|
||||
| {
|
||||
__typename: "ComponentMetadataVideo";
|
||||
subtype?: {
|
||||
data?: {
|
||||
attributes?: {
|
||||
slug: string;
|
||||
titles?: Array<{
|
||||
title: string;
|
||||
} | null> | null;
|
||||
} | null;
|
||||
} | null;
|
||||
} | null;
|
||||
}
|
||||
| { __typename: "Error" }
|
||||
| null
|
||||
): string {
|
||||
if (metadata) {
|
||||
switch (metadata.__typename) {
|
||||
case "ComponentMetadataAudio":
|
||||
case "ComponentMetadataBooks":
|
||||
case "ComponentMetadataVideo":
|
||||
return metadata.subtype.data.attributes.titles.length > 0
|
||||
return metadata.subtype?.data?.attributes?.titles &&
|
||||
metadata.subtype?.data?.attributes?.titles.length > 0 &&
|
||||
metadata.subtype.data.attributes.titles[0]
|
||||
? metadata.subtype.data.attributes.titles[0].title
|
||||
: prettySlug(metadata.subtype.data.attributes.slug);
|
||||
: prettySlug(metadata.subtype?.data?.attributes?.slug);
|
||||
case "ComponentMetadataGame":
|
||||
return metadata.platforms.data.length > 0
|
||||
return metadata.platforms?.data &&
|
||||
metadata.platforms?.data.length > 0 &&
|
||||
metadata.platforms.data[0].attributes
|
||||
? metadata.platforms.data[0].attributes.short
|
||||
: "";
|
||||
|
||||
case "ComponentMetadataGroup": {
|
||||
const firstPart =
|
||||
metadata.subtype.data.attributes.titles.length > 0
|
||||
metadata.subtype?.data?.attributes?.titles &&
|
||||
metadata.subtype?.data?.attributes?.titles.length > 0 &&
|
||||
metadata.subtype.data.attributes.titles[0]
|
||||
? metadata.subtype.data.attributes.titles[0].title
|
||||
: prettySlug(metadata.subtype.data.attributes.slug);
|
||||
: prettySlug(metadata.subtype?.data?.attributes?.slug);
|
||||
|
||||
const secondPart =
|
||||
metadata.subitems_type.data.attributes.titles.length > 0
|
||||
metadata.subitems_type?.data?.attributes?.titles &&
|
||||
metadata.subitems_type?.data?.attributes?.titles.length > 0 &&
|
||||
metadata.subitems_type.data.attributes.titles[0]
|
||||
? metadata.subitems_type.data.attributes.titles[0].title
|
||||
: prettySlug(metadata.subitems_type.data.attributes.slug);
|
||||
: prettySlug(metadata.subitems_type?.data?.attributes?.slug);
|
||||
return `${secondPart} ${firstPart}`;
|
||||
}
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
}
|
||||
|
||||
export function prettyLanguage(
|
||||
code: string,
|
||||
languages: GetLanguagesQuery["languages"]["data"]
|
||||
languages: AppStaticProps["languages"]
|
||||
): string {
|
||||
let result = code;
|
||||
languages.forEach((language) => {
|
||||
if (language.attributes.code === code)
|
||||
if (language?.attributes?.code === code)
|
||||
result = language.attributes.localized_name;
|
||||
});
|
||||
return result;
|
||||
|
@ -207,8 +299,8 @@ export function capitalizeString(string: string): string {
|
|||
return words.join(" ");
|
||||
}
|
||||
|
||||
export function convertMmToInch(mm: number): string {
|
||||
return (mm * 0.03937008).toPrecision(3);
|
||||
export function convertMmToInch(mm: number | null | undefined): string {
|
||||
return mm ? (mm * 0.03937008).toPrecision(3) : "";
|
||||
}
|
||||
|
||||
export type OgImage = {
|
||||
|
@ -218,31 +310,44 @@ export type OgImage = {
|
|||
alt: string;
|
||||
};
|
||||
|
||||
export function getOgImage(quality: ImageQuality, image: StrapiImage): OgImage {
|
||||
export function getOgImage(
|
||||
quality: ImageQuality,
|
||||
image: UploadImageFragment
|
||||
): OgImage {
|
||||
const imgSize = getImgSizesByQuality(
|
||||
image.width,
|
||||
image.height,
|
||||
image.width ?? 0,
|
||||
image.height ?? 0,
|
||||
quality ? quality : ImageQuality.Small
|
||||
);
|
||||
return {
|
||||
image: getAssetURL(image.url, quality),
|
||||
width: imgSize.width,
|
||||
height: imgSize.height,
|
||||
alt: image.alternativeText,
|
||||
alt: image.alternativeText || "",
|
||||
};
|
||||
}
|
||||
|
||||
export function sortContent(contents: {
|
||||
data: {
|
||||
attributes: {
|
||||
range: GetLibraryItemQuery["libraryItems"]["data"][number]["attributes"]["contents"]["data"][number]["attributes"]["range"];
|
||||
};
|
||||
}[];
|
||||
}) {
|
||||
contents.data.sort((a, b) => {
|
||||
export function sortContent(
|
||||
contents:
|
||||
| Exclude<
|
||||
Exclude<
|
||||
GetLibraryItemQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>["contents"]
|
||||
| Exclude<
|
||||
Exclude<
|
||||
GetLibraryItemScansQuery["libraryItems"],
|
||||
null | undefined
|
||||
>["data"][number]["attributes"],
|
||||
null | undefined
|
||||
>["contents"]
|
||||
) {
|
||||
contents?.data.sort((a, b) => {
|
||||
if (
|
||||
a.attributes.range[0].__typename === "ComponentRangePageRange" &&
|
||||
b.attributes.range[0].__typename === "ComponentRangePageRange"
|
||||
a.attributes?.range[0]?.__typename === "ComponentRangePageRange" &&
|
||||
b.attributes?.range[0]?.__typename === "ComponentRangePageRange"
|
||||
) {
|
||||
return (
|
||||
a.attributes.range[0].starting_page -
|
||||
|
@ -255,8 +360,8 @@ export function sortContent(contents: {
|
|||
|
||||
export function getStatusDescription(
|
||||
status: string,
|
||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"]
|
||||
): string {
|
||||
langui: AppStaticProps["langui"]
|
||||
): string | null | undefined {
|
||||
switch (status) {
|
||||
case Enum_Componentsetstextset_Status.Incomplete:
|
||||
return langui.status_incomplete;
|
||||
|
@ -300,15 +405,15 @@ export function randomInt(min: number, max: number) {
|
|||
}
|
||||
|
||||
export function getLocalesFromLanguages(
|
||||
languages: {
|
||||
language: {
|
||||
data: {
|
||||
attributes: {
|
||||
code: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
}[]
|
||||
languages?: Array<{
|
||||
language?: {
|
||||
data?: {
|
||||
attributes?: { code: string } | null;
|
||||
} | null;
|
||||
} | null;
|
||||
} | null> | null
|
||||
) {
|
||||
return languages.map((language) => language.language.data.attributes.code);
|
||||
return languages
|
||||
? languages.map((language) => language?.language?.data?.attributes?.code)
|
||||
: [];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue