feat: initial payload scaffolding
This commit is contained in:
parent
e4a367489f
commit
4d639387f4
34 changed files with 948 additions and 339 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"singleQuote": true,
|
"singleQuote": false,
|
||||||
"trailingComma": "all",
|
"trailingComma": "all",
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"semi": false
|
"semi": true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
.vscode/extensions.json
vendored
5
.vscode/extensions.json
vendored
|
|
@ -1,3 +1,6 @@
|
||||||
{
|
{
|
||||||
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
|
"recommendations": [
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"esbenp.prettier-vscode"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
.vscode/launch.json
vendored
8
.vscode/launch.json
vendored
|
|
@ -9,8 +9,12 @@
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/node_modules/next/dist/bin/next",
|
"program": "${workspaceFolder}/node_modules/next/dist/bin/next",
|
||||||
"runtimeArgs": ["--inspect"],
|
"runtimeArgs": [
|
||||||
"skipFiles": ["<node_internals>/**"],
|
"--inspect"
|
||||||
|
],
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
"serverReadyAction": {
|
"serverReadyAction": {
|
||||||
"action": "debugWithChrome",
|
"action": "debugWithChrome",
|
||||||
"killOnServerStop": true,
|
"killOnServerStop": true,
|
||||||
|
|
|
||||||
38
README.md
38
README.md
|
|
@ -4,7 +4,8 @@ This template comes configured with the bare minimum to get started on anything
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
This template can be deployed directly from our Cloud hosting and it will setup MongoDB and cloud S3 object storage for media.
|
This template can be deployed directly from our Cloud hosting and it will setup MongoDB and cloud S3 object storage for
|
||||||
|
media.
|
||||||
|
|
||||||
## Quick Start - local setup
|
## Quick Start - local setup
|
||||||
|
|
||||||
|
|
@ -12,21 +13,27 @@ To spin up this template locally, follow these steps:
|
||||||
|
|
||||||
### Clone
|
### Clone
|
||||||
|
|
||||||
After you click the `Deploy` button above, you'll want to have standalone copy of this repo on your machine. If you've already cloned this repo, skip to [Development](#development).
|
After you click the `Deploy` button above, you'll want to have standalone copy of this repo on your machine. If you've
|
||||||
|
already cloned this repo, skip to [Development](#development).
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
1. First [clone the repo](#clone) if you have not done so already
|
1. First [clone the repo](#clone) if you have not done so already
|
||||||
2. `cd my-project && cp .env.example .env` to copy the example environment variables. You'll need to add the `MONGODB_URI` from your Cloud project to your `.env` if you want to use S3 storage and the MongoDB database that was created for you.
|
2. `cd my-project && cp .env.example .env` to copy the example environment variables. You'll need to add the
|
||||||
|
`MONGODB_URI` from your Cloud project to your `.env` if you want to use S3 storage and the MongoDB database that was
|
||||||
|
created for you.
|
||||||
|
|
||||||
3. `pnpm install && pnpm dev` to install dependencies and start the dev server
|
3. `pnpm install && pnpm dev` to install dependencies and start the dev server
|
||||||
4. open `http://localhost:3000` to open the app in your browser
|
4. open `http://localhost:3000` to open the app in your browser
|
||||||
|
|
||||||
That's it! Changes made in `./src` will be reflected in your app. Follow the on-screen instructions to login and create your first admin user. Then check out [Production](#production) once you're ready to build and serve your app, and [Deployment](#deployment) when you're ready to go live.
|
That's it! Changes made in `./src` will be reflected in your app. Follow the on-screen instructions to login and create
|
||||||
|
your first admin user. Then check out [Production](#production) once you're ready to build and serve your app,
|
||||||
|
and [Deployment](#deployment) when you're ready to go live.
|
||||||
|
|
||||||
#### Docker (Optional)
|
#### Docker (Optional)
|
||||||
|
|
||||||
If you prefer to use Docker for local development instead of a local MongoDB instance, the provided docker-compose.yml file can be used.
|
If you prefer to use Docker for local development instead of a local MongoDB instance, the provided docker-compose.yml
|
||||||
|
file can be used.
|
||||||
|
|
||||||
To do so, follow these steps:
|
To do so, follow these steps:
|
||||||
|
|
||||||
|
|
@ -40,28 +47,35 @@ The Payload config is tailored specifically to the needs of most websites. It is
|
||||||
|
|
||||||
### Collections
|
### Collections
|
||||||
|
|
||||||
See the [Collections](https://payloadcms.com/docs/configuration/collections) docs for details on how to extend this functionality.
|
See the [Collections](https://payloadcms.com/docs/configuration/collections) docs for details on how to extend this
|
||||||
|
functionality.
|
||||||
|
|
||||||
- #### Users (Authentication)
|
- #### Users (Authentication)
|
||||||
|
|
||||||
Users are auth-enabled collections that have access to the admin panel.
|
Users are auth-enabled collections that have access to the admin panel.
|
||||||
|
|
||||||
For additional help, see the official [Auth Example](https://github.com/payloadcms/payload/tree/main/examples/auth) or the [Authentication](https://payloadcms.com/docs/authentication/overview#authentication-overview) docs.
|
For additional help, see the official [Auth Example](https://github.com/payloadcms/payload/tree/main/examples/auth) or
|
||||||
|
the [Authentication](https://payloadcms.com/docs/authentication/overview#authentication-overview) docs.
|
||||||
|
|
||||||
- #### Media
|
- #### Media
|
||||||
|
|
||||||
This is the uploads enabled collection. It features pre-configured sizes, focal point and manual resizing to help you manage your pictures.
|
This is the uploads enabled collection. It features pre-configured sizes, focal point and manual resizing to help you
|
||||||
|
manage your pictures.
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
Alternatively, you can use [Docker](https://www.docker.com) to spin up this template locally. To do so, follow these steps:
|
Alternatively, you can use [Docker](https://www.docker.com) to spin up this template locally. To do so, follow these
|
||||||
|
steps:
|
||||||
|
|
||||||
1. Follow [steps 1 and 2 from above](#development), the docker-compose file will automatically use the `.env` file in your project root
|
1. Follow [steps 1 and 2 from above](#development), the docker-compose file will automatically use the `.env` file in
|
||||||
|
your project root
|
||||||
1. Next run `docker-compose up`
|
1. Next run `docker-compose up`
|
||||||
1. Follow [steps 4 and 5 from above](#development) to login and create your first admin user
|
1. Follow [steps 4 and 5 from above](#development) to login and create your first admin user
|
||||||
|
|
||||||
That's it! The Docker instance will help you get up and running quickly while also standardizing the development environment across your teams.
|
That's it! The Docker instance will help you get up and running quickly while also standardizing the development
|
||||||
|
environment across your teams.
|
||||||
|
|
||||||
## Questions
|
## Questions
|
||||||
|
|
||||||
If you have any issues or questions, reach out to us on [Discord](https://discord.com/invite/payload) or start a [GitHub discussion](https://github.com/payloadcms/payload/discussions).
|
If you have any issues or questions, reach out to us on [Discord](https://discord.com/invite/payload) or start
|
||||||
|
a [GitHub discussion](https://github.com/payloadcms/payload/discussions).
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,38 @@
|
||||||
import { dirname } from 'path'
|
import { dirname } from "path";
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from "url";
|
||||||
import { FlatCompat } from '@eslint/eslintrc'
|
import { FlatCompat } from "@eslint/eslintrc";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url)
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename)
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
const compat = new FlatCompat({
|
const compat = new FlatCompat({
|
||||||
baseDirectory: __dirname,
|
baseDirectory: __dirname,
|
||||||
})
|
});
|
||||||
|
|
||||||
const eslintConfig = [
|
const eslintConfig = [
|
||||||
...compat.extends('next/core-web-vitals', 'next/typescript'),
|
...compat.extends("next/core-web-vitals", "next/typescript"),
|
||||||
{
|
{
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/ban-ts-comment': 'warn',
|
"@typescript-eslint/ban-ts-comment": "warn",
|
||||||
'@typescript-eslint/no-empty-object-type': 'warn',
|
"@typescript-eslint/no-empty-object-type": "warn",
|
||||||
'@typescript-eslint/no-explicit-any': 'warn',
|
"@typescript-eslint/no-explicit-any": "warn",
|
||||||
'@typescript-eslint/no-unused-vars': [
|
"@typescript-eslint/no-unused-vars": [
|
||||||
'warn',
|
"warn",
|
||||||
{
|
{
|
||||||
vars: 'all',
|
vars: "all",
|
||||||
args: 'after-used',
|
args: "after-used",
|
||||||
ignoreRestSiblings: false,
|
ignoreRestSiblings: false,
|
||||||
argsIgnorePattern: '^_',
|
argsIgnorePattern: "^_",
|
||||||
varsIgnorePattern: '^_',
|
varsIgnorePattern: "^_",
|
||||||
destructuredArrayIgnorePattern: '^_',
|
destructuredArrayIgnorePattern: "^_",
|
||||||
caughtErrorsIgnorePattern: '^(_|ignore)',
|
caughtErrorsIgnorePattern: "^(_|ignore)",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ignores: ['.next/'],
|
ignores: [".next/"],
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
export default eslintConfig
|
export default eslintConfig;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
import { withPayload } from '@payloadcms/next/withPayload'
|
import { withPayload } from "@payloadcms/next/withPayload";
|
||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
// Your Next.js config here
|
// Your Next.js config here
|
||||||
webpack: (webpackConfig) => {
|
webpack: (webpackConfig) => {
|
||||||
webpackConfig.resolve.extensionAlias = {
|
webpackConfig.resolve.extensionAlias = {
|
||||||
'.cjs': ['.cts', '.cjs'],
|
".cjs": [".cts", ".cjs"],
|
||||||
'.js': ['.ts', '.tsx', '.js', '.jsx'],
|
".js": [".ts", ".tsx", ".js", ".jsx"],
|
||||||
'.mjs': ['.mts', '.mjs'],
|
".mjs": [".mts", ".mjs"],
|
||||||
}
|
};
|
||||||
|
|
||||||
return webpackConfig
|
return webpackConfig;
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default withPayload(nextConfig, { devBundleServerPackages: false })
|
export default withPayload(nextConfig, { devBundleServerPackages: false });
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
import { defineConfig, devices } from '@playwright/test'
|
import { defineConfig, devices } from "@playwright/test";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read environment variables from file.
|
* Read environment variables from file.
|
||||||
* https://github.com/motdotla/dotenv
|
* https://github.com/motdotla/dotenv
|
||||||
*/
|
*/
|
||||||
import 'dotenv/config'
|
import "dotenv/config";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See https://playwright.dev/docs/test-configuration.
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
*/
|
*/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
testDir: './tests/e2e',
|
testDir: "./tests/e2e",
|
||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: !!process.env.CI,
|
||||||
/* Retry on CI only */
|
/* Retry on CI only */
|
||||||
|
|
@ -18,24 +18,24 @@ export default defineConfig({
|
||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests on CI. */
|
||||||
workers: process.env.CI ? 1 : undefined,
|
workers: process.env.CI ? 1 : undefined,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: 'html',
|
reporter: "html",
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
// baseURL: 'http://localhost:3000',
|
// baseURL: 'http://localhost:3000',
|
||||||
|
|
||||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
trace: 'on-first-retry',
|
trace: "on-first-retry",
|
||||||
},
|
},
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
name: 'chromium',
|
name: "chromium",
|
||||||
use: { ...devices['Desktop Chrome'] },
|
use: { ...devices["Desktop Chrome"] },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'pnpm dev',
|
command: "pnpm dev",
|
||||||
reuseExistingServer: true,
|
reuseExistingServer: true,
|
||||||
url: 'http://localhost:3000',
|
url: "http://localhost:3000",
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import React from 'react'
|
import React from "react";
|
||||||
import './styles.css'
|
import "./styles.css";
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
description: 'A blank template using Payload in a Next.js app.',
|
description: "A blank template using Payload in a Next.js app.",
|
||||||
title: 'Payload Blank Template',
|
title: "Payload Blank Template",
|
||||||
}
|
};
|
||||||
|
|
||||||
export default async function RootLayout(props: { children: React.ReactNode }) {
|
export default async function RootLayout(props: { children: React.ReactNode }) {
|
||||||
const { children } = props
|
const { children } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
@ -15,5 +15,5 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
|
||||||
<main>{children}</main>
|
<main>{children}</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
import { headers as getHeaders } from 'next/headers.js'
|
import { headers as getHeaders } from "next/headers.js";
|
||||||
import Image from 'next/image'
|
import Image from "next/image";
|
||||||
import { getPayload } from 'payload'
|
import { getPayload } from "payload";
|
||||||
import React from 'react'
|
import React from "react";
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
import config from '@/payload.config'
|
import config from "@/payload.config";
|
||||||
import './styles.css'
|
import "./styles.css";
|
||||||
|
|
||||||
export default async function HomePage() {
|
export default async function HomePage() {
|
||||||
const headers = await getHeaders()
|
const headers = await getHeaders();
|
||||||
const payloadConfig = await config
|
const payloadConfig = await config;
|
||||||
const payload = await getPayload({ config: payloadConfig })
|
const payload = await getPayload({ config: payloadConfig });
|
||||||
const { user } = await payload.auth({ headers })
|
const { user } = await payload.auth({ headers });
|
||||||
|
|
||||||
const fileURL = `vscode://file/${fileURLToPath(import.meta.url)}`
|
const fileURL = `webstorm://file/${fileURLToPath(import.meta.url)}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="home">
|
<div className="home">
|
||||||
|
|
@ -27,8 +27,10 @@ export default async function HomePage() {
|
||||||
width={65}
|
width={65}
|
||||||
/>
|
/>
|
||||||
</picture>
|
</picture>
|
||||||
{!user && <h1>Welcome to your new project.</h1>}
|
<h1>Polaris Task Force</h1>
|
||||||
{user && <h1>Welcome back, {user.email}</h1>}
|
{/*{!user && <h1>Welcome to your new project.</h1>}
|
||||||
|
{user && <h1>Welcome back, {user.email}</h1>}*/}
|
||||||
|
<p>This site is under construction.</p>
|
||||||
<div className="links">
|
<div className="links">
|
||||||
<a
|
<a
|
||||||
className="admin"
|
className="admin"
|
||||||
|
|
@ -48,12 +50,12 @@ export default async function HomePage() {
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="footer">
|
{/* <div className="footer">
|
||||||
<p>Update this page by editing</p>
|
<p>Update this page by editing</p>
|
||||||
<a className="codeLink" href={fileURL}>
|
<a className="codeLink" href={fileURL}>
|
||||||
<code>app/(frontend)/page.tsx</code>
|
<code>app/(frontend)/page.tsx</code>
|
||||||
</a>
|
</a>
|
||||||
|
</div>*/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
import type { Metadata } from 'next'
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
import config from '@payload-config'
|
import config from "@payload-config";
|
||||||
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views'
|
import { generatePageMetadata, NotFoundPage } from "@payloadcms/next/views";
|
||||||
import { importMap } from '../importMap'
|
import { importMap } from "../importMap";
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
params: Promise<{
|
params: Promise<{
|
||||||
segments: string[]
|
segments: string[];
|
||||||
}>
|
}>;
|
||||||
searchParams: Promise<{
|
searchParams: Promise<{
|
||||||
[key: string]: string | string[]
|
[key: string]: string | string[];
|
||||||
}>
|
}>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
||||||
generatePageMetadata({ config, params, searchParams })
|
generatePageMetadata({ config, params, searchParams });
|
||||||
|
|
||||||
const NotFound = ({ params, searchParams }: Args) =>
|
const NotFound = ({ params, searchParams }: Args) =>
|
||||||
NotFoundPage({ config, params, searchParams, importMap })
|
NotFoundPage({ config, params, searchParams, importMap });
|
||||||
|
|
||||||
export default NotFound
|
export default NotFound;
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
import type { Metadata } from 'next'
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
import config from '@payload-config'
|
import config from "@payload-config";
|
||||||
import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
|
import { generatePageMetadata, RootPage } from "@payloadcms/next/views";
|
||||||
import { importMap } from '../importMap'
|
import { importMap } from "../importMap";
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
params: Promise<{
|
params: Promise<{
|
||||||
segments: string[]
|
segments: string[];
|
||||||
}>
|
}>;
|
||||||
searchParams: Promise<{
|
searchParams: Promise<{
|
||||||
[key: string]: string | string[]
|
[key: string]: string | string[];
|
||||||
}>
|
}>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
||||||
generatePageMetadata({ config, params, searchParams })
|
generatePageMetadata({ config, params, searchParams });
|
||||||
|
|
||||||
const Page = ({ params, searchParams }: Args) =>
|
const Page = ({ params, searchParams }: Args) =>
|
||||||
RootPage({ config, params, searchParams, importMap })
|
RootPage({ config, params, searchParams, importMap });
|
||||||
|
|
||||||
export default Page
|
export default Page;
|
||||||
|
|
|
||||||
|
|
@ -1 +1,49 @@
|
||||||
export const importMap = {}
|
import { RscEntryLexicalCell as RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc'
|
||||||
|
import { RscEntryLexicalField as RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc'
|
||||||
|
import { LexicalDiffComponent as LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc'
|
||||||
|
import { InlineToolbarFeatureClient as InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { UploadFeatureClient as UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { BlockquoteFeatureClient as BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { RelationshipFeatureClient as RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { LinkFeatureClient as LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { ChecklistFeatureClient as ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { OrderedListFeatureClient as OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { UnorderedListFeatureClient as UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { IndentFeatureClient as IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { AlignFeatureClient as AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { HeadingFeatureClient as HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { ParagraphFeatureClient as ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { InlineCodeFeatureClient as InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { SuperscriptFeatureClient as SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { SubscriptFeatureClient as SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { StrikethroughFeatureClient as StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
|
||||||
|
export const importMap = {
|
||||||
|
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||||
|
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalField": RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||||
|
"@payloadcms/richtext-lexical/rsc#LexicalDiffComponent": LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||||
|
"@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient": InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#UploadFeatureClient": UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#BlockquoteFeatureClient": BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#RelationshipFeatureClient": RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#LinkFeatureClient": LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#ChecklistFeatureClient": ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#OrderedListFeatureClient": OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#UnorderedListFeatureClient": UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#IndentFeatureClient": IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#AlignFeatureClient": AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#HeadingFeatureClient": HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#ParagraphFeatureClient": ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#InlineCodeFeatureClient": InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#SuperscriptFeatureClient": SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#SubscriptFeatureClient": SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#StrikethroughFeatureClient": StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,12 @@
|
||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
import config from '@payload-config'
|
import config from "@payload-config";
|
||||||
import '@payloadcms/next/css'
|
import "@payloadcms/next/css";
|
||||||
import {
|
import { REST_DELETE, REST_GET, REST_OPTIONS, REST_PATCH, REST_POST, REST_PUT, } from "@payloadcms/next/routes";
|
||||||
REST_DELETE,
|
|
||||||
REST_GET,
|
|
||||||
REST_OPTIONS,
|
|
||||||
REST_PATCH,
|
|
||||||
REST_POST,
|
|
||||||
REST_PUT,
|
|
||||||
} from '@payloadcms/next/routes'
|
|
||||||
|
|
||||||
export const GET = REST_GET(config)
|
export const GET = REST_GET(config);
|
||||||
export const POST = REST_POST(config)
|
export const POST = REST_POST(config);
|
||||||
export const DELETE = REST_DELETE(config)
|
export const DELETE = REST_DELETE(config);
|
||||||
export const PATCH = REST_PATCH(config)
|
export const PATCH = REST_PATCH(config);
|
||||||
export const PUT = REST_PUT(config)
|
export const PUT = REST_PUT(config);
|
||||||
export const OPTIONS = REST_OPTIONS(config)
|
export const OPTIONS = REST_OPTIONS(config);
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ import config from '@payload-config'
|
||||||
import '@payloadcms/next/css'
|
import '@payloadcms/next/css'
|
||||||
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
|
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
|
||||||
|
|
||||||
export const GET = GRAPHQL_PLAYGROUND_GET(config)
|
export const GET = GRAPHQL_PLAYGROUND_GET(config);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,6 @@
|
||||||
import config from '@payload-config'
|
import config from '@payload-config'
|
||||||
import { GRAPHQL_POST, REST_OPTIONS } from '@payloadcms/next/routes'
|
import { GRAPHQL_POST, REST_OPTIONS } from '@payloadcms/next/routes'
|
||||||
|
|
||||||
export const POST = GRAPHQL_POST(config)
|
export const POST = GRAPHQL_POST(config);
|
||||||
|
|
||||||
export const OPTIONS = REST_OPTIONS(config)
|
export const OPTIONS = REST_OPTIONS(config);
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,31 @@
|
||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||||
import config from '@payload-config'
|
import config from "@payload-config";
|
||||||
import '@payloadcms/next/css'
|
import "@payloadcms/next/css";
|
||||||
import type { ServerFunctionClient } from 'payload'
|
import type { ServerFunctionClient } from "payload";
|
||||||
import { handleServerFunctions, RootLayout } from '@payloadcms/next/layouts'
|
import { handleServerFunctions, RootLayout } from "@payloadcms/next/layouts";
|
||||||
import React from 'react'
|
import React from "react";
|
||||||
|
|
||||||
import { importMap } from './admin/importMap.js'
|
import { importMap } from "./admin/importMap.js";
|
||||||
import './custom.scss'
|
import "./custom.scss";
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
children: React.ReactNode
|
children: React.ReactNode;
|
||||||
}
|
};
|
||||||
|
|
||||||
const serverFunction: ServerFunctionClient = async function (args) {
|
const serverFunction: ServerFunctionClient = async function (args) {
|
||||||
'use server'
|
"use server";
|
||||||
return handleServerFunctions({
|
return handleServerFunctions({
|
||||||
...args,
|
...args,
|
||||||
config,
|
config,
|
||||||
importMap,
|
importMap,
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const Layout = ({ children }: Args) => (
|
const Layout = ({ children }: Args) => (
|
||||||
<RootLayout config={config} importMap={importMap} serverFunction={serverFunction}>
|
<RootLayout config={config} importMap={importMap} serverFunction={serverFunction}>
|
||||||
{children}
|
{children}
|
||||||
</RootLayout>
|
</RootLayout>
|
||||||
)
|
);
|
||||||
|
|
||||||
export default Layout
|
export default Layout;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import configPromise from '@payload-config'
|
import configPromise from "@payload-config";
|
||||||
import { getPayload } from 'payload'
|
import { getPayload } from "payload";
|
||||||
|
|
||||||
export const GET = async (request: Request) => {
|
export const GET = async (request: Request) => {
|
||||||
const payload = await getPayload({
|
const payload = await getPayload({
|
||||||
config: configPromise,
|
config: configPromise,
|
||||||
})
|
});
|
||||||
|
|
||||||
return Response.json({
|
return Response.json({
|
||||||
message: 'This is an example of a custom route.',
|
message: "This is an example of a custom route.",
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
import type { CollectionConfig } from 'payload'
|
import type { CollectionConfig } from "payload";
|
||||||
|
|
||||||
export const Media: CollectionConfig = {
|
export const Media: CollectionConfig = {
|
||||||
slug: 'media',
|
slug: "media",
|
||||||
access: {
|
access: {
|
||||||
read: () => true,
|
read: () => true,
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'alt',
|
name: "alt",
|
||||||
type: 'text',
|
type: "text",
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
upload: true,
|
upload: true,
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import type { CollectionConfig } from 'payload'
|
|
||||||
|
|
||||||
export const Users: CollectionConfig = {
|
|
||||||
slug: 'users',
|
|
||||||
admin: {
|
|
||||||
useAsTitle: 'email',
|
|
||||||
},
|
|
||||||
auth: true,
|
|
||||||
fields: [
|
|
||||||
// Email added by default
|
|
||||||
// Add more fields as needed
|
|
||||||
],
|
|
||||||
}
|
|
||||||
57
src/collections/users/Awards.ts
Normal file
57
src/collections/users/Awards.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { CollectionConfig } from "payload";
|
||||||
|
import { isAdmin } from "@/utils/access-control/isRole";
|
||||||
|
|
||||||
|
export const Awards: CollectionConfig = {
|
||||||
|
slug: "awards",
|
||||||
|
access: {
|
||||||
|
create: isAdmin,
|
||||||
|
update: isAdmin,
|
||||||
|
delete: isAdmin,
|
||||||
|
},
|
||||||
|
admin: {
|
||||||
|
useAsTitle: "name",
|
||||||
|
group: "Users",
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "description",
|
||||||
|
type: "richText",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "type",
|
||||||
|
type: "select",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "Commendation",
|
||||||
|
value: "commendation",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Ribbon",
|
||||||
|
value: "ribbon",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Medal",
|
||||||
|
value: "medal",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultValue: "commendation",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "image",
|
||||||
|
type: "upload",
|
||||||
|
relationTo: "media",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "experiencePoints",
|
||||||
|
type: "number",
|
||||||
|
min: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
98
src/collections/users/Profiles.ts
Normal file
98
src/collections/users/Profiles.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { CollectionConfig } from "payload";
|
||||||
|
import { Award } from "@/payload-types";
|
||||||
|
|
||||||
|
export const Profiles: CollectionConfig = {
|
||||||
|
slug: "profiles",
|
||||||
|
admin: {
|
||||||
|
useAsTitle: "profileTitle",
|
||||||
|
group: "Users",
|
||||||
|
defaultColumns: ["profileTitle", "user", "rank"],
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "user",
|
||||||
|
type: "relationship",
|
||||||
|
relationTo: "users",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rank",
|
||||||
|
type: "relationship",
|
||||||
|
relationTo: "ranks",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "profileTitle",
|
||||||
|
type: "text",
|
||||||
|
virtual: "user.displayName",
|
||||||
|
admin: {
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
label: "Operator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dossier",
|
||||||
|
label: "Personnel Dossier",
|
||||||
|
type: "group",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "personalExcerpt",
|
||||||
|
type: "textarea",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "intelExcerpt",
|
||||||
|
label: "Intelligence Record",
|
||||||
|
type: "richText",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "progression",
|
||||||
|
label: "Progression & XP",
|
||||||
|
type: "group",
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "xp",
|
||||||
|
label: "Experience Points (XP)",
|
||||||
|
type: "number",
|
||||||
|
virtual: true,
|
||||||
|
defaultValue: 0,
|
||||||
|
admin: {
|
||||||
|
readOnly: true,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
// beforeChange: [({ siblingData }) => delete siblingData["xp"]],
|
||||||
|
afterRead: [
|
||||||
|
async ({ req, siblingData }) => {
|
||||||
|
let xpAcc = 0;
|
||||||
|
|
||||||
|
await req.payload
|
||||||
|
.find({
|
||||||
|
collection: "awards",
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
in: (siblingData as { awards: number[] }).awards,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
const awards: Award[] = res.docs;
|
||||||
|
xpAcc += awards.reduce((prev, cur) => prev + (cur.experiencePoints ?? 0), 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
return xpAcc;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "awards",
|
||||||
|
type: "relationship",
|
||||||
|
relationTo: "awards",
|
||||||
|
hasMany: true,
|
||||||
|
admin: {
|
||||||
|
appearance: "drawer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
40
src/collections/users/Ranks.ts
Normal file
40
src/collections/users/Ranks.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { CollectionConfig } from "payload";
|
||||||
|
import { isAdmin } from "@/utils/access-control/isRole";
|
||||||
|
|
||||||
|
export const Ranks: CollectionConfig = {
|
||||||
|
slug: "ranks",
|
||||||
|
access: {
|
||||||
|
create: isAdmin,
|
||||||
|
update: isAdmin,
|
||||||
|
delete: isAdmin,
|
||||||
|
},
|
||||||
|
admin: {
|
||||||
|
useAsTitle: "name",
|
||||||
|
group: "Users"
|
||||||
|
},
|
||||||
|
orderable: true,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "abbreviation",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "description",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "insignia",
|
||||||
|
type: "upload",
|
||||||
|
relationTo: "media",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
64
src/collections/users/Users.ts
Normal file
64
src/collections/users/Users.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
import type { CollectionConfig } from "payload";
|
||||||
|
import { isAdmin } from "@/utils/access-control/isRole";
|
||||||
|
|
||||||
|
export const Users: CollectionConfig = {
|
||||||
|
slug: "users",
|
||||||
|
access: {
|
||||||
|
admin: isAdmin,
|
||||||
|
unlock: isAdmin,
|
||||||
|
},
|
||||||
|
admin: {
|
||||||
|
useAsTitle: "username",
|
||||||
|
group: "Users",
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
loginWithUsername: {
|
||||||
|
requireUsername: true,
|
||||||
|
allowEmailLogin: false,
|
||||||
|
requireEmail: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
// Email added by default by Payload, but essentially ignored in this application
|
||||||
|
{
|
||||||
|
name: "username",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "discordUsername",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "displayName",
|
||||||
|
type: "text",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "roles",
|
||||||
|
type: "select",
|
||||||
|
hasMany: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "Guest",
|
||||||
|
value: "guest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "User",
|
||||||
|
value: "user",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Admin",
|
||||||
|
value: "admin",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Developer",
|
||||||
|
value: "developer",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
@ -69,6 +69,9 @@ export interface Config {
|
||||||
collections: {
|
collections: {
|
||||||
users: User;
|
users: User;
|
||||||
media: Media;
|
media: Media;
|
||||||
|
ranks: Rank;
|
||||||
|
profiles: Profile;
|
||||||
|
awards: Award;
|
||||||
'payload-locked-documents': PayloadLockedDocument;
|
'payload-locked-documents': PayloadLockedDocument;
|
||||||
'payload-preferences': PayloadPreference;
|
'payload-preferences': PayloadPreference;
|
||||||
'payload-migrations': PayloadMigration;
|
'payload-migrations': PayloadMigration;
|
||||||
|
|
@ -77,12 +80,15 @@ export interface Config {
|
||||||
collectionsSelect: {
|
collectionsSelect: {
|
||||||
users: UsersSelect<false> | UsersSelect<true>;
|
users: UsersSelect<false> | UsersSelect<true>;
|
||||||
media: MediaSelect<false> | MediaSelect<true>;
|
media: MediaSelect<false> | MediaSelect<true>;
|
||||||
|
ranks: RanksSelect<false> | RanksSelect<true>;
|
||||||
|
profiles: ProfilesSelect<false> | ProfilesSelect<true>;
|
||||||
|
awards: AwardsSelect<false> | AwardsSelect<true>;
|
||||||
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
||||||
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
||||||
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
||||||
};
|
};
|
||||||
db: {
|
db: {
|
||||||
defaultIDType: string;
|
defaultIDType: number;
|
||||||
};
|
};
|
||||||
globals: {};
|
globals: {};
|
||||||
globalsSelect: {};
|
globalsSelect: {};
|
||||||
|
|
@ -97,20 +103,18 @@ export interface Config {
|
||||||
}
|
}
|
||||||
export interface UserAuthOperations {
|
export interface UserAuthOperations {
|
||||||
forgotPassword: {
|
forgotPassword: {
|
||||||
email: string;
|
username: string;
|
||||||
password: string;
|
|
||||||
};
|
};
|
||||||
login: {
|
login: {
|
||||||
email: string;
|
|
||||||
password: string;
|
password: string;
|
||||||
|
username: string;
|
||||||
};
|
};
|
||||||
registerFirstUser: {
|
registerFirstUser: {
|
||||||
email: string;
|
|
||||||
password: string;
|
password: string;
|
||||||
|
username: string;
|
||||||
};
|
};
|
||||||
unlock: {
|
unlock: {
|
||||||
email: string;
|
username: string;
|
||||||
password: string;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
@ -118,10 +122,14 @@ export interface UserAuthOperations {
|
||||||
* via the `definition` "users".
|
* via the `definition` "users".
|
||||||
*/
|
*/
|
||||||
export interface User {
|
export interface User {
|
||||||
id: string;
|
id: number;
|
||||||
|
discordUsername: string;
|
||||||
|
displayName: string;
|
||||||
|
roles?: ('guest' | 'user' | 'admin' | 'developer')[] | null;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
email: string;
|
email?: string | null;
|
||||||
|
username: string;
|
||||||
resetPasswordToken?: string | null;
|
resetPasswordToken?: string | null;
|
||||||
resetPasswordExpiration?: string | null;
|
resetPasswordExpiration?: string | null;
|
||||||
salt?: string | null;
|
salt?: string | null;
|
||||||
|
|
@ -142,7 +150,7 @@ export interface User {
|
||||||
* via the `definition` "media".
|
* via the `definition` "media".
|
||||||
*/
|
*/
|
||||||
export interface Media {
|
export interface Media {
|
||||||
id: string;
|
id: number;
|
||||||
alt: string;
|
alt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|
@ -156,25 +164,113 @@ export interface Media {
|
||||||
focalX?: number | null;
|
focalX?: number | null;
|
||||||
focalY?: number | null;
|
focalY?: number | null;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "ranks".
|
||||||
|
*/
|
||||||
|
export interface Rank {
|
||||||
|
id: number;
|
||||||
|
_order?: string | null;
|
||||||
|
name: string;
|
||||||
|
abbreviation: string;
|
||||||
|
description: string;
|
||||||
|
insignia?: (number | null) | Media;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "profiles".
|
||||||
|
*/
|
||||||
|
export interface Profile {
|
||||||
|
id: number;
|
||||||
|
user?: (number | null) | User;
|
||||||
|
rank?: (number | null) | Rank;
|
||||||
|
profileTitle?: string | null;
|
||||||
|
dossier?: {
|
||||||
|
personalExcerpt?: string | null;
|
||||||
|
intelExcerpt?: {
|
||||||
|
root: {
|
||||||
|
type: string;
|
||||||
|
children: {
|
||||||
|
type: any;
|
||||||
|
version: number;
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
|
direction: ('ltr' | 'rtl') | null;
|
||||||
|
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||||
|
indent: number;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
[k: string]: unknown;
|
||||||
|
} | null;
|
||||||
|
};
|
||||||
|
progression?: {
|
||||||
|
xp?: number | null;
|
||||||
|
awards?: (number | Award)[] | null;
|
||||||
|
};
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "awards".
|
||||||
|
*/
|
||||||
|
export interface Award {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
description: {
|
||||||
|
root: {
|
||||||
|
type: string;
|
||||||
|
children: {
|
||||||
|
type: any;
|
||||||
|
version: number;
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
|
direction: ('ltr' | 'rtl') | null;
|
||||||
|
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||||
|
indent: number;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
[k: string]: unknown;
|
||||||
|
};
|
||||||
|
type?: ('commendation' | 'ribbon' | 'medal') | null;
|
||||||
|
image?: (number | null) | Media;
|
||||||
|
experiencePoints?: number | null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "payload-locked-documents".
|
* via the `definition` "payload-locked-documents".
|
||||||
*/
|
*/
|
||||||
export interface PayloadLockedDocument {
|
export interface PayloadLockedDocument {
|
||||||
id: string;
|
id: number;
|
||||||
document?:
|
document?:
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'users';
|
relationTo: 'users';
|
||||||
value: string | User;
|
value: number | User;
|
||||||
} | null)
|
} | null)
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'media';
|
relationTo: 'media';
|
||||||
value: string | Media;
|
value: number | Media;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'ranks';
|
||||||
|
value: number | Rank;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'profiles';
|
||||||
|
value: number | Profile;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'awards';
|
||||||
|
value: number | Award;
|
||||||
} | null);
|
} | null);
|
||||||
globalSlug?: string | null;
|
globalSlug?: string | null;
|
||||||
user: {
|
user: {
|
||||||
relationTo: 'users';
|
relationTo: 'users';
|
||||||
value: string | User;
|
value: number | User;
|
||||||
};
|
};
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|
@ -184,10 +280,10 @@ export interface PayloadLockedDocument {
|
||||||
* via the `definition` "payload-preferences".
|
* via the `definition` "payload-preferences".
|
||||||
*/
|
*/
|
||||||
export interface PayloadPreference {
|
export interface PayloadPreference {
|
||||||
id: string;
|
id: number;
|
||||||
user: {
|
user: {
|
||||||
relationTo: 'users';
|
relationTo: 'users';
|
||||||
value: string | User;
|
value: number | User;
|
||||||
};
|
};
|
||||||
key?: string | null;
|
key?: string | null;
|
||||||
value?:
|
value?:
|
||||||
|
|
@ -207,7 +303,7 @@ export interface PayloadPreference {
|
||||||
* via the `definition` "payload-migrations".
|
* via the `definition` "payload-migrations".
|
||||||
*/
|
*/
|
||||||
export interface PayloadMigration {
|
export interface PayloadMigration {
|
||||||
id: string;
|
id: number;
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
batch?: number | null;
|
batch?: number | null;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
|
@ -218,9 +314,13 @@ export interface PayloadMigration {
|
||||||
* via the `definition` "users_select".
|
* via the `definition` "users_select".
|
||||||
*/
|
*/
|
||||||
export interface UsersSelect<T extends boolean = true> {
|
export interface UsersSelect<T extends boolean = true> {
|
||||||
|
discordUsername?: T;
|
||||||
|
displayName?: T;
|
||||||
|
roles?: T;
|
||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
email?: T;
|
email?: T;
|
||||||
|
username?: T;
|
||||||
resetPasswordToken?: T;
|
resetPasswordToken?: T;
|
||||||
resetPasswordExpiration?: T;
|
resetPasswordExpiration?: T;
|
||||||
salt?: T;
|
salt?: T;
|
||||||
|
|
@ -253,6 +353,55 @@ export interface MediaSelect<T extends boolean = true> {
|
||||||
focalX?: T;
|
focalX?: T;
|
||||||
focalY?: T;
|
focalY?: T;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "ranks_select".
|
||||||
|
*/
|
||||||
|
export interface RanksSelect<T extends boolean = true> {
|
||||||
|
_order?: T;
|
||||||
|
name?: T;
|
||||||
|
abbreviation?: T;
|
||||||
|
description?: T;
|
||||||
|
insignia?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "profiles_select".
|
||||||
|
*/
|
||||||
|
export interface ProfilesSelect<T extends boolean = true> {
|
||||||
|
user?: T;
|
||||||
|
rank?: T;
|
||||||
|
profileTitle?: T;
|
||||||
|
dossier?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
personalExcerpt?: T;
|
||||||
|
intelExcerpt?: T;
|
||||||
|
};
|
||||||
|
progression?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
xp?: T;
|
||||||
|
awards?: T;
|
||||||
|
};
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "awards_select".
|
||||||
|
*/
|
||||||
|
export interface AwardsSelect<T extends boolean = true> {
|
||||||
|
name?: T;
|
||||||
|
description?: T;
|
||||||
|
type?: T;
|
||||||
|
image?: T;
|
||||||
|
experiencePoints?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "payload-locked-documents_select".
|
* via the `definition` "payload-locked-documents_select".
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,20 @@
|
||||||
// storage-adapter-import-placeholder
|
// storage-adapter-import-placeholder
|
||||||
import { postgresAdapter } from '@payloadcms/db-postgres'
|
import { postgresAdapter } from "@payloadcms/db-postgres";
|
||||||
import { payloadCloudPlugin } from '@payloadcms/payload-cloud'
|
import { payloadCloudPlugin } from "@payloadcms/payload-cloud";
|
||||||
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
import { lexicalEditor } from "@payloadcms/richtext-lexical";
|
||||||
import path from 'path'
|
import path from "path";
|
||||||
import { buildConfig } from 'payload'
|
import { buildConfig } from "payload";
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from "url";
|
||||||
import sharp from 'sharp'
|
import sharp from "sharp";
|
||||||
|
|
||||||
import { Users } from './collections/Users'
|
import { Users } from "@/collections/users/Users";
|
||||||
import { Media } from './collections/Media'
|
import { Media } from "@/collections/Media";
|
||||||
|
import { Profiles } from "@/collections/users/Profiles";
|
||||||
|
import { Ranks } from "@/collections/users/Ranks";
|
||||||
|
import { Awards } from "@/collections/users/Awards";
|
||||||
|
|
||||||
const filename = fileURLToPath(import.meta.url)
|
const filename = fileURLToPath(import.meta.url);
|
||||||
const dirname = path.dirname(filename)
|
const dirname = path.dirname(filename);
|
||||||
|
|
||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
admin: {
|
admin: {
|
||||||
|
|
@ -20,15 +23,15 @@ export default buildConfig({
|
||||||
baseDir: path.resolve(dirname),
|
baseDir: path.resolve(dirname),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
collections: [Users, Media],
|
collections: [Users, Media, Ranks, Profiles, Awards],
|
||||||
editor: lexicalEditor(),
|
editor: lexicalEditor(),
|
||||||
secret: process.env.PAYLOAD_SECRET || '',
|
secret: process.env.PAYLOAD_SECRET || "",
|
||||||
typescript: {
|
typescript: {
|
||||||
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
outputFile: path.resolve(dirname, "payload-types.ts"),
|
||||||
},
|
},
|
||||||
db: postgresAdapter({
|
db: postgresAdapter({
|
||||||
pool: {
|
pool: {
|
||||||
connectionString: process.env.DATABASE_URI || '',
|
connectionString: process.env.DATABASE_URI || "",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
sharp,
|
sharp,
|
||||||
|
|
@ -36,4 +39,4 @@ export default buildConfig({
|
||||||
payloadCloudPlugin(),
|
payloadCloudPlugin(),
|
||||||
// storage-adapter-placeholder
|
// storage-adapter-placeholder
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
|
|
|
||||||
122
src/tools/seed/seedRanks.ts
Normal file
122
src/tools/seed/seedRanks.ts
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
import { getPayload } from "payload";
|
||||||
|
import config from "@payload-config";
|
||||||
|
|
||||||
|
const DEFAULT_USMC_RANKS = [
|
||||||
|
{
|
||||||
|
name: "Recruit",
|
||||||
|
abbreviation: "Rct",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Private",
|
||||||
|
abbreviation: "Pvt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Private First Class",
|
||||||
|
abbreviation: "PFC",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Lance Corporal",
|
||||||
|
abbreviation: "LCpl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Corporal",
|
||||||
|
abbreviation: "Cpl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sergeant",
|
||||||
|
abbreviation: "Sgt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Staff Sergeant",
|
||||||
|
abbreviation: "SSgt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Gunnery Sergeant",
|
||||||
|
abbreviation: "GySgt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Master Sergeant",
|
||||||
|
abbreviation: "MSgt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "First Sergeant",
|
||||||
|
abbreviation: "1stSgt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sergeant Major",
|
||||||
|
abbreviation: "SgtMaj",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Master Gunnery Sergeant",
|
||||||
|
abbreviation: "MGySgt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Second Lieutenant",
|
||||||
|
abbreviation: "2ndLt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "First Lieutenant",
|
||||||
|
abbreviation: "1stLt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Captain",
|
||||||
|
abbreviation: "Cpt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Major",
|
||||||
|
abbreviation: "Maj",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Lieutenant Colonel",
|
||||||
|
abbreviation: "LtCol",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Colonel",
|
||||||
|
abbreviation: "Col",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Brigadier General",
|
||||||
|
abbreviation: "BGen",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Major General",
|
||||||
|
abbreviation: "MajGen",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Lieutenant General",
|
||||||
|
abbreviation: "LtGen",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "General",
|
||||||
|
abbreviation: "Gen",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const seedRanks = async () => {
|
||||||
|
const payload = await getPayload({ config });
|
||||||
|
|
||||||
|
payload.logger.info("Seeding rank data...");
|
||||||
|
|
||||||
|
payload.logger.warn("Deleting all existing ranks...");
|
||||||
|
await payload.delete({
|
||||||
|
collection: "ranks",
|
||||||
|
where: {
|
||||||
|
name: { exists: true },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
payload.logger.info(`Creating ${DEFAULT_USMC_RANKS.length} new ranks...`);
|
||||||
|
for (const rank of DEFAULT_USMC_RANKS) {
|
||||||
|
const result = await payload.create({
|
||||||
|
collection: "ranks",
|
||||||
|
data: {
|
||||||
|
...rank,
|
||||||
|
description: "A rank that needs a description. ",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
payload.logger.info(`Rank '${result.name}' created.`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await seedRanks();
|
||||||
7
src/utils/access-control/hasRoles.ts
Normal file
7
src/utils/access-control/hasRoles.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { User } from "@/payload-types";
|
||||||
|
|
||||||
|
export default function hasRoles(roles: NonNullable<User['roles']>, user: User | null | undefined) {
|
||||||
|
if (!user) return false;
|
||||||
|
|
||||||
|
return roles.some((role) => user.roles?.some((urole) => urole === role || urole === "developer"));
|
||||||
|
}
|
||||||
18
src/utils/access-control/isRole.ts
Normal file
18
src/utils/access-control/isRole.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import hasRoles from "@/utils/access-control/hasRoles";
|
||||||
|
import { PayloadRequest } from "payload";
|
||||||
|
|
||||||
|
export function isDeveloper({ req: { user } }: { req: PayloadRequest }) {
|
||||||
|
return hasRoles(["developer"], user);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isGuest({ req: { user } }: { req: PayloadRequest }) {
|
||||||
|
return hasRoles(["guest"], user);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isUser({ req: { user } }: { req: PayloadRequest }) {
|
||||||
|
return hasRoles(["user"], user);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAdmin({ req: { user } }: { req: PayloadRequest }) {
|
||||||
|
return hasRoles(["admin"], user);
|
||||||
|
}
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
import { test, expect, Page } from '@playwright/test'
|
import { expect, Page, test } from "@playwright/test";
|
||||||
|
|
||||||
test.describe('Frontend', () => {
|
test.describe("Frontend", () => {
|
||||||
let page: Page
|
let page: Page;
|
||||||
|
|
||||||
test.beforeAll(async ({ browser }, testInfo) => {
|
test.beforeAll(async ({ browser }, testInfo) => {
|
||||||
const context = await browser.newContext()
|
const context = await browser.newContext();
|
||||||
page = await context.newPage()
|
page = await context.newPage();
|
||||||
})
|
});
|
||||||
|
|
||||||
test('can go on homepage', async ({ page }) => {
|
test("can go on homepage", async ({ page }) => {
|
||||||
await page.goto('http://localhost:3000')
|
await page.goto("http://localhost:3000");
|
||||||
|
|
||||||
await expect(page).toHaveTitle(/Payload Blank Template/)
|
await expect(page).toHaveTitle(/Payload Blank Template/);
|
||||||
|
|
||||||
const heading = page.locator('h1').first()
|
const heading = page.locator("h1").first();
|
||||||
|
|
||||||
await expect(heading).toHaveText('Welcome to your new project.')
|
await expect(heading).toHaveText("Welcome to your new project.");
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
import { getPayload, Payload } from 'payload'
|
import { getPayload, Payload } from "payload";
|
||||||
import config from '@/payload.config'
|
import config from "@/payload.config";
|
||||||
|
|
||||||
import { describe, it, beforeAll, expect } from 'vitest'
|
import { beforeAll, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
let payload: Payload
|
let payload: Payload;
|
||||||
|
|
||||||
describe('API', () => {
|
describe("API", () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const payloadConfig = await config
|
const payloadConfig = await config;
|
||||||
payload = await getPayload({ config: payloadConfig })
|
payload = await getPayload({ config: payloadConfig });
|
||||||
})
|
});
|
||||||
|
|
||||||
it('fetches users', async () => {
|
it("fetches users", async () => {
|
||||||
const users = await payload.find({
|
const users = await payload.find({
|
||||||
collection: 'users',
|
collection: "users",
|
||||||
})
|
});
|
||||||
expect(users).toBeDefined()
|
expect(users).toBeDefined();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
"./src/payload.config.ts"
|
"./src/payload.config.ts"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"target": "ES2022",
|
"target": "ES2022"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"next-env.d.ts",
|
"next-env.d.ts",
|
||||||
|
|
@ -40,5 +40,5 @@
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules"
|
"node_modules"
|
||||||
],
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { defineConfig } from 'vitest/config'
|
import { defineConfig } from "vitest/config";
|
||||||
import react from '@vitejs/plugin-react'
|
import react from "@vitejs/plugin-react";
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
import tsconfigPaths from "vite-tsconfig-paths";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [tsconfigPaths(), react()],
|
plugins: [tsconfigPaths(), react()],
|
||||||
test: {
|
test: {
|
||||||
environment: 'jsdom',
|
environment: "jsdom",
|
||||||
setupFiles: ['./vitest.setup.ts'],
|
setupFiles: ["./vitest.setup.ts"],
|
||||||
include: ['tests/int/**/*.int.spec.ts'],
|
include: ["tests/int/**/*.int.spec.ts"],
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Any setup scripts you might need go here
|
// Any setup scripts you might need go here
|
||||||
|
|
||||||
// Load .env files
|
// Load .env files
|
||||||
import 'dotenv/config'
|
import "dotenv/config";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue