diff --git a/src/collections/Collectibles/Collectibles.ts b/src/collections/Collectibles/Collectibles.ts index a75c637..4d47d1f 100644 --- a/src/collections/Collectibles/Collectibles.ts +++ b/src/collections/Collectibles/Collectibles.ts @@ -22,6 +22,10 @@ import { createEditor } from "../../utils/editor"; import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; import { RowLabel } from "./components/RowLabel"; import { getBySlugEndpoint } from "./endpoints/getBySlugEndpoint"; +import { getBySlugEndpointGallery } from "./endpoints/getBySlugEndpointGallery"; +import { getBySlugEndpointGalleryImage } from "./endpoints/getBySlugEndpointGalleryImage"; +import { getBySlugEndpointScanPage } from "./endpoints/getBySlugEndpointScanPage"; +import { getBySlugEndpointScans } from "./endpoints/getBySlugEndpointScans"; const fields = { status: "_status", @@ -137,7 +141,13 @@ export const Collectibles = buildVersionedCollectionConfig({ ]), }, }, - endpoints: [getBySlugEndpoint], + endpoints: [ + getBySlugEndpoint, + getBySlugEndpointScans, + getBySlugEndpointScanPage, + getBySlugEndpointGallery, + getBySlugEndpointGalleryImage, + ], fields: [ { type: "tabs", diff --git a/src/collections/Collectibles/endpoints/getBySlugEndpoint.ts b/src/collections/Collectibles/endpoints/getBySlugEndpoint.ts index c69abd6..92cc8a9 100644 --- a/src/collections/Collectibles/endpoints/getBySlugEndpoint.ts +++ b/src/collections/Collectibles/endpoints/getBySlugEndpoint.ts @@ -32,7 +32,7 @@ export const convertCollectibleToEndpointCollectible = ({ nature, urls, subitems, - gallery, + gallery: rawGallery, contents, priceEnabled, price, @@ -50,39 +50,47 @@ export const convertCollectibleToEndpointCollectible = ({ translations, releaseDate, languages, - scans, + scans: rawScans, tags, -}: Collectible): EndpointCollectible => ({ - slug, - languages: languages?.map((language) => (isPayloadType(language) ? language.id : language)) ?? [], - ...(isDefined(releaseDate) ? { releaseDate } : {}), - ...(isValidPayloadImage(thumbnail) ? { thumbnail: convertImageToEndpointImage(thumbnail) } : {}), - ...(isValidPayloadImage(backgroundImage) - ? { backgroundImage: convertImageToEndpointImage(backgroundImage) } - : {}), - tagGroups: convertTagsEndpointTagsGroups(tags), - translations: - translations?.map(({ language, title, description, pretitle, subtitle }) => ({ - language: isPayloadType(language) ? language.id : language, - title, - ...(isNotEmpty(pretitle) ? { pretitle } : {}), - ...(isNotEmpty(subtitle) ? { subtitle } : {}), - ...(isNotEmpty(description) ? { description } : {}), - })) ?? [], - contents: handleContents(contents), - gallery: handleGallery(gallery), - scans: handleScans(scans), - nature: nature === "Physical" ? CollectibleNature.Physical : CollectibleNature.Digital, - parentPages: convertSourceToEndpointSource({ collectibles: parentItems, folders }), - subitems: isPayloadArrayType(subitems) - ? subitems.filter(isPublished).map(convertCollectibleToEndpointCollectible) - : [], - urls: urls?.map(({ url }) => ({ url, label: getDomainFromUrl(url) })) ?? [], - ...(weightEnabled && isDefined(weight) ? { weight: weight.amount } : {}), - ...handleSize(size, sizeEnabled), - ...handlePageInfo(pageInfo, pageInfoEnabled), - ...handlePrice(price, priceEnabled), -}); +}: Collectible): EndpointCollectible => { + const gallery = handleGallery(rawGallery); + const scans = handleScans(rawScans); + + return { + slug, + languages: + languages?.map((language) => (isPayloadType(language) ? language.id : language)) ?? [], + ...(isDefined(releaseDate) ? { releaseDate } : {}), + ...(isValidPayloadImage(thumbnail) + ? { thumbnail: convertImageToEndpointImage(thumbnail) } + : {}), + ...(isValidPayloadImage(backgroundImage) + ? { backgroundImage: convertImageToEndpointImage(backgroundImage) } + : {}), + tagGroups: convertTagsEndpointTagsGroups(tags), + translations: + translations?.map(({ language, title, description, pretitle, subtitle }) => ({ + language: isPayloadType(language) ? language.id : language, + title, + ...(isNotEmpty(pretitle) ? { pretitle } : {}), + ...(isNotEmpty(subtitle) ? { subtitle } : {}), + ...(isNotEmpty(description) ? { description } : {}), + })) ?? [], + contents: handleContents(contents), + ...(gallery ? { gallery } : {}), + ...(scans ? { scans } : {}), + nature: nature === "Physical" ? CollectibleNature.Physical : CollectibleNature.Digital, + parentPages: convertSourceToEndpointSource({ collectibles: parentItems, folders }), + subitems: isPayloadArrayType(subitems) + ? subitems.filter(isPublished).map(convertCollectibleToEndpointCollectible) + : [], + urls: urls?.map(({ url }) => ({ url, label: getDomainFromUrl(url) })) ?? [], + ...(weightEnabled && isDefined(weight) ? { weight: weight.amount } : {}), + ...handleSize(size, sizeEnabled), + ...handlePageInfo(pageInfo, pageInfoEnabled), + ...handlePrice(price, priceEnabled), + }; +}; const handlePrice = ( price: Collectible["price"], @@ -122,13 +130,11 @@ const handlePageInfo = ( }; }; -const handleGallery = (gallery: Collectible["gallery"]): EndpointCollectible["gallery"] => - gallery - ?.flatMap(({ image }) => { - if (!isValidPayloadImage(image)) return []; - return convertImageToEndpointImage(image); - }) - .slice(0, 10) ?? []; +const handleGallery = (gallery: Collectible["gallery"]): EndpointCollectible["gallery"] => { + const thumbnail = gallery?.[0]?.image; + if (!thumbnail || !isValidPayloadImage(thumbnail)) return; + return { count: gallery.length, thumbnail: convertImageToEndpointImage(thumbnail) }; +}; const handleScans = (scans: Collectible["scans"]): EndpointCollectible["scans"] => { const result = @@ -137,23 +143,23 @@ const handleScans = (scans: Collectible["scans"]): EndpointCollectible["scans"] return image; }) ?? []; + const totalCount = + Object.keys(scans?.cover ?? {}).length + + Object.keys(scans?.dustjacket ?? {}).length + + Object.keys(scans?.obi ?? {}).length + + result.length; + if (isValidPayloadImage(scans?.cover?.front)) { result.push(scans.cover.front); } - if (isValidPayloadImage(scans?.cover?.back)) { - result.push(scans.cover.back); - } - if (isValidPayloadImage(scans?.dustjacket?.front)) { result.push(scans.dustjacket.front); } - if (isValidPayloadImage(scans?.dustjacket?.back)) { - result.push(scans.dustjacket.back); - } - - return result.slice(0, 10); + const thumbnail = result?.[0]; + if (!thumbnail || !isValidPayloadImage(thumbnail)) return; + return { count: totalCount, thumbnail }; }; const handleContents = (contents: Collectible["contents"]): EndpointCollectible["contents"] => { diff --git a/src/collections/Collectibles/endpoints/getBySlugEndpointGallery.ts b/src/collections/Collectibles/endpoints/getBySlugEndpointGallery.ts new file mode 100644 index 0000000..b4830b0 --- /dev/null +++ b/src/collections/Collectibles/endpoints/getBySlugEndpointGallery.ts @@ -0,0 +1,35 @@ +import { Collections } from "../../../constants"; +import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; +import { EndpointCollectibleGallery } from "../../../sdk"; +import { isNotEmpty, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; +import { convertSourceToEndpointSource } from "../../../utils/endpoints"; +import { convertImageToEndpointImage } from "../../Images/endpoints/getByID"; + +export const getBySlugEndpointGallery = createGetByEndpoint({ + collection: Collections.Collectibles, + attribute: "slug", + suffix: "/gallery", + depth: 3, + handler: (collectible): EndpointCollectibleGallery => { + const { slug, thumbnail, translations, gallery } = collectible; + return { + slug, + translations: + translations?.map(({ language, title, description, pretitle, subtitle }) => ({ + language: isPayloadType(language) ? language.id : language, + title, + ...(isNotEmpty(pretitle) ? { pretitle } : {}), + ...(isNotEmpty(subtitle) ? { subtitle } : {}), + ...(isNotEmpty(description) ? { description } : {}), + })) ?? [], + ...(isValidPayloadImage(thumbnail) + ? { thumbnail: convertImageToEndpointImage(thumbnail) } + : {}), + images: + gallery?.flatMap(({ image }) => + isValidPayloadImage(image) ? convertImageToEndpointImage(image) : [] + ) ?? [], + parentPages: convertSourceToEndpointSource({ collectibles: [collectible] }), + }; + }, +}); diff --git a/src/collections/Collectibles/endpoints/getBySlugEndpointGalleryImage.ts b/src/collections/Collectibles/endpoints/getBySlugEndpointGalleryImage.ts new file mode 100644 index 0000000..009a750 --- /dev/null +++ b/src/collections/Collectibles/endpoints/getBySlugEndpointGalleryImage.ts @@ -0,0 +1,104 @@ +import payload from "payload"; +import { Collections } from "../../../constants"; +import { EndpointCollectibleGalleryImage } from "../../../sdk"; +import { Collectible, Image } from "../../../types/collections"; +import { CollectionEndpoint } from "../../../types/payload"; +import { isDefined, isNotEmpty, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; +import { convertSourceToEndpointSource } from "../../../utils/endpoints"; +import { convertImageToEndpointImage } from "../../Images/endpoints/getByID"; + +export const getBySlugEndpointGalleryImage: CollectionEndpoint = { + path: "/slug/:slug/gallery/:index", + method: "get", + handler: async (req, res) => { + if (!req.user) { + return res.status(403).send({ + errors: [ + { + message: "You are not allowed to perform this action.", + }, + ], + }); + } + + const { slug, index } = req.params; + + if (!slug) { + return res.status(400).send({ error: "Missing 'slug' in endpoint path" }); + } + if (!index) { + return res.status(400).send({ error: "Missing 'index' in endpoint path" }); + } + + const result = await payload.find({ + collection: Collections.Collectibles, + where: { slug: { equals: slug } }, + }); + + const collectible = result.docs[0]; + + if (!collectible || !collectible.gallery) { + return res.sendStatus(404); + } + + const image = getImageFromIndex(index, collectible.gallery); + + if (!image || !isValidPayloadImage(image)) { + return res.sendStatus(404); + } + + const previousIndex = getPreviousIndex(index); + const nextIndex = getNextIndex(index, collectible.gallery); + + const scanPage: EndpointCollectibleGalleryImage = { + image: convertImageToEndpointImage(image), + parentPages: convertSourceToEndpointSource({ gallery: [collectible] }), + slug, + ...(isValidPayloadImage(collectible.thumbnail) + ? { thumbnail: convertImageToEndpointImage(collectible.thumbnail) } + : {}), + translations: + collectible.translations?.map(({ language, title, description, pretitle, subtitle }) => ({ + language: isPayloadType(language) ? language.id : language, + title, + ...(isNotEmpty(pretitle) ? { pretitle } : {}), + ...(isNotEmpty(subtitle) ? { subtitle } : {}), + ...(isNotEmpty(description) ? { description } : {}), + })) ?? [], + ...(isDefined(previousIndex) ? { previousIndex } : {}), + ...(isDefined(nextIndex) ? { nextIndex } : {}), + }; + + res.status(200).send(scanPage); + }, +}; + +const getPreviousIndex = (index: string): string | undefined => { + const pageIndex = parseInt(index, 10); + if (isNaN(pageIndex)) return; + if (pageIndex <= 0) return; + return (pageIndex - 1).toString(); +}; + +const getNextIndex = ( + index: string, + gallery: NonNullable +): string | undefined => { + const pageIndex = parseInt(index, 10); + if (isNaN(pageIndex)) return; + if (pageIndex >= gallery.length - 1) return; + return (pageIndex + 1).toString(); +}; + +const getImageFromIndex = ( + index: string, + gallery: NonNullable +): string | Image | null | undefined => { + const pageIndex = parseInt(index, 10); + if (isNaN(pageIndex)) return; + + const page = gallery[pageIndex]; + if (!page) return; + + return page.image; +}; diff --git a/src/collections/Collectibles/endpoints/getBySlugEndpointScanPage.ts b/src/collections/Collectibles/endpoints/getBySlugEndpointScanPage.ts new file mode 100644 index 0000000..3644f24 --- /dev/null +++ b/src/collections/Collectibles/endpoints/getBySlugEndpointScanPage.ts @@ -0,0 +1,179 @@ +import payload from "payload"; +import { Collections } from "../../../constants"; +import { EndpointCollectibleScanPage } from "../../../sdk"; +import { Collectible, Scan } from "../../../types/collections"; +import { CollectionEndpoint } from "../../../types/payload"; +import { isDefined, isNotEmpty, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; +import { convertSourceToEndpointSource } from "../../../utils/endpoints"; +import { convertImageToEndpointImage } from "../../Images/endpoints/getByID"; + +export const getBySlugEndpointScanPage: CollectionEndpoint = { + path: "/slug/:slug/scans/:index", + method: "get", + handler: async (req, res) => { + if (!req.user) { + return res.status(403).send({ + errors: [ + { + message: "You are not allowed to perform this action.", + }, + ], + }); + } + + const { slug, index } = req.params; + + if (!slug) { + return res.status(400).send({ error: "Missing 'slug' in endpoint path" }); + } + if (!index) { + return res.status(400).send({ error: "Missing 'index' in endpoint path" }); + } + + const result = await payload.find({ + collection: Collections.Collectibles, + where: { slug: { equals: slug } }, + }); + + const collectible = result.docs[0]; + + if (!collectible || !collectible.scansEnabled || !collectible.scans) { + return res.sendStatus(404); + } + + const image = getImageFromIndex(index, collectible.scans); + + if (!image || !isValidPayloadImage(image)) { + return res.sendStatus(404); + } + + const previousIndex = getPreviousIndex(index, collectible.scans); + const nextIndex = getNextIndex(index, collectible.scans); + + const scanPage: EndpointCollectibleScanPage = { + image: { ...image, index }, + parentPages: convertSourceToEndpointSource({ scans: [collectible] }), + slug, + ...(isValidPayloadImage(collectible.thumbnail) + ? { thumbnail: convertImageToEndpointImage(collectible.thumbnail) } + : {}), + translations: + collectible.translations?.map(({ language, title, description, pretitle, subtitle }) => ({ + language: isPayloadType(language) ? language.id : language, + title, + ...(isNotEmpty(pretitle) ? { pretitle } : {}), + ...(isNotEmpty(subtitle) ? { subtitle } : {}), + ...(isNotEmpty(description) ? { description } : {}), + })) ?? [], + ...(isDefined(previousIndex) ? { previousIndex } : {}), + ...(isDefined(nextIndex) ? { nextIndex } : {}), + }; + + res.status(200).send(scanPage); + }, +}; + +const getPreviousIndex = ( + index: string, + scans: NonNullable +): string | undefined => { + const pageIndex = parseInt(index, 10); + if (isNaN(pageIndex)) return; + + const page = scans.pages?.find(({ page }) => page === pageIndex - 1); + if (!page) return; + + return page.page.toString(); +}; + +const getNextIndex = ( + index: string, + scans: NonNullable +): string | undefined => { + const pageIndex = parseInt(index, 10); + if (isNaN(pageIndex)) return; + + const page = scans.pages?.find(({ page }) => page === pageIndex + 1); + if (!page) return; + + return page.page.toString(); +}; + +const getImageFromIndex = ( + index: string, + scans: NonNullable +): string | Scan | null | undefined => { + switch (index) { + case "cover-flap-front": + return scans.cover?.flapFront; + case "cover-front": + return scans.cover?.front; + case "cover-spine": + return scans.cover?.spine; + case "cover-back": + return scans.cover?.back; + case "cover-flap-back": + return scans.cover?.flapBack; + + case "cover-inside-flap-front": + return scans.cover?.insideFlapFront; + case "cover-inside-front": + return scans.cover?.insideFront; + case "cover-inside-back": + return scans.cover?.insideBack; + case "cover-inside-flap-back": + return scans.cover?.insideFlapBack; + + case "dustjacket-flap-front": + return scans.dustjacket?.flapFront; + case "dustjacket-front": + return scans.dustjacket?.front; + case "dustjacket-spine": + return scans.dustjacket?.spine; + case "dustjacket-back": + return scans.dustjacket?.back; + case "dustjacket-flap-back": + return scans.dustjacket?.flapBack; + + case "dustjacket-inside-flap-front": + return scans.dustjacket?.insideFlapFront; + case "dustjacket-inside-front": + return scans.dustjacket?.insideFront; + case "dustjacket-inside-spine": + return scans.dustjacket?.insideSpine; + case "dustjacket-inside-back": + return scans.dustjacket?.insideBack; + case "dustjacket-inside-flap-back": + return scans.dustjacket?.insideFlapBack; + + case "obi-flap-front": + return scans.obi?.flapFront; + case "obi-front": + return scans.obi?.front; + case "obi-spine": + return scans.obi?.spine; + case "obi-back": + return scans.obi?.back; + case "obi-flap-back": + return scans.obi?.flapBack; + + case "obi-inside-flap-front": + return scans.obi?.insideFlapFront; + case "obi-inside-front": + return scans.obi?.insideFront; + case "obi-inside-spine": + return scans.obi?.insideSpine; + case "obi-inside-back": + return scans.obi?.insideBack; + case "obi-inside-flap-back": + return scans.obi?.insideFlapBack; + } + + const pageIndex = parseInt(index, 10); + if (isNaN(pageIndex)) return; + + const page = scans.pages?.find(({ page }) => page === pageIndex); + if (!page) return; + + return page.image; +}; diff --git a/src/collections/Collectibles/endpoints/getBySlugEndpointScans.ts b/src/collections/Collectibles/endpoints/getBySlugEndpointScans.ts new file mode 100644 index 0000000..9d6b693 --- /dev/null +++ b/src/collections/Collectibles/endpoints/getBySlugEndpointScans.ts @@ -0,0 +1,167 @@ +import { Collections } from "../../../constants"; +import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; +import { EndpointCollectibleScans } from "../../../sdk"; +import { Collectible } from "../../../types/collections"; +import { isNotEmpty, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; +import { + convertCreditsToEndpointCredits, + convertSourceToEndpointSource, +} from "../../../utils/endpoints"; +import { convertImageToEndpointImage } from "../../Images/endpoints/getByID"; + +export const getBySlugEndpointScans = createGetByEndpoint({ + collection: Collections.Collectibles, + attribute: "slug", + suffix: "/scans", + depth: 3, + handler: (collectible): EndpointCollectibleScans => { + const { slug, thumbnail, translations, scans, scansEnabled } = collectible; + return { + slug, + translations: + translations?.map(({ language, title, description, pretitle, subtitle }) => ({ + language: isPayloadType(language) ? language.id : language, + title, + ...(isNotEmpty(pretitle) ? { pretitle } : {}), + ...(isNotEmpty(subtitle) ? { subtitle } : {}), + ...(isNotEmpty(description) ? { description } : {}), + })) ?? [], + ...(isValidPayloadImage(thumbnail) + ? { thumbnail: convertImageToEndpointImage(thumbnail) } + : {}), + ...(scansEnabled && scans ? handleScans(scans) : { credits: [], pages: [] }), + parentPages: convertSourceToEndpointSource({ collectibles: [collectible] }), + }; + }, +}); + +const handleScans = ({ + credits, + cover, + coverEnabled, + dustjacket, + dustjacketEnabled, + obi, + obiEnabled, + pages, +}: NonNullable): Pick< + EndpointCollectibleScans, + "cover" | "obi" | "dustjacket" | "pages" | "credits" +> => ({ + credits: convertCreditsToEndpointCredits(credits), + pages: + pages?.flatMap(({ image, page }) => + isValidPayloadImage(image) ? { ...image, index: page.toString() } : [] + ) ?? [], + ...(coverEnabled && cover ? { cover: handleCover(cover) } : {}), + ...(dustjacketEnabled && dustjacket ? { dustjacket: handleDustjacket(dustjacket) } : {}), + ...(obiEnabled && obi ? { obi: handleObi(obi) } : {}), +}); + +const handleCover = ({ + back, + flapBack, + flapFront, + front, + insideBack, + insideFlapBack, + insideFlapFront, + insideFront, + spine, +}: NonNullable["cover"]>): EndpointCollectibleScans["cover"] => ({ + ...(isValidPayloadImage(back) ? { back: { ...back, index: "cover-back" } } : {}), + ...(isValidPayloadImage(flapBack) ? { flapBack: { ...flapBack, index: "cover-flap-back" } } : {}), + ...(isValidPayloadImage(flapFront) + ? { flapFront: { ...flapFront, index: "cover-flap-front" } } + : {}), + ...(isValidPayloadImage(front) ? { front: { ...front, index: "cover-front" } } : {}), + ...(isValidPayloadImage(insideBack) + ? { insideBack: { ...insideBack, index: "cover-inside-back" } } + : {}), + ...(isValidPayloadImage(insideFlapBack) + ? { insideFlapBack: { ...insideFlapBack, index: "cover-inside-flap-back" } } + : {}), + ...(isValidPayloadImage(insideFlapFront) + ? { insideFlapFront: { ...insideFlapFront, index: "cover-inside-flap-front" } } + : {}), + ...(isValidPayloadImage(insideFront) + ? { insideFront: { ...insideFront, index: "cover-inside-front" } } + : {}), + ...(isValidPayloadImage(spine) ? { spine: { ...spine, index: "cover-spine" } } : {}), +}); + +const handleDustjacket = ({ + back, + flapBack, + flapFront, + front, + insideBack, + insideFlapBack, + insideFlapFront, + insideFront, + insideSpine, + spine, +}: NonNullable< + NonNullable["dustjacket"] +>): EndpointCollectibleScans["dustjacket"] => ({ + ...(isValidPayloadImage(back) ? { back: { ...back, index: "dustjacket-back" } } : {}), + ...(isValidPayloadImage(flapBack) + ? { flapBack: { ...flapBack, index: "dustjacket-flap-back" } } + : {}), + ...(isValidPayloadImage(flapFront) + ? { flapFront: { ...flapFront, index: "dustjacket-flap-front" } } + : {}), + ...(isValidPayloadImage(front) ? { front: { ...front, index: "dustjacket-front" } } : {}), + ...(isValidPayloadImage(insideBack) + ? { insideBack: { ...insideBack, index: "dustjacket-inside-back" } } + : {}), + ...(isValidPayloadImage(insideFlapBack) + ? { insideFlapBack: { ...insideFlapBack, index: "dustjacket-inside-flap-back" } } + : {}), + ...(isValidPayloadImage(insideFlapFront) + ? { insideFlapFront: { ...insideFlapFront, index: "dustjacket-inside-flap-front" } } + : {}), + ...(isValidPayloadImage(insideFront) + ? { insideFront: { ...insideFront, index: "dustjacket-inside-front" } } + : {}), + ...(isValidPayloadImage(spine) ? { spine: { ...spine, index: "dustjacket-spine" } } : {}), + ...(isValidPayloadImage(insideSpine) + ? { insideSpine: { ...insideSpine, index: "dustjacket-inside-spine" } } + : {}), +}); + +const handleObi = ({ + back, + flapBack, + flapFront, + front, + insideBack, + insideFlapBack, + insideFlapFront, + insideFront, + insideSpine, + spine, +}: NonNullable["obi"]>): EndpointCollectibleScans["obi"] => ({ + ...(isValidPayloadImage(back) ? { back: { ...back, index: "obi-back" } } : {}), + ...(isValidPayloadImage(flapBack) ? { flapBack: { ...flapBack, index: "obi-flap-back" } } : {}), + ...(isValidPayloadImage(flapFront) + ? { flapFront: { ...flapFront, index: "obi-flap-front" } } + : {}), + ...(isValidPayloadImage(front) ? { front: { ...front, index: "obi-front" } } : {}), + ...(isValidPayloadImage(insideBack) + ? { insideBack: { ...insideBack, index: "obi-inside-back" } } + : {}), + ...(isValidPayloadImage(insideFlapBack) + ? { insideFlapBack: { ...insideFlapBack, index: "obi-inside-flap-back" } } + : {}), + ...(isValidPayloadImage(insideFlapFront) + ? { insideFlapFront: { ...insideFlapFront, index: "obi-inside-flap-front" } } + : {}), + ...(isValidPayloadImage(insideFront) + ? { insideFront: { ...insideFront, index: "obi-inside-front" } } + : {}), + ...(isValidPayloadImage(spine) ? { spine: { ...spine, index: "obi-spine" } } : {}), + ...(isValidPayloadImage(insideSpine) + ? { insideSpine: { ...insideSpine, index: "obi-inside-spine" } } + : {}), +}); diff --git a/src/endpoints/createGetByEndpoint.ts b/src/endpoints/createGetByEndpoint.ts index a011b6b..09cf314 100644 --- a/src/endpoints/createGetByEndpoint.ts +++ b/src/endpoints/createGetByEndpoint.ts @@ -7,6 +7,7 @@ interface Params { attribute: string; handler: (doc: GeneratedTypes["collections"][C]) => Promise | R; depth?: number; + suffix?: string; } export const createGetByEndpoint = ({ @@ -14,8 +15,9 @@ export const createGetByEndpoint = ): CollectionEndpoint => ({ - path: `/${attribute}/:${attribute}`, + path: `/${attribute}/:${attribute}${suffix}`, method: "get", handler: async (req, res) => { if (!req.user) { diff --git a/src/sdk.ts b/src/sdk.ts index 2e82c8a..ed7a6e1 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -233,8 +233,8 @@ export type EndpointCollectible = { languages: string[]; backgroundImage?: EndpointImage; nature: CollectibleNature; - gallery: EndpointImage[]; - scans: PayloadImage[]; + gallery?: { count: number; thumbnail: EndpointImage }; + scans?: { count: number; thumbnail: PayloadImage }; urls: { url: string; label: string }[]; price?: { amount: number; @@ -298,6 +298,104 @@ export type EndpointCollectible = { parentPages: EndpointSource[]; }; +export type EndpointCollectibleScans = { + slug: string; + thumbnail?: EndpointImage; + translations: { + language: string; + pretitle?: string; + title: string; + subtitle?: string; + description?: RichTextContent; + }[]; + credits: EndpointCredit[]; + cover?: { + front?: EndpointScanImage; + spine?: EndpointScanImage; + back?: EndpointScanImage; + insideFront?: EndpointScanImage; + insideBack?: EndpointScanImage; + flapFront?: EndpointScanImage; + flapBack?: EndpointScanImage; + insideFlapFront?: EndpointScanImage; + insideFlapBack?: EndpointScanImage; + }; + dustjacket?: { + front?: EndpointScanImage; + spine?: EndpointScanImage; + back?: EndpointScanImage; + insideFront?: EndpointScanImage; + insideSpine?: EndpointScanImage; + insideBack?: EndpointScanImage; + flapFront?: EndpointScanImage; + flapBack?: EndpointScanImage; + insideFlapFront?: EndpointScanImage; + insideFlapBack?: EndpointScanImage; + }; + obi?: { + front?: EndpointScanImage; + spine?: EndpointScanImage; + back?: EndpointScanImage; + insideFront?: EndpointScanImage; + insideSpine?: EndpointScanImage; + insideBack?: EndpointScanImage; + flapFront?: EndpointScanImage; + flapBack?: EndpointScanImage; + insideFlapFront?: EndpointScanImage; + insideFlapBack?: EndpointScanImage; + }; + pages: EndpointScanImage[]; + parentPages: EndpointSource[]; +}; + +export type EndpointCollectibleGallery = { + slug: string; + thumbnail?: EndpointImage; + translations: { + language: string; + pretitle?: string; + title: string; + subtitle?: string; + description?: RichTextContent; + }[]; + images: EndpointImage[]; + parentPages: EndpointSource[]; +}; + +export type EndpointCollectibleGalleryImage = { + slug: string; + thumbnail?: EndpointImage; + translations: { + language: string; + pretitle?: string; + title: string; + subtitle?: string; + }[]; + image: EndpointImage; + previousIndex?: string; + nextIndex?: string; + parentPages: EndpointSource[]; +}; + +export type EndpointCollectibleScanPage = { + slug: string; + thumbnail?: EndpointImage; + translations: { + language: string; + pretitle?: string; + title: string; + subtitle?: string; + }[]; + image: EndpointScanImage; + previousIndex?: string; + nextIndex?: string; + parentPages: EndpointSource[]; +}; + +export type EndpointScanImage = PayloadImage & { + index: string; +}; + export type TableOfContentEntry = { prefix: string; title: string; @@ -337,7 +435,9 @@ export type EndpointSource = | { type: "custom"; translations: { language: string; note: string }[] }; } | { type: "page"; page: EndpointPage } - | { type: "folder"; folder: EndpointFolder }; + | { type: "folder"; folder: EndpointFolder } + | { type: "scans"; collectible: EndpointCollectible } + | { type: "gallery"; collectible: EndpointCollectible }; export type EndpointMedia = { id: string; @@ -416,6 +516,24 @@ export const payload = { await (await request(payloadApiUrl(Collections.Pages, `slug/${slug}`))).json(), getCollectible: async (slug: string): Promise => await (await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}`))).json(), + getCollectibleScans: async (slug: string): Promise => + await (await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/scans`))).json(), + getCollectibleScanPage: async ( + slug: string, + index: string + ): Promise => + await ( + await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/scans/${index}`)) + ).json(), + getCollectibleGallery: async (slug: string): Promise => + await (await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/gallery`))).json(), + getCollectibleGalleryImage: async ( + slug: string, + index: string + ): Promise => + await ( + await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}/gallery/${index}`)) + ).json(), getChronologyEvents: async (): Promise => await (await request(payloadApiUrl(Collections.ChronologyEvents, `all`))).json(), getChronologyEventByID: async (id: string): Promise => diff --git a/src/utils/endpoints.ts b/src/utils/endpoints.ts index 359cafa..d6ce0b7 100644 --- a/src/utils/endpoints.ts +++ b/src/utils/endpoints.ts @@ -154,8 +154,12 @@ export const convertRTCToEndpointRTC = ( export const convertSourceToEndpointSource = ({ collectibles, folders, + gallery, + scans, }: { collectibles?: (string | Collectible)[] | null | undefined; + scans?: (string | Collectible)[] | null | undefined; + gallery?: (string | Collectible)[] | null | undefined; folders?: (string | Folder)[] | null | undefined; }): EndpointSource[] => { const result: EndpointSource[] = []; @@ -169,6 +173,24 @@ export const convertSourceToEndpointSource = ({ }); } + if (scans && isPayloadArrayType(scans)) { + scans.filter(isPublished).forEach((collectible) => { + result.push({ + type: "scans", + collectible: convertCollectibleToEndpointCollectible(collectible), + }); + }); + } + + if (gallery && isPayloadArrayType(gallery)) { + gallery.filter(isPublished).forEach((collectible) => { + result.push({ + type: "gallery", + collectible: convertCollectibleToEndpointCollectible(collectible), + }); + }); + } + if (folders && isPayloadArrayType(folders)) { folders.forEach((folder) => { result.push({