Simplified crediting

This commit is contained in:
DrMint 2024-04-08 23:12:19 +02:00
parent 40e54ea2a0
commit f46bdcaa03
19 changed files with 211 additions and 308 deletions

View File

@ -1,4 +1,5 @@
import { CollectionGroups, Collections } from "../../constants"; import { CollectionGroups, Collections } from "../../constants";
import { creditsField } from "../../fields/creditsField/creditsField";
import { imageField } from "../../fields/imageField/imageField"; import { imageField } from "../../fields/imageField/imageField";
import { rowField } from "../../fields/rowField/rowField"; import { rowField } from "../../fields/rowField/rowField";
import { tagsField } from "../../fields/tagsField/tagsField"; import { tagsField } from "../../fields/tagsField/tagsField";
@ -18,6 +19,7 @@ const fields = {
thumbnail: "thumbnail", thumbnail: "thumbnail",
duration: "duration", duration: "duration",
tags: "tags", tags: "tags",
credits: "credits",
}; };
export const Audios = buildCollectionConfig({ export const Audios = buildCollectionConfig({
@ -63,5 +65,6 @@ export const Audios = buildCollectionConfig({
], ],
}), }),
tagsField({ name: fields.tags }), tagsField({ name: fields.tags }),
creditsField({ name: fields.credits }),
], ],
}); });

View File

@ -5,6 +5,7 @@ import { Audio } from "../../../types/collections";
import { CollectionEndpoint } from "../../../types/payload"; import { CollectionEndpoint } from "../../../types/payload";
import { isNotEmpty, isValidPayloadImage, isValidPayloadMedia } from "../../../utils/asserts"; import { isNotEmpty, isValidPayloadImage, isValidPayloadMedia } from "../../../utils/asserts";
import { import {
convertCreditsToEndpointCredits,
convertRTCToEndpointRTC, convertRTCToEndpointRTC,
convertTagsEndpointTagsGroups, convertTagsEndpointTagsGroups,
getLanguageId, getLanguageId,
@ -57,6 +58,7 @@ export const convertAudioToEndpointAudio = ({
duration, duration,
id, id,
thumbnail, thumbnail,
credits,
}: Audio & PayloadMedia): EndpointAudio => ({ }: Audio & PayloadMedia): EndpointAudio => ({
url, url,
tagGroups: convertTagsEndpointTagsGroups(tags), tagGroups: convertTagsEndpointTagsGroups(tags),
@ -74,4 +76,5 @@ export const convertAudioToEndpointAudio = ({
})) ?? [], })) ?? [],
duration, duration,
...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}), ...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
credits: convertCreditsToEndpointCredits(credits),
}); });

View File

@ -5,6 +5,7 @@ import {
publishStatusFilters, publishStatusFilters,
} from "../../components/QuickFilters"; } from "../../components/QuickFilters";
import { CollectionGroups, Collections } from "../../constants"; import { CollectionGroups, Collections } from "../../constants";
import { creditsField } from "../../fields/creditsField/creditsField";
import { rowField } from "../../fields/rowField/rowField"; import { rowField } from "../../fields/rowField/rowField";
import { translatedFields } from "../../fields/translatedFields/translatedFields"; import { translatedFields } from "../../fields/translatedFields/translatedFields";
import { createEditor } from "../../utils/editor"; import { createEditor } from "../../utils/editor";
@ -28,6 +29,7 @@ const fields = {
eventsTranslationsTitle: "title", eventsTranslationsTitle: "title",
eventsTranslationsDescription: "description", eventsTranslationsDescription: "description",
eventsTranslationsNotes: "notes", eventsTranslationsNotes: "notes",
eventsCredits: "credits",
date: "date", date: "date",
dateYear: "year", dateYear: "year",
dateMonth: "month", dateMonth: "month",
@ -119,7 +121,6 @@ export const ChronologyEvents: CollectionConfig = buildVersionedCollectionConfig
admin: { admin: {
useAsTitle: fields.eventsTranslationsTitle, useAsTitle: fields.eventsTranslationsTitle,
hasSourceLanguage: true, hasSourceLanguage: true,
hasCredits: true,
}, },
fields: [ fields: [
{ {
@ -138,6 +139,7 @@ export const ChronologyEvents: CollectionConfig = buildVersionedCollectionConfig
type: "richText", type: "richText",
editor: createEditor({ inlines: true, lists: true, links: true }), editor: createEditor({ inlines: true, lists: true, links: true }),
}, },
creditsField({ name: fields.eventsCredits }),
], ],
}), }),
], ],

View File

@ -3,11 +3,10 @@ import { Collections } from "../../../constants";
import { EndpointChronologyEvent, EndpointSource } from "../../../sdk"; import { EndpointChronologyEvent, EndpointSource } from "../../../sdk";
import { ChronologyEvent, CollectibleBlock } from "../../../types/collections"; import { ChronologyEvent, CollectibleBlock } from "../../../types/collections";
import { CollectionEndpoint } from "../../../types/payload"; import { CollectionEndpoint } from "../../../types/payload";
import { isDefined, isNotEmpty, isPayloadArrayType, isPayloadType } from "../../../utils/asserts"; import { isDefined, isNotEmpty, isPayloadType } from "../../../utils/asserts";
import { getDomainFromUrl } from "../../../utils/endpoints"; import { convertCreditsToEndpointCredits, getDomainFromUrl } from "../../../utils/endpoints";
import { convertCollectibleToEndpointCollectible } from "../../Collectibles/endpoints/getBySlugEndpoint"; import { convertCollectibleToEndpointCollectible } from "../../Collectibles/endpoints/getBySlugEndpoint";
import { convertPageToEndpointPage } from "../../Pages/endpoints/getBySlugEndpoint"; import { convertPageToEndpointPage } from "../../Pages/endpoints/getBySlugEndpoint";
import { convertRecorderToEndpointRecorder } from "../../Recorders/endpoints/getByUsername";
export const getAllEndpoint: CollectionEndpoint = { export const getAllEndpoint: CollectionEndpoint = {
method: "get", method: "get",
@ -68,30 +67,13 @@ export const eventToEndpointEvent = ({
}, },
events: events.map<EndpointChronologyEvent["events"][number]>(({ sources, translations }) => ({ events: events.map<EndpointChronologyEvent["events"][number]>(({ sources, translations }) => ({
translations: translations.map( translations: translations.map(
({ ({ language, sourceLanguage, description, notes, title, credits }) => ({
language,
sourceLanguage,
description,
notes,
proofreaders,
title,
transcribers,
translators,
}) => ({
language: isPayloadType(language) ? language.id : language, language: isPayloadType(language) ? language.id : language,
sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage, sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage,
...(isNotEmpty(title) ? { title } : {}), ...(isNotEmpty(title) ? { title } : {}),
...(isNotEmpty(description) ? { description } : {}), ...(isNotEmpty(description) ? { description } : {}),
...(isNotEmpty(notes) ? { notes } : {}), ...(isNotEmpty(notes) ? { notes } : {}),
proofreaders: isPayloadArrayType(proofreaders) credits: convertCreditsToEndpointCredits(credits),
? proofreaders.map(convertRecorderToEndpointRecorder)
: [],
transcribers: isPayloadArrayType(transcribers)
? transcribers.map(convertRecorderToEndpointRecorder)
: [],
translators: isPayloadArrayType(translators)
? translators.map(convertRecorderToEndpointRecorder)
: [],
}) })
), ),
sources: handleSources(sources), sources: handleSources(sources),

View File

@ -6,10 +6,10 @@ import {
CollectiblePageOrders, CollectiblePageOrders,
CollectionGroups, CollectionGroups,
Collections, Collections,
PageType,
} from "../../constants"; } from "../../constants";
import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; import { backPropagationField } from "../../fields/backPropagationField/backPropagationField";
import { componentField } from "../../fields/componentField/componentField"; import { componentField } from "../../fields/componentField/componentField";
import { creditsField } from "../../fields/creditsField/creditsField";
import { imageField } from "../../fields/imageField/imageField"; import { imageField } from "../../fields/imageField/imageField";
import { rowField } from "../../fields/rowField/rowField"; import { rowField } from "../../fields/rowField/rowField";
import { slugField } from "../../fields/slugField/slugField"; import { slugField } from "../../fields/slugField/slugField";
@ -54,9 +54,7 @@ const fields = {
urlsUrl: "url", urlsUrl: "url",
scans: "scans", scans: "scans",
scansScanners: "scanners", scansCredits: "credits",
scansCleaners: "cleaners",
scansTypesetters: "typesetters",
scansCover: "cover", scansCover: "cover",
scansCoverFlapFront: "flapFront", scansCoverFlapFront: "flapFront",
@ -232,28 +230,7 @@ export const Collectibles = buildVersionedCollectionConfig({
componentField({ componentField({
name: fields.scans, name: fields.scans,
fields: [ fields: [
rowField([ creditsField({ name: fields.scansCredits }),
{
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,
},
]),
componentField({ componentField({
name: fields.scansCover, name: fields.scansCover,
fields: [ fields: [
@ -621,15 +598,6 @@ export const Collectibles = buildVersionedCollectionConfig({
allowCreate: false, allowCreate: false,
}, },
required: true, required: true,
filterOptions: ({ relationTo }) => {
switch (relationTo) {
case Collections.Pages:
return { type: { equals: PageType.Content } };
default:
return true;
}
},
}, },
{ {
name: "range", name: "range",

View File

@ -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 }],
}),
],
});

View File

@ -1,4 +1,5 @@
import { Collections } from "../../constants"; import { Collections } from "../../constants";
import { creditsField } from "../../fields/creditsField/creditsField";
import { tagsField } from "../../fields/tagsField/tagsField"; import { tagsField } from "../../fields/tagsField/tagsField";
import { translatedFields } from "../../fields/translatedFields/translatedFields"; import { translatedFields } from "../../fields/translatedFields/translatedFields";
import { createEditor } from "../../utils/editor"; import { createEditor } from "../../utils/editor";
@ -15,6 +16,7 @@ const fields = {
translationsTitle: "title", translationsTitle: "title",
translationsDescription: "description", translationsDescription: "description",
tags: "tags", tags: "tags",
credits: "credits",
} as const satisfies Record<string, string>; } as const satisfies Record<string, string>;
export const Images = buildImageCollectionConfig({ export const Images = buildImageCollectionConfig({
@ -52,5 +54,6 @@ export const Images = buildImageCollectionConfig({
], ],
}), }),
tagsField({ name: fields.tags }), tagsField({ name: fields.tags }),
creditsField({ name: fields.credits }),
], ],
}); });

View File

@ -5,6 +5,7 @@ import { Image } from "../../../types/collections";
import { CollectionEndpoint } from "../../../types/payload"; import { CollectionEndpoint } from "../../../types/payload";
import { isNotEmpty, isValidPayloadImage } from "../../../utils/asserts"; import { isNotEmpty, isValidPayloadImage } from "../../../utils/asserts";
import { import {
convertCreditsToEndpointCredits,
convertRTCToEndpointRTC, convertRTCToEndpointRTC,
convertTagsEndpointTagsGroups, convertTagsEndpointTagsGroups,
getLanguageId, getLanguageId,
@ -57,6 +58,7 @@ export const convertImageToEndpointImage = ({
filename, filename,
filesize, filesize,
id, id,
credits,
}: Image & PayloadImage): EndpointImage => ({ }: Image & PayloadImage): EndpointImage => ({
url, url,
width, width,
@ -74,4 +76,5 @@ export const convertImageToEndpointImage = ({
title, title,
...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}), ...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}),
})) ?? [], })) ?? [],
credits: convertCreditsToEndpointCredits(credits),
}); });

View File

@ -3,8 +3,9 @@ import { breakBlock } from "../../blocks/breakBlock";
import { sectionBlock } from "../../blocks/sectionBlock"; import { sectionBlock } from "../../blocks/sectionBlock";
import { transcriptBlock } from "../../blocks/transcriptBlock"; import { transcriptBlock } from "../../blocks/transcriptBlock";
import { QuickFilters, publishStatusFilters } from "../../components/QuickFilters"; import { QuickFilters, publishStatusFilters } from "../../components/QuickFilters";
import { CollectionGroups, Collections, PageType } from "../../constants"; import { CollectionGroups, Collections } from "../../constants";
import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; import { backPropagationField } from "../../fields/backPropagationField/backPropagationField";
import { creditsField } from "../../fields/creditsField/creditsField";
import { imageField } from "../../fields/imageField/imageField"; import { imageField } from "../../fields/imageField/imageField";
import { rowField } from "../../fields/rowField/rowField"; import { rowField } from "../../fields/rowField/rowField";
import { slugField } from "../../fields/slugField/slugField"; import { slugField } from "../../fields/slugField/slugField";
@ -13,15 +14,12 @@ import { translatedFields } from "../../fields/translatedFields/translatedFields
import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo";
import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping"; import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping";
import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish"; import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish";
import { isDefined, isUndefined } from "../../utils/asserts";
import { createEditor } from "../../utils/editor"; import { createEditor } from "../../utils/editor";
import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig";
import { getBySlugEndpoint } from "./endpoints/getBySlugEndpoint"; import { getBySlugEndpoint } from "./endpoints/getBySlugEndpoint";
const fields = { const fields = {
slug: "slug", slug: "slug",
type: "type",
authors: "authors",
thumbnail: "thumbnail", thumbnail: "thumbnail",
backgroundImage: "backgroundImage", backgroundImage: "backgroundImage",
translations: "translations", translations: "translations",
@ -32,17 +30,11 @@ const fields = {
subtitle: "subtitle", subtitle: "subtitle",
summary: "summary", summary: "summary",
content: "content", content: "content",
transcribers: "transcribers", credits: "credits",
translators: "translators",
proofreaders: "proofreaders",
collectibles: "collectibles", collectibles: "collectibles",
folders: "folders", folders: "folders",
} as const satisfies Record<string, string>; } as const satisfies Record<string, string>;
const pageTypesWithAuthor = [PageType.Post];
const pageTypesWithCollectibles = [PageType.Content];
const pageTypesWithTranscribers = [PageType.Content];
export const Pages = buildVersionedCollectionConfig({ export const Pages = buildVersionedCollectionConfig({
slug: Collections.Pages, slug: Collections.Pages,
labels: { labels: {
@ -56,7 +48,6 @@ export const Pages = buildVersionedCollectionConfig({
fields.slug, fields.slug,
fields.thumbnail, fields.thumbnail,
fields.backgroundImage, fields.backgroundImage,
fields.type,
fields.tags, fields.tags,
fields.translations, fields.translations,
fields.folders, fields.folders,
@ -81,19 +72,7 @@ export const Pages = buildVersionedCollectionConfig({
}, },
endpoints: [getBySlugEndpoint], endpoints: [getBySlugEndpoint],
fields: [ fields: [
rowField([ slugField({ name: fields.slug }),
slugField({ name: fields.slug }),
{
name: fields.type,
type: "radio",
required: true,
defaultValue: PageType.Generic,
options: Object.entries(PageType).map(([_, value]) => ({
label: value,
value: value,
})),
},
]),
rowField([ rowField([
imageField({ imageField({
name: fields.thumbnail, name: fields.thumbnail,
@ -109,20 +88,7 @@ export const Pages = buildVersionedCollectionConfig({
}, },
}), }),
]), ]),
rowField([ tagsField({ name: fields.tags }),
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,
},
]),
translatedFields({ translatedFields({
name: fields.translations, name: fields.translations,
admin: { useAsTitle: fields.title, hasSourceLanguage: true }, admin: { useAsTitle: fields.title, hasSourceLanguage: true },
@ -156,66 +122,7 @@ export const Pages = buildVersionedCollectionConfig({
lists: true, lists: true,
}), }),
}, },
rowField([ creditsField({ name: fields.credits }),
{
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,
},
]),
], ],
}), }),
rowField([ rowField([
@ -234,10 +141,6 @@ export const Pages = buildVersionedCollectionConfig({
name: fields.collectibles, name: fields.collectibles,
hasMany: true, hasMany: true,
relationTo: Collections.Collectibles, relationTo: Collections.Collectibles,
admin: {
condition: (_, siblingData) =>
pageTypesWithCollectibles.includes(siblingData[fields.type]),
},
where: ({ id }) => ({ where: ({ id }) => ({
and: [ and: [
{ "contents.content.value": { equals: id } }, { "contents.content.value": { equals: id } },

View File

@ -1,7 +1,6 @@
import { import {
BreakBlockType, BreakBlockType,
Collections, Collections,
PageType,
RichTextContent, RichTextContent,
isBlockNodeBreakBlock, isBlockNodeBreakBlock,
isBlockNodeSectionBlock, isBlockNodeSectionBlock,
@ -10,18 +9,13 @@ import {
import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint";
import { EndpointPage, TableOfContentEntry } from "../../../sdk"; import { EndpointPage, TableOfContentEntry } from "../../../sdk";
import { Page } from "../../../types/collections"; import { Page } from "../../../types/collections";
import { isNotEmpty, isPayloadType, isValidPayloadImage } from "../../../utils/asserts";
import { import {
isNotEmpty, convertCreditsToEndpointCredits,
isPayloadArrayType,
isPayloadType,
isValidPayloadImage,
} from "../../../utils/asserts";
import {
convertRTCToEndpointRTC, convertRTCToEndpointRTC,
convertSourceToEndpointSource, convertSourceToEndpointSource,
convertTagsEndpointTagsGroups, convertTagsEndpointTagsGroups,
} from "../../../utils/endpoints"; } from "../../../utils/endpoints";
import { convertRecorderToEndpointRecorder } from "../../Recorders/endpoints/getByUsername";
export const getBySlugEndpoint = createGetByEndpoint({ export const getBySlugEndpoint = createGetByEndpoint({
collection: Collections.Pages, collection: Collections.Pages,
@ -34,31 +28,16 @@ export const convertPageToEndpointPage = ({
collectibles, collectibles,
folders, folders,
backgroundImage, backgroundImage,
authors,
slug, slug,
tags, tags,
thumbnail, thumbnail,
type,
}: Page): EndpointPage => ({ }: Page): EndpointPage => ({
slug, slug,
type: type as PageType,
...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}), ...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
tagGroups: convertTagsEndpointTagsGroups(tags), tagGroups: convertTagsEndpointTagsGroups(tags),
authors: isPayloadArrayType(authors) ? authors.map(convertRecorderToEndpointRecorder) : [],
...(isValidPayloadImage(backgroundImage) ? { backgroundImage } : {}), ...(isValidPayloadImage(backgroundImage) ? { backgroundImage } : {}),
translations: translations.map( translations: translations.map(
({ ({ content, language, sourceLanguage, title, pretitle, subtitle, summary, credits }) => ({
content,
language,
sourceLanguage,
title,
pretitle,
subtitle,
proofreaders,
summary,
transcribers,
translators,
}) => ({
language: isPayloadType(language) ? language.id : language, language: isPayloadType(language) ? language.id : language,
sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage, sourceLanguage: isPayloadType(sourceLanguage) ? sourceLanguage.id : sourceLanguage,
...(isNotEmpty(pretitle) ? { pretitle } : {}), ...(isNotEmpty(pretitle) ? { pretitle } : {}),
@ -67,15 +46,7 @@ export const convertPageToEndpointPage = ({
...(isNotEmpty(summary) ? { summary } : {}), ...(isNotEmpty(summary) ? { summary } : {}),
content: convertRTCToEndpointRTC(content), content: convertRTCToEndpointRTC(content),
toc: handleToc(content), toc: handleToc(content),
translators: isPayloadArrayType(translators) credits: convertCreditsToEndpointCredits(credits),
? translators.map(convertRecorderToEndpointRecorder)
: [],
transcribers: isPayloadArrayType(transcribers)
? transcribers.map(convertRecorderToEndpointRecorder)
: [],
proofreaders: isPayloadArrayType(proofreaders)
? proofreaders.map(convertRecorderToEndpointRecorder)
: [],
}) })
), ),
parentPages: convertSourceToEndpointSource({ collectibles, folders }), parentPages: convertSourceToEndpointSource({ collectibles, folders }),

View File

@ -1,5 +1,6 @@
import { CollectionGroups, Collections } from "../../constants"; import { CollectionGroups, Collections } from "../../constants";
import { componentField } from "../../fields/componentField/componentField"; import { componentField } from "../../fields/componentField/componentField";
import { creditsField } from "../../fields/creditsField/creditsField";
import { imageField } from "../../fields/imageField/imageField"; import { imageField } from "../../fields/imageField/imageField";
import { rowField } from "../../fields/rowField/rowField"; import { rowField } from "../../fields/rowField/rowField";
import { tagsField } from "../../fields/tagsField/tagsField"; import { tagsField } from "../../fields/tagsField/tagsField";
@ -27,6 +28,7 @@ const fields = {
platformUrl: "url", platformUrl: "url",
platformLikes: "likes", platformLikes: "likes",
platformDislikes: "dislikes", platformDislikes: "dislikes",
credits: "credits",
}; };
export const Videos = buildCollectionConfig({ export const Videos = buildCollectionConfig({
@ -78,6 +80,7 @@ export const Videos = buildCollectionConfig({
], ],
}), }),
tagsField({ name: fields.tags }), tagsField({ name: fields.tags }),
creditsField({ name: fields.credits }),
componentField({ componentField({
name: fields.platform, name: fields.platform,
admin: { admin: {

View File

@ -13,6 +13,7 @@ import {
isValidPayloadMedia, isValidPayloadMedia,
} from "../../../utils/asserts"; } from "../../../utils/asserts";
import { import {
convertCreditsToEndpointCredits,
convertRTCToEndpointRTC, convertRTCToEndpointRTC,
convertTagsEndpointTagsGroups, convertTagsEndpointTagsGroups,
getLanguageId, getLanguageId,
@ -67,6 +68,7 @@ export const convertVideoToEndpointVideo = ({
thumbnail, thumbnail,
platform, platform,
platformEnabled, platformEnabled,
credits,
}: Video & PayloadMedia): EndpointVideo => ({ }: Video & PayloadMedia): EndpointVideo => ({
url, url,
tagGroups: convertTagsEndpointTagsGroups(tags), tagGroups: convertTagsEndpointTagsGroups(tags),
@ -105,4 +107,5 @@ export const convertVideoToEndpointVideo = ({
return []; return [];
return { language: getLanguageId(language), url: subfile.url }; return { language: getLanguageId(language), url: subfile.url };
}) ?? [], }) ?? [],
credits: convertCreditsToEndpointCredits(credits),
}); });

View File

@ -23,6 +23,7 @@ export enum Collections {
VideosChannels = "videos-channels", VideosChannels = "videos-channels",
MediaThumbnails = "media-thumbnails", MediaThumbnails = "media-thumbnails",
Scans = "scans", Scans = "scans",
CreditsRole = "credits-roles",
} }
export enum CollectionGroups { export enum CollectionGroups {
@ -79,12 +80,6 @@ export enum CollectionStatus {
Published = "published", Published = "published",
} }
export enum PageType {
Content = "Content",
Post = "Post",
Generic = "Generic",
}
/* RICH TEXT */ /* RICH TEXT */
export type RichTextContent = { export type RichTextContent = {

View File

@ -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<ArrayField, "type" | "fields">;
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,
},
],
});

View File

@ -19,7 +19,6 @@ type LocalizedFieldsProps = Omit<ArrayField, "type" | "admin"> & {
admin?: ArrayField["admin"] & { admin?: ArrayField["admin"] & {
useAsTitle?: string; useAsTitle?: string;
hasSourceLanguage?: boolean; hasSourceLanguage?: boolean;
hasCredits?: boolean;
}; };
}; };
type ArrayData = { [fieldsNames.language]?: string }[] | number | undefined; type ArrayData = { [fieldsNames.language]?: string }[] | number | undefined;
@ -40,92 +39,12 @@ const sourceLanguageField: Field = {
admin: { allowCreate: false }, 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<string, any> & { [fieldsNames.language]: string }; type FieldData = Record<string, any> & { [fieldsNames.language]: string };
export const translatedFields = ({ export const translatedFields = ({
fields, fields,
validate, validate,
admin: { useAsTitle, hasSourceLanguage, hasCredits, ...admin } = {}, admin: { useAsTitle, hasSourceLanguage, ...admin } = {},
...otherProps ...otherProps
}: LocalizedFieldsProps): ArrayField => ({ }: LocalizedFieldsProps): ArrayField => ({
...otherProps, ...otherProps,
@ -172,6 +91,5 @@ export const translatedFields = ({
fields: [ fields: [
rowField(hasSourceLanguage ? [languageField, sourceLanguageField] : [languageField]), rowField(hasSourceLanguage ? [languageField, sourceLanguageField] : [languageField]),
...fields, ...fields,
...(hasCredits ? [creditFields] : []),
], ],
}); });

View File

@ -7,6 +7,7 @@ import { sftpAdapter } from "payloadcms-sftp-storage";
import { Audios } from "./collections/Audios/Audios"; import { Audios } from "./collections/Audios/Audios";
import { ChronologyEvents } from "./collections/ChronologyEvents/ChronologyEvents"; import { ChronologyEvents } from "./collections/ChronologyEvents/ChronologyEvents";
import { Collectibles } from "./collections/Collectibles/Collectibles"; import { Collectibles } from "./collections/Collectibles/Collectibles";
import { CreditsRoles } from "./collections/CreditsRoles/CreditsRoles";
import { Currencies } from "./collections/Currencies/Currencies"; import { Currencies } from "./collections/Currencies/Currencies";
import { Folders } from "./collections/Folders/Folders"; import { Folders } from "./collections/Folders/Folders";
import { GenericContents } from "./collections/GenericContents/GenericContents"; import { GenericContents } from "./collections/GenericContents/GenericContents";
@ -68,6 +69,7 @@ export default buildConfig({
Tags, Tags,
TagsGroups, TagsGroups,
CreditsRoles,
Recorders, Recorders,
Languages, Languages,
Currencies, Currencies,

View File

@ -3,7 +3,6 @@ import {
CollectibleNature, CollectibleNature,
CollectiblePageOrders, CollectiblePageOrders,
Collections, Collections,
PageType,
RichTextContent, RichTextContent,
} from "./constants"; } from "./constants";
import { Currency, Language } from "./types/collections"; import { Currency, Language } from "./types/collections";
@ -187,11 +186,22 @@ export type EndpointTagsGroup = {
tags: EndpointTag[]; tags: EndpointTag[];
}; };
export type EndpointRole = {
icon: string;
translations: {
language: string;
name: string;
}[];
};
export type EndpointCredit = {
role: EndpointRole;
recorders: EndpointRecorder[];
};
export type EndpointPage = { export type EndpointPage = {
slug: string; slug: string;
type: PageType;
thumbnail?: PayloadImage; thumbnail?: PayloadImage;
authors: EndpointRecorder[];
tagGroups: EndpointTagsGroup[]; tagGroups: EndpointTagsGroup[];
backgroundImage?: PayloadImage; backgroundImage?: PayloadImage;
translations: { translations: {
@ -202,9 +212,7 @@ export type EndpointPage = {
sourceLanguage: string; sourceLanguage: string;
summary?: RichTextContent; summary?: RichTextContent;
content: RichTextContent; content: RichTextContent;
transcribers: EndpointRecorder[]; credits: EndpointCredit[];
translators: EndpointRecorder[];
proofreaders: EndpointRecorder[];
toc: TableOfContentEntry[]; toc: TableOfContentEntry[];
}[]; }[];
parentPages: EndpointSource[]; parentPages: EndpointSource[];
@ -313,9 +321,7 @@ export type EndpointChronologyEvent = {
title?: string; title?: string;
description?: RichTextContent; description?: RichTextContent;
notes?: RichTextContent; notes?: RichTextContent;
transcribers: EndpointRecorder[]; credits: EndpointCredit[];
translators: EndpointRecorder[];
proofreaders: EndpointRecorder[];
}[]; }[];
}[]; }[];
}; };
@ -347,6 +353,7 @@ export type EndpointMedia = {
title: string; title: string;
description?: RichTextContent; description?: RichTextContent;
}[]; }[];
credits: EndpointCredit[];
}; };
export type EndpointImage = EndpointMedia & { export type EndpointImage = EndpointMedia & {

View File

@ -6,6 +6,18 @@
* and re-run `payload generate:types` to regenerate this file. * 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 { export interface Config {
collections: { collections: {
pages: Page; pages: Page;
@ -21,6 +33,7 @@ export interface Config {
scans: Scan; scans: Scan;
tags: Tag; tags: Tag;
"tags-groups": TagsGroup; "tags-groups": TagsGroup;
"credits-roles": CreditsRole;
recorders: Recorder; recorders: Recorder;
languages: Language; languages: Language;
currencies: Currency; currencies: Currency;
@ -40,11 +53,9 @@ export interface Config {
export interface Page { export interface Page {
id: string; id: string;
slug: string; slug: string;
type: "Content" | "Post" | "Generic";
thumbnail?: string | Image | null; thumbnail?: string | Image | null;
backgroundImage?: string | Image | null; backgroundImage?: string | Image | null;
tags?: (string | Tag)[] | null; tags?: (string | Tag)[] | null;
authors?: (string | Recorder)[] | null;
translations: { translations: {
language: string | Language; language: string | Language;
sourceLanguage: string | Language; sourceLanguage: string | Language;
@ -81,9 +92,7 @@ export interface Page {
}; };
[k: string]: unknown; [k: string]: unknown;
}; };
transcribers?: (string | Recorder)[] | null; credits?: Credits;
translators?: (string | Recorder)[] | null;
proofreaders?: (string | Recorder)[] | null;
id?: string | null; id?: string | null;
}[]; }[];
folders?: (string | Folder)[] | null; folders?: (string | Folder)[] | null;
@ -122,6 +131,7 @@ export interface Image {
}[] }[]
| null; | null;
tags?: (string | Tag)[] | null; tags?: (string | Tag)[] | null;
credits?: Credits;
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
url?: string | null; url?: string | null;
@ -190,6 +200,22 @@ export interface TagsGroup {
updatedAt: string; updatedAt: string;
createdAt: 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 * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "recorders". * via the `definition` "recorders".
@ -321,9 +347,7 @@ export interface Collectible {
| null; | null;
scansEnabled?: boolean | null; scansEnabled?: boolean | null;
scans?: { scans?: {
scanners: (string | Recorder)[]; credits?: Credits;
cleaners: (string | Recorder)[];
typesetters?: (string | Recorder)[] | null;
coverEnabled?: boolean | null; coverEnabled?: boolean | null;
cover?: { cover?: {
front?: string | Scan | null; front?: string | Scan | null;
@ -554,6 +578,7 @@ export interface Audio {
id?: string | null; id?: string | null;
}[]; }[];
tags?: (string | Tag)[] | null; tags?: (string | Tag)[] | null;
credits?: Credits;
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
url?: string | null; url?: string | null;
@ -626,6 +651,7 @@ export interface Video {
id?: string | null; id?: string | null;
}[]; }[];
tags?: (string | Tag)[] | null; tags?: (string | Tag)[] | null;
credits?: Credits;
platformEnabled?: boolean | null; platformEnabled?: boolean | null;
platform?: { platform?: {
channel: string | VideosChannel; channel: string | VideosChannel;
@ -716,9 +742,7 @@ export interface ChronologyEvent {
}; };
[k: string]: unknown; [k: string]: unknown;
} | null; } | null;
transcribers?: (string | Recorder)[] | null; credits?: Credits;
translators?: (string | Recorder)[] | null;
proofreaders?: (string | Recorder)[] | null;
id?: string | null; id?: string | null;
}[]; }[];
id?: string | null; id?: string | null;

View File

@ -2,6 +2,7 @@ import { convertAudioToEndpointAudio } from "../collections/Audios/endpoints/get
import { convertCollectibleToEndpointCollectible } from "../collections/Collectibles/endpoints/getBySlugEndpoint"; import { convertCollectibleToEndpointCollectible } from "../collections/Collectibles/endpoints/getBySlugEndpoint";
import { convertFolderToEndpointFolder } from "../collections/Folders/endpoints/getBySlugEndpoint"; import { convertFolderToEndpointFolder } from "../collections/Folders/endpoints/getBySlugEndpoint";
import { convertImageToEndpointImage } from "../collections/Images/endpoints/getByID"; import { convertImageToEndpointImage } from "../collections/Images/endpoints/getByID";
import { convertRecorderToEndpointRecorder } from "../collections/Recorders/endpoints/getByUsername";
import { convertVideoToEndpointVideo } from "../collections/Videos/endpoints/getByID"; import { convertVideoToEndpointVideo } from "../collections/Videos/endpoints/getByID";
import { import {
RichTextBreakBlock, RichTextBreakBlock,
@ -16,8 +17,24 @@ import {
isUploadNodeImageNode, isUploadNodeImageNode,
isUploadNodeVideoNode, isUploadNodeVideoNode,
} from "../constants"; } from "../constants";
import { EndpointSource, EndpointTag, EndpointTagsGroup } from "../sdk"; import {
import { Audio, Collectible, Folder, Image, Language, Tag, Video } from "../types/collections"; EndpointCredit,
EndpointRole,
EndpointSource,
EndpointTag,
EndpointTagsGroup,
} from "../sdk";
import {
Audio,
Collectible,
Credits,
CreditsRole,
Folder,
Image,
Language,
Tag,
Video,
} from "../types/collections";
import { import {
isPayloadArrayType, isPayloadArrayType,
isPayloadType, isPayloadType,
@ -106,21 +123,21 @@ export const convertRTCToEndpointRTC = (
version: 1, version: 1,
}; };
if (isUploadNodeImageNode(node)) { 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; if (!isPayloadType(value) || !isValidPayloadImage(value)) return errorUploadNode;
return { return {
...node, ...node,
value: convertImageToEndpointImage(value), value: convertImageToEndpointImage(value),
}; };
} else if (isUploadNodeAudioNode(node)) { } 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; if (!isPayloadType(value) || !isValidPayloadMedia(value)) return errorUploadNode;
return { return {
...node, ...node,
value: convertAudioToEndpointAudio(value), value: convertAudioToEndpointAudio(value),
}; };
} else if (isUploadNodeVideoNode(node)) { } 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; if (!isPayloadType(value) || !isValidPayloadMedia(value)) return errorUploadNode;
return { return {
...node, ...node,
@ -175,3 +192,22 @@ export const getDomainFromUrl = (url: string): string => {
export const getLanguageId = (language: string | Language) => export const getLanguageId = (language: string | Language) =>
typeof language === "object" ? language.id : 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<EndpointCredit>(({ recorders, role }) => {
if (!isPayloadArrayType(recorders) || !isPayloadType(role)) return [];
return [
{
role: convertRoleToEndpointRole(role),
recorders: recorders.map(convertRecorderToEndpointRecorder),
},
];
}) ?? [];