Added website config collection

This commit is contained in:
DrMint 2024-04-05 17:02:06 +02:00
parent af7c5ee5a0
commit 39e2642c55
12 changed files with 167 additions and 130 deletions

View File

@ -13,7 +13,7 @@
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" dist/ && copyfiles -u 1 \"src/sdk.ts\" dist/ && copyfiles -u 1 \"src/constants.ts\" dist/ && copyfiles -u 1 \"src/types/collections.ts\" dist/",
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
"generate:graphQLSchema": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:graphQLSchema",
"unused-exports": "ts-unused-exports ./tsconfig.json --excludePathsFromReport='src/payload.config.ts;src/sdk.ts;src/types/collections.ts'",
"unused-exports": "ts-unused-exports ./tsconfig.json --excludePathsFromReport='src/payload.config.ts;src/constants.ts;src/sdk.ts;src/types/collections.ts'",
"prettier": "prettier --list-different --end-of-line auto --write src",
"tsc": "tsc --noEmit",
"precommit": "npm run generate:types && npm run prettier && npm run unused-exports && npm run tsc",

View File

@ -1,9 +0,0 @@
import { RecordersRoles } from "../../constants";
import { Recorder } from "../../types/collections";
import { EndpointAccess } from "../../types/payload";
import { isDefined, isUndefined } from "../../utils/asserts";
export const mustBeAdmin: EndpointAccess<Recorder> = ({ user }) => {
if (isUndefined(user)) return false;
return isDefined(user.role) && user.role.includes(RecordersRoles.Admin);
};

View File

@ -1,46 +0,0 @@
import { GlobalConfig } from "payload/types";
import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin";
import { CollectionGroups, Collections } from "../../constants";
import { imageField } from "../../fields/imageField/imageField";
import { rowField } from "../../fields/rowField/rowField";
import { getAllEndpoint } from "./endpoints/getAllEndpoint";
const fields = {
folders: "folders",
darkThumbnail: "darkThumbnail",
lightThumbnail: "lightThumbnail",
folder: "folder",
icon: "icon",
} as const satisfies Record<string, string>;
export const HomeFolders: GlobalConfig = {
slug: Collections.HomeFolders,
typescript: { interface: "HomeFolder" },
admin: {
group: CollectionGroups.Meta,
},
access: { update: mustBeAdmin },
endpoints: [getAllEndpoint],
fields: [
{
name: fields.folders,
admin: {
description:
"These will be the folders displayed on the home page, under the Library section.",
},
type: "array",
fields: [
rowField([
imageField({ name: fields.lightThumbnail, relationTo: Collections.Images }),
imageField({ name: fields.darkThumbnail, relationTo: Collections.Images }),
{
name: fields.folder,
type: "relationship",
relationTo: Collections.Folders,
required: true,
},
]),
],
},
],
};

View File

@ -1,47 +0,0 @@
import payload from "payload";
import { Collections } from "../../../constants";
import { EndpointHomeFolder } from "../../../sdk";
import { Folder } from "../../../types/collections";
import { CollectionEndpoint } from "../../../types/payload";
import { isPayloadType, isValidPayloadImage } from "../../../utils/asserts";
import { convertFolderToPreview } from "../../Folders/endpoints/getBySlugEndpoint";
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 homeFolders = await payload.findGlobal({
slug: Collections.HomeFolders,
});
const result =
homeFolders.folders?.flatMap<EndpointHomeFolder>(
({ folder, darkThumbnail, lightThumbnail }) => {
if (!isPayloadType(folder)) return [];
if (isEmptyFolder(folder)) return [];
return [
{
...(isValidPayloadImage(darkThumbnail) ? { darkThumbnail } : {}),
...(isValidPayloadImage(lightThumbnail) ? { lightThumbnail } : {}),
...convertFolderToPreview(folder),
},
];
}
) ?? [];
res.status(200).json(result);
},
};
const isEmptyFolder = ({ sections, files }: Folder): boolean =>
(!files || files.length === 0) && (!sections || sections.length === 0);

View File

@ -0,0 +1,77 @@
import { GlobalConfig } from "payload/types";
import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin";
import { CollectionGroups, Collections } from "../../constants";
import { imageField } from "../../fields/imageField/imageField";
import { rowField } from "../../fields/rowField/rowField";
import { getConfigEndpoint } from "./endpoints/getConfigEndpoint";
const fields = {
homeFolders: "homeFolders",
homeFoldersDarkThumbnail: "darkThumbnail",
homeFoldersLightThumbnail: "lightThumbnail",
homeFoldersFolder: "folder",
eras: "eras",
name: "name",
timeline: "timeline",
erasStartingYear: "startingYear",
erasEndingYear: "endingYear",
erasWording: "name",
timelineBreaks: "breaks",
} as const satisfies Record<string, string>;
export const WebsiteConfig: GlobalConfig = {
slug: Collections.WebsiteConfig,
typescript: { interface: "WebsiteConfig" },
admin: {
group: CollectionGroups.Meta,
},
access: { update: mustBeAdmin, read: mustBeAdmin },
endpoints: [getConfigEndpoint],
fields: [
{
name: fields.homeFolders,
admin: {
description:
"These will be the folders displayed on the home page, under the Library section.",
},
type: "array",
fields: [
rowField([
imageField({ name: fields.homeFoldersLightThumbnail, relationTo: Collections.Images }),
imageField({ name: fields.homeFoldersDarkThumbnail, relationTo: Collections.Images }),
{
name: fields.homeFoldersFolder,
type: "relationship",
relationTo: Collections.Folders,
required: true,
},
]),
],
},
{
name: fields.timeline,
type: "group",
fields: [
{
name: fields.timelineBreaks,
type: "number",
hasMany: true,
},
{
name: fields.eras,
type: "array",
fields: [
{
name: fields.erasWording,
type: "relationship",
relationTo: Collections.Wordings,
required: true,
},
{ name: fields.erasStartingYear, type: "number", required: true, min: 0 },
{ name: fields.erasEndingYear, type: "number", required: true, min: 0 },
],
},
],
},
],
};

View File

@ -0,0 +1,51 @@
import payload from "payload";
import { Collections } from "../../../constants";
import { EndpointWebsiteConfig } from "../../../sdk";
import { CollectionEndpoint } from "../../../types/payload";
import { isPayloadType, isValidPayloadImage } from "../../../utils/asserts";
import { convertFolderToPreview } from "../../Folders/endpoints/getBySlugEndpoint";
export const getConfigEndpoint: CollectionEndpoint = {
method: "get",
path: "/config",
handler: async (req, res) => {
if (!req.user) {
return res.status(403).send({
errors: [
{
message: "You are not allowed to perform this action.",
},
],
});
}
const { homeFolders, timeline } = await payload.findGlobal({
slug: Collections.WebsiteConfig,
});
const endpointWebsiteConfig: EndpointWebsiteConfig = {
homeFolders:
homeFolders?.flatMap(({ folder, darkThumbnail, lightThumbnail }) => {
if (!isPayloadType(folder)) return [];
return {
...convertFolderToPreview(folder),
...(isValidPayloadImage(darkThumbnail) ? { darkThumbnail } : {}),
...(isValidPayloadImage(lightThumbnail) ? { lightThumbnail } : {}),
};
}) ?? [],
timeline: {
breaks: timeline?.breaks ?? [],
eras:
timeline?.eras?.flatMap(({ endingYear, name, startingYear }) => {
if (!isPayloadType(name)) return [];
return {
name: isPayloadType(name) ? name.name : name,
startingYear,
endingYear,
};
}) ?? [],
},
};
res.status(200).json(endpointWebsiteConfig);
},
};

View File

@ -58,7 +58,6 @@ export const Wordings: CollectionConfig = buildCollectionConfig({
name: fields.translations,
minRows: 1,
required: true,
interfaceName: "CategoryTranslations",
admin: {
useAsTitle: fields.translationsName,
},

View File

@ -16,7 +16,7 @@ export enum Collections {
Wordings = "wordings",
Collectibles = "collectibles",
GenericContents = "generic-contents",
HomeFolders = "home-folders",
WebsiteConfig = "website-config",
Videos = "videos",
VideosSubtitles = "videos-subtitles",
VideosChannels = "videos-channels",

View File

@ -9,7 +9,6 @@ import { Collectibles } from "./collections/Collectibles/Collectibles";
import { Currencies } from "./collections/Currencies/Currencies";
import { Folders } from "./collections/Folders/Folders";
import { GenericContents } from "./collections/GenericContents/GenericContents";
import { HomeFolders } from "./collections/HomeFolders/HomeFolders";
import { Images } from "./collections/Images/Images";
import { Languages } from "./collections/Languages/Languages";
import { Pages } from "./collections/Pages/Pages";
@ -21,6 +20,7 @@ import { Videos } from "./collections/Videos/Videos";
import { VideosChannels } from "./collections/VideosChannels/VideosChannels";
import { VideosSubtitles } from "./collections/VideosSubtitles/VideosSubtitles";
import { MediaThumbnails } from "./collections/VideosThumbnails/VideosThumbnails";
import { WebsiteConfig } from "./collections/WebsiteConfig/WebsiteConfig";
import { Wordings } from "./collections/Wordings/Wordings";
import { Icon } from "./components/Icon";
import { Logo } from "./components/Logo";
@ -75,7 +75,7 @@ export default buildConfig({
db: mongooseAdapter({
url: process.env.MONGODB_URI ?? "",
}),
globals: [HomeFolders],
globals: [WebsiteConfig],
telemetry: false,
typescript: {
outputFile: path.resolve(__dirname, "types/collections.ts"),

View File

@ -129,9 +129,19 @@ export type EndpointFolder = EndpointFolderPreview & {
parentPages: EndpointSource[];
};
export type EndpointHomeFolder = EndpointFolderPreview & {
export type EndpointWebsiteConfig = {
homeFolders: (EndpointFolderPreview & {
lightThumbnail?: PayloadImage;
darkThumbnail?: PayloadImage;
})[];
timeline: {
breaks: number[];
eras: {
startingYear: number;
endingYear: number;
name: string;
}[];
};
};
export type EndpointRecorder = {
@ -322,8 +332,8 @@ export type PayloadImage = {
};
export const payload = {
getHomeFolders: async (): Promise<EndpointHomeFolder[]> =>
await (await request(payloadApiUrl(Collections.HomeFolders, `all`, true))).json(),
getConfig: async (): Promise<EndpointWebsiteConfig> =>
await (await request(payloadApiUrl(Collections.WebsiteConfig, `config`, true))).json(),
getFolder: async (slug: string): Promise<EndpointFolder> =>
await (await request(payloadApiUrl(Collections.Folders, `slug/${slug}`))).json(),
getLanguages: async (): Promise<Language[]> =>

View File

@ -6,16 +6,6 @@
* and re-run `payload generate:types` to regenerate this file.
*/
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "CategoryTranslations".
*/
export type CategoryTranslations = {
language: string | Language;
name: string;
id?: string | null;
}[];
export interface Config {
collections: {
pages: Page;
@ -40,7 +30,7 @@ export interface Config {
"payload-migrations": PayloadMigration;
};
globals: {
config: Config1;
"website-config": WebsiteConfig;
};
}
/**
@ -802,7 +792,11 @@ export interface PageBlock {
export interface Wording {
id: string;
name: string;
translations: CategoryTranslations;
translations: {
language: string | Language;
name: string;
id?: string | null;
}[];
updatedAt: string;
createdAt: string;
}
@ -842,11 +836,11 @@ export interface PayloadMigration {
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "config".
* via the `definition` "website-config".
*/
export interface Config1 {
export interface WebsiteConfig {
id: string;
folders?:
homeFolders?:
| {
lightThumbnail?: string | Image | null;
darkThumbnail?: string | Image | null;
@ -854,6 +848,17 @@ export interface Config1 {
id?: string | null;
}[]
| null;
timeline?: {
breaks?: number[] | null;
eras?:
| {
name: string | Wording;
startingYear: number;
endingYear: number;
id?: string | null;
}[]
| null;
};
updatedAt?: string | null;
createdAt?: string | null;
}

View File

@ -1,6 +1,3 @@
import { Endpoint } from "payload/config";
import { PayloadRequest } from "payload/types";
export type CollectionEndpoint = Omit<Endpoint, "root">;
export type EndpointAccess<U> = (req: PayloadRequest<U>) => boolean;