Removed library and keys collections
This commit is contained in:
		
							parent
							
								
									e9fbb0a3b7
								
							
						
					
					
						commit
						b06918b346
					
				| @ -11,9 +11,9 @@ export const spacerBlock: Block = { | ||||
|       type: "radio", | ||||
|       defaultValue: "medium", | ||||
|       required: true, | ||||
|       options: Object.entries(SpacerSizes).map(([value, label]) => ({ | ||||
|         label, | ||||
|         value, | ||||
|       options: Object.entries(SpacerSizes).map(([_, value]) => ({ | ||||
|         label: value, | ||||
|         value: value, | ||||
|       })), | ||||
|     }, | ||||
|   ], | ||||
|  | ||||
| @ -21,6 +21,7 @@ import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish"; | ||||
| import { createEditor } from "../../utils/editor"; | ||||
| import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; | ||||
| import { RowLabel } from "./components/RowLabel"; | ||||
| import { getBySlugEndpoint } from "./endpoints/getBySlugEndpoint"; | ||||
| 
 | ||||
| const fields = { | ||||
|   status: "_status", | ||||
| @ -131,6 +132,7 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|       ]), | ||||
|     }, | ||||
|   }, | ||||
|   endpoints: [getBySlugEndpoint], | ||||
|   fields: [ | ||||
|     { | ||||
|       type: "tabs", | ||||
| @ -152,9 +154,9 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|                 type: "radio", | ||||
|                 required: true, | ||||
|                 defaultValue: CollectibleNature.Physical, | ||||
|                 options: Object.entries(CollectibleNature).map(([value, label]) => ({ | ||||
|                   label, | ||||
|                   value, | ||||
|                 options: Object.entries(CollectibleNature).map(([_, value]) => ({ | ||||
|                   label: value, | ||||
|                   value: value, | ||||
|                 })), | ||||
|               }, | ||||
|               { | ||||
| @ -207,7 +209,8 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|               fields: [ | ||||
|                 imageField({ | ||||
|                   name: fields.galleryImage, | ||||
|                   relationTo: Collections.LibraryItemsGallery, | ||||
|                   required: true, | ||||
|                   relationTo: Collections.Images, | ||||
|                 }), | ||||
|               ], | ||||
|             }, | ||||
| @ -242,43 +245,43 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverInsideFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverInsideBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverInsideFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverInsideFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                     ]), | ||||
|                   ], | ||||
| @ -295,47 +298,47 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                     ]), | ||||
|                   ], | ||||
| @ -352,47 +355,47 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                       }), | ||||
|                     ]), | ||||
|                   ], | ||||
| @ -418,7 +421,7 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|                       }, | ||||
|                       imageField({ | ||||
|                         name: fields.scansPagesImage, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         relationTo: Collections.Images, | ||||
|                         required: true, | ||||
|                       }), | ||||
|                     ]), | ||||
| @ -534,9 +537,9 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|                   { | ||||
|                     name: fields.pageInfoBindingType, | ||||
|                     type: "radio", | ||||
|                     options: Object.entries(CollectibleBindingTypes).map(([value, label]) => ({ | ||||
|                       label, | ||||
|                       value, | ||||
|                     options: Object.entries(CollectibleBindingTypes).map(([_, value]) => ({ | ||||
|                       label: value, | ||||
|                       value: value, | ||||
|                     })), | ||||
|                     admin: { | ||||
|                       condition: ({ nature }) => nature === CollectibleNature.Physical, | ||||
| @ -545,9 +548,9 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|                   { | ||||
|                     name: fields.pageInfoPageOrder, | ||||
|                     type: "radio", | ||||
|                     options: Object.entries(CollectiblePageOrders).map(([value, label]) => ({ | ||||
|                       label, | ||||
|                       value, | ||||
|                     options: Object.entries(CollectiblePageOrders).map(([_, value]) => ({ | ||||
|                       label: value, | ||||
|                       value: value, | ||||
|                     })), | ||||
|                   }, | ||||
|                 ]), | ||||
| @ -683,6 +686,7 @@ export const Collectibles = buildVersionedCollectionConfig({ | ||||
|                             { | ||||
|                               name: "note", | ||||
|                               type: "richText", | ||||
|                               required: true, | ||||
|                               editor: createEditor({ inlines: true, lists: true, links: true }), | ||||
|                             }, | ||||
|                           ], | ||||
|  | ||||
							
								
								
									
										124
									
								
								src/collections/Collectibles/endpoints/getBySlugEndpoint.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/collections/Collectibles/endpoints/getBySlugEndpoint.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | ||||
| import { CollectibleNature, CollectionStatus, Collections } from "../../../constants"; | ||||
| import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; | ||||
| import { EndpointCollectible, EndpointCollectiblePreview } from "../../../sdk"; | ||||
| import { Collectible } from "../../../types/collections"; | ||||
| import { isPayloadArrayType, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; | ||||
| import { convertTagsToGroups } from "../../../utils/endpoints"; | ||||
| 
 | ||||
| export const getBySlugEndpoint = createGetByEndpoint( | ||||
|   Collections.Collectibles, | ||||
|   "slug", | ||||
|   (collectible: Collectible): EndpointCollectible => { | ||||
|     const { nature, urls, subitems, gallery, contents } = collectible; | ||||
|     return { | ||||
|       ...convertCollectibleToPreview(collectible), | ||||
|       contents: handleContents(contents), | ||||
|       gallery: | ||||
|         gallery | ||||
|           ?.map(({ image }) => image) | ||||
|           .flatMap((image) => (isValidPayloadImage(image) ? [image] : [])) ?? [], | ||||
|       nature: nature === "Physical" ? CollectibleNature.Physical : CollectibleNature.Digital, | ||||
|       parentPages: [], // TODO: todo
 | ||||
|       subitems: isPayloadArrayType(subitems) ? subitems.map(convertCollectibleToPreview) : [], | ||||
|       urls: urls?.map(({ url }) => ({ url, label: getLabelFromUrl(url) })) ?? [], | ||||
|     }; | ||||
|   } | ||||
| ); | ||||
| 
 | ||||
| export const handleContents = ( | ||||
|   contents: Collectible["contents"] | ||||
| ): EndpointCollectible["contents"] => { | ||||
|   if (!contents) return []; | ||||
| 
 | ||||
|   return contents.flatMap(({ content, range: rangeArray }) => { | ||||
|     const handleRange = (): EndpointCollectible["contents"][number]["range"] => { | ||||
|       const range = rangeArray?.[0]; | ||||
|       switch (range?.blockType) { | ||||
|         case "other": { | ||||
|           const { translations, blockType } = range; | ||||
|           return { | ||||
|             type: blockType, | ||||
|             translations: | ||||
|               translations?.map(({ language, note }) => ({ | ||||
|                 language: isPayloadType(language) ? language.id : language, | ||||
|                 note, | ||||
|               })) ?? [], | ||||
|           }; | ||||
|         } | ||||
| 
 | ||||
|         case "pageRange": { | ||||
|           const { blockType, end, start } = range; | ||||
|           return { type: blockType, end, start }; | ||||
|         } | ||||
| 
 | ||||
|         case "timeRange": { | ||||
|           const { blockType, end, start } = range; | ||||
|           return { type: blockType, end, start }; | ||||
|         } | ||||
| 
 | ||||
|         default: | ||||
|           return undefined; | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     const handleContent = (): EndpointCollectible["contents"][number]["content"] | undefined => { | ||||
|       switch (content.relationTo) { | ||||
|         case "generic-contents": | ||||
|           return isPayloadType(content.value) | ||||
|             ? { relationTo: "generic-contents", value: content.value } | ||||
|             : undefined; | ||||
| 
 | ||||
|         case "pages": | ||||
|           return isPayloadType(content.value) | ||||
|             ? { relationTo: "pages", value: content.value } | ||||
|             : undefined; | ||||
| 
 | ||||
|         default: | ||||
|           return undefined; | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     const newContent = handleContent(); | ||||
|     const range = handleRange(); | ||||
| 
 | ||||
|     if (!newContent) return []; | ||||
|     return [{ content: newContent, range }]; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| export const convertCollectibleToPreview = ({ | ||||
|   slug, | ||||
|   _status, | ||||
|   thumbnail, | ||||
|   translations, | ||||
|   releaseDate, | ||||
|   languages, | ||||
|   tags, | ||||
| }: Collectible): EndpointCollectiblePreview => { | ||||
|   return { | ||||
|     slug, | ||||
|     languages: | ||||
|       languages?.map((language) => (isPayloadType(language) ? language.id : language)) ?? [], | ||||
|     status: _status === "draft" ? CollectionStatus.Draft : CollectionStatus.Published, | ||||
|     ...(releaseDate ? { releaseDate } : {}), | ||||
|     ...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}), | ||||
|     tagGroups: convertTagsToGroups(tags), | ||||
|     translations: | ||||
|       translations?.map(({ language, title, description, pretitle, subtitle }) => ({ | ||||
|         language: isPayloadType(language) ? language.id : language, | ||||
|         title, | ||||
|         ...(pretitle ? { pretitle } : {}), | ||||
|         ...(subtitle ? { subtitle } : {}), | ||||
|         ...(description ? { description } : {}), | ||||
|       })) ?? [], | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const getLabelFromUrl = (url: string): string => { | ||||
|   const urlObject = new URL(url); | ||||
|   let domain = urlObject.hostname; | ||||
|   if (domain.startsWith("www.")) { | ||||
|     domain = domain.substring("www.".length); | ||||
|   } | ||||
|   return domain; | ||||
| }; | ||||
| @ -1,46 +0,0 @@ | ||||
| import { CollectionGroups, Collections, FileTypes } from "../../constants"; | ||||
| import { File } from "../../types/collections"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { | ||||
|   beforeValidateCheckFileExists, | ||||
|   generatePathForFile, | ||||
| } from "./hooks/beforeValidateCheckFileExists"; | ||||
| 
 | ||||
| const fields = { | ||||
|   filename: "filename", | ||||
|   type: "type", | ||||
| } as const satisfies Record<string, string>; | ||||
| 
 | ||||
| export const Files = buildCollectionConfig({ | ||||
|   slug: Collections.Files, | ||||
|   labels: { | ||||
|     singular: "File", | ||||
|     plural: "Files", | ||||
|   }, | ||||
|   defaultSort: fields.filename, | ||||
|   admin: { | ||||
|     useAsTitle: fields.filename, | ||||
|     disableDuplicate: true, | ||||
|     group: CollectionGroups.Media, | ||||
|     preview: (doc) => { | ||||
|       const { filename, type } = doc as unknown as File; | ||||
|       return generatePathForFile(type, filename); | ||||
|     }, | ||||
|   }, | ||||
|   hooks: { | ||||
|     beforeValidate: [beforeValidateCheckFileExists], | ||||
|   }, | ||||
|   fields: [ | ||||
|     { | ||||
|       name: fields.filename, | ||||
|       required: true, | ||||
|       type: "text", | ||||
|     }, | ||||
|     { | ||||
|       name: fields.type, | ||||
|       type: "select", | ||||
|       required: true, | ||||
|       options: Object.entries(FileTypes).map(([value, label]) => ({ label, value })), | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| @ -1,45 +0,0 @@ | ||||
| import { CollectionBeforeValidateHook } from "payload/types"; | ||||
| import { FileTypes } from "../../../constants"; | ||||
| import { File } from "../../../types/collections"; | ||||
| import { isUndefined } from "../../../utils/asserts"; | ||||
| 
 | ||||
| const reshareSubFolderFromType: Record<keyof typeof FileTypes, string> = { | ||||
|   ContentAudio: "/contents/audios", | ||||
|   ContentVideo: "/contents/videos", | ||||
|   LibraryScans: "/library/scans", | ||||
|   LibrarySoundtracks: "/library/tracks", | ||||
| }; | ||||
| 
 | ||||
| const expectedMimeFromType = { | ||||
|   ContentAudio: "audio/", | ||||
|   ContentVideo: "video/", | ||||
|   LibraryScans: "application/zip", | ||||
|   LibrarySoundtracks: "audio/", | ||||
| }; | ||||
| 
 | ||||
| export const generatePathForFile = (type: keyof typeof FileTypes, filename: string) => | ||||
|   `https://resha.re/accords${reshareSubFolderFromType[type]}/${filename}`; | ||||
| 
 | ||||
| export const beforeValidateCheckFileExists: CollectionBeforeValidateHook<File> = async ({ | ||||
|   data, | ||||
| }) => { | ||||
|   if (isUndefined(data)) throw new Error("The data is undefined"); | ||||
|   const { type, filename } = data; | ||||
|   if (isUndefined(filename)) throw new Error("Filename is undefined"); | ||||
|   if (isUndefined(type)) throw new Error("Filename is undefined"); | ||||
| 
 | ||||
|   const url = generatePathForFile(type, filename); | ||||
| 
 | ||||
|   const result = await fetch(url, { method: "head" }); | ||||
| 
 | ||||
|   if (result.status !== 200) { | ||||
|     throw new Error(`Unable to locate the file at the following address: ${url}`); | ||||
|   } | ||||
| 
 | ||||
|   const contentType = result.headers.get("content-type"); | ||||
|   if (isUndefined(contentType) || !contentType.startsWith(expectedMimeFromType[type])) { | ||||
|     throw new Error( | ||||
|       `Wrong MIME type found: ${contentType}. The expected MIME type was ${expectedMimeFromType[type]}` | ||||
|     ); | ||||
|   } | ||||
| }; | ||||
| @ -35,7 +35,7 @@ export const getBySlugEndpoint = createGetByEndpoint( | ||||
|             return []; | ||||
|           } | ||||
|           switch (relationTo) { | ||||
|             case "library-items": | ||||
|             case "collectibles": | ||||
|               return [{ relationTo, value }]; | ||||
|             case "pages": | ||||
|               return [{ relationTo, value }]; | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { QuickFilters } from "../../components/QuickFilters"; | ||||
| import { CollectionGroups, Collections, LanguageCodes } from "../../constants"; | ||||
| import { QuickFilters, languageBasedFilters } from "../../components/QuickFilters"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; | ||||
| @ -31,12 +31,7 @@ export const GenericContents: CollectionConfig = buildCollectionConfig({ | ||||
|         () => | ||||
|           QuickFilters({ | ||||
|             slug: Collections.GenericContents, | ||||
|             filterGroups: [ | ||||
|               Object.entries(LanguageCodes).map(([key, value]) => ({ | ||||
|                 label: `∅ ${value}`, | ||||
|                 filter: { where: { "translations.language": { not_equals: key } } }, | ||||
|               })), | ||||
|             ], | ||||
|             filterGroups: [languageBasedFilters("translations.language")], | ||||
|           }), | ||||
|       ], | ||||
|     }, | ||||
| @ -52,7 +47,6 @@ export const GenericContents: CollectionConfig = buildCollectionConfig({ | ||||
|       name: fields.translations, | ||||
|       minRows: 1, | ||||
|       required: true, | ||||
|       interfaceName: "CategoryTranslations", | ||||
|       admin: { | ||||
|         useAsTitle: fields.translationsName, | ||||
|       }, | ||||
|  | ||||
| @ -1,118 +0,0 @@ | ||||
| import payload from "payload"; | ||||
| import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { QuickFilters } from "../../components/QuickFilters"; | ||||
| import { CollectionGroups, Collections, KeysTypes, LanguageCodes } from "../../constants"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; | ||||
| import { Key } from "../../types/collections"; | ||||
| import { isDefined, isUndefined } from "../../utils/asserts"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { getAllEndpoint } from "./endpoints/getAllEndpoint"; | ||||
| import { importFromStrapi } from "./endpoints/importFromStrapi"; | ||||
| 
 | ||||
| const fields = { | ||||
|   name: "name", | ||||
|   type: "type", | ||||
|   translations: "translations", | ||||
|   translationsName: "name", | ||||
|   translationsShort: "short", | ||||
| } as const satisfies Record<string, string>; | ||||
| 
 | ||||
| const keysTypesWithShort: (keyof typeof KeysTypes)[] = ["Categories", "GamePlatforms"]; | ||||
| 
 | ||||
| // TODO: Maybe make sure there is at least one English translation as a fallback
 | ||||
| 
 | ||||
| export const Keys = buildCollectionConfig({ | ||||
|   slug: Collections.Keys, | ||||
|   labels: { | ||||
|     singular: "Key", | ||||
|     plural: "Keys", | ||||
|   }, | ||||
|   defaultSort: fields.name, | ||||
|   admin: { | ||||
|     useAsTitle: fields.name, | ||||
|     defaultColumns: [fields.name, fields.type, fields.translations], | ||||
|     group: CollectionGroups.Meta, | ||||
|     components: { | ||||
|       BeforeListTable: [ | ||||
|         () => | ||||
|           QuickFilters({ | ||||
|             slug: Collections.Keys, | ||||
|             filterGroups: [ | ||||
|               Object.entries(KeysTypes).map(([key, value]) => ({ | ||||
|                 label: value, | ||||
|                 filter: { where: { type: { equals: key } } }, | ||||
|               })), | ||||
|               Object.entries(LanguageCodes).map(([key, value]) => ({ | ||||
|                 label: `∅ ${value}`, | ||||
|                 filter: { where: { "translations.language": { not_equals: key } } }, | ||||
|               })), | ||||
|             ], | ||||
|           }), | ||||
|       ], | ||||
|     }, | ||||
|     hooks: { | ||||
|       beforeDuplicate: beforeDuplicateAddCopyTo(fields.name), | ||||
|     }, | ||||
|   }, | ||||
|   access: { | ||||
|     create: mustBeAdmin, | ||||
|     delete: mustBeAdmin, | ||||
|   }, | ||||
|   hooks: { | ||||
|     beforeValidate: [ | ||||
|       async ({ data }) => { | ||||
|         if (isUndefined(data)) return; | ||||
|         const { name, type } = data; | ||||
|         const result = await payload.find({ | ||||
|           collection: Collections.Keys, | ||||
|           where: { name: { equals: name }, type: { equals: type } }, | ||||
|         }); | ||||
|         if (result.docs.length > 0) { | ||||
|           throw new Error(`A Key of type "${type}" already exists with the name "${name}"`); | ||||
|         } | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   endpoints: [importFromStrapi, getAllEndpoint], | ||||
|   timestamps: false, | ||||
|   versions: false, | ||||
|   fields: [ | ||||
|     { | ||||
|       name: fields.name, | ||||
|       type: "text", | ||||
|       required: true, | ||||
|     }, | ||||
|     { | ||||
|       name: fields.type, | ||||
|       type: "select", | ||||
|       required: true, | ||||
|       options: Object.entries(KeysTypes).map(([value, label]) => ({ label, value })), | ||||
|     }, | ||||
|     translatedFields({ | ||||
|       name: fields.translations, | ||||
|       interfaceName: "CategoryTranslations", | ||||
|       admin: { | ||||
|         useAsTitle: fields.translationsName, | ||||
|       }, | ||||
|       fields: [ | ||||
|         rowField([ | ||||
|           { | ||||
|             name: fields.translationsName, | ||||
|             type: "text", | ||||
|             required: true, | ||||
|           }, | ||||
|           { | ||||
|             name: fields.translationsShort, | ||||
|             type: "text", | ||||
|             admin: { | ||||
|               condition: (data: Partial<Key>) => | ||||
|                 isDefined(data.type) && keysTypesWithShort.includes(data.type), | ||||
|             }, | ||||
|           }, | ||||
|         ]), | ||||
|       ], | ||||
|     }), | ||||
|   ], | ||||
| }); | ||||
| @ -1,42 +0,0 @@ | ||||
| import payload from "payload"; | ||||
| import { Collections } from "../../../constants"; | ||||
| import { EndpointKey } from "../../../sdk"; | ||||
| import { Key } from "../../../types/collections"; | ||||
| import { CollectionEndpoint } from "../../../types/payload"; | ||||
| import { isPayloadType } from "../../../utils/asserts"; | ||||
| 
 | ||||
| export const getAllEndpoint: CollectionEndpoint = { | ||||
|   method: "get", | ||||
|   path: "/all", | ||||
|   handler: async (req, res) => { | ||||
|     if (!req.user) { | ||||
|       return res.status(403).send({ | ||||
|         errors: [ | ||||
|           { | ||||
|             message: "You are not allowed to perform this action.", | ||||
|           }, | ||||
|         ], | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     const keys: Key[] = ( | ||||
|       await payload.find({ | ||||
|         collection: Collections.Keys, | ||||
|         sort: "id", | ||||
|         pagination: false, | ||||
|       }) | ||||
|     ).docs; | ||||
| 
 | ||||
|     const result: EndpointKey[] = keys.map(({ translations, ...others }) => ({ | ||||
|       ...others, | ||||
|       translations: | ||||
|         translations?.map(({ language, name, short }) => ({ | ||||
|           language: isPayloadType(language) ? language.id : language, | ||||
|           name, | ||||
|           short: short ?? name, | ||||
|         })) ?? [], | ||||
|     })); | ||||
| 
 | ||||
|     res.status(200).json(result); | ||||
|   }, | ||||
| }; | ||||
| @ -1,365 +0,0 @@ | ||||
| import payload from "payload"; | ||||
| import { Collections } from "../../../constants"; | ||||
| import { | ||||
|   getAllStrapiEntries, | ||||
|   importStrapiEntries, | ||||
| } from "../../../endpoints/createStrapiImportEndpoint"; | ||||
| import { Key } from "../../../types/collections"; | ||||
| import { CollectionEndpoint } from "../../../types/payload"; | ||||
| import { StrapiLanguage } from "../../../types/strapi"; | ||||
| import { isDefined, isUndefined } from "../../../utils/asserts"; | ||||
| import { formatToCamelCase } from "../../../utils/string"; | ||||
| 
 | ||||
| const importStrapiWordings: typeof importStrapiEntries = async ({ strapi: strapiParams, user }) => { | ||||
|   const rawEntries = await getAllStrapiEntries(strapiParams.collection, strapiParams.params); | ||||
| 
 | ||||
|   const { ui_language, createdAt, updatedAt, ...otherKeys } = rawEntries[0].attributes; | ||||
| 
 | ||||
|   const errors: string[] = []; | ||||
| 
 | ||||
|   await Promise.all( | ||||
|     Object.keys(otherKeys).map(async (key) => { | ||||
|       try { | ||||
|         await payload.create({ | ||||
|           collection: Collections.Keys, | ||||
|           data: { | ||||
|             name: formatToCamelCase(key), | ||||
|             type: "Wordings", | ||||
|             translations: rawEntries | ||||
|               .map((entry) => ({ | ||||
|                 language: entry.attributes.ui_language.data.attributes.code, | ||||
|                 name: entry.attributes[key], | ||||
|               })) | ||||
|               .filter(({ name }) => isDefined(name) && name !== ""), | ||||
|           }, | ||||
|           user, | ||||
|         }); | ||||
|       } catch (e) { | ||||
|         console.warn(e); | ||||
|         if (typeof e === "object" && isDefined(e) && "name" in e) { | ||||
|           errors.push(`${e.name} with ${key}`); | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
|   ); | ||||
| 
 | ||||
|   return { count: Object.keys(otherKeys).length, errors }; | ||||
| }; | ||||
| 
 | ||||
| export const importFromStrapi: CollectionEndpoint = { | ||||
|   method: "post", | ||||
|   path: "/strapi", | ||||
|   handler: async (req, res) => { | ||||
|     if (!req.user) { | ||||
|       return res.status(403).send({ | ||||
|         errors: [ | ||||
|           { | ||||
|             message: "You are not allowed to perform this action.", | ||||
|           }, | ||||
|         ], | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     type StrapiCategories = { | ||||
|       slug: string; | ||||
|       titles: { title?: string; short?: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: categoriesCount, errors: categoriesErrors } = | ||||
|       await importStrapiEntries<StrapiCategories>({ | ||||
|         strapi: { | ||||
|           collection: "categories", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "Categories", | ||||
|             translations: titles.map(({ title, short, language }) => { | ||||
|               if (isUndefined(language.data)) | ||||
|                 throw new Error("A language is required for a Keys title translation"); | ||||
|               if (isUndefined(title)) | ||||
|                 throw new Error("A title is required for a Keys title translation"); | ||||
|               return { | ||||
|                 name: title, | ||||
|                 short, | ||||
|                 language: language.data.attributes.code, | ||||
|               }; | ||||
|             }), | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
| 
 | ||||
|     type StrapiContentType = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: contentTypesCount, errors: contentTypesErrors } = | ||||
|       await importStrapiEntries<StrapiContentType>({ | ||||
|         strapi: { | ||||
|           collection: "content-types", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "Contents", | ||||
|             translations: titles.map(({ title, language }) => { | ||||
|               if (isUndefined(language.data)) | ||||
|                 throw new Error("A language is required for a Keys title translation"); | ||||
|               return { | ||||
|                 name: title, | ||||
|                 language: language.data.attributes.code, | ||||
|               }; | ||||
|             }), | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
| 
 | ||||
|     type StrapiGamePlatform = { | ||||
|       slug: string; | ||||
|       titles: { title?: string; short?: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: gamePlatformsCount, errors: gamePlatformsErrors } = | ||||
|       await importStrapiEntries<StrapiGamePlatform>({ | ||||
|         strapi: { | ||||
|           collection: "game-platforms", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "GamePlatforms", | ||||
|             translations: titles.map(({ title, short, language }) => { | ||||
|               if (isUndefined(language.data)) | ||||
|                 throw new Error("A language is required for a Keys title translation"); | ||||
|               if (isUndefined(title)) | ||||
|                 throw new Error("A title is required for a Keys title translation"); | ||||
|               return { | ||||
|                 name: title, | ||||
|                 short, | ||||
|                 language: language.data.attributes.code, | ||||
|               }; | ||||
|             }), | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
| 
 | ||||
|     type StrapiMetadataTypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryCount, errors: libraryErrors } = | ||||
|       await importStrapiEntries<StrapiMetadataTypes>({ | ||||
|         strapi: { | ||||
|           collection: "metadata-types", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "Library", | ||||
|             translations: titles.map(({ title, language }) => { | ||||
|               if (isUndefined(language.data)) | ||||
|                 throw new Error("A language is required for a Keys title translation"); | ||||
|               return { | ||||
|                 name: title, | ||||
|                 language: language.data.attributes.code, | ||||
|               }; | ||||
|             }), | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
| 
 | ||||
|     type StrapiAudioSubtypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryAudioCount, errors: libraryAudioErrors } = | ||||
|       await importStrapiEntries<StrapiAudioSubtypes>({ | ||||
|         strapi: { | ||||
|           collection: "audio-subtypes", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "LibraryAudio", | ||||
|             translations: titles.map(({ title, language }) => { | ||||
|               if (isUndefined(language.data)) | ||||
|                 throw new Error("A language is required for a Keys title translation"); | ||||
|               return { | ||||
|                 name: title, | ||||
|                 language: language.data.attributes.code, | ||||
|               }; | ||||
|             }), | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
| 
 | ||||
|     type StrapiGroupSubtypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryGroupCount, errors: libraryGroupErrors } = | ||||
|       await importStrapiEntries<StrapiGroupSubtypes>({ | ||||
|         strapi: { | ||||
|           collection: "group-subtypes", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "LibraryGroup", | ||||
|             translations: titles.map(({ title, language }) => { | ||||
|               if (isUndefined(language.data)) | ||||
|                 throw new Error("A language is required for a Keys title translation"); | ||||
|               return { | ||||
|                 name: title, | ||||
|                 language: language.data.attributes.code, | ||||
|               }; | ||||
|             }), | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
| 
 | ||||
|     type StrapiTextualSubtypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryTextualCount, errors: libraryTextualErrors } = | ||||
|       await importStrapiEntries<StrapiTextualSubtypes>({ | ||||
|         strapi: { | ||||
|           collection: "textual-subtypes", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "LibraryTextual", | ||||
|             translations: titles.map(({ title, language }) => { | ||||
|               if (isUndefined(language.data)) | ||||
|                 throw new Error("A language is required for a Keys title translation"); | ||||
|               return { | ||||
|                 name: title, | ||||
|                 language: language.data.attributes.code, | ||||
|               }; | ||||
|             }), | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
| 
 | ||||
|     type StrapiVideoSubtypes = { | ||||
|       slug: string; | ||||
|       titles: { title: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: libraryVideoCount, errors: libraryVideoErrors } = | ||||
|       await importStrapiEntries<StrapiVideoSubtypes>({ | ||||
|         strapi: { | ||||
|           collection: "video-subtypes", | ||||
|           params: { populate: { titles: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, titles }) => ({ | ||||
|             name: slug, | ||||
|             type: "LibraryVideo", | ||||
|             translations: titles.map(({ title, language }) => { | ||||
|               if (isUndefined(language.data)) | ||||
|                 throw new Error("A language is required for a Keys title translation"); | ||||
|               return { | ||||
|                 name: title, | ||||
|                 language: language.data.attributes.code, | ||||
|               }; | ||||
|             }), | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
| 
 | ||||
|     type StrapiWeaponTypes = { | ||||
|       slug: string; | ||||
|       translations: { name?: string; language: StrapiLanguage }[]; | ||||
|     }; | ||||
| 
 | ||||
|     const { count: weaponsCount, errors: weaponsErrors } = | ||||
|       await importStrapiEntries<StrapiWeaponTypes>({ | ||||
|         strapi: { | ||||
|           collection: "weapon-story-types", | ||||
|           params: { populate: { translations: { populate: "language" } } }, | ||||
|         }, | ||||
|         payload: { | ||||
|           collection: Collections.Keys, | ||||
|           convert: ({ slug, translations }) => ({ | ||||
|             name: slug, | ||||
|             type: "Weapons", | ||||
|             translations: translations.map(({ name, language }) => { | ||||
|               if (isUndefined(language.data)) | ||||
|                 throw new Error("A language is required for a Keys title translation"); | ||||
|               if (isUndefined(name)) | ||||
|                 throw new Error("A name is required for a Keys title translation"); | ||||
|               return { | ||||
|                 name, | ||||
|                 language: language.data.attributes.code, | ||||
|               }; | ||||
|             }), | ||||
|           }), | ||||
|         }, | ||||
|         user: req.user, | ||||
|       }); | ||||
| 
 | ||||
|     const { count: wordingsCount, errors: wordingsErrors } = await importStrapiWordings<Key>({ | ||||
|       strapi: { collection: "website-interfaces", params: { populate: "ui_language" } }, | ||||
|       payload: { collection: Collections.Keys, convert: (strapiObject) => strapiObject }, | ||||
|       user: req.user, | ||||
|     }); | ||||
| 
 | ||||
|     res.status(200).json({ | ||||
|       message: `${ | ||||
|         categoriesCount + | ||||
|         contentTypesCount + | ||||
|         gamePlatformsCount + | ||||
|         libraryCount + | ||||
|         libraryAudioCount + | ||||
|         libraryGroupCount + | ||||
|         libraryTextualCount + | ||||
|         libraryVideoCount + | ||||
|         weaponsCount + | ||||
|         wordingsCount | ||||
|       } entries have been added successfully.`,
 | ||||
|       errors: { | ||||
|         categoriesErrors, | ||||
|         contentTypesErrors, | ||||
|         gamePlatformsErrors, | ||||
|         libraryErrors, | ||||
|         libraryAudioErrors, | ||||
|         libraryGroupErrors, | ||||
|         libraryTextualErrors, | ||||
|         libraryVideoErrors, | ||||
|         weaponsErrors, | ||||
|         wordingsErrors, | ||||
|       }, | ||||
|     }); | ||||
|   }, | ||||
| }; | ||||
| @ -1,790 +0,0 @@ | ||||
| import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types"; | ||||
| import { | ||||
|   CollectibleBindingTypes, | ||||
|   CollectiblePageOrders, | ||||
|   CollectionGroups, | ||||
|   Collections, | ||||
|   FileTypes, | ||||
|   KeysTypes, | ||||
|   LibraryItemsTypes, | ||||
|   PageType, | ||||
| } from "../../constants"; | ||||
| import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; | ||||
| import { componentField } from "../../fields/componentField/componentField"; | ||||
| import { fileField } from "../../fields/fileField/fileField"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| import { keysField } from "../../fields/keysField/keysField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { slugField } from "../../fields/slugField/slugField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; | ||||
| import { beforeDuplicatePiping } from "../../hooks/beforeDuplicatePiping"; | ||||
| import { beforeDuplicateUnpublish } from "../../hooks/beforeDuplicateUnpublish"; | ||||
| import { LibraryItem } from "../../types/collections"; | ||||
| import { isDefined } from "../../utils/asserts"; | ||||
| import { createEditor } from "../../utils/editor"; | ||||
| import { buildVersionedCollectionConfig } from "../../utils/versionedCollectionConfig"; | ||||
| import { RowLabel } from "./components/RowLabel"; | ||||
| 
 | ||||
| const fields = { | ||||
|   status: "_status", | ||||
|   itemType: "itemType", | ||||
|   language: "language", | ||||
| 
 | ||||
|   slug: "slug", | ||||
|   thumbnail: "thumbnail", | ||||
| 
 | ||||
|   pretitle: "pretitle", | ||||
|   title: "title", | ||||
|   subtitle: "subtitle", | ||||
| 
 | ||||
|   translations: "translations", | ||||
|   translationsDescription: "description", | ||||
| 
 | ||||
|   digital: "digital", | ||||
| 
 | ||||
|   size: "size", | ||||
|   width: "width", | ||||
|   height: "height", | ||||
|   thickness: "thickness", | ||||
| 
 | ||||
|   price: "price", | ||||
|   priceAmount: "amount", | ||||
|   priceCurrency: "currency", | ||||
|   releaseDate: "releaseDate", | ||||
| 
 | ||||
|   gallery: "gallery", | ||||
|   galleryImage: "image", | ||||
| 
 | ||||
|   urls: "urls", | ||||
|   urlsUrl: "url", | ||||
| 
 | ||||
|   categories: "categories", | ||||
| 
 | ||||
|   textual: "textual", | ||||
|   textualSubtype: "subtype", | ||||
|   textualBindingType: "bindingType", | ||||
|   textualPageCount: "pageCount", | ||||
|   textualPageOrder: "pageOrder", | ||||
| 
 | ||||
|   audio: "audio", | ||||
|   audioSubtype: "audioSubtype", | ||||
|   audioTracks: "tracks", | ||||
|   audioTracksFile: "file", | ||||
|   audioTracksTitle: "title", | ||||
| 
 | ||||
|   video: "video", | ||||
|   videoSubtype: "subtype", | ||||
| 
 | ||||
|   game: "game", | ||||
|   gameDemo: "demo", | ||||
|   gamePlatform: "platform", | ||||
|   gameAudioLanguages: "audioLanguages", | ||||
|   gameSubtitleLanguages: "subtitleLanguages", | ||||
|   gameInterfacesLanguages: "interfacesLanguages", | ||||
| 
 | ||||
|   scans: "scans", | ||||
|   scansScanners: "scanners", | ||||
|   scansCleaners: "cleaners", | ||||
|   scansTypesetters: "typesetters", | ||||
| 
 | ||||
|   scansCover: "cover", | ||||
|   scansCoverFlapFront: "flapFront", | ||||
|   scansCoverFront: "front", | ||||
|   scansCoverSpine: "spine", | ||||
|   scansCoverBack: "back", | ||||
|   scansCoverFlapBack: "flapBack", | ||||
|   scansCoverInsideFlapFront: "insideFlapFront", | ||||
|   scansCoverInsideFront: "insideFront", | ||||
|   scansCoverInsideBack: "insideBack", | ||||
|   scansCoverInsideFlapBack: "insideFlapBack", | ||||
| 
 | ||||
|   scansDustjacket: "dustjacket", | ||||
|   scansDustjacketFlapFront: "flapFront", | ||||
|   scansDustjacketFront: "front", | ||||
|   scansDustjacketSpine: "spine", | ||||
|   scansDustjacketBack: "back", | ||||
|   scansDustjacketFlapBack: "flapBack", | ||||
|   scansDustjacketInsideFlapFront: "insideFlapFront", | ||||
|   scansDustjacketInsideFront: "insideFront", | ||||
|   scansDustjacketInsideSpine: "insideSpine", | ||||
|   scansDustjacketInsideBack: "insideBack", | ||||
|   scansDustjacketInsideFlapBack: "insideFlapBack", | ||||
| 
 | ||||
|   scansObi: "obi", | ||||
|   scansObiFlapFront: "flapFront", | ||||
|   scansObiFront: "front", | ||||
|   scansObiSpine: "spine", | ||||
|   scansObiBack: "back", | ||||
|   scansObiFlapBack: "flapBack", | ||||
|   scansObiInsideFlapFront: "insideFlapFront", | ||||
|   scansObiInsideFront: "insideFront", | ||||
|   scansObiInsideSpine: "insideSpine", | ||||
|   scansObiInsideBack: "insideBack", | ||||
|   scansObiInsideFlapBack: "insideFlapBack", | ||||
| 
 | ||||
|   scansPages: "pages", | ||||
|   scansPagesPage: "page", | ||||
|   scansPagesImage: "image", | ||||
| 
 | ||||
|   scanArchiveFile: "archiveFile", | ||||
| 
 | ||||
|   contents: "contents", | ||||
|   contentsContent: "content", | ||||
|   contentsPageStart: "pageStart", | ||||
|   contentsPageEnd: "pageEnd", | ||||
|   contentsTimeStart: "timeStart", | ||||
|   contentsTimeEnd: "timeEnd", | ||||
|   contentsNote: "note", | ||||
| 
 | ||||
|   parentFolders: "parentFolders", | ||||
|   parentItems: "parentItems", | ||||
|   subitems: "subitems", | ||||
| } as const satisfies Record<string, string>; | ||||
| 
 | ||||
| export const LibraryItems = buildVersionedCollectionConfig({ | ||||
|   slug: Collections.LibraryItems, | ||||
|   labels: { | ||||
|     singular: "Library Item", | ||||
|     plural: "Library Items", | ||||
|   }, | ||||
|   defaultSort: fields.slug, | ||||
|   admin: { | ||||
|     useAsTitle: fields.slug, | ||||
|     description: | ||||
|       "A comprehensive list of all Yokoverse’s side materials (books, novellas, artbooks, \ | ||||
|          stage plays, manga, drama CDs, and comics).", | ||||
|     defaultColumns: [fields.thumbnail, fields.slug, fields.status], | ||||
|     group: CollectionGroups.Collections, | ||||
|     hooks: { | ||||
|       beforeDuplicate: beforeDuplicatePiping([ | ||||
|         beforeDuplicateUnpublish, | ||||
|         beforeDuplicateAddCopyTo(fields.slug), | ||||
|       ]), | ||||
|     }, | ||||
|   }, | ||||
|   fields: [ | ||||
|     rowField([ | ||||
|       { | ||||
|         name: fields.itemType, | ||||
|         type: "radio", | ||||
|         options: Object.entries(LibraryItemsTypes).map(([value, label]) => ({ | ||||
|           label, | ||||
|           value, | ||||
|         })), | ||||
|         admin: { | ||||
|           layout: "horizontal", | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         name: fields.language, | ||||
|         type: "relationship", | ||||
|         relationTo: Collections.Languages, | ||||
|         required: true, | ||||
|         admin: { | ||||
|           allowCreate: false, | ||||
|           description: | ||||
|             "This item sole or primary language (most notably, the language used on the cover)", | ||||
|         }, | ||||
|       }, | ||||
|     ]), | ||||
|     { | ||||
|       type: "tabs", | ||||
|       admin: { | ||||
|         condition: ({ itemType }) => isDefined(itemType), | ||||
|       }, | ||||
|       tabs: [ | ||||
|         { | ||||
|           label: "Overview", | ||||
|           fields: [ | ||||
|             rowField([ | ||||
|               slugField({ | ||||
|                 name: fields.slug, | ||||
|               }), | ||||
|               imageField({ | ||||
|                 name: fields.thumbnail, | ||||
|                 relationTo: Collections.LibraryItemsThumbnails, | ||||
|               }), | ||||
|             ]), | ||||
|             rowField([ | ||||
|               { name: fields.pretitle, type: "text" }, | ||||
|               { name: fields.title, type: "text", required: true }, | ||||
|               { name: fields.subtitle, type: "text" }, | ||||
|             ]), | ||||
|             { | ||||
|               name: fields.digital, | ||||
|               type: "checkbox", | ||||
|               required: true, | ||||
|               defaultValue: false, | ||||
|               admin: { | ||||
|                 description: | ||||
|                   "The item is the digital version of another item, or the item is sold only digitally.", | ||||
|               }, | ||||
|             }, | ||||
|           ], | ||||
|         }, | ||||
|         { | ||||
|           label: "Images", | ||||
|           fields: [ | ||||
|             { | ||||
|               name: fields.gallery, | ||||
|               type: "array", | ||||
|               admin: { | ||||
|                 description: | ||||
|                   "Additional images of the item (unboxing, on shelf, promotional images...)", | ||||
|               }, | ||||
|               labels: { singular: "Image", plural: "Images" }, | ||||
|               fields: [ | ||||
|                 imageField({ | ||||
|                   name: fields.galleryImage, | ||||
|                   relationTo: Collections.LibraryItemsGallery, | ||||
|                 }), | ||||
|               ], | ||||
|             }, | ||||
|             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, | ||||
|                   }, | ||||
|                 ]), | ||||
|                 componentField({ | ||||
|                   name: fields.scansCover, | ||||
|                   fields: [ | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverInsideFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverInsideBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverInsideFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansCoverInsideFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                     ]), | ||||
|                   ], | ||||
|                 }), | ||||
|                 componentField({ | ||||
|                   name: fields.scansDustjacket, | ||||
|                   label: "Dust Jacket", | ||||
|                   admin: { | ||||
|                     description: | ||||
|                       "The dust jacket of a book is the detachable outer cover with folded \ | ||||
|                   flaps that hold it to the front and back book covers", | ||||
|                   }, | ||||
|                   fields: [ | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansDustjacketInsideFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                     ]), | ||||
|                   ], | ||||
|                 }), | ||||
|                 componentField({ | ||||
|                   name: fields.scansObi, | ||||
|                   label: "Obi", | ||||
|                   admin: { | ||||
|                     description: | ||||
|                       "An obi is a strip of paper looped around a book or other product. \ | ||||
|                     it typically add marketing claims, or other relevant information about the product.", | ||||
|                   }, | ||||
|                   fields: [ | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideSpine, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                     ]), | ||||
|                     rowField([ | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideFlapFront, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                       imageField({ | ||||
|                         name: fields.scansObiInsideFlapBack, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                       }), | ||||
|                     ]), | ||||
|                   ], | ||||
|                 }), | ||||
|                 { | ||||
|                   name: fields.scansPages, | ||||
|                   type: "array", | ||||
|                   admin: { | ||||
|                     initCollapsed: true, | ||||
|                     description: | ||||
|                       "Make sure the page number corresponds to the page number written on \ | ||||
|                   the scan. You can use negative page numbers if necessary.", | ||||
|                     components: { | ||||
|                       RowLabel: ({ data }: RowLabelArgs) => RowLabel(data), | ||||
|                     }, | ||||
|                   }, | ||||
|                   fields: [ | ||||
|                     rowField([ | ||||
|                       { | ||||
|                         name: fields.scansPagesPage, | ||||
|                         type: "number", | ||||
|                         required: true, | ||||
|                       }, | ||||
|                       imageField({ | ||||
|                         name: fields.scansPagesImage, | ||||
|                         relationTo: Collections.LibraryItemsScans, | ||||
|                         required: true, | ||||
|                       }), | ||||
|                     ]), | ||||
|                   ], | ||||
|                 }, | ||||
|                 fileField({ | ||||
|                   name: fields.scanArchiveFile, | ||||
|                   relationTo: FileTypes.LibraryScans, | ||||
|                 }), | ||||
|               ], | ||||
|             }), | ||||
|           ], | ||||
|         }, | ||||
|         { | ||||
|           label: "Type", | ||||
|           admin: { condition: () => false }, | ||||
|           fields: [ | ||||
|             { | ||||
|               name: fields.textual, | ||||
|               type: "group", | ||||
|               label: false, | ||||
|               admin: { | ||||
|                 condition: (data: Partial<LibraryItem>) => | ||||
|                   data.itemType === LibraryItemsTypes.Textual, | ||||
|               }, | ||||
|               fields: [ | ||||
|                 { | ||||
|                   type: "row", | ||||
|                   fields: [ | ||||
|                     keysField({ | ||||
|                       name: fields.textualSubtype, | ||||
|                       relationTo: KeysTypes.LibraryTextual, | ||||
|                     }), | ||||
|                     { | ||||
|                       name: fields.textualPageCount, | ||||
|                       type: "number", | ||||
|                       min: 1, | ||||
|                     }, | ||||
|                   ], | ||||
|                 }, | ||||
|                 rowField([ | ||||
|                   { | ||||
|                     name: fields.textualBindingType, | ||||
|                     type: "radio", | ||||
|                     options: Object.entries(CollectibleBindingTypes).map( | ||||
|                       ([value, label]) => ({ | ||||
|                         label, | ||||
|                         value, | ||||
|                       }) | ||||
|                     ), | ||||
|                     admin: { | ||||
|                       condition: (data: Partial<LibraryItem>) => !data.digital, | ||||
|                       layout: "horizontal", | ||||
|                     }, | ||||
|                   }, | ||||
|                   { | ||||
|                     name: fields.textualPageOrder, | ||||
|                     type: "radio", | ||||
|                     options: Object.entries(CollectiblePageOrders).map( | ||||
|                       ([value, label]) => ({ | ||||
|                         label, | ||||
|                         value, | ||||
|                       }) | ||||
|                     ), | ||||
|                     admin: { | ||||
|                       layout: "horizontal", | ||||
|                     }, | ||||
|                   }, | ||||
|                 ]), | ||||
|               ], | ||||
|             }, | ||||
|             { | ||||
|               name: fields.audio, | ||||
|               type: "group", | ||||
|               label: false, | ||||
|               admin: { | ||||
|                 condition: (data: Partial<LibraryItem>) => | ||||
|                   data.itemType === LibraryItemsTypes.Audio, | ||||
|               }, | ||||
|               fields: [ | ||||
|                 keysField({ | ||||
|                   name: fields.audioSubtype, | ||||
|                   relationTo: KeysTypes.LibraryAudio, | ||||
|                 }), | ||||
|                 { | ||||
|                   name: fields.audioTracks, | ||||
|                   type: "array", | ||||
|                   fields: [ | ||||
|                     rowField([ | ||||
|                       { | ||||
|                         name: fields.audioTracksTitle, | ||||
|                         type: "text", | ||||
|                         required: true, | ||||
|                       }, | ||||
|                       fileField({ | ||||
|                         name: fields.audioTracksFile, | ||||
|                         relationTo: FileTypes.LibrarySoundtracks, | ||||
|                         required: true, | ||||
|                       }), | ||||
|                     ]), | ||||
|                   ], | ||||
|                 }, | ||||
|               ], | ||||
|             }, | ||||
|             { | ||||
|               name: fields.video, | ||||
|               type: "group", | ||||
|               label: false, | ||||
|               admin: { | ||||
|                 condition: (data: Partial<LibraryItem>) => | ||||
|                   data.itemType === LibraryItemsTypes.Video, | ||||
|               }, | ||||
|               fields: [ | ||||
|                 keysField({ | ||||
|                   name: fields.videoSubtype, | ||||
|                   relationTo: KeysTypes.LibraryVideo, | ||||
|                 }), | ||||
|               ], | ||||
|             }, | ||||
|             { | ||||
|               name: fields.game, | ||||
|               type: "group", | ||||
|               label: false, | ||||
|               admin: { | ||||
|                 condition: (data: Partial<LibraryItem>) => data.itemType === LibraryItemsTypes.Game, | ||||
|               }, | ||||
|               fields: [ | ||||
|                 rowField([ | ||||
|                   { | ||||
|                     name: fields.gameDemo, | ||||
|                     type: "checkbox", | ||||
|                     admin: { description: "Is this item a demo for the game" }, | ||||
|                   }, | ||||
|                   keysField({ | ||||
|                     name: fields.gamePlatform, | ||||
|                     relationTo: KeysTypes.GamePlatforms, | ||||
|                   }), | ||||
|                 ]), | ||||
|                 rowField([ | ||||
|                   { | ||||
|                     name: fields.gameAudioLanguages, | ||||
|                     type: "relationship", | ||||
|                     relationTo: Collections.Languages, | ||||
|                     hasMany: true, | ||||
|                   }, | ||||
|                   { | ||||
|                     name: fields.gameSubtitleLanguages, | ||||
|                     type: "relationship", | ||||
|                     relationTo: Collections.Languages, | ||||
|                     hasMany: true, | ||||
|                   }, | ||||
|                   { | ||||
|                     name: fields.gameInterfacesLanguages, | ||||
|                     type: "relationship", | ||||
|                     relationTo: Collections.Languages, | ||||
|                     hasMany: true, | ||||
|                   }, | ||||
|                 ]), | ||||
|               ], | ||||
|             }, | ||||
|           ], | ||||
|         }, | ||||
|         { | ||||
|           label: "Details", | ||||
|           fields: [ | ||||
|             rowField([ | ||||
|               { | ||||
|                 name: fields.releaseDate, | ||||
|                 type: "date", | ||||
|                 admin: { | ||||
|                   date: { pickerAppearance: "dayOnly", displayFormat: "yyyy-MM-dd" }, | ||||
|                 }, | ||||
|               }, | ||||
|               keysField({ | ||||
|                 name: fields.categories, | ||||
|                 relationTo: KeysTypes.Categories, | ||||
|                 hasMany: true, | ||||
|               }), | ||||
|             ]), | ||||
|             componentField({ | ||||
|               name: fields.size, | ||||
|               admin: { | ||||
|                 condition: (data: Partial<LibraryItem>) => !data.digital, | ||||
|                 description: "Add physical size information about the item", | ||||
|               }, | ||||
|               fields: [ | ||||
|                 rowField([ | ||||
|                   { | ||||
|                     name: fields.width, | ||||
|                     type: "number", | ||||
|                     required: true, | ||||
|                     admin: { step: 1, description: "in mm." }, | ||||
|                   }, | ||||
|                   { | ||||
|                     name: fields.height, | ||||
|                     type: "number", | ||||
|                     required: true, | ||||
|                     admin: { step: 1, description: "in mm." }, | ||||
|                   }, | ||||
|                   { | ||||
|                     name: fields.thickness, | ||||
|                     type: "number", | ||||
|                     admin: { step: 1, description: "in mm." }, | ||||
|                   }, | ||||
|                 ]), | ||||
|               ], | ||||
|             }), | ||||
|             componentField({ | ||||
|               name: fields.price, | ||||
|               admin: { description: "Add pricing information about the item" }, | ||||
|               fields: [ | ||||
|                 rowField([ | ||||
|                   { | ||||
|                     name: fields.priceAmount, | ||||
|                     type: "number", | ||||
|                     required: true, | ||||
|                     min: 0, | ||||
|                   }, | ||||
|                   { | ||||
|                     name: fields.priceCurrency, | ||||
|                     type: "relationship", | ||||
|                     relationTo: Collections.Currencies, | ||||
|                     required: true, | ||||
|                     admin: { allowCreate: false }, | ||||
|                   }, | ||||
|                 ]), | ||||
|               ], | ||||
|             }), | ||||
|             translatedFields({ | ||||
|               name: fields.translations, | ||||
|               label: "Descriptions", | ||||
|               admin: { initCollapsed: true, useAsTitle: fields.translationsDescription }, | ||||
|               fields: [ | ||||
|                 { | ||||
|                   name: fields.translationsDescription, | ||||
|                   required: true, | ||||
|                   type: "richText", | ||||
|                   editor: createEditor({ inlines: true, lists: true, links: true }), | ||||
|                 }, | ||||
|               ], | ||||
|             }), | ||||
|             { | ||||
|               name: fields.urls, | ||||
|               label: "URLs", | ||||
|               type: "array", | ||||
|               admin: { | ||||
|                 description: "Links to official websites where to get/buy the item.", | ||||
|               }, | ||||
|               fields: [{ name: fields.urlsUrl, type: "text", required: true }], | ||||
|             }, | ||||
|           ], | ||||
|         }, | ||||
|         { | ||||
|           label: "Contents", | ||||
|           fields: [ | ||||
|             rowField([ | ||||
|               // TODO: Uncomment when the Folders are ready
 | ||||
|               // backPropagationField({
 | ||||
|               //   name: fields.parentFolders,
 | ||||
|               //   relationTo: Collections.Folders,
 | ||||
|               //   hasMany: true,
 | ||||
|               //   where: ({ id }) => ({ files: { equals: id } }),
 | ||||
|               //   admin: {
 | ||||
|               //     description: `You can set the folders from the "Folders" collection`,
 | ||||
|               //   },
 | ||||
|               // }),
 | ||||
|               backPropagationField({ | ||||
|                 name: fields.parentItems, | ||||
|                 relationTo: Collections.LibraryItems, | ||||
|                 hasMany: true, | ||||
|                 where: ({ id }) => ({ [fields.subitems]: { equals: id } }), | ||||
|               }), | ||||
|               { | ||||
|                 name: fields.subitems, | ||||
|                 type: "relationship", | ||||
|                 hasMany: true, | ||||
|                 relationTo: Collections.LibraryItems, | ||||
|               }, | ||||
|             ]), | ||||
|             { | ||||
|               name: fields.contents, | ||||
|               type: "array", | ||||
|               fields: [ | ||||
|                 { | ||||
|                   name: fields.contentsContent, | ||||
|                   type: "relationship", | ||||
|                   relationTo: Collections.Pages, | ||||
|                   admin: { | ||||
|                     allowCreate: false, | ||||
|                   }, | ||||
|                   required: true, | ||||
|                   filterOptions: { type: { equals: PageType.Content } }, | ||||
|                 }, | ||||
|                 { | ||||
|                   type: "row", | ||||
|                   admin: { | ||||
|                     // TODO: Check why those condition doesn't work
 | ||||
|                     condition: ({ itemType }: Partial<LibraryItem>) => | ||||
|                       itemType === LibraryItemsTypes.Textual, | ||||
|                   }, | ||||
|                   fields: [ | ||||
|                     { | ||||
|                       name: fields.contentsPageStart, | ||||
|                       type: "number", | ||||
|                     }, | ||||
|                     { name: fields.contentsPageEnd, type: "number" }, | ||||
|                   ], | ||||
|                 }, | ||||
|                 { | ||||
|                   type: "row", | ||||
|                   admin: { | ||||
|                     condition: ({ itemType }: Partial<LibraryItem>) => | ||||
|                       itemType === LibraryItemsTypes.Audio || itemType === LibraryItemsTypes.Video, | ||||
|                   }, | ||||
|                   fields: [ | ||||
|                     { | ||||
|                       name: fields.contentsTimeStart, | ||||
|                       type: "number", | ||||
|                     }, | ||||
|                     { name: fields.contentsTimeEnd, type: "number" }, | ||||
|                   ], | ||||
|                 }, | ||||
|                 { | ||||
|                   name: fields.contentsNote, | ||||
|                   type: "richText", | ||||
|                   editor: createEditor({ inlines: true, lists: true, links: true }), | ||||
|                   admin: { | ||||
|                     condition: ({ itemType }: Partial<LibraryItem>) => | ||||
|                       itemType === LibraryItemsTypes.Game || itemType === LibraryItemsTypes.Other, | ||||
|                   }, | ||||
|                 }, | ||||
|               ], | ||||
|             }, | ||||
|           ], | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| @ -1,26 +0,0 @@ | ||||
| import React from "react"; | ||||
| import styled from "styled-components"; | ||||
| import { isDefined } from "../../../utils/asserts"; | ||||
| 
 | ||||
| interface Props { | ||||
|   page?: number; | ||||
|   image?: string; | ||||
| } | ||||
| 
 | ||||
| const Container = styled.div` | ||||
|   display: flex; | ||||
|   place-items: center; | ||||
|   gap: 10px; | ||||
| `;
 | ||||
| 
 | ||||
| const Title = styled.div` | ||||
|   font-weight: 600; | ||||
|   font-size: 1.2rem; | ||||
| `;
 | ||||
| 
 | ||||
| export const RowLabel = ({ page, image }: Props): JSX.Element => ( | ||||
|   <Container> | ||||
|     {isDefined(page) && <div className="pill pill--style-white">{`Page ${page}`}</div>} | ||||
|     {isDefined(image) && <Title>{image}</Title>} | ||||
|   </Container> | ||||
| ); | ||||
| @ -1,33 +0,0 @@ | ||||
| import { Collections } from "../../constants"; | ||||
| import { buildImageCollectionConfig } from "../../utils/imageCollectionConfig"; | ||||
| 
 | ||||
| const fields = { | ||||
|   filename: "filename", | ||||
|   mimeType: "mimeType", | ||||
|   filesize: "filesize", | ||||
|   updatedAt: "updatedAt", | ||||
| } as const satisfies Record<string, string>; | ||||
| 
 | ||||
| export const LibraryItemsGallery = buildImageCollectionConfig({ | ||||
|   slug: Collections.LibraryItemsGallery, | ||||
|   labels: { | ||||
|     singular: "Library Item Gallery", | ||||
|     plural: "Library Item Gallery", | ||||
|   }, | ||||
|   admin: { defaultColumns: [fields.filename, fields.updatedAt] }, | ||||
|   upload: { | ||||
|     imageSizes: [ | ||||
|       { | ||||
|         name: "small", | ||||
|         height: 512, | ||||
|         width: 512, | ||||
|         fit: "cover", | ||||
|         formatOptions: { | ||||
|           format: "webp", | ||||
|           options: { effort: 6, quality: 60, alphaQuality: 60 }, | ||||
|         }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   fields: [], | ||||
| }); | ||||
| @ -1,53 +0,0 @@ | ||||
| import { Collections } from "../../constants"; | ||||
| import { buildImageCollectionConfig } from "../../utils/imageCollectionConfig"; | ||||
| 
 | ||||
| const fields = { | ||||
|   filename: "filename", | ||||
|   mimeType: "mimeType", | ||||
|   filesize: "filesize", | ||||
|   updatedAt: "updatedAt", | ||||
| } as const satisfies Record<string, string>; | ||||
| 
 | ||||
| export const LibraryItemsScans = buildImageCollectionConfig({ | ||||
|   slug: Collections.LibraryItemsScans, | ||||
|   labels: { | ||||
|     singular: "Library Item Scans", | ||||
|     plural: "Library Item Scans", | ||||
|   }, | ||||
|   admin: { defaultColumns: [fields.filename, fields.updatedAt] }, | ||||
|   upload: { | ||||
|     imageSizes: [ | ||||
|       { | ||||
|         name: "og", | ||||
|         height: 1024, | ||||
|         width: 1024, | ||||
|         fit: "contain", | ||||
|         formatOptions: { | ||||
|           format: "jpg", | ||||
|           options: { progressive: true, mozjpeg: true, compressionLevel: 9, quality: 80 }, | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         name: "medium", | ||||
|         height: 1024, | ||||
|         width: 1024, | ||||
|         fit: "contain", | ||||
|         formatOptions: { | ||||
|           format: "webp", | ||||
|           options: { effort: 6, quality: 80, alphaQuality: 80 }, | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         name: "large", | ||||
|         height: 2048, | ||||
|         width: 2048, | ||||
|         fit: "contain", | ||||
|         formatOptions: { | ||||
|           format: "webp", | ||||
|           options: { effort: 6, quality: 80, alphaQuality: 80 }, | ||||
|         }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   fields: [], | ||||
| }); | ||||
| @ -1,53 +0,0 @@ | ||||
| import { Collections } from "../../constants"; | ||||
| import { backPropagationField } from "../../fields/backPropagationField/backPropagationField"; | ||||
| import { buildImageCollectionConfig } from "../../utils/imageCollectionConfig"; | ||||
| 
 | ||||
| const fields = { | ||||
|   filename: "filename", | ||||
|   mimeType: "mimeType", | ||||
|   filesize: "filesize", | ||||
|   libraryItem: "libraryItem", | ||||
|   updatedAt: "updatedAt", | ||||
| } as const satisfies Record<string, string>; | ||||
| 
 | ||||
| export const LibraryItemsThumbnails = buildImageCollectionConfig({ | ||||
|   slug: Collections.LibraryItemsThumbnails, | ||||
|   labels: { | ||||
|     singular: "Library Item Thumbnail", | ||||
|     plural: "Library Item Thumbnails", | ||||
|   }, | ||||
|   admin: { defaultColumns: [fields.filename, fields.libraryItem, fields.updatedAt] }, | ||||
|   upload: { | ||||
|     imageSizes: [ | ||||
|       { | ||||
|         name: "og", | ||||
|         height: 1024, | ||||
|         width: 1024, | ||||
|         fit: "inside", | ||||
|         formatOptions: { | ||||
|           format: "jpg", | ||||
|           options: { progressive: true, mozjpeg: true, compressionLevel: 9, quality: 80 }, | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         name: "square", | ||||
|         height: 1024, | ||||
|         width: 1024, | ||||
|         fit: "contain", | ||||
|         background: { r: 0, g: 0, b: 0, alpha: 0 }, | ||||
|         formatOptions: { | ||||
|           format: "webp", | ||||
|           options: { effort: 6, quality: 80, alphaQuality: 80 }, | ||||
|         }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   fields: [ | ||||
|     backPropagationField({ | ||||
|       name: fields.libraryItem, | ||||
|       hasMany: true, | ||||
|       relationTo: Collections.LibraryItems, | ||||
|       where: ({ id }) => ({ thumbnail: { equals: id } }), | ||||
|     }), | ||||
|   ], | ||||
| }); | ||||
| @ -38,7 +38,7 @@ const fields = { | ||||
|   folders: "folders", | ||||
| } as const satisfies Record<string, string>; | ||||
| 
 | ||||
| const pageTypesWithAuthor = [PageType.Article]; | ||||
| const pageTypesWithAuthor = [PageType.Post]; | ||||
| const pageTypesWithCollectibles = [PageType.Content]; | ||||
| const pageTypesWithTranscribers = [PageType.Content]; | ||||
| 
 | ||||
| @ -76,7 +76,10 @@ export const Pages = buildVersionedCollectionConfig({ | ||||
|       type: "radio", | ||||
|       required: true, | ||||
|       defaultValue: PageType.Generic, | ||||
|       options: Object.entries(PageType).map(([value, label]) => ({ label, value })), | ||||
|       options: Object.entries(PageType).map(([_, value]) => ({ | ||||
|         label: value, | ||||
|         value: value, | ||||
|       })), | ||||
|     }, | ||||
|     rowField([ | ||||
|       slugField({ name: fields.slug }), | ||||
| @ -119,7 +122,10 @@ export const Pages = buildVersionedCollectionConfig({ | ||||
|           name: fields.content, | ||||
|           type: "richText", | ||||
|           required: true, | ||||
|           admin: {description: "Looking for help? Read the Rich Text Editor guide here: https://accords-library.com/dev/rich-text"}, | ||||
|           admin: { | ||||
|             description: | ||||
|               "Looking for help? Read the Rich Text Editor guide here: https://accords-library.com/dev/rich-text", | ||||
|           }, | ||||
|           editor: createEditor({ | ||||
|             images: true, | ||||
|             inlines: true, | ||||
| @ -206,12 +212,17 @@ export const Pages = buildVersionedCollectionConfig({ | ||||
|       backPropagationField({ | ||||
|         name: fields.collectibles, | ||||
|         hasMany: true, | ||||
|         relationTo: Collections.LibraryItems, | ||||
|         relationTo: Collections.Collectibles, | ||||
|         admin: { | ||||
|           condition: (_, siblingData) => | ||||
|             pageTypesWithCollectibles.includes(siblingData[fields.type]), | ||||
|         }, | ||||
|         where: ({ id }) => ({ "contents.content": { equals: id } }), | ||||
|         where: ({ id }) => ({ | ||||
|           and: [ | ||||
|             { "contents.content.value": { equals: id } }, | ||||
|             { "contents.content.relationTo": { equals: Collections.Pages } }, | ||||
|           ] as Where[], | ||||
|         }), | ||||
|       }), | ||||
|     ]), | ||||
|   ], | ||||
|  | ||||
| @ -9,7 +9,7 @@ import { createGetByEndpoint } from "../../../endpoints/createGetByEndpoint"; | ||||
| import { EndpointPage, ParentPage, TableOfContentEntry } from "../../../sdk"; | ||||
| import { Page } from "../../../types/collections"; | ||||
| import { isPayloadArrayType, isPayloadType, isValidPayloadImage } from "../../../utils/asserts"; | ||||
| import { convertTagsToGroups } from "../../../utils/tags"; | ||||
| import { convertTagsToGroups } from "../../../utils/endpoints"; | ||||
| 
 | ||||
| export const getBySlugEndpoint = createGetByEndpoint( | ||||
|   Collections.Pages, | ||||
| @ -105,11 +105,14 @@ const handleParentPages = ({ | ||||
|   const result: ParentPage[] = []; | ||||
| 
 | ||||
|   if (collectibles && isPayloadArrayType(collectibles)) { | ||||
|     collectibles.forEach(({ slug, title }) => { | ||||
|     collectibles.forEach(({ slug, translations }) => { | ||||
|       result.push({ | ||||
|         collection: Collections.LibraryItems, | ||||
|         collection: Collections.Collectibles, | ||||
|         slug, | ||||
|         translations: [{ language: "en", name: title }], | ||||
|         translations: translations.map(({ language, title }) => ({ | ||||
|           language: isPayloadType(language) ? language.id : language, | ||||
|           name: title, // TODO: Use the entire pretitle + title + subtitle
 | ||||
|         })), | ||||
|         tag: "collectible", | ||||
|       }); | ||||
|     }); | ||||
|  | ||||
| @ -51,9 +51,9 @@ export const Recorders = buildCollectionConfig({ | ||||
|             slug: Collections.Recorders, | ||||
|             filterGroups: [ | ||||
|               [ | ||||
|                 ...Object.entries(RecordersRoles).map(([key, value]) => ({ | ||||
|                 ...Object.entries(RecordersRoles).map(([_, value]) => ({ | ||||
|                   label: value, | ||||
|                   filter: { where: { role: { equals: key } } }, | ||||
|                   filter: { where: { role: { equals: value } } }, | ||||
|                 })), | ||||
|                 { | ||||
|                   label: "∅ Role", | ||||
| @ -127,9 +127,9 @@ export const Recorders = buildCollectionConfig({ | ||||
|         create: mustBeAdminForFields, | ||||
|       }, | ||||
|       hasMany: true, | ||||
|       options: Object.entries(RecordersRoles).map(([value, label]) => ({ | ||||
|         label, | ||||
|         value, | ||||
|       options: Object.entries(RecordersRoles).map(([_, value]) => ({ | ||||
|         label: value, | ||||
|         value: value, | ||||
|       })), | ||||
|     }, | ||||
|     { | ||||
|  | ||||
| @ -3,6 +3,7 @@ import { CollectionBeforeChangeHook, CollectionConfig } from "payload/types"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { slugField } from "../../fields/slugField/slugField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo"; | ||||
| import { buildCollectionConfig } from "../../utils/collectionConfig"; | ||||
| import { getAllEndpoint } from "./endpoints/getAllEndpoint"; | ||||
| 
 | ||||
| @ -40,6 +41,9 @@ export const Tags: CollectionConfig = buildCollectionConfig({ | ||||
|     group: CollectionGroups.Meta, | ||||
|     useAsTitle: fields.name, | ||||
|     defaultColumns: [fields.slug, fields.group, fields.translations], | ||||
|     hooks: { | ||||
|       beforeDuplicate: beforeDuplicateAddCopyTo(fields.slug), | ||||
|     }, | ||||
|   }, | ||||
|   endpoints: [getAllEndpoint], | ||||
|   hooks: { beforeChange: [beforeChangeUpdateName] }, | ||||
| @ -53,6 +57,11 @@ export const Tags: CollectionConfig = buildCollectionConfig({ | ||||
|       minRows: 1, | ||||
|       fields: [{ name: fields.translationsName, type: "text", required: true }], | ||||
|     }), | ||||
|     { name: fields.group, type: "relationship", required: true, relationTo: Collections.TagsGroups }, | ||||
|     { | ||||
|       name: fields.group, | ||||
|       type: "relationship", | ||||
|       required: true, | ||||
|       relationTo: Collections.TagsGroups, | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
|  | ||||
| @ -64,7 +64,10 @@ export const Videos: CollectionConfig = buildCollectionConfig({ | ||||
|         name: fields.source, | ||||
|         type: "select", | ||||
|         required: true, | ||||
|         options: Object.entries(VideoSources).map(([value, label]) => ({ label, value })), | ||||
|         options: Object.entries(VideoSources).map(([_, value]) => ({ | ||||
|           label: value, | ||||
|           value: value, | ||||
|         })), | ||||
|       }, | ||||
|     ]), | ||||
|     { name: fields.title, type: "text", required: true }, | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types"; | ||||
| import { CollectionGroups, Collections, KeysTypes } from "../../constants"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { imageField } from "../../fields/imageField/imageField"; | ||||
| import { keysField } from "../../fields/keysField/keysField"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { slugField } from "../../fields/slugField/slugField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| @ -54,11 +53,6 @@ export const Weapons = buildVersionedCollectionConfig({ | ||||
|       }), | ||||
|     ]), | ||||
|     rowField([ | ||||
|       keysField({ | ||||
|         name: fields.type, | ||||
|         relationTo: KeysTypes.Weapons, | ||||
|         required: true, | ||||
|       }), | ||||
|       { | ||||
|         name: fields.group, | ||||
|         type: "relationship", | ||||
| @ -78,12 +72,6 @@ export const Weapons = buildVersionedCollectionConfig({ | ||||
|         }, | ||||
|       }, | ||||
|       fields: [ | ||||
|         keysField({ | ||||
|           name: fields.appearancesCategories, | ||||
|           required: true, | ||||
|           hasMany: true, | ||||
|           relationTo: KeysTypes.Categories, | ||||
|         }), | ||||
|         translatedFields({ | ||||
|           name: fields.appearancesTranslations, | ||||
|           required: true, | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import { CollectionConfig } from "payload/types"; | ||||
| import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin"; | ||||
| import { QuickFilters } from "../../components/QuickFilters"; | ||||
| import { CollectionGroups, Collections, LanguageCodes } from "../../constants"; | ||||
| import { QuickFilters, languageBasedFilters } from "../../components/QuickFilters"; | ||||
| import { CollectionGroups, Collections } from "../../constants"; | ||||
| import { rowField } from "../../fields/rowField/rowField"; | ||||
| import { translatedFields } from "../../fields/translatedFields/translatedFields"; | ||||
| import { afterOperationWebhook } from "../../hooks/afterOperationWebhook"; | ||||
| @ -34,12 +34,7 @@ export const Wordings: CollectionConfig = buildCollectionConfig({ | ||||
|         () => | ||||
|           QuickFilters({ | ||||
|             slug: Collections.Wordings, | ||||
|             filterGroups: [ | ||||
|               Object.entries(LanguageCodes).map(([key, value]) => ({ | ||||
|                 label: `∅ ${value}`, | ||||
|                 filter: { where: { "translations.language": { not_equals: key } } }, | ||||
|               })), | ||||
|             ], | ||||
|             filterGroups: [languageBasedFilters("translations.language")], | ||||
|           }), | ||||
|       ], | ||||
|     }, | ||||
|  | ||||
| @ -13,12 +13,7 @@ export enum Collections { | ||||
|   ChronologyItems = "chronology-items", | ||||
|   Currencies = "currencies", | ||||
|   Files = "files", | ||||
|   Keys = "keys", | ||||
|   Languages = "languages", | ||||
|   LibraryItems = "library-items", | ||||
|   LibraryItemsThumbnails = "library-items-thumbnails", | ||||
|   LibraryItemsScans = "library-items-scans", | ||||
|   LibraryItemsGallery = "library-items-gallery", | ||||
|   Notes = "notes", | ||||
|   Pages = "pages", | ||||
|   PagesThumbnails = "pages-thumbnails", | ||||
| @ -45,19 +40,6 @@ export enum CollectionGroups { | ||||
|   Meta = "Meta", | ||||
| } | ||||
| 
 | ||||
| export enum KeysTypes { | ||||
|   Contents = "Contents", | ||||
|   LibraryAudio = "Library / Audio", | ||||
|   LibraryVideo = "Library / Video", | ||||
|   LibraryTextual = "Library / Textual", | ||||
|   LibraryGroup = "Library / Group", | ||||
|   Library = "Library", | ||||
|   Weapons = "Weapons", | ||||
|   GamePlatforms = "Game Platforms", | ||||
|   Categories = "Categories", | ||||
|   Wordings = "Wordings", | ||||
| } | ||||
| 
 | ||||
| export enum LanguageCodes { | ||||
|   en = "English", | ||||
|   fr = "French", | ||||
| @ -67,21 +49,6 @@ export enum LanguageCodes { | ||||
|   "zh" = "Chinese", | ||||
| } | ||||
| 
 | ||||
| export enum FileTypes { | ||||
|   LibraryScans = "Library / Scans", | ||||
|   LibrarySoundtracks = "Library / Soundtracks", | ||||
|   ContentVideo = "Content / Video", | ||||
|   ContentAudio = "Content / Audio", | ||||
| } | ||||
| 
 | ||||
| export enum LibraryItemsTypes { | ||||
|   Textual = "Textual", | ||||
|   Audio = "Audio", | ||||
|   Video = "Video", | ||||
|   Game = "Game", | ||||
|   Other = "Other", | ||||
| } | ||||
| 
 | ||||
| export enum CollectibleBindingTypes { | ||||
|   Paperback = "Paperback", | ||||
|   Hardcover = "Hardcover", | ||||
| @ -92,6 +59,17 @@ export enum CollectiblePageOrders { | ||||
|   RightToLeft = "Right to left", | ||||
| } | ||||
| 
 | ||||
| export enum CollectibleNature { | ||||
|   Physical = "Physical", | ||||
|   Digital = "Digital", | ||||
| } | ||||
| 
 | ||||
| export enum CollectibleContentType { | ||||
|   None = "None", | ||||
|   Indexes = "Index-based", | ||||
|   Pages = "Page-based", | ||||
| } | ||||
| 
 | ||||
| export enum RecordersRoles { | ||||
|   Admin = "Admin", | ||||
|   Recorder = "Recorder", | ||||
| @ -122,17 +100,6 @@ export enum SpacerSizes { | ||||
|   XLarge = "Extra Large", | ||||
| } | ||||
| 
 | ||||
| export enum CollectibleNature { | ||||
|   Physical = "Physical", | ||||
|   Digital = "Digital", | ||||
| } | ||||
| 
 | ||||
| export enum CollectibleContentType { | ||||
|   None = "None", | ||||
|   Indexes = "Index-based", | ||||
|   Pages = "Page-based", | ||||
| } | ||||
| 
 | ||||
| /* RICH TEXT */ | ||||
| 
 | ||||
| export type RichTextContent = { | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| import payload from "payload"; | ||||
| import { FieldBase } from "payload/dist/fields/config/types"; | ||||
| import { RelationshipField, Where } from "payload/types"; | ||||
| import { Collections } from "../../constants"; | ||||
| import payload, { GeneratedTypes } from "payload"; | ||||
| import { FieldBase, SingleRelationshipField } from "payload/dist/fields/config/types"; | ||||
| import { Where } from "payload/types"; | ||||
| import { isEmpty } from "../../utils/asserts"; | ||||
| 
 | ||||
| type BackPropagationField = FieldBase & { | ||||
|   where: (data: any) => Where; | ||||
|   relationTo: Collections; | ||||
|   relationTo: keyof GeneratedTypes["collections"]; | ||||
|   hasMany?: boolean; | ||||
| }; | ||||
| export const backPropagationField = ({ | ||||
| @ -15,7 +14,7 @@ export const backPropagationField = ({ | ||||
|   where, | ||||
|   hasMany = false, | ||||
|   ...params | ||||
| }: BackPropagationField): RelationshipField => ({ | ||||
| }: BackPropagationField): SingleRelationshipField => ({ | ||||
|   ...params, | ||||
|   type: "relationship", | ||||
|   hasMany: hasMany, | ||||
|  | ||||
| @ -1,23 +0,0 @@ | ||||
| import { FieldBase, RelationshipField } from "payload/dist/fields/config/types"; | ||||
| import { Collections, FileTypes } from "../../constants"; | ||||
| 
 | ||||
| type FileField = FieldBase & { | ||||
|   relationTo: FileTypes; | ||||
|   hasMany?: boolean; | ||||
|   admin?: RelationshipField["admin"]; | ||||
| }; | ||||
| 
 | ||||
| export const fileField = ({ | ||||
|   relationTo, | ||||
|   hasMany = false, | ||||
|   ...props | ||||
| }: FileField): RelationshipField => ({ | ||||
|   ...props, | ||||
|   type: "relationship", | ||||
|   hasMany: hasMany, | ||||
|   relationTo: Collections.Files, | ||||
|   filterOptions: { type: { equals: getFileTypesKey(relationTo) } }, | ||||
| }); | ||||
| 
 | ||||
| const getFileTypesKey = (fileType: FileTypes): string | undefined => | ||||
|   Object.entries(FileTypes).find(([, value]) => value === fileType)?.[0]; | ||||
| @ -1,28 +0,0 @@ | ||||
| import { FieldBase, SingleRelationshipField } from "payload/dist/fields/config/types"; | ||||
| import { Collections, KeysTypes } from "../../constants"; | ||||
| 
 | ||||
| type KeysField = FieldBase & { | ||||
|   relationTo: KeysTypes; | ||||
|   hasMany?: boolean; | ||||
|   admin?: SingleRelationshipField["admin"]; | ||||
| }; | ||||
| 
 | ||||
| export const keysField = ({ | ||||
|   relationTo, | ||||
|   hasMany = false, | ||||
|   admin, | ||||
|   ...props | ||||
| }: KeysField): SingleRelationshipField => ({ | ||||
|   ...props, | ||||
|   admin: { | ||||
|     allowCreate: false, | ||||
|     ...admin, | ||||
|   }, | ||||
|   type: "relationship", | ||||
|   hasMany: hasMany, | ||||
|   relationTo: Collections.Keys, | ||||
|   filterOptions: { type: { equals: getKeysTypesKey(relationTo) } }, | ||||
| }); | ||||
| 
 | ||||
| const getKeysTypesKey = (keyType: KeysTypes): string | undefined => | ||||
|   Object.entries(KeysTypes).find(([, value]) => value === keyType)?.[0]; | ||||
| @ -1,7 +1,7 @@ | ||||
| import { TextField } from "payload/types"; | ||||
| import { isUndefined } from "../../utils/asserts"; | ||||
| 
 | ||||
| type Props = Omit<TextField, "type">; | ||||
| type Props = Omit<TextField, "type" | "hasMany" | "minRows" | "maxRows">; | ||||
| 
 | ||||
| const validateSlug = (value?: string) => { | ||||
|   if (isUndefined(value) || value === "") return "This field is required."; | ||||
|  | ||||
| @ -6,17 +6,11 @@ import { ChronologyEras } from "./collections/ChronologyEras/ChronologyEras"; | ||||
| import { ChronologyItems } from "./collections/ChronologyItems/ChronologyItems"; | ||||
| import { Collectibles } from "./collections/Collectibles/Collectibles"; | ||||
| import { Currencies } from "./collections/Currencies/Currencies"; | ||||
| import { Files } from "./collections/Files/Files"; | ||||
| import { Folders } from "./collections/Folders/Folders"; | ||||
| import { FoldersThumbnails } from "./collections/FoldersThumbnails/FoldersThumbnails"; | ||||
| import { GenericContents } from "./collections/GenericContents/GenericContents"; | ||||
| import { Images } from "./collections/Images/Images"; | ||||
| import { Keys } from "./collections/Keys/Keys"; | ||||
| import { Languages } from "./collections/Languages/Languages"; | ||||
| import { LibraryItems } from "./collections/LibraryItems/LibraryItems"; | ||||
| import { LibraryItemsGallery } from "./collections/LibraryItemsGallery/LibraryItemsGallery"; | ||||
| import { LibraryItemsScans } from "./collections/LibraryItemsScans/LibraryItemsScans"; | ||||
| import { LibraryItemsThumbnails } from "./collections/LibraryItemsThumbnails/LibraryItemsThumbnails"; | ||||
| import { Notes } from "./collections/Notes/Notes"; | ||||
| import { Pages } from "./collections/Pages/Pages"; | ||||
| import { Recorders } from "./collections/Recorders/Recorders"; | ||||
| @ -51,25 +45,19 @@ export default buildConfig({ | ||||
|   collections: [ | ||||
|     Folders, | ||||
|     FoldersThumbnails, | ||||
|     LibraryItems, | ||||
|     Pages, | ||||
|     ChronologyItems, | ||||
|     ChronologyEras, | ||||
|     Weapons, | ||||
|     WeaponsGroups, | ||||
|     WeaponsThumbnails, | ||||
|     LibraryItemsThumbnails, | ||||
|     LibraryItemsScans, | ||||
|     LibraryItemsGallery, | ||||
|     RecordersThumbnails, | ||||
|     Files, | ||||
|     Notes, | ||||
|     Videos, | ||||
|     VideosChannels, | ||||
|     Languages, | ||||
|     Currencies, | ||||
|     Recorders, | ||||
|     Keys, | ||||
|     Tags, | ||||
|     TagsGroups, | ||||
|     Images, | ||||
|  | ||||
							
								
								
									
										99
									
								
								src/sdk.ts
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								src/sdk.ts
									
									
									
									
									
								
							| @ -1,5 +1,12 @@ | ||||
| import { Collections, PageType, RichTextContent } from "./constants"; | ||||
| import { Currency, Key, Language, LibraryItem, Page } from "./types/collections"; | ||||
| import { | ||||
|   CollectibleBindingTypes, | ||||
|   CollectibleNature, | ||||
|   CollectiblePageOrders, | ||||
|   Collections, | ||||
|   PageType, | ||||
|   RichTextContent, | ||||
| } from "./constants"; | ||||
| import { Collectible, Currency, GenericContent, Language, Page } from "./types/collections"; | ||||
| 
 | ||||
| class NodeCache { | ||||
|   constructor(_params: any) {} | ||||
| @ -171,8 +178,8 @@ export type EndpointFolder = EndpointFolderPreview & { | ||||
|       }; | ||||
|   files: ( | ||||
|     | { | ||||
|         relationTo: "library-items"; | ||||
|         value: LibraryItem; | ||||
|         relationTo: "collectibles"; | ||||
|         value: Collectible; | ||||
|       } | ||||
|     | { | ||||
|         relationTo: "pages"; | ||||
| @ -204,17 +211,6 @@ export type EndpointRecorder = { | ||||
|   }[]; | ||||
| }; | ||||
| 
 | ||||
| export type EndpointKey = { | ||||
|   id: string; | ||||
|   name: string; | ||||
|   type: Key["type"]; | ||||
|   translations: { | ||||
|     language: string; | ||||
|     name: string; | ||||
|     short: string; | ||||
|   }[]; | ||||
| }; | ||||
| 
 | ||||
| export type EndpointWording = { | ||||
|   name: string; | ||||
|   translations: { | ||||
| @ -272,6 +268,77 @@ export type ParentPage = { | ||||
|   tag: string; | ||||
| }; | ||||
| 
 | ||||
| export type EndpointCollectiblePreview = { | ||||
|   slug: string; | ||||
|   thumbnail?: PayloadImage; | ||||
|   translations: { | ||||
|     language: string; | ||||
|     pretitle?: string; | ||||
|     title: string; | ||||
|     subtitle?: string; | ||||
|     description?: RichTextContent; | ||||
|   }[]; | ||||
|   tagGroups: TagGroup[]; | ||||
|   status: "draft" | "published"; | ||||
|   releaseDate?: string; | ||||
|   languages: string[]; | ||||
| }; | ||||
| 
 | ||||
| export type EndpointCollectible = EndpointCollectiblePreview & { | ||||
|   nature: CollectibleNature; | ||||
|   gallery: PayloadImage[]; | ||||
|   urls: { url: string; label: string }[]; | ||||
|   price?: { | ||||
|     amount: number; | ||||
|     currency: string; | ||||
|   }; | ||||
|   size?: { | ||||
|     width: number; | ||||
|     height: number; | ||||
|     thickness?: number; | ||||
|   }; | ||||
|   weight?: { | ||||
|     amount: number; | ||||
|   }; | ||||
|   pageInfo?: { | ||||
|     pageCount: number; | ||||
|     bindingType?: CollectibleBindingTypes; | ||||
|     pageOrder?: CollectiblePageOrders; | ||||
|   }; | ||||
|   subitems: EndpointCollectiblePreview[]; | ||||
|   contents: { | ||||
|     content: | ||||
|       | { | ||||
|           relationTo: "pages"; | ||||
|           value: Page; | ||||
|         } | ||||
|       | { | ||||
|           relationTo: "generic-contents"; | ||||
|           value: GenericContent; | ||||
|         }; | ||||
| 
 | ||||
|     range?: | ||||
|       | { | ||||
|           type: "pageRange"; | ||||
|           start: number; | ||||
|           end: number; | ||||
|         } | ||||
|       | { | ||||
|           type: "timeRange"; | ||||
|           start: string; | ||||
|           end: string; | ||||
|         } | ||||
|       | { | ||||
|           type: "other"; | ||||
|           translations: { | ||||
|             language: string; | ||||
|             note: RichTextContent; | ||||
|           }[]; | ||||
|         }; | ||||
|   }[]; | ||||
|   parentPages: ParentPage[]; | ||||
| }; | ||||
| 
 | ||||
| export type TagGroup = { slug: string; icon: string; values: string[] }; | ||||
| 
 | ||||
| export type TableOfContentEntry = { | ||||
| @ -311,4 +378,6 @@ export const payload = { | ||||
|     await (await request(payloadApiUrl(Collections.TagsGroups, `all`))).json(), | ||||
|   getPage: async (slug: string): Promise<EndpointPage> => | ||||
|     await (await request(payloadApiUrl(Collections.Pages, `slug/${slug}`))).json(), | ||||
|   getCollectible: async (slug: string): Promise<EndpointCollectible> => | ||||
|     await (await request(payloadApiUrl(Collections.Collectibles, `slug/${slug}`))).json(), | ||||
| }; | ||||
|  | ||||
| @ -35,41 +35,35 @@ export type RecorderBiographies = | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "CategoryTranslations". | ||||
|  */ | ||||
| export type CategoryTranslations = | ||||
|   | { | ||||
|       language: string | Language; | ||||
|       name: string; | ||||
|       id?: string | null; | ||||
|     }[] | ||||
|   | null; | ||||
| export type CategoryTranslations = { | ||||
|   language: string | Language; | ||||
|   name: string; | ||||
|   id?: string | null; | ||||
| }[]; | ||||
| 
 | ||||
| export interface Config { | ||||
|   collections: { | ||||
|     folders: Folder; | ||||
|     'folders-thumbnails': FoldersThumbnail; | ||||
|     'library-items': LibraryItem; | ||||
|     pages: Page; | ||||
|     'chronology-items': ChronologyItem; | ||||
|     'chronology-eras': ChronologyEra; | ||||
|     weapons: Weapon; | ||||
|     'weapons-groups': WeaponsGroup; | ||||
|     'weapons-thumbnails': WeaponsThumbnail; | ||||
|     'library-items-thumbnails': LibraryItemThumbnail; | ||||
|     'library-items-scans': LibraryItemScans; | ||||
|     'library-items-gallery': LibraryItemGallery; | ||||
|     'recorders-thumbnails': RecordersThumbnail; | ||||
|     files: File; | ||||
|     notes: Note; | ||||
|     videos: Video; | ||||
|     'videos-channels': VideosChannel; | ||||
|     languages: Language; | ||||
|     currencies: Currency; | ||||
|     recorders: Recorder; | ||||
|     keys: Key; | ||||
|     tags: Tag; | ||||
|     'tags-groups': TagsGroup; | ||||
|     images: Image; | ||||
|     wordings: Wording; | ||||
|     collectibles: Collectible; | ||||
|     'generic-contents': GenericContent; | ||||
|     'payload-preferences': PayloadPreference; | ||||
|     'payload-migrations': PayloadMigration; | ||||
|   }; | ||||
| @ -123,8 +117,8 @@ export interface Folder { | ||||
|   files?: | ||||
|     | ( | ||||
|         | { | ||||
|             relationTo: 'library-items'; | ||||
|             value: string | LibraryItem; | ||||
|             relationTo: 'collectibles'; | ||||
|             value: string | Collectible; | ||||
|           } | ||||
|         | { | ||||
|             relationTo: 'pages'; | ||||
| @ -170,21 +164,40 @@ export interface Language { | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "library-items". | ||||
|  * via the `definition` "collectibles". | ||||
|  */ | ||||
| export interface LibraryItem { | ||||
| export interface Collectible { | ||||
|   id: string; | ||||
|   itemType?: ('Textual' | 'Audio' | 'Video' | 'Game' | 'Other') | null; | ||||
|   language: string | Language; | ||||
|   slug: string; | ||||
|   thumbnail?: string | LibraryItemThumbnail | null; | ||||
|   pretitle?: string | null; | ||||
|   title: string; | ||||
|   subtitle?: string | null; | ||||
|   digital: boolean; | ||||
|   thumbnail?: string | Image | null; | ||||
|   nature: 'Physical' | 'Digital'; | ||||
|   languages?: (string | Language)[] | null; | ||||
|   tags?: (string | Tag)[] | null; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     pretitle?: string | null; | ||||
|     title: string; | ||||
|     subtitle?: string | null; | ||||
|     description?: { | ||||
|       root: { | ||||
|         children: { | ||||
|           type: string; | ||||
|           version: number; | ||||
|           [k: string]: unknown; | ||||
|         }[]; | ||||
|         direction: ('ltr' | 'rtl') | null; | ||||
|         format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; | ||||
|         indent: number; | ||||
|         type: string; | ||||
|         version: number; | ||||
|       }; | ||||
|       [k: string]: unknown; | ||||
|     } | null; | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   gallery?: | ||||
|     | { | ||||
|         image?: string | LibraryItemGallery | null; | ||||
|         image: string | Image; | ||||
|         id?: string | null; | ||||
|       }[] | ||||
|     | null; | ||||
| @ -195,141 +208,136 @@ export interface LibraryItem { | ||||
|     typesetters?: (string | Recorder)[] | null; | ||||
|     coverEnabled?: boolean | null; | ||||
|     cover?: { | ||||
|       front?: string | LibraryItemScans | null; | ||||
|       spine?: string | LibraryItemScans | null; | ||||
|       back?: string | LibraryItemScans | null; | ||||
|       insideFront?: string | LibraryItemScans | null; | ||||
|       insideBack?: string | LibraryItemScans | null; | ||||
|       flapFront?: string | LibraryItemScans | null; | ||||
|       flapBack?: string | LibraryItemScans | null; | ||||
|       insideFlapFront?: string | LibraryItemScans | null; | ||||
|       insideFlapBack?: string | LibraryItemScans | null; | ||||
|       front?: string | Image | null; | ||||
|       spine?: string | Image | null; | ||||
|       back?: string | Image | null; | ||||
|       insideFront?: string | Image | null; | ||||
|       insideBack?: string | Image | null; | ||||
|       flapFront?: string | Image | null; | ||||
|       flapBack?: string | Image | null; | ||||
|       insideFlapFront?: string | Image | null; | ||||
|       insideFlapBack?: string | Image | null; | ||||
|     }; | ||||
|     dustjacketEnabled?: boolean | null; | ||||
|     dustjacket?: { | ||||
|       front?: string | LibraryItemScans | null; | ||||
|       spine?: string | LibraryItemScans | null; | ||||
|       back?: string | LibraryItemScans | null; | ||||
|       insideFront?: string | LibraryItemScans | null; | ||||
|       insideSpine?: string | LibraryItemScans | null; | ||||
|       insideBack?: string | LibraryItemScans | null; | ||||
|       flapFront?: string | LibraryItemScans | null; | ||||
|       flapBack?: string | LibraryItemScans | null; | ||||
|       insideFlapFront?: string | LibraryItemScans | null; | ||||
|       insideFlapBack?: string | LibraryItemScans | null; | ||||
|       front?: string | Image | null; | ||||
|       spine?: string | Image | null; | ||||
|       back?: string | Image | null; | ||||
|       insideFront?: string | Image | null; | ||||
|       insideSpine?: string | Image | null; | ||||
|       insideBack?: string | Image | null; | ||||
|       flapFront?: string | Image | null; | ||||
|       flapBack?: string | Image | null; | ||||
|       insideFlapFront?: string | Image | null; | ||||
|       insideFlapBack?: string | Image | null; | ||||
|     }; | ||||
|     obiEnabled?: boolean | null; | ||||
|     obi?: { | ||||
|       front?: string | LibraryItemScans | null; | ||||
|       spine?: string | LibraryItemScans | null; | ||||
|       back?: string | LibraryItemScans | null; | ||||
|       insideFront?: string | LibraryItemScans | null; | ||||
|       insideSpine?: string | LibraryItemScans | null; | ||||
|       insideBack?: string | LibraryItemScans | null; | ||||
|       flapFront?: string | LibraryItemScans | null; | ||||
|       flapBack?: string | LibraryItemScans | null; | ||||
|       insideFlapFront?: string | LibraryItemScans | null; | ||||
|       insideFlapBack?: string | LibraryItemScans | null; | ||||
|       front?: string | Image | null; | ||||
|       spine?: string | Image | null; | ||||
|       back?: string | Image | null; | ||||
|       insideFront?: string | Image | null; | ||||
|       insideSpine?: string | Image | null; | ||||
|       insideBack?: string | Image | null; | ||||
|       flapFront?: string | Image | null; | ||||
|       flapBack?: string | Image | null; | ||||
|       insideFlapFront?: string | Image | null; | ||||
|       insideFlapBack?: string | Image | null; | ||||
|     }; | ||||
|     pages?: | ||||
|       | { | ||||
|           page: number; | ||||
|           image: string | LibraryItemScans; | ||||
|           id?: string | null; | ||||
|         }[] | ||||
|       | null; | ||||
|     archiveFile?: (string | null) | File; | ||||
|   }; | ||||
|   textual?: { | ||||
|     subtype?: (string | null) | Key; | ||||
|     pageCount?: number | null; | ||||
|     bindingType?: ('Paperback' | 'Hardcover') | null; | ||||
|     pageOrder?: ('LeftToRight' | 'RightToLeft') | null; | ||||
|   }; | ||||
|   audio?: { | ||||
|     audioSubtype?: (string | null) | Key; | ||||
|     tracks?: | ||||
|       | { | ||||
|           title: string; | ||||
|           file: string | File; | ||||
|           image: string | Image; | ||||
|           id?: string | null; | ||||
|         }[] | ||||
|       | null; | ||||
|   }; | ||||
|   video?: { | ||||
|     subtype?: (string | null) | Key; | ||||
|   }; | ||||
|   game?: { | ||||
|     demo?: boolean | null; | ||||
|     platform?: (string | null) | Key; | ||||
|     audioLanguages?: (string | Language)[] | null; | ||||
|     subtitleLanguages?: (string | Language)[] | null; | ||||
|     interfacesLanguages?: (string | Language)[] | null; | ||||
|   }; | ||||
|   releaseDate?: string | null; | ||||
|   categories?: (string | Key)[] | null; | ||||
|   sizeEnabled?: boolean | null; | ||||
|   size?: { | ||||
|     width: number; | ||||
|     height: number; | ||||
|     thickness?: number | null; | ||||
|   }; | ||||
|   priceEnabled?: boolean | null; | ||||
|   price?: { | ||||
|     amount: number; | ||||
|     currency: string | Currency; | ||||
|   }; | ||||
|   translations?: | ||||
|     | { | ||||
|         language: string | Language; | ||||
|         description: { | ||||
|           root: { | ||||
|             children: { | ||||
|               type: string; | ||||
|               version: number; | ||||
|               [k: string]: unknown; | ||||
|             }[]; | ||||
|             direction: ('ltr' | 'rtl') | null; | ||||
|             format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; | ||||
|             indent: number; | ||||
|             type: string; | ||||
|             version: number; | ||||
|           }; | ||||
|           [k: string]: unknown; | ||||
|         }; | ||||
|         id?: string | null; | ||||
|       }[] | ||||
|     | null; | ||||
|   urls?: | ||||
|     | { | ||||
|         url: string; | ||||
|         id?: string | null; | ||||
|       }[] | ||||
|     | null; | ||||
|   parentItems?: (string | LibraryItem)[] | null; | ||||
|   subitems?: (string | LibraryItem)[] | null; | ||||
|   releaseDate?: string | null; | ||||
|   priceEnabled?: boolean | null; | ||||
|   price?: { | ||||
|     amount: number; | ||||
|     currency: string | Currency; | ||||
|   }; | ||||
|   sizeEnabled?: boolean | null; | ||||
|   size?: { | ||||
|     width: number; | ||||
|     height: number; | ||||
|     thickness?: number | null; | ||||
|   }; | ||||
|   weightEnabled?: boolean | null; | ||||
|   weight?: { | ||||
|     amount: number; | ||||
|   }; | ||||
|   pageInfoEnabled?: boolean | null; | ||||
|   pageInfo?: { | ||||
|     pageCount: number; | ||||
|     bindingType?: ('Paperback' | 'Hardcover') | null; | ||||
|     pageOrder?: ('Left to right' | 'Right to left') | null; | ||||
|   }; | ||||
|   folders?: (string | Folder)[] | null; | ||||
|   parentItems?: (string | Collectible)[] | null; | ||||
|   subitems?: (string | Collectible)[] | null; | ||||
|   contents?: | ||||
|     | { | ||||
|         content: string | Page; | ||||
|         pageStart?: number | null; | ||||
|         pageEnd?: number | null; | ||||
|         timeStart?: number | null; | ||||
|         timeEnd?: number | null; | ||||
|         note?: { | ||||
|           root: { | ||||
|             children: { | ||||
|               type: string; | ||||
|               version: number; | ||||
|               [k: string]: unknown; | ||||
|             }[]; | ||||
|             direction: ('ltr' | 'rtl') | null; | ||||
|             format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; | ||||
|             indent: number; | ||||
|             type: string; | ||||
|             version: number; | ||||
|           }; | ||||
|           [k: string]: unknown; | ||||
|         } | null; | ||||
|         content: | ||||
|           | { | ||||
|               relationTo: 'pages'; | ||||
|               value: string | Page; | ||||
|             } | ||||
|           | { | ||||
|               relationTo: 'generic-contents'; | ||||
|               value: string | GenericContent; | ||||
|             }; | ||||
|         range?: | ||||
|           | ( | ||||
|               | { | ||||
|                   start: number; | ||||
|                   end: number; | ||||
|                   id?: string | null; | ||||
|                   blockName?: string | null; | ||||
|                   blockType: 'pageRange'; | ||||
|                 } | ||||
|               | { | ||||
|                   start: string; | ||||
|                   end: string; | ||||
|                   id?: string | null; | ||||
|                   blockName?: string | null; | ||||
|                   blockType: 'timeRange'; | ||||
|                 } | ||||
|               | { | ||||
|                   translations?: | ||||
|                     | { | ||||
|                         language: string | Language; | ||||
|                         note: { | ||||
|                           root: { | ||||
|                             children: { | ||||
|                               type: string; | ||||
|                               version: number; | ||||
|                               [k: string]: unknown; | ||||
|                             }[]; | ||||
|                             direction: ('ltr' | 'rtl') | null; | ||||
|                             format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; | ||||
|                             indent: number; | ||||
|                             type: string; | ||||
|                             version: number; | ||||
|                           }; | ||||
|                           [k: string]: unknown; | ||||
|                         }; | ||||
|                         id?: string | null; | ||||
|                       }[] | ||||
|                     | null; | ||||
|                   id?: string | null; | ||||
|                   blockName?: string | null; | ||||
|                   blockType: 'other'; | ||||
|                 } | ||||
|             )[] | ||||
|           | null; | ||||
|         id?: string | null; | ||||
|       }[] | ||||
|     | null; | ||||
| @ -340,11 +348,10 @@ export interface LibraryItem { | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "library-items-thumbnails". | ||||
|  * via the `definition` "images". | ||||
|  */ | ||||
| export interface LibraryItemThumbnail { | ||||
| export interface Image { | ||||
|   id: string; | ||||
|   libraryItem?: (string | LibraryItem)[] | null; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
|   url?: string | null; | ||||
| @ -370,48 +377,40 @@ export interface LibraryItemThumbnail { | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|     square?: { | ||||
|       url?: string | null; | ||||
|       width?: number | null; | ||||
|       height?: number | null; | ||||
|       mimeType?: string | null; | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "library-items-gallery". | ||||
|  * via the `definition` "tags". | ||||
|  */ | ||||
| export interface LibraryItemGallery { | ||||
| export interface Tag { | ||||
|   id: string; | ||||
|   name?: string | null; | ||||
|   slug: string; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     name: string; | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   group: string | TagsGroup; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "tags-groups". | ||||
|  */ | ||||
| export interface TagsGroup { | ||||
|   id: string; | ||||
|   slug: string; | ||||
|   icon?: string | null; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     name: string; | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
|   url?: string | null; | ||||
|   filename?: string | null; | ||||
|   mimeType?: string | null; | ||||
|   filesize?: number | null; | ||||
|   width?: number | null; | ||||
|   height?: number | null; | ||||
|   sizes?: { | ||||
|     thumb?: { | ||||
|       url?: string | null; | ||||
|       width?: number | null; | ||||
|       height?: number | null; | ||||
|       mimeType?: string | null; | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|     small?: { | ||||
|       url?: string | null; | ||||
|       width?: number | null; | ||||
|       height?: number | null; | ||||
|       mimeType?: string | null; | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
| @ -468,86 +467,6 @@ export interface RecordersThumbnail { | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "library-items-scans". | ||||
|  */ | ||||
| export interface LibraryItemScans { | ||||
|   id: string; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
|   url?: string | null; | ||||
|   filename?: string | null; | ||||
|   mimeType?: string | null; | ||||
|   filesize?: number | null; | ||||
|   width?: number | null; | ||||
|   height?: number | null; | ||||
|   sizes?: { | ||||
|     thumb?: { | ||||
|       url?: string | null; | ||||
|       width?: number | null; | ||||
|       height?: number | null; | ||||
|       mimeType?: string | null; | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|     og?: { | ||||
|       url?: string | null; | ||||
|       width?: number | null; | ||||
|       height?: number | null; | ||||
|       mimeType?: string | null; | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|     medium?: { | ||||
|       url?: string | null; | ||||
|       width?: number | null; | ||||
|       height?: number | null; | ||||
|       mimeType?: string | null; | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|     large?: { | ||||
|       url?: string | null; | ||||
|       width?: number | null; | ||||
|       height?: number | null; | ||||
|       mimeType?: string | null; | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "files". | ||||
|  */ | ||||
| export interface File { | ||||
|   id: string; | ||||
|   filename: string; | ||||
|   type: 'LibraryScans' | 'LibrarySoundtracks' | 'ContentVideo' | 'ContentAudio'; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "keys". | ||||
|  */ | ||||
| export interface Key { | ||||
|   id: string; | ||||
|   name: string; | ||||
|   type: | ||||
|     | 'Contents' | ||||
|     | 'LibraryAudio' | ||||
|     | 'LibraryVideo' | ||||
|     | 'LibraryTextual' | ||||
|     | 'LibraryGroup' | ||||
|     | 'Library' | ||||
|     | 'Weapons' | ||||
|     | 'GamePlatforms' | ||||
|     | 'Categories' | ||||
|     | 'Wordings'; | ||||
|   translations?: CategoryTranslations; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "currencies". | ||||
| @ -561,7 +480,7 @@ export interface Currency { | ||||
|  */ | ||||
| export interface Page { | ||||
|   id: string; | ||||
|   type: 'Content' | 'Article' | 'Generic'; | ||||
|   type: 'Content' | 'Post' | 'Generic'; | ||||
|   slug: string; | ||||
|   thumbnail?: string | Image | null; | ||||
|   tags?: (string | Tag)[] | null; | ||||
| @ -608,7 +527,7 @@ export interface Page { | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   folders?: (string | Folder)[] | null; | ||||
|   collectibles?: (string | LibraryItem)[] | null; | ||||
|   collectibles?: (string | Collectible)[] | null; | ||||
|   updatedBy: string | Recorder; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| @ -616,71 +535,16 @@ export interface Page { | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "images". | ||||
|  * via the `definition` "generic-contents". | ||||
|  */ | ||||
| export interface Image { | ||||
| export interface GenericContent { | ||||
|   id: string; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
|   url?: string | null; | ||||
|   filename?: string | null; | ||||
|   mimeType?: string | null; | ||||
|   filesize?: number | null; | ||||
|   width?: number | null; | ||||
|   height?: number | null; | ||||
|   sizes?: { | ||||
|     thumb?: { | ||||
|       url?: string | null; | ||||
|       width?: number | null; | ||||
|       height?: number | null; | ||||
|       mimeType?: string | null; | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|     og?: { | ||||
|       url?: string | null; | ||||
|       width?: number | null; | ||||
|       height?: number | null; | ||||
|       mimeType?: string | null; | ||||
|       filesize?: number | null; | ||||
|       filename?: string | null; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "tags". | ||||
|  */ | ||||
| export interface Tag { | ||||
|   id: string; | ||||
|   name?: string | null; | ||||
|   slug: string; | ||||
|   translations?: | ||||
|     | { | ||||
|         language: string | Language; | ||||
|         name: string; | ||||
|         id?: string | null; | ||||
|       }[] | ||||
|     | null; | ||||
|   group: string | TagsGroup; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `Config`'s JSON-Schema | ||||
|  * via the `definition` "tags-groups". | ||||
|  */ | ||||
| export interface TagsGroup { | ||||
|   id: string; | ||||
|   slug: string; | ||||
|   icon?: string | null; | ||||
|   translations?: | ||||
|     | { | ||||
|         language: string | Language; | ||||
|         name: string; | ||||
|         id?: string | null; | ||||
|       }[] | ||||
|     | null; | ||||
|   name: string; | ||||
|   translations: { | ||||
|     language: string | Language; | ||||
|     name: string; | ||||
|     id?: string | null; | ||||
|   }[]; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| @ -786,10 +650,8 @@ export interface Weapon { | ||||
|   id: string; | ||||
|   slug: string; | ||||
|   thumbnail?: string | WeaponsThumbnail | null; | ||||
|   type: string | Key; | ||||
|   group?: (string | null) | WeaponsGroup; | ||||
|   appearances: { | ||||
|     categories: (string | Key)[]; | ||||
|     translations: { | ||||
|       language: string | Language; | ||||
|       sourceLanguage: string | Language; | ||||
| @ -1004,7 +866,7 @@ export interface VideosChannel { | ||||
| export interface Wording { | ||||
|   id: string; | ||||
|   name: string; | ||||
|   translations?: CategoryTranslations; | ||||
|   translations: CategoryTranslations; | ||||
|   updatedAt: string; | ||||
|   createdAt: string; | ||||
| } | ||||
| @ -1047,7 +909,7 @@ export interface PayloadMigration { | ||||
|  * via the `definition` "SpacerBlock". | ||||
|  */ | ||||
| export interface SpacerBlock { | ||||
|   size: 'Small' | 'Medium' | 'Large' | 'XLarge'; | ||||
|   size: 'Small' | 'Medium' | 'Large' | 'Extra Large'; | ||||
|   blockType: 'spacerBlock'; | ||||
| } | ||||
| /** | ||||
|  | ||||
							
								
								
									
										28
									
								
								src/utils/endpoints.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/utils/endpoints.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| import { TagGroup } from "../sdk"; | ||||
| import { Tag } from "../types/collections"; | ||||
| import { isPayloadArrayType, isPayloadType } from "./asserts"; | ||||
| 
 | ||||
| export const convertTagsToGroups = (tags: (string | Tag)[] | null | undefined): TagGroup[] => { | ||||
|   if (!isPayloadArrayType(tags)) { | ||||
|     return []; | ||||
|   } | ||||
| 
 | ||||
|   const groups: TagGroup[] = []; | ||||
| 
 | ||||
|   tags.forEach(({ group, slug }) => { | ||||
|     if (isPayloadType(group)) { | ||||
|       const existingGroup = groups.find((existingGroup) => existingGroup.slug === group.slug); | ||||
|       if (existingGroup) { | ||||
|         existingGroup.values.push(slug); | ||||
|       } else { | ||||
|         groups.push({ | ||||
|           slug: group.slug, | ||||
|           icon: group.icon ?? "material-symbols:category-outline", | ||||
|           values: [slug], | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   return groups; | ||||
| }; | ||||
| @ -1,28 +1,8 @@ | ||||
| import payload, { GeneratedTypes } from "payload"; | ||||
| import { Collections, KeysTypes } from "../constants"; | ||||
| import { Collections } from "../constants"; | ||||
| import { StrapiImage } from "../types/strapi"; | ||||
| import { isDefined } from "./asserts"; | ||||
| 
 | ||||
| export const findWeaponType = async (name: string): Promise<string> => { | ||||
|   const key = await payload.find({ | ||||
|     collection: Collections.Keys, | ||||
|     where: { name: { equals: name }, type: { equals: KeysTypes.Weapons } }, | ||||
|     depth: 0, | ||||
|   }); | ||||
|   if (!key.docs[0]) throw new Error(`Weapon type ${name} wasn't found`); | ||||
|   return key.docs[0].id; | ||||
| }; | ||||
| 
 | ||||
| export const findCategory = async (name: string): Promise<string> => { | ||||
|   const key = await payload.find({ | ||||
|     collection: Collections.Keys, | ||||
|     where: { name: { equals: name }, type: { equals: KeysTypes.Categories } }, | ||||
|     depth: 0, | ||||
|   }); | ||||
|   if (!key.docs[0]) throw new Error(`Category ${name} wasn't found`); | ||||
|   return key.docs[0].id; | ||||
| }; | ||||
| 
 | ||||
| export const findRecorder = async (name: string): Promise<string> => { | ||||
|   const recorder = await payload.find({ | ||||
|     collection: Collections.Recorders, | ||||
|  | ||||
| @ -1,29 +0,0 @@ | ||||
| import { TagGroup } from "../sdk"; | ||||
| import { Tag } from "../types/collections"; | ||||
| import { isPayloadArrayType, isPayloadType } from "./asserts"; | ||||
| 
 | ||||
| export const convertTagsToGroups = (tags: (string | Tag)[] | null | undefined): TagGroup[] => { | ||||
|     if (!isPayloadArrayType(tags)) { | ||||
|       return []; | ||||
|     } | ||||
|    | ||||
|     const groups: TagGroup[] = []; | ||||
|    | ||||
|     tags.forEach(({ group, slug }) => { | ||||
|       if (isPayloadType(group)) { | ||||
|         const existingGroup = groups.find((existingGroup) => existingGroup.slug === group.slug); | ||||
|         if (existingGroup) { | ||||
|           existingGroup.values.push(slug); | ||||
|         } else { | ||||
|           groups.push({ | ||||
|             slug: group.slug, | ||||
|             icon: group.icon ?? "material-symbols:category-outline", | ||||
|             values: [slug], | ||||
|           }); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|    | ||||
|     return groups; | ||||
|   }; | ||||
|    | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint