From f46bdcaa038a0751709089f6a1aaca55163a3851 Mon Sep 17 00:00:00 2001 From: DrMint <29893320+DrMint@users.noreply.github.com> Date: Mon, 8 Apr 2024 23:12:19 +0200 Subject: [PATCH] Simplified crediting --- src/collections/Audios/Audios.ts | 3 + src/collections/Audios/endpoints/getByID.ts | 3 + .../ChronologyEvents/ChronologyEvents.ts | 4 +- .../endpoints/getAllEndpoint.ts | 26 +---- src/collections/Collectibles/Collectibles.ts | 38 +----- src/collections/CreditsRoles/CreditsRoles.ts | 34 ++++++ src/collections/Images/Images.ts | 3 + src/collections/Images/endpoints/getByID.ts | 3 + src/collections/Pages/Pages.ts | 109 +----------------- .../Pages/endpoints/getBySlugEndpoint.ts | 37 +----- src/collections/Videos/Videos.ts | 3 + src/collections/Videos/endpoints/getByID.ts | 3 + src/constants.ts | 7 +- src/fields/creditsField/creditsField.ts | 43 +++++++ .../translatedFields/translatedFields.ts | 84 +------------- src/payload.config.ts | 2 + src/sdk.ts | 25 ++-- src/types/collections.ts | 46 ++++++-- src/utils/endpoints.ts | 46 +++++++- 19 files changed, 211 insertions(+), 308 deletions(-) create mode 100644 src/collections/CreditsRoles/CreditsRoles.ts create mode 100644 src/fields/creditsField/creditsField.ts diff --git a/src/collections/Audios/Audios.ts b/src/collections/Audios/Audios.ts index 0871759..bb9d36e 100644 --- a/src/collections/Audios/Audios.ts +++ b/src/collections/Audios/Audios.ts @@ -1,4 +1,5 @@ import { CollectionGroups, Collections } from "../../constants"; +import { creditsField } from "../../fields/creditsField/creditsField"; import { imageField } from "../../fields/imageField/imageField"; import { rowField } from "../../fields/rowField/rowField"; import { tagsField } from "../../fields/tagsField/tagsField"; @@ -18,6 +19,7 @@ const fields = { thumbnail: "thumbnail", duration: "duration", tags: "tags", + credits: "credits", }; export const Audios = buildCollectionConfig({ @@ -63,5 +65,6 @@ export const Audios = buildCollectionConfig({ ], }), tagsField({ name: fields.tags }), + creditsField({ name: fields.credits }), ], }); diff --git a/src/collections/Audios/endpoints/getByID.ts b/src/collections/Audios/endpoints/getByID.ts index 7de9ff8..5d49c27 100644 --- a/src/collections/Audios/endpoints/getByID.ts +++ b/src/collections/Audios/endpoints/getByID.ts @@ -5,6 +5,7 @@ import { Audio } from "../../../types/collections"; import { CollectionEndpoint } from "../../../types/payload"; import { isNotEmpty, isValidPayloadImage, isValidPayloadMedia } from "../../../utils/asserts"; import { + convertCreditsToEndpointCredits, convertRTCToEndpointRTC, convertTagsEndpointTagsGroups, getLanguageId, @@ -57,6 +58,7 @@ export const convertAudioToEndpointAudio = ({ duration, id, thumbnail, + credits, }: Audio & PayloadMedia): EndpointAudio => ({ url, tagGroups: convertTagsEndpointTagsGroups(tags), @@ -74,4 +76,5 @@ export const convertAudioToEndpointAudio = ({ })) ?? [], duration, ...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}), + credits: convertCreditsToEndpointCredits(credits), }); diff --git a/src/collections/ChronologyEvents/ChronologyEvents.ts b/src/collections/ChronologyEvents/ChronologyEvents.ts index 241879b..e407ea5 100644 --- a/src/collections/ChronologyEvents/ChronologyEvents.ts +++ b/src/collections/ChronologyEvents/ChronologyEvents.ts @@ -5,6 +5,7 @@ import { publishStatusFilters, } from "../../components/QuickFilters"; import { CollectionGroups, Collections } from "../../constants"; +import { creditsField } from "../../fields/creditsField/creditsField"; import { rowField } from "../../fields/rowField/rowField"; import { translatedFields } from "../../fields/translatedFields/translatedFields"; import { createEditor } from "../../utils/editor"; @@ -28,6 +29,7 @@ const fields = { eventsTranslationsTitle: "title", eventsTranslationsDescription: "description", eventsTranslationsNotes: "notes", + eventsCredits: "credits", date: "date", dateYear: "year", dateMonth: "month", @@ -119,7 +121,6 @@ export const ChronologyEvents: CollectionConfig = buildVersionedCollectionConfig admin: { useAsTitle: fields.eventsTranslationsTitle, hasSourceLanguage: true, - hasCredits: true, }, fields: [ { @@ -138,6 +139,7 @@ export const ChronologyEvents: CollectionConfig = buildVersionedCollectionConfig type: "richText", editor: createEditor({ inlines: true, lists: true, links: true }), }, + creditsField({ name: fields.eventsCredits }), ], }), ], diff --git a/src/collections/ChronologyEvents/endpoints/getAllEndpoint.ts b/src/collections/ChronologyEvents/endpoints/getAllEndpoint.ts index 2106ba1..43e8630 100644 --- a/src/collections/ChronologyEvents/endpoints/getAllEndpoint.ts +++ b/src/collections/ChronologyEvents/endpoints/getAllEndpoint.ts @@ -3,11 +3,10 @@ import { Collections } from "../../../constants"; import { EndpointChronologyEvent, EndpointSource } from "../../../sdk"; import { ChronologyEvent, CollectibleBlock } from "../../../types/collections"; import { CollectionEndpoint } from "../../../types/payload"; -import { isDefined, isNotEmpty, isPayloadArrayType, isPayloadType } from "../../../utils/asserts"; -import { getDomainFromUrl } from "../../../utils/endpoints"; +import { isDefined, isNotEmpty, isPayloadType } from "../../../utils/asserts"; +import { convertCreditsToEndpointCredits, getDomainFromUrl } from "../../../utils/endpoints"; import { convertCollectibleToEndpointCollectible } from "../../Collectibles/endpoints/getBySlugEndpoint"; import { convertPageToEndpointPage } from "../../Pages/endpoints/getBySlugEndpoint"; -import { convertRecorderToEndpointRecorder } from "../../Recorders/endpoints/getByUsername"; export const getAllEndpoint: CollectionEndpoint = { method: "get", @@ -68,30 +67,13 @@ export const eventToEndpointEvent = ({ }, events: events.map(({ sources, translations }) => ({ translations: translations.map( - ({ - language, - sourceLanguage, - description, - notes, - proofreaders, - title, - transcribers, - translators, - }) => ({ + ({ language, sourceLanguage, description, notes, title, credits }) => ({ language: isPayloadType(language) ? language.id : language, sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage, ...(isNotEmpty(title) ? { title } : {}), ...(isNotEmpty(description) ? { description } : {}), ...(isNotEmpty(notes) ? { notes } : {}), - proofreaders: isPayloadArrayType(proofreaders) - ? proofreaders.map(convertRecorderToEndpointRecorder) - : [], - transcribers: isPayloadArrayType(transcribers) - ? transcribers.map(convertRecorderToEndpointRecorder) - : [], - translators: isPayloadArrayType(translators) - ? translators.map(convertRecorderToEndpointRecorder) - : [], + credits: convertCreditsToEndpointCredits(credits), }) ), sources: handleSources(sources), diff --git a/src/collections/Collectibles/Collectibles.ts b/src/collections/Collectibles/Collectibles.ts index 9b314cb..9d78042 100644 --- a/src/collections/Collectibles/Collectibles.ts +++ b/src/collections/Collectibles/Collectibles.ts @@ -6,10 +6,10 @@ import { CollectiblePageOrders, CollectionGroups, Collections, - PageType, } from "../../constants"; import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; import { componentField } from "../../fields/componentField/componentField"; +import { creditsField } from "../../fields/creditsField/creditsField"; import { imageField } from "../../fields/imageField/imageField"; import { rowField } from "../../fields/rowField/rowField"; import { slugField } from "../../fields/slugField/slugField"; @@ -54,9 +54,7 @@ const fields = { urlsUrl: "url", scans: "scans", - scansScanners: "scanners", - scansCleaners: "cleaners", - scansTypesetters: "typesetters", + scansCredits: "credits", scansCover: "cover", scansCoverFlapFront: "flapFront", @@ -232,28 +230,7 @@ export const Collectibles = buildVersionedCollectionConfig({ componentField({ name: fields.scans, fields: [ - rowField([ - { - name: fields.scansScanners, - type: "relationship", - relationTo: Collections.Recorders, - hasMany: true, - required: true, - }, - { - name: fields.scansCleaners, - type: "relationship", - relationTo: Collections.Recorders, - hasMany: true, - required: true, - }, - { - name: fields.scansTypesetters, - type: "relationship", - relationTo: Collections.Recorders, - hasMany: true, - }, - ]), + creditsField({ name: fields.scansCredits }), componentField({ name: fields.scansCover, fields: [ @@ -621,15 +598,6 @@ export const Collectibles = buildVersionedCollectionConfig({ allowCreate: false, }, required: true, - filterOptions: ({ relationTo }) => { - switch (relationTo) { - case Collections.Pages: - return { type: { equals: PageType.Content } }; - - default: - return true; - } - }, }, { name: "range", diff --git a/src/collections/CreditsRoles/CreditsRoles.ts b/src/collections/CreditsRoles/CreditsRoles.ts new file mode 100644 index 0000000..33c9674 --- /dev/null +++ b/src/collections/CreditsRoles/CreditsRoles.ts @@ -0,0 +1,34 @@ +import { CollectionConfig } from "payload/types"; +import { CollectionGroups, Collections } from "../../constants"; +import { iconField } from "../../fields/iconField/iconField"; +import { slugField } from "../../fields/slugField/slugField"; +import { translatedFields } from "../../fields/translatedFields/translatedFields"; +import { buildCollectionConfig } from "../../utils/collectionConfig"; + +const fields = { + slug: "slug", + translations: "translations", + translationsName: "name", + icon: "icon", +}; + +export const CreditsRoles: CollectionConfig = buildCollectionConfig({ + slug: Collections.CreditsRole, + labels: { singular: "Credits Role", plural: "Credits Roles" }, + admin: { + group: CollectionGroups.Meta, + useAsTitle: fields.slug, + defaultColumns: [fields.slug, fields.translations], + }, + fields: [ + slugField({ name: fields.slug }), + iconField({ name: fields.icon }), + translatedFields({ + name: fields.translations, + admin: { useAsTitle: fields.translationsName }, + required: true, + minRows: 1, + fields: [{ name: fields.translationsName, type: "text", required: true }], + }), + ], +}); diff --git a/src/collections/Images/Images.ts b/src/collections/Images/Images.ts index d1bce51..388e40b 100644 --- a/src/collections/Images/Images.ts +++ b/src/collections/Images/Images.ts @@ -1,4 +1,5 @@ import { Collections } from "../../constants"; +import { creditsField } from "../../fields/creditsField/creditsField"; import { tagsField } from "../../fields/tagsField/tagsField"; import { translatedFields } from "../../fields/translatedFields/translatedFields"; import { createEditor } from "../../utils/editor"; @@ -15,6 +16,7 @@ const fields = { translationsTitle: "title", translationsDescription: "description", tags: "tags", + credits: "credits", } as const satisfies Record; export const Images = buildImageCollectionConfig({ @@ -52,5 +54,6 @@ export const Images = buildImageCollectionConfig({ ], }), tagsField({ name: fields.tags }), + creditsField({ name: fields.credits }), ], }); diff --git a/src/collections/Images/endpoints/getByID.ts b/src/collections/Images/endpoints/getByID.ts index 9047daf..f320c09 100644 --- a/src/collections/Images/endpoints/getByID.ts +++ b/src/collections/Images/endpoints/getByID.ts @@ -5,6 +5,7 @@ import { Image } from "../../../types/collections"; import { CollectionEndpoint } from "../../../types/payload"; import { isNotEmpty, isValidPayloadImage } from "../../../utils/asserts"; import { + convertCreditsToEndpointCredits, convertRTCToEndpointRTC, convertTagsEndpointTagsGroups, getLanguageId, @@ -57,6 +58,7 @@ export const convertImageToEndpointImage = ({ filename, filesize, id, + credits, }: Image & PayloadImage): EndpointImage => ({ url, width, @@ -74,4 +76,5 @@ export const convertImageToEndpointImage = ({ title, ...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}), })) ?? [], + credits: convertCreditsToEndpointCredits(credits), }); diff --git a/src/collections/Pages/Pages.ts b/src/collections/Pages/Pages.ts index ff244b0..21a5990 100644 --- a/src/collections/Pages/Pages.ts +++ b/src/collections/Pages/Pages.ts @@ -3,8 +3,9 @@ import { breakBlock } from "../../blocks/breakBlock"; import { sectionBlock } from "../../blocks/sectionBlock"; import { transcriptBlock } from "../../blocks/transcriptBlock"; import { QuickFilters, publishStatusFilters } from "../../components/QuickFilters"; -import { CollectionGroups, Collections, PageType } from "../../constants"; +import { CollectionGroups, Collections } from "../../constants"; import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; +import { creditsField } from "../../fields/creditsField/creditsField"; import { imageField } from "../../fields/imageField/imageField"; import { rowField } from "../../fields/rowField/rowField"; import { slugField } from "../../fields/slugField/slugField"; @@ -13,15 +14,12 @@ import { translatedFields } from "../../fields/translatedFields/translatedFields import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping"; import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish"; -import { isDefined, isUndefined } from "../../utils/asserts"; import { createEditor } from "../../utils/editor"; import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; import { getBySlugEndpoint } from "./endpoints/getBySlugEndpoint"; const fields = { slug: "slug", - type: "type", - authors: "authors", thumbnail: "thumbnail", backgroundImage: "backgroundImage", translations: "translations", @@ -32,17 +30,11 @@ const fields = { subtitle: "subtitle", summary: "summary", content: "content", - transcribers: "transcribers", - translators: "translators", - proofreaders: "proofreaders", + credits: "credits", collectibles: "collectibles", folders: "folders", } as const satisfies Record; -const pageTypesWithAuthor = [PageType.Post]; -const pageTypesWithCollectibles = [PageType.Content]; -const pageTypesWithTranscribers = [PageType.Content]; - export const Pages = buildVersionedCollectionConfig({ slug: Collections.Pages, labels: { @@ -56,7 +48,6 @@ export const Pages = buildVersionedCollectionConfig({ fields.slug, fields.thumbnail, fields.backgroundImage, - fields.type, fields.tags, fields.translations, fields.folders, @@ -81,19 +72,7 @@ export const Pages = buildVersionedCollectionConfig({ }, endpoints: [getBySlugEndpoint], fields: [ - rowField([ - slugField({ name: fields.slug }), - { - name: fields.type, - type: "radio", - required: true, - defaultValue: PageType.Generic, - options: Object.entries(PageType).map(([_, value]) => ({ - label: value, - value: value, - })), - }, - ]), + slugField({ name: fields.slug }), rowField([ imageField({ name: fields.thumbnail, @@ -109,20 +88,7 @@ export const Pages = buildVersionedCollectionConfig({ }, }), ]), - rowField([ - tagsField({ name: fields.tags }), - { - name: fields.authors, - type: "relationship", - admin: { - condition: (_, siblingData) => pageTypesWithAuthor.includes(siblingData[fields.type]), - }, - relationTo: Collections.Recorders, - required: true, - minRows: 1, - hasMany: true, - }, - ]), + tagsField({ name: fields.tags }), translatedFields({ name: fields.translations, admin: { useAsTitle: fields.title, hasSourceLanguage: true }, @@ -156,66 +122,7 @@ export const Pages = buildVersionedCollectionConfig({ lists: true, }), }, - rowField([ - { - name: fields.transcribers, - type: "relationship", - relationTo: Collections.Recorders, - hasMany: true, - admin: { - condition: (data, siblingData) => { - if (!pageTypesWithTranscribers.includes(data[fields.type])) { - return false; - } - if (isUndefined(siblingData.language) || isUndefined(siblingData.sourceLanguage)) { - return false; - } - return siblingData.language === siblingData.sourceLanguage; - }, - }, - }, - { - name: fields.translators, - type: "relationship", - relationTo: Collections.Recorders, - hasMany: true, - hooks: { - beforeChange: [ - ({ siblingData }) => { - if (siblingData.language === siblingData.sourceLanguage) { - delete siblingData.translators; - } - }, - ], - }, - admin: { - condition: (_, siblingData) => { - if (isUndefined(siblingData.language) || isUndefined(siblingData.sourceLanguage)) { - return false; - } - return siblingData.language !== siblingData.sourceLanguage; - }, - }, - validate: (translators, { siblingData }) => { - if (isUndefined(siblingData.language) || isUndefined(siblingData.sourceLanguage)) { - return true; - } - if (siblingData.language === siblingData.sourceLanguage) { - return true; - } - if (isDefined(translators) && translators.length > 0) { - return true; - } - return "This field is required when the language is different from the source language."; - }, - }, - { - name: fields.proofreaders, - type: "relationship", - relationTo: Collections.Recorders, - hasMany: true, - }, - ]), + creditsField({ name: fields.credits }), ], }), rowField([ @@ -234,10 +141,6 @@ export const Pages = buildVersionedCollectionConfig({ name: fields.collectibles, hasMany: true, relationTo: Collections.Collectibles, - admin: { - condition: (_, siblingData) => - pageTypesWithCollectibles.includes(siblingData[fields.type]), - }, where: ({ id }) => ({ and: [ { "contents.content.value": { equals: id } }, diff --git a/src/collections/Pages/endpoints/getBySlugEndpoint.ts b/src/collections/Pages/endpoints/getBySlugEndpoint.ts index d085317..4b6c224 100644 --- a/src/collections/Pages/endpoints/getBySlugEndpoint.ts +++ b/src/collections/Pages/endpoints/getBySlugEndpoint.ts @@ -1,7 +1,6 @@ import { BreakBlockType, Collections, - PageType, RichTextContent, isBlockNodeBreakBlock, isBlockNodeSectionBlock, @@ -10,18 +9,13 @@ import { import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; import { EndpointPage, TableOfContentEntry } from "../../../sdk"; import { Page } from "../../../types/collections"; +import { isNotEmpty, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; import { - isNotEmpty, - isPayloadArrayType, - isPayloadType, - isValidPayloadImage, -} from "../../../utils/asserts"; -import { + convertCreditsToEndpointCredits, convertRTCToEndpointRTC, convertSourceToEndpointSource, convertTagsEndpointTagsGroups, } from "../../../utils/endpoints"; -import { convertRecorderToEndpointRecorder } from "../../Recorders/endpoints/getByUsername"; export const getBySlugEndpoint = createGetByEndpoint({ collection: Collections.Pages, @@ -34,31 +28,16 @@ export const convertPageToEndpointPage = ({ collectibles, folders, backgroundImage, - authors, slug, tags, thumbnail, - type, }: Page): EndpointPage => ({ slug, - type: type as PageType, ...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}), tagGroups: convertTagsEndpointTagsGroups(tags), - authors: isPayloadArrayType(authors) ? authors.map(convertRecorderToEndpointRecorder) : [], ...(isValidPayloadImage(backgroundImage) ? { backgroundImage } : {}), translations: translations.map( - ({ - content, - language, - sourceLanguage, - title, - pretitle, - subtitle, - proofreaders, - summary, - transcribers, - translators, - }) => ({ + ({ content, language, sourceLanguage, title, pretitle, subtitle, summary, credits }) => ({ language: isPayloadType(language) ? language.id : language, sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage, ...(isNotEmpty(pretitle) ? { pretitle } : {}), @@ -67,15 +46,7 @@ export const convertPageToEndpointPage = ({ ...(isNotEmpty(summary) ? { summary } : {}), content: convertRTCToEndpointRTC(content), toc: handleToc(content), - translators: isPayloadArrayType(translators) - ? translators.map(convertRecorderToEndpointRecorder) - : [], - transcribers: isPayloadArrayType(transcribers) - ? transcribers.map(convertRecorderToEndpointRecorder) - : [], - proofreaders: isPayloadArrayType(proofreaders) - ? proofreaders.map(convertRecorderToEndpointRecorder) - : [], + credits: convertCreditsToEndpointCredits(credits), }) ), parentPages: convertSourceToEndpointSource({ collectibles, folders }), diff --git a/src/collections/Videos/Videos.ts b/src/collections/Videos/Videos.ts index 19f11ef..dfe12e5 100644 --- a/src/collections/Videos/Videos.ts +++ b/src/collections/Videos/Videos.ts @@ -1,5 +1,6 @@ import { CollectionGroups, Collections } from "../../constants"; import { componentField } from "../../fields/componentField/componentField"; +import { creditsField } from "../../fields/creditsField/creditsField"; import { imageField } from "../../fields/imageField/imageField"; import { rowField } from "../../fields/rowField/rowField"; import { tagsField } from "../../fields/tagsField/tagsField"; @@ -27,6 +28,7 @@ const fields = { platformUrl: "url", platformLikes: "likes", platformDislikes: "dislikes", + credits: "credits", }; export const Videos = buildCollectionConfig({ @@ -78,6 +80,7 @@ export const Videos = buildCollectionConfig({ ], }), tagsField({ name: fields.tags }), + creditsField({ name: fields.credits }), componentField({ name: fields.platform, admin: { diff --git a/src/collections/Videos/endpoints/getByID.ts b/src/collections/Videos/endpoints/getByID.ts index d61ba6b..b5239e6 100644 --- a/src/collections/Videos/endpoints/getByID.ts +++ b/src/collections/Videos/endpoints/getByID.ts @@ -13,6 +13,7 @@ import { isValidPayloadMedia, } from "../../../utils/asserts"; import { + convertCreditsToEndpointCredits, convertRTCToEndpointRTC, convertTagsEndpointTagsGroups, getLanguageId, @@ -67,6 +68,7 @@ export const convertVideoToEndpointVideo = ({ thumbnail, platform, platformEnabled, + credits, }: Video & PayloadMedia): EndpointVideo => ({ url, tagGroups: convertTagsEndpointTagsGroups(tags), @@ -105,4 +107,5 @@ export const convertVideoToEndpointVideo = ({ return []; return { language: getLanguageId(language), url: subfile.url }; }) ?? [], + credits: convertCreditsToEndpointCredits(credits), }); diff --git a/src/constants.ts b/src/constants.ts index 0fd48d4..dee1ff9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -23,6 +23,7 @@ export enum Collections { VideosChannels = "videos-channels", MediaThumbnails = "media-thumbnails", Scans = "scans", + CreditsRole = "credits-roles", } export enum CollectionGroups { @@ -79,12 +80,6 @@ export enum CollectionStatus { Published = "published", } -export enum PageType { - Content = "Content", - Post = "Post", - Generic = "Generic", -} - /* RICH TEXT */ export type RichTextContent = { diff --git a/src/fields/creditsField/creditsField.ts b/src/fields/creditsField/creditsField.ts new file mode 100644 index 0000000..3106d41 --- /dev/null +++ b/src/fields/creditsField/creditsField.ts @@ -0,0 +1,43 @@ +import { array } from "payload/dist/fields/validations"; +import { ArrayField } from "payload/types"; +import { Collections } from "../../constants"; +import { Credits } from "../../types/collections"; +import { hasDuplicates, isDefined, isPayloadType, isUndefined } from "../../utils/asserts"; + +type Props = Omit; + +export const creditsField = ({ validate, admin, ...props }: Props): ArrayField => ({ + ...props, + type: "array", + admin: { initCollapsed: true, ...admin }, + interfaceName: "Credits", + validate: (value, options) => { + const defaultValidation = array(value, options); + if (defaultValidation !== true) return defaultValidation; + + if (isDefined(validate)) { + const propsValidation = validate(value, options); + if (propsValidation !== true) return propsValidation; + } + + const data = options.data[props.name] as Credits | undefined | null; + if (isUndefined(data)) return true; + + const roles = data.map((row) => (isPayloadType(row.role) ? row.role.id : row.role)); + if (hasDuplicates(roles)) { + return `There cannot be multiple ${props.name} with the same role`; + } + + return true; + }, + fields: [ + { name: "role", type: "relationship", relationTo: Collections.CreditsRole, required: true }, + { + name: "recorders", + type: "relationship", + relationTo: Collections.Recorders, + required: true, + hasMany: true, + }, + ], +}); diff --git a/src/fields/translatedFields/translatedFields.ts b/src/fields/translatedFields/translatedFields.ts index 36db56a..64149d1 100644 --- a/src/fields/translatedFields/translatedFields.ts +++ b/src/fields/translatedFields/translatedFields.ts @@ -19,7 +19,6 @@ type LocalizedFieldsProps = Omit & { admin?: ArrayField["admin"] & { useAsTitle?: string; hasSourceLanguage?: boolean; - hasCredits?: boolean; }; }; type ArrayData = { [fieldsNames.language]?: string }[] | number | undefined; @@ -40,92 +39,12 @@ const sourceLanguageField: Field = { admin: { allowCreate: false }, }; -const creditFields: Field = { - type: "row", - admin: { - condition: (_, siblingData) => - isDefined(siblingData[fieldsNames.language]) && - isDefined(siblingData[fieldsNames.sourceLanguage]), - }, - fields: [ - { - name: fieldsNames.transcribers, - label: "Transcribers", - type: "relationship", - relationTo: "recorders", - hasMany: true, - hooks: { - beforeChange: [ - ({ siblingData }) => { - if (siblingData[fieldsNames.language] !== siblingData[fieldsNames.sourceLanguage]) { - delete siblingData[fieldsNames.transcribers]; - } - }, - ], - }, - admin: { - condition: (_, siblingData) => siblingData.language === siblingData.sourceLanguage, - width: "0%", - }, - validate: (count, { siblingData }) => { - if (siblingData[fieldsNames.language] !== siblingData[fieldsNames.sourceLanguage]) { - return true; - } - if (isDefined(count) && count.length > 0) { - return true; - } - return `This field is required when the ${fieldsNames.language} \ - is the same as the ${fieldsNames.sourceLanguage}.`; - }, - }, - { - name: fieldsNames.translators, - label: "Translators", - type: "relationship", - relationTo: "recorders", - hasMany: true, - hooks: { - beforeChange: [ - ({ siblingData }) => { - if (siblingData[fieldsNames.language] === siblingData[fieldsNames.sourceLanguage]) { - delete siblingData[fieldsNames.translators]; - } - }, - ], - }, - admin: { - condition: (_, siblingData) => - siblingData[fieldsNames.language] !== siblingData[fieldsNames.sourceLanguage], - width: "0%", - }, - validate: (count, { siblingData }) => { - if (siblingData[fieldsNames.language] === siblingData[fieldsNames.sourceLanguage]) { - return true; - } - if (isDefined(count) && count.length > 0) { - return true; - } - return `This field is required when the ${fieldsNames.language} \ - is different from the ${fieldsNames.sourceLanguage}.`; - }, - }, - { - name: fieldsNames.proofreaders, - label: "Proofreaders", - type: "relationship", - relationTo: "recorders", - hasMany: true, - admin: { width: "0%" }, - }, - ], -}; - type FieldData = Record & { [fieldsNames.language]: string }; export const translatedFields = ({ fields, validate, - admin: { useAsTitle, hasSourceLanguage, hasCredits, ...admin } = {}, + admin: { useAsTitle, hasSourceLanguage, ...admin } = {}, ...otherProps }: LocalizedFieldsProps): ArrayField => ({ ...otherProps, @@ -172,6 +91,5 @@ export const translatedFields = ({ fields: [ rowField(hasSourceLanguage ? [languageField, sourceLanguageField] : [languageField]), ...fields, - ...(hasCredits ? [creditFields] : []), ], }); diff --git a/src/payload.config.ts b/src/payload.config.ts index 8961db4..2ec318b 100644 --- a/src/payload.config.ts +++ b/src/payload.config.ts @@ -7,6 +7,7 @@ import { sftpAdapter } from "payloadcms-sftp-storage"; import { Audios } from "./collections/Audios/Audios"; import { ChronologyEvents } from "./collections/ChronologyEvents/ChronologyEvents"; import { Collectibles } from "./collections/Collectibles/Collectibles"; +import { CreditsRoles } from "./collections/CreditsRoles/CreditsRoles"; import { Currencies } from "./collections/Currencies/Currencies"; import { Folders } from "./collections/Folders/Folders"; import { GenericContents } from "./collections/GenericContents/GenericContents"; @@ -68,6 +69,7 @@ export default buildConfig({ Tags, TagsGroups, + CreditsRoles, Recorders, Languages, Currencies, diff --git a/src/sdk.ts b/src/sdk.ts index 0993181..d2344fe 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -3,7 +3,6 @@ import { CollectibleNature, CollectiblePageOrders, Collections, - PageType, RichTextContent, } from "./constants"; import { Currency, Language } from "./types/collections"; @@ -187,11 +186,22 @@ export type EndpointTagsGroup = { tags: EndpointTag[]; }; +export type EndpointRole = { + icon: string; + translations: { + language: string; + name: string; + }[]; +}; + +export type EndpointCredit = { + role: EndpointRole; + recorders: EndpointRecorder[]; +}; + export type EndpointPage = { slug: string; - type: PageType; thumbnail?: PayloadImage; - authors: EndpointRecorder[]; tagGroups: EndpointTagsGroup[]; backgroundImage?: PayloadImage; translations: { @@ -202,9 +212,7 @@ export type EndpointPage = { sourceLanguage: string; summary?: RichTextContent; content: RichTextContent; - transcribers: EndpointRecorder[]; - translators: EndpointRecorder[]; - proofreaders: EndpointRecorder[]; + credits: EndpointCredit[]; toc: TableOfContentEntry[]; }[]; parentPages: EndpointSource[]; @@ -313,9 +321,7 @@ export type EndpointChronologyEvent = { title?: string; description?: RichTextContent; notes?: RichTextContent; - transcribers: EndpointRecorder[]; - translators: EndpointRecorder[]; - proofreaders: EndpointRecorder[]; + credits: EndpointCredit[]; }[]; }[]; }; @@ -347,6 +353,7 @@ export type EndpointMedia = { title: string; description?: RichTextContent; }[]; + credits: EndpointCredit[]; }; export type EndpointImage = EndpointMedia & { diff --git a/src/types/collections.ts b/src/types/collections.ts index 541b7a2..bea7f43 100644 --- a/src/types/collections.ts +++ b/src/types/collections.ts @@ -6,6 +6,18 @@ * and re-run `payload generate:types` to regenerate this file. */ +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "Credits". + */ +export type Credits = + | { + role: string | CreditsRole; + recorders: (string | Recorder)[]; + id?: string | null; + }[] + | null; + export interface Config { collections: { pages: Page; @@ -21,6 +33,7 @@ export interface Config { scans: Scan; tags: Tag; "tags-groups": TagsGroup; + "credits-roles": CreditsRole; recorders: Recorder; languages: Language; currencies: Currency; @@ -40,11 +53,9 @@ export interface Config { export interface Page { id: string; slug: string; - type: "Content" | "Post" | "Generic"; thumbnail?: string | Image | null; backgroundImage?: string | Image | null; tags?: (string | Tag)[] | null; - authors?: (string | Recorder)[] | null; translations: { language: string | Language; sourceLanguage: string | Language; @@ -81,9 +92,7 @@ export interface Page { }; [k: string]: unknown; }; - transcribers?: (string | Recorder)[] | null; - translators?: (string | Recorder)[] | null; - proofreaders?: (string | Recorder)[] | null; + credits?: Credits; id?: string | null; }[]; folders?: (string | Folder)[] | null; @@ -122,6 +131,7 @@ export interface Image { }[] | null; tags?: (string | Tag)[] | null; + credits?: Credits; updatedAt: string; createdAt: string; url?: string | null; @@ -190,6 +200,22 @@ export interface TagsGroup { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "credits-roles". + */ +export interface CreditsRole { + id: string; + slug: string; + icon?: string | null; + translations: { + language: string | Language; + name: string; + id?: string | null; + }[]; + updatedAt: string; + createdAt: string; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "recorders". @@ -321,9 +347,7 @@ export interface Collectible { | null; scansEnabled?: boolean | null; scans?: { - scanners: (string | Recorder)[]; - cleaners: (string | Recorder)[]; - typesetters?: (string | Recorder)[] | null; + credits?: Credits; coverEnabled?: boolean | null; cover?: { front?: string | Scan | null; @@ -554,6 +578,7 @@ export interface Audio { id?: string | null; }[]; tags?: (string | Tag)[] | null; + credits?: Credits; updatedAt: string; createdAt: string; url?: string | null; @@ -626,6 +651,7 @@ export interface Video { id?: string | null; }[]; tags?: (string | Tag)[] | null; + credits?: Credits; platformEnabled?: boolean | null; platform?: { channel: string | VideosChannel; @@ -716,9 +742,7 @@ export interface ChronologyEvent { }; [k: string]: unknown; } | null; - transcribers?: (string | Recorder)[] | null; - translators?: (string | Recorder)[] | null; - proofreaders?: (string | Recorder)[] | null; + credits?: Credits; id?: string | null; }[]; id?: string | null; diff --git a/src/utils/endpoints.ts b/src/utils/endpoints.ts index 5ef5a32..359cafa 100644 --- a/src/utils/endpoints.ts +++ b/src/utils/endpoints.ts @@ -2,6 +2,7 @@ import { convertAudioToEndpointAudio } from "../collections/Audios/endpoints/get import { convertCollectibleToEndpointCollectible } from "../collections/Collectibles/endpoints/getBySlugEndpoint"; import { convertFolderToEndpointFolder } from "../collections/Folders/endpoints/getBySlugEndpoint"; import { convertImageToEndpointImage } from "../collections/Images/endpoints/getByID"; +import { convertRecorderToEndpointRecorder } from "../collections/Recorders/endpoints/getByUsername"; import { convertVideoToEndpointVideo } from "../collections/Videos/endpoints/getByID"; import { RichTextBreakBlock, @@ -16,8 +17,24 @@ import { isUploadNodeImageNode, isUploadNodeVideoNode, } from "../constants"; -import { EndpointSource, EndpointTag, EndpointTagsGroup } from "../sdk"; -import { Audio, Collectible, Folder, Image, Language, Tag, Video } from "../types/collections"; +import { + EndpointCredit, + EndpointRole, + EndpointSource, + EndpointTag, + EndpointTagsGroup, +} from "../sdk"; +import { + Audio, + Collectible, + Credits, + CreditsRole, + Folder, + Image, + Language, + Tag, + Video, +} from "../types/collections"; import { isPayloadArrayType, isPayloadType, @@ -106,21 +123,21 @@ export const convertRTCToEndpointRTC = ( version: 1, }; if (isUploadNodeImageNode(node)) { - const value = node.value as Image | string; + const value = node.value as unknown as Image | string; if (!isPayloadType(value) || !isValidPayloadImage(value)) return errorUploadNode; return { ...node, value: convertImageToEndpointImage(value), }; } else if (isUploadNodeAudioNode(node)) { - const value = node.value as Audio | string; + const value = node.value as unknown as Audio | string; if (!isPayloadType(value) || !isValidPayloadMedia(value)) return errorUploadNode; return { ...node, value: convertAudioToEndpointAudio(value), }; } else if (isUploadNodeVideoNode(node)) { - const value = node.value as Video | string; + const value = node.value as unknown as Video | string; if (!isPayloadType(value) || !isValidPayloadMedia(value)) return errorUploadNode; return { ...node, @@ -175,3 +192,22 @@ export const getDomainFromUrl = (url: string): string => { export const getLanguageId = (language: string | Language) => typeof language === "object" ? language.id : language; + +const convertRoleToEndpointRole = ({ icon, translations }: CreditsRole): EndpointRole => ({ + icon: icon ?? "material-symbols:person", + translations: translations.map(({ language, name }) => ({ + language: getLanguageId(language), + name, + })), +}); + +export const convertCreditsToEndpointCredits = (credits?: Credits | null): EndpointCredit[] => + credits?.flatMap(({ recorders, role }) => { + if (!isPayloadArrayType(recorders) || !isPayloadType(role)) return []; + return [ + { + role: convertRoleToEndpointRole(role), + recorders: recorders.map(convertRecorderToEndpointRecorder), + }, + ]; + }) ?? [];