import { GetStaticProps } from "next"; import { useMemo } from "react"; import { AppLayout, AppLayoutRequired } from "components/AppLayout"; import { Chip } from "components/Chip"; import { Button } from "components/Inputs/Button"; import { ContentPanel, ContentPanelWidthSizes, } from "components/Panels/ContentPanel"; import { ToolTip } from "components/ToolTip"; import { DevGetLibraryItemsQuery, Enum_Componentcollectionscomponentlibraryimages_Status, } from "graphql/generated"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { getReadySdk } from "graphql/sdk"; import { Report, Severity } from "helpers/types/Report"; import { getOpenGraph } from "helpers/openGraph"; /* * ╭────────╮ * ──────────────────────────────────────────╯ PAGE ╰───────────────────────────────────────────── */ interface Props extends AppStaticProps, AppLayoutRequired { libraryItems: DevGetLibraryItemsQuery; } const CheckupLibraryItems = ({ libraryItems, ...otherProps }: Props): JSX.Element => { const testReport = testingLibraryItem(libraryItems); const contentPanel = useMemo( () => ( <ContentPanel width={ContentPanelWidthSizes.Full}> {<h2 className="text-2xl">{testReport.title}</h2>} <div className="my-4 grid grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] items-center gap-2"> <p></p> <p></p> <p className="font-headers">Ref</p> <p className="font-headers">Name</p> <p className="font-headers">Type</p> <p className="font-headers">Severity</p> <p className="font-headers">Description</p> </div> {testReport.lines .sort((a, b) => a.name.localeCompare(b.name)) .sort((a, b) => b.severity - a.severity) .map((line, index) => ( <div key={index} className="mb-2 grid grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] items-center justify-items-start gap-2" > <Button href={line.frontendUrl} className="w-4 text-xs" text="F" alwaysNewTab /> <Button href={line.backendUrl} className="w-4 text-xs" text="B" alwaysNewTab /> <p>{line.subitems.join(" -> ")}</p> <p>{line.name}</p> <Chip text={line.type} /> <Chip className={ line.severity === Severity.VeryHigh ? "bg-[#f00] font-bold !opacity-100" : line.severity === Severity.High ? "bg-[#ff6600] font-bold !opacity-100" : line.severity === Severity.Medium ? "bg-[#fff344] !opacity-100" : "" } text={Severity[line.severity]} /> <ToolTip content={line.recommandation} placement="left"> <p>{line.description}</p> </ToolTip> </div> ))} </ContentPanel> ), [testReport.lines, testReport.title] ); return <AppLayout contentPanel={contentPanel} {...otherProps} />; }; export default CheckupLibraryItems; /* * ╭──────────────────────╮ * ───────────────────────────────────╯ NEXT DATA FETCHING ╰────────────────────────────────────── */ export const getStaticProps: GetStaticProps = async (context) => { const sdk = getReadySdk(); const libraryItems = await sdk.devGetLibraryItems(); const appStaticProps = await getAppStaticProps(context); const props: Props = { ...appStaticProps, libraryItems: libraryItems, openGraph: getOpenGraph(appStaticProps.langui, "Checkup Library Items"), }; return { props: props, }; }; /* * ╭───────────────────╮ * ─────────────────────────────────────╯ PRIVATE METHODS ╰─────────────────────────────────────── */ const testingLibraryItem = (libraryItems: Props["libraryItems"]): Report => { const report: Report = { title: "Contents", lines: [], }; libraryItems.libraryItems?.data.map((item) => { if (item.attributes) { const backendUrl = `${process.env.NEXT_PUBLIC_URL_CMS}/admin/content-manager/collectionType/api::library-item.library-item/${item.id}`; const frontendUrl = `${process.env.NEXT_PUBLIC_URL_SELF}/library/${item.attributes.slug}`; if (item.attributes.categories?.data.length === 0) { report.lines.push({ subitems: [item.attributes.slug], name: "No Category", type: "Missing", severity: Severity.High, description: "The Item has no Category.", recommandation: "Select a Category in relation with the Item", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if ( !item.attributes.root_item && item.attributes.subitem_of?.data.length === 0 ) { report.lines.push({ subitems: [item.attributes.slug], name: "Disconnected Item", type: "Error", severity: Severity.VeryHigh, description: "The Item is neither a Root Item, nor is it a subitem of another item.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (item.attributes.contents?.data.length === 0) { report.lines.push({ subitems: [item.attributes.slug], name: "No Contents", type: "Missing", severity: Severity.Low, description: "The Item has no Contents.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!item.attributes.thumbnail?.data?.id) { report.lines.push({ subitems: [item.attributes.slug], name: "No Thumbnail", type: "Missing", severity: Severity.High, description: "The Item has no Thumbnail.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (item.attributes.images?.length === 0) { report.lines.push({ subitems: [item.attributes.slug], name: "No Images", type: "Missing", severity: Severity.Low, description: "The Item has no Images.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } else { item.attributes.images?.map((image, imageIndex) => { const imagesLanguages: string[] = []; if (image && item.attributes) { if (image.language?.data?.id) { if (image.language.data.id in imagesLanguages) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "Duplicate Language", type: "Error", severity: Severity.High, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } else { imagesLanguages.push(image.language.data.id); } } else { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "No Language", type: "Error", severity: Severity.VeryHigh, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.source_language?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "No Source Language", type: "Error", severity: Severity.VeryHigh, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if ( image.status !== Enum_Componentcollectionscomponentlibraryimages_Status.Done ) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "Not Done Status", type: "Improvement", severity: Severity.Low, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (image.source_language?.data?.id === image.language?.data?.id) { if (image.scanners?.data.length === 0) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "No Scanners", type: "Missing", severity: Severity.High, description: "The Item is a Scan but doesn't credit any Scanners.", recommandation: "Add the appropriate Scanners.", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (image.cleaners?.data.length === 0) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "No Cleaners", type: "Missing", severity: Severity.High, description: "The Item is a Scan but doesn't credit any Cleaners.", recommandation: "Add the appropriate Cleaners.", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if ( image.typesetters?.data && image.typesetters.data.length > 0 ) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "Credited Typesetters", type: "Error", severity: Severity.High, description: "The Item is a Scan but credits one or more Typesetters.", recommandation: "If appropriate, create a Scanlation Images Set Set with the Typesetters credited there.", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } else { if (image.typesetters?.data.length === 0) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "No Typesetters", type: "Missing", severity: Severity.High, description: "The Item is a Scanlation but doesn't credit any Typesetters.", recommandation: "Add the appropriate Typesetters.", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (image.scanners?.data && image.scanners.data.length > 0) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "Credited Scanners", type: "Error", severity: Severity.High, description: "The Item is a Scanlation but credits one or more Scanners.", recommandation: "If appropriate, create a Scanners Images Set Set with the Scanners credited there.", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } if (image.cover) { if (!image.cover.front?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Cover", ], name: "No Front", type: "Missing", severity: Severity.VeryHigh, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.cover.spine?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Cover", ], name: "No spine", type: "Missing", severity: Severity.Low, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.cover.back?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Cover", ], name: "No Back", type: "Missing", severity: Severity.High, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.cover.full?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Cover", ], name: "No Full", type: "Missing", severity: Severity.Low, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } else { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "No Cover", type: "Missing", severity: Severity.Medium, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (image.dust_jacket) { if (!image.dust_jacket.front?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Dust Jacket", ], name: "No Front", type: "Missing", severity: Severity.VeryHigh, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.dust_jacket.spine?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Dust Jacket", ], name: "No spine", type: "Missing", severity: Severity.Low, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.dust_jacket.back?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Dust Jacket", ], name: "No Back", type: "Missing", severity: Severity.High, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.dust_jacket.full?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Dust Jacket", ], name: "No Full", type: "Missing", severity: Severity.Low, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.dust_jacket.flap_front?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Dust Jacket", ], name: "No Flap Front", type: "Missing", severity: Severity.Medium, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.dust_jacket.flap_back?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Dust Jacket", ], name: "No Flap Back", type: "Missing", severity: Severity.Medium, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } else { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "No Dust Jacket", type: "Missing", severity: Severity.VeryLow, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (image.obi_belt) { if (!image.obi_belt.front?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Obi Belt", ], name: "No Front", type: "Missing", severity: Severity.VeryHigh, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.obi_belt.spine?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Obi Belt", ], name: "No spine", type: "Missing", severity: Severity.Low, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.obi_belt.back?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Obi Belt", ], name: "No Back", type: "Missing", severity: Severity.High, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.obi_belt.full?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Obi Belt", ], name: "No Full", type: "Missing", severity: Severity.Low, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.obi_belt.flap_front?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Obi Belt", ], name: "No Flap Front", type: "Missing", severity: Severity.Medium, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (!image.obi_belt.flap_back?.data?.id) { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, "Obi Belt", ], name: "No Flap Back", type: "Missing", severity: Severity.Medium, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } else { report.lines.push({ subitems: [ item.attributes.slug, `Images ${imageIndex.toString()}`, ], name: "No Obi Belt", type: "Missing", severity: Severity.VeryLow, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } }); } if ( item.attributes.descriptions && item.attributes.descriptions.length > 0 ) { const descriptionLanguages: string[] = []; item.attributes.descriptions.map((description, descriptionIndex) => { if (description && item.attributes) { if (description.description.length < 10) { report.lines.push({ subitems: [ item.attributes.slug, `Description ${descriptionIndex}`, ], name: "No Text", type: "Missing", severity: Severity.VeryHigh, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (description.language?.data?.id) { if (description.language.data.id in descriptionLanguages) { report.lines.push({ subitems: [ item.attributes.slug, `Description ${descriptionIndex}`, ], name: "Duplicate Language", type: "Error", severity: Severity.High, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } else { descriptionLanguages.push(description.language.data.id); } } else { report.lines.push({ subitems: [ item.attributes.slug, `Description ${descriptionIndex}`, ], name: "No Language", type: "Error", severity: Severity.VeryHigh, description: "", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } }); } else { report.lines.push({ subitems: [item.attributes.slug], name: "No Description", type: "Missing", severity: Severity.Medium, description: "The Item has no Description.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } if (item.attributes.urls?.length === 0) { report.lines.push({ subitems: [item.attributes.slug], name: "No URLs", type: "Missing", severity: Severity.VeryLow, description: "The Item has no URLs.", recommandation: "", backendUrl: backendUrl, frontendUrl: frontendUrl, }); } } }); return report; };