Switched to new content data model

This commit is contained in:
DrMint 2022-05-14 22:47:00 +02:00
parent 2e0af56aa8
commit 461bd08a3d
13 changed files with 461 additions and 568 deletions

View File

@ -39,12 +39,12 @@ export function ContentLine(props: Immutable<Props>): JSX.Element {
>
<a>
<h3 className="cursor-pointer" onClick={() => setOpened(!opened)}>
{content.attributes.content?.data?.attributes?.titles?.[0]
{content.attributes.content?.data?.attributes?.translations?.[0]
? prettyinlineTitle(
content.attributes.content.data.attributes.titles[0]
content.attributes.content.data.attributes.translations[0]
?.pre_title,
content.attributes.content.data.attributes.titles[0]?.title,
content.attributes.content.data.attributes.titles[0]
content.attributes.content.data.attributes.translations[0]?.title,
content.attributes.content.data.attributes.translations[0]
?.subtitle
)
: prettySlug(content.attributes.slug, props.parentSlug)}

View File

@ -55,10 +55,10 @@ export function ScanSet(props: Immutable<Props>): JSX.Element {
const [selectedScan, LanguageSwitcher] = useSmartLanguage({
items: scanSet,
languages: languages,
languageExtractor: (item) => item?.language?.data?.attributes?.code,
languageExtractor: (item) => item.language?.data?.attributes?.code,
transform: (item) => {
const newItem = { ...item } as Props["scanSet"][number];
newItem?.pages?.data.sort((a, b) => {
const newItem = { ...item } as Exclude<Props["scanSet"][number], null>;
newItem.pages?.data.sort((a, b) => {
if (a.attributes?.url && b.attributes?.url) {
let aName = getAssetFilename(a.attributes.url);
let bName = getAssetFilename(b.attributes.url);

View File

@ -2,7 +2,7 @@ import { Chip } from "components/Chip";
import { Img } from "components/Img";
import { InsetBox } from "components/InsetBox";
import { Markdawn } from "components/Markdown/Markdawn";
import { GetContentQuery, UploadImageFragment } from "graphql/generated";
import { GetContentTextQuery, UploadImageFragment } from "graphql/generated";
import { AppStaticProps } from "graphql/getAppStaticProps";
import { prettyinlineTitle, prettySlug, slugify } from "helpers/formatters";
import { getAssetURL, ImageQuality } from "helpers/img";
@ -16,14 +16,14 @@ interface Props {
description?: string | null | undefined;
type?: Exclude<
Exclude<
GetContentQuery["contents"],
GetContentTextQuery["contents"],
null | undefined
>["data"][number]["attributes"],
null | undefined
>["type"];
categories?: Exclude<
Exclude<
GetContentQuery["contents"],
GetContentTextQuery["contents"],
null | undefined
>["data"][number]["attributes"],
null | undefined

View File

@ -14,7 +14,13 @@ query devGetContents {
id
}
}
titles {
ranged_contents {
data {
id
}
}
translations {
language {
data {
id
@ -22,18 +28,7 @@ query devGetContents {
}
title
description
}
ranged_contents {
data {
id
}
}
text_set {
language {
data {
id
}
}
source_language {
data {
id
@ -57,12 +52,8 @@ query devGetContents {
}
text
}
video_set {
id
}
audio_set {
id
}
thumbnail {
data {
id

View File

@ -1,77 +0,0 @@
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
}
}
}
}
}
}
}

View File

@ -4,12 +4,7 @@ query getContentText($slug: String, $language_code: String) {
id
attributes {
slug
titles {
pre_title
title
subtitle
description
}
categories {
data {
id
@ -56,9 +51,7 @@ query getContentText($slug: String, $language_code: String) {
}
}
}
text_set {
status
text
translations {
language {
data {
attributes {
@ -66,6 +59,13 @@ query getContentText($slug: String, $language_code: String) {
}
}
}
pre_title
title
subtitle
description
text_set {
status
text
source_language {
data {
attributes {
@ -99,6 +99,8 @@ query getContentText($slug: String, $language_code: String) {
}
notes
}
}
thumbnail {
data {
attributes {
@ -110,7 +112,7 @@ query getContentText($slug: String, $language_code: String) {
data {
attributes {
slug
titles(filters: { language: { code: { eq: $language_code } } }) {
translations {
pre_title
title
subtitle
@ -149,7 +151,7 @@ query getContentText($slug: String, $language_code: String) {
data {
attributes {
slug
titles(filters: { language: { code: { eq: $language_code } } }) {
translations {
pre_title
title
subtitle

View File

@ -4,7 +4,14 @@ query getContents($language_code: String) {
id
attributes {
slug
titles {
translations {
language {
data {
attributes {
code
}
}
}
pre_title
title
subtitle
@ -65,15 +72,6 @@ query getContents($language_code: String) {
id
}
}
text_set {
id
}
video_set {
id
}
audio_set {
id
}
thumbnail {
data {
attributes {

View File

@ -362,22 +362,18 @@ query getLibraryItem($slug: String, $language_code: String) {
}
}
}
titles(
filters: { language: { code: { eq: $language_code } } }
) {
translations {
language {
data {
attributes {
code
}
}
}
pre_title
title
subtitle
}
text_set {
id
}
video_set {
id
}
audio_set {
id
}
}
}
}

View File

@ -1,4 +1,4 @@
import { GetPostQuery } from "graphql/generated";
import { GetContentTextQuery, GetPostQuery } from "graphql/generated";
import React from "react";
type Post = Exclude<
@ -13,6 +13,18 @@ export interface PostWithTranslations extends Omit<Post, "translations"> {
translations: Exclude<Post["translations"], null | undefined>;
}
type Content = Exclude<
Exclude<
GetContentTextQuery["contents"],
null | undefined
>["data"][number]["attributes"],
null | undefined
>;
export interface ContentWithTranslations extends Omit<Content, "translations"> {
translations: Exclude<Content["translations"], null | undefined>;
}
type ImmutableBlackList<T> = JSX.Element | React.ReactNode | Function;
export type Immutable<T> = {

View File

@ -8,8 +8,12 @@ import { useEffect, useMemo, useState } from "react";
interface Props<T> {
items: Immutable<T[]>;
languages: AppStaticProps["languages"];
languageExtractor: (item: Immutable<T>) => string | undefined;
transform?: (item: Immutable<T>) => Immutable<T>;
languageExtractor: (
item: Exclude<Immutable<T>, null | undefined>
) => string | undefined;
transform?: (
item: Exclude<Immutable<T>, null | undefined>
) => Exclude<Immutable<T>, null | undefined>;
}
function getPreferredLanguage(
@ -45,8 +49,10 @@ export function useSmartLanguage<T>(
useEffect(() => {
items.map((elem, index) => {
if (elem !== null && elem !== undefined) {
const result = languageExtractor(elem);
if (result !== undefined) availableLocales.set(result, index);
}
});
}, [availableLocales, items, languageExtractor]);

View File

@ -13,7 +13,6 @@ import { PreviewLine } from "components/PreviewLine";
import { RecorderChip } from "components/RecorderChip";
import { ThumbnailHeader } from "components/ThumbnailHeader";
import { ToolTip } from "components/ToolTip";
import { GetContentTextQuery } from "graphql/generated";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk";
import {
@ -22,7 +21,7 @@ import {
prettySlug,
} from "helpers/formatters";
import { getStatusDescription } from "helpers/others";
import { Immutable } from "helpers/types";
import { ContentWithTranslations, Immutable } from "helpers/types";
import { useMediaMobile } from "hooks/useMediaQuery";
import { useSmartLanguage } from "hooks/useSmartLanguage";
import {
@ -32,28 +31,19 @@ import {
} from "next";
interface Props extends AppStaticProps {
content: Exclude<
GetContentTextQuery["contents"],
null | undefined
>["data"][number]["attributes"];
contentId: Exclude<
GetContentTextQuery["contents"],
null | undefined
>["data"][number]["id"];
content: ContentWithTranslations;
}
export default function Content(props: Immutable<Props>): JSX.Element {
const { langui, content, languages } = props;
const isMobile = useMediaMobile();
const [selectedTextSet, LanguageSwitcher] = useSmartLanguage({
items: content?.text_set,
const [selectedTranslation, LanguageSwitcher] = useSmartLanguage({
items: content.translations,
languages: languages,
languageExtractor: (item) => item?.language?.data?.attributes?.code,
languageExtractor: (item) => item.language?.data?.attributes?.code,
});
const selectedTitle = content?.titles?.[0];
const subPanel = (
<SubPanel>
<ReturnButton
@ -64,22 +54,26 @@ export default function Content(props: Immutable<Props>): JSX.Element {
horizontalLine
/>
{selectedTextSet?.source_language?.data?.attributes && (
{selectedTranslation?.text_set && (
<div className="grid gap-5">
<h2 className="text-xl">
{selectedTextSet.source_language.data.attributes.code ===
selectedTextSet.language?.data?.attributes?.code
{selectedTranslation.text_set.source_language?.data?.attributes
?.code === selectedTranslation.language?.data?.attributes?.code
? langui.transcript_notice
: langui.translation_notice}
</h2>
{selectedTextSet.source_language.data.attributes.code !==
selectedTextSet.language?.data?.attributes?.code && (
{selectedTranslation.text_set.source_language?.data?.attributes
?.code &&
selectedTranslation.text_set.source_language.data.attributes
.code !==
selectedTranslation.language?.data?.attributes?.code && (
<div className="grid place-items-center gap-2">
<p className="font-headers">{langui.source_language}:</p>
<Chip>
{prettyLanguage(
selectedTextSet.source_language.data.attributes.code,
selectedTranslation.text_set.source_language.data.attributes
.code,
languages
)}
</Chip>
@ -90,19 +84,23 @@ export default function Content(props: Immutable<Props>): JSX.Element {
<p className="font-headers">{langui.status}:</p>
<ToolTip
content={getStatusDescription(selectedTextSet.status, langui)}
content={getStatusDescription(
selectedTranslation.text_set.status,
langui
)}
maxWidth={"20rem"}
>
<Chip>{selectedTextSet.status}</Chip>
<Chip>{selectedTranslation.text_set.status}</Chip>
</ToolTip>
</div>
{selectedTextSet.transcribers &&
selectedTextSet.transcribers.data.length > 0 && (
{selectedTranslation.text_set.transcribers &&
selectedTranslation.text_set.transcribers.data.length > 0 && (
<div>
<p className="font-headers">{langui.transcribers}:</p>
<div className="grid place-items-center place-content-center gap-2">
{selectedTextSet.transcribers.data.map((recorder) => (
{selectedTranslation.text_set.transcribers.data.map(
(recorder) => (
<>
{recorder.attributes && (
<RecorderChip
@ -112,17 +110,19 @@ export default function Content(props: Immutable<Props>): JSX.Element {
/>
)}
</>
))}
)
)}
</div>
</div>
)}
{selectedTextSet.translators &&
selectedTextSet.translators.data.length > 0 && (
{selectedTranslation.text_set.translators &&
selectedTranslation.text_set.translators.data.length > 0 && (
<div>
<p className="font-headers">{langui.translators}:</p>
<div className="grid place-items-center place-content-center gap-2">
{selectedTextSet.translators.data.map((recorder) => (
{selectedTranslation.text_set.translators.data.map(
(recorder) => (
<>
{recorder.attributes && (
<RecorderChip
@ -132,17 +132,19 @@ export default function Content(props: Immutable<Props>): JSX.Element {
/>
)}
</>
))}
)
)}
</div>
</div>
)}
{selectedTextSet.proofreaders &&
selectedTextSet.proofreaders.data.length > 0 && (
{selectedTranslation.text_set.proofreaders &&
selectedTranslation.text_set.proofreaders.data.length > 0 && (
<div>
<p className="font-headers">{langui.proofreaders}:</p>
<div className="grid place-items-center place-content-center gap-2">
{selectedTextSet.proofreaders.data.map((recorder) => (
{selectedTranslation.text_set.proofreaders.data.map(
(recorder) => (
<>
{recorder.attributes && (
<RecorderChip
@ -152,36 +154,33 @@ export default function Content(props: Immutable<Props>): JSX.Element {
/>
)}
</>
))}
)
)}
</div>
</div>
)}
{selectedTextSet.notes && (
{selectedTranslation.text_set.notes && (
<div>
<p className="font-headers">{"Notes"}:</p>
<div className="grid place-items-center place-content-center gap-2">
<Markdawn text={selectedTextSet.notes} />
<Markdawn text={selectedTranslation.text_set.notes} />
</div>
</div>
)}
</div>
)}
{selectedTextSet && content?.text_set && selectedTextSet.text && (
{selectedTranslation?.text_set?.text && (
<>
<HorizontalLine />
<TOC
text={selectedTextSet.text}
title={
content.titles && content.titles.length > 0 && selectedTitle
? prettyinlineTitle(
selectedTitle.pre_title,
selectedTitle.title,
selectedTitle.subtitle
)
: prettySlug(content.slug)
}
text={selectedTranslation.text_set.text}
title={prettyinlineTitle(
selectedTranslation.pre_title,
selectedTranslation.title,
selectedTranslation.subtitle
)}
/>
</>
)}
@ -190,7 +189,7 @@ export default function Content(props: Immutable<Props>): JSX.Element {
const contentPanel = (
<ContentPanel>
<ReturnButton
href={`/contents/${content?.slug}`}
href={`/contents/${content.slug}`}
title={langui.content}
langui={langui}
displayOn={ReturnButtonType.mobile}
@ -201,14 +200,10 @@ export default function Content(props: Immutable<Props>): JSX.Element {
<div className="grid place-items-center">
<ThumbnailHeader
thumbnail={content.thumbnail?.data?.attributes}
pre_title={
selectedTitle?.pre_title ?? content.titles?.[0]?.pre_title
}
title={selectedTitle?.title ?? content.titles?.[0]?.title}
subtitle={selectedTitle?.subtitle ?? content.titles?.[0]?.subtitle}
description={
selectedTitle?.description ?? content.titles?.[0]?.description
}
pre_title={selectedTranslation?.pre_title}
title={selectedTranslation?.title}
subtitle={selectedTranslation?.subtitle}
description={selectedTranslation?.description}
type={content.type}
categories={content.categories}
langui={langui}
@ -221,16 +216,16 @@ export default function Content(props: Immutable<Props>): JSX.Element {
<PreviewLine
href={`/contents/${content.previous_recommended.data.attributes.slug}`}
pre_title={
content.previous_recommended.data.attributes.titles?.[0]
content.previous_recommended.data.attributes.translations?.[0]
?.pre_title
}
title={
content.previous_recommended.data.attributes.titles?.[0]
content.previous_recommended.data.attributes.translations?.[0]
?.title ??
prettySlug(content.previous_recommended.data.attributes.slug)
}
subtitle={
content.previous_recommended.data.attributes.titles?.[0]
content.previous_recommended.data.attributes.translations?.[0]
?.subtitle
}
thumbnail={
@ -268,7 +263,7 @@ export default function Content(props: Immutable<Props>): JSX.Element {
<HorizontalLine />
<Markdawn text={selectedTextSet?.text ?? ""} />
<Markdawn text={selectedTranslation?.text_set?.text ?? ""} />
{content.next_recommended?.data?.attributes && (
<>
@ -277,15 +272,17 @@ export default function Content(props: Immutable<Props>): JSX.Element {
<PreviewLine
href={`/contents/${content.next_recommended.data.attributes.slug}`}
pre_title={
content.next_recommended.data.attributes.titles?.[0]
content.next_recommended.data.attributes.translations?.[0]
?.pre_title
}
title={
content.next_recommended.data.attributes.titles?.[0]?.title ??
content.next_recommended.data.attributes.translations?.[0]
?.title ??
prettySlug(content.next_recommended.data.attributes.slug)
}
subtitle={
content.next_recommended.data.attributes.titles?.[0]?.subtitle
content.next_recommended.data.attributes.translations?.[0]
?.subtitle
}
thumbnail={
content.next_recommended.data.attributes.thumbnail?.data
@ -325,7 +322,7 @@ export default function Content(props: Immutable<Props>): JSX.Element {
);
let description = "";
if (content?.type?.data) {
if (content.type?.data) {
description += `${langui.type}: `;
description +=
@ -334,7 +331,7 @@ export default function Content(props: Immutable<Props>): JSX.Element {
description += "\n";
}
if (content?.categories?.data && 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)
@ -345,15 +342,15 @@ export default function Content(props: Immutable<Props>): JSX.Element {
return (
<AppLayout
navTitle={
content?.titles && content.titles.length > 0 && content.titles[0]
selectedTranslation
? prettyinlineTitle(
content.titles[0].pre_title,
content.titles[0].title,
content.titles[0].subtitle
selectedTranslation.pre_title,
selectedTranslation.title,
selectedTranslation.subtitle
)
: prettySlug(content?.slug)
: prettySlug(content.slug)
}
thumbnail={content?.thumbnail?.data?.attributes ?? undefined}
thumbnail={content.thumbnail?.data?.attributes ?? undefined}
contentPanel={contentPanel}
subPanel={subPanel}
description={description}
@ -372,12 +369,12 @@ export async function getStaticProps(
language_code: context.locale ?? "en",
});
if (!content.contents || content.contents.data.length === 0)
if (!content.contents || !content.contents.data[0].attributes?.translations) {
return { notFound: true };
}
const props: Props = {
...(await getAppStaticProps(context)),
content: content.contents.data[0].attributes,
contentId: content.contents.data[0].id,
content: content.contents.data[0].attributes as ContentWithTranslations,
};
return {
props: props,

View File

@ -111,12 +111,12 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
<PreviewCard
key={item.id}
href={`/contents/${item.attributes.slug}`}
pre_title={item.attributes.titles?.[0]?.pre_title}
pre_title={item.attributes.translations?.[0]?.pre_title}
title={
item.attributes.titles?.[0]?.title ??
item.attributes.translations?.[0]?.title ??
prettySlug(item.attributes.slug)
}
subtitle={item.attributes.titles?.[0]?.subtitle}
subtitle={item.attributes.translations?.[0]?.subtitle}
thumbnail={item.attributes.thumbnail?.data?.attributes}
thumbnailAspectRatio="3/2"
stackEffect={
@ -171,18 +171,18 @@ export async function getStaticProps(
});
if (!contents.contents) return { notFound: true };
contents.contents.data.sort((a, b) => {
const titleA = a.attributes?.titles?.[0]
const titleA = a.attributes?.translations?.[0]
? prettyinlineTitle(
a.attributes.titles[0].pre_title,
a.attributes.titles[0].title,
a.attributes.titles[0].subtitle
a.attributes.translations[0].pre_title,
a.attributes.translations[0].title,
a.attributes.translations[0].subtitle
)
: a.attributes?.slug ?? "";
const titleB = b.attributes?.titles?.[0]
const titleB = b.attributes?.translations?.[0]
? prettyinlineTitle(
b.attributes.titles[0].pre_title,
b.attributes.titles[0].title,
b.attributes.titles[0].subtitle
b.attributes.translations[0].pre_title,
b.attributes.translations[0].title,
b.attributes.translations[0].subtitle
)
: b.attributes?.slug ?? "";
return titleA.localeCompare(titleB);

View File

@ -6,10 +6,7 @@ import {
ContentPanelWidthSizes,
} from "components/Panels/ContentPanel";
import { ToolTip } from "components/ToolTip";
import {
DevGetContentsQuery,
Enum_Componentsetstextset_Status,
} from "graphql/generated";
import { DevGetContentsQuery } from "graphql/generated";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk";
import { Immutable } from "helpers/types";
@ -196,7 +193,7 @@ function testingContent(contents: Immutable<Props["contents"]>): Report {
});
}
if (content.attributes.titles?.length === 0) {
if (content.attributes.translations?.length === 0) {
report.lines.push({
subitems: [content.attributes.slug],
name: "No Titles",
@ -210,10 +207,10 @@ function testingContent(contents: Immutable<Props["contents"]>): Report {
} else {
const titleLanguages: string[] = [];
content.attributes.titles?.map((title, titleIndex) => {
if (title && content.attributes) {
if (title.language?.data?.id) {
if (title.language.data.id in titleLanguages) {
content.attributes.translations?.map((translation, titleIndex) => {
if (translation && content.attributes) {
if (translation.language?.data?.id) {
if (translation.language.data.id in titleLanguages) {
report.lines.push({
subitems: [
content.attributes.slug,
@ -228,7 +225,7 @@ function testingContent(contents: Immutable<Props["contents"]>): Report {
frontendUrl: frontendUrl,
});
} else {
titleLanguages.push(title.language.data.id);
titleLanguages.push(translation.language.data.id);
}
} else {
report.lines.push({
@ -245,7 +242,7 @@ function testingContent(contents: Immutable<Props["contents"]>): Report {
frontendUrl: frontendUrl,
});
}
if (!title.description) {
if (!translation.description) {
report.lines.push({
subitems: [
content.attributes.slug,
@ -260,51 +257,8 @@ function testingContent(contents: Immutable<Props["contents"]>): Report {
frontendUrl: frontendUrl,
});
}
}
});
}
if (
content.attributes.text_set?.length === 0 &&
content.attributes.audio_set?.length === 0 &&
content.attributes.video_set?.length === 0
) {
report.lines.push({
subitems: [content.attributes.slug],
name: "No Sets",
type: "Missing",
severity: "Medium",
description: "The Content has no Sets.",
recommandation: "",
backendUrl: backendUrl,
frontendUrl: frontendUrl,
});
} else {
if (content.attributes.video_set?.length === 0) {
report.lines.push({
subitems: [content.attributes.slug],
name: "No Video Sets",
type: "Missing",
severity: "Very Low",
description: "The Content has no Video Sets.",
recommandation: "",
backendUrl: backendUrl,
frontendUrl: frontendUrl,
});
}
if (content.attributes.audio_set?.length === 0) {
report.lines.push({
subitems: [content.attributes.slug],
name: "No Audio Sets",
type: "Missing",
severity: "Very Low",
description: "The Content has no Audio Sets.",
recommandation: "",
backendUrl: backendUrl,
frontendUrl: frontendUrl,
});
}
if (content.attributes.text_set?.length === 0) {
if (translation.text_set) {
report.lines.push({
subitems: [content.attributes.slug],
name: "No Text Set",
@ -318,7 +272,7 @@ function testingContent(contents: Immutable<Props["contents"]>): Report {
} else {
const textSetLanguages: string[] = [];
content.attributes.text_set?.map((textSet, textSetIndex) => {
/*
if (content.attributes && textSet) {
if (textSet.language?.data?.id) {
if (textSet.language.data.id in textSetLanguages) {
@ -403,7 +357,8 @@ function testingContent(contents: Immutable<Props["contents"]>): Report {
}
if (
textSet.source_language?.data?.id === textSet.language?.data?.id
textSet.source_language?.data?.id ===
textSet.language?.data?.id
) {
if (textSet.transcribers?.data.length === 0) {
report.lines.push({
@ -480,8 +435,21 @@ function testingContent(contents: Immutable<Props["contents"]>): Report {
}
}
}
*/
}
report.lines.push({
subitems: [content.attributes.slug],
name: "No Sets",
type: "Missing",
severity: "Medium",
description: "The Content has no Sets.",
recommandation: "",
backendUrl: backendUrl,
frontendUrl: frontendUrl,
});
}
});
}
}
});