Removed library and keys collections

This commit is contained in:
DrMint 2024-03-04 10:51:47 +01:00
parent e9fbb0a3b7
commit b06918b346
33 changed files with 537 additions and 2164 deletions

View File

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

View File

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

View 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;
};

View File

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

View File

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

View File

@ -35,7 +35,7 @@ export const getBySlugEndpoint = createGetByEndpoint(
return [];
}
switch (relationTo) {
case "library-items":
case "collectibles":
return [{ relationTo, value }];
case "pages":
return [{ relationTo, value }];

View File

@ -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,
},

View File

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

View File

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

View File

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

View File

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

View File

@ -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>
);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 },

View File

@ -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,

View File

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

View File

@ -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 = {

View File

@ -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,

View File

@ -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];

View File

@ -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];

View File

@ -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.";

View File

@ -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,

View File

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

View File

@ -35,41 +35,35 @@ export type RecorderBiographies =
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "CategoryTranslations".
*/
export type CategoryTranslations =
| {
export type CategoryTranslations = {
language: string | Language;
name: string;
id?: string | null;
}[]
| 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,152 +164,21 @@ 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;
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;
digital: boolean;
gallery?:
| {
image?: string | LibraryItemGallery | null;
id?: string | null;
}[]
| null;
scansEnabled?: boolean | null;
scans?: {
scanners: (string | Recorder)[];
cleaners: (string | Recorder)[];
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;
};
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;
};
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;
};
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;
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;
contents?:
| {
content: string | Page;
pageStart?: number | null;
pageEnd?: number | null;
timeStart?: number | null;
timeEnd?: number | null;
note?: {
description?: {
root: {
children: {
type: string;
@ -331,6 +194,151 @@ export interface LibraryItem {
[k: string]: unknown;
} | null;
id?: string | null;
}[];
gallery?:
| {
image: string | Image;
id?: string | null;
}[]
| null;
scansEnabled?: boolean | null;
scans?: {
scanners: (string | Recorder)[];
cleaners: (string | Recorder)[];
typesetters?: (string | Recorder)[] | null;
coverEnabled?: boolean | null;
cover?: {
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 | 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 | 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 | Image;
id?: string | null;
}[]
| null;
};
urls?:
| {
url: string;
id?: string | null;
}[]
| 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:
| {
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;
updatedBy: string | Recorder;
@ -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?:
| {
name: 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;
}[];
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
View 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;
};

View File

@ -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,

View File

@ -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;
};