chore: migrates form builder example cms to examples

This commit is contained in:
PatrikKozak
2023-03-10 10:55:31 -05:00
parent 85dee9a7bc
commit 1356b4db40
35 changed files with 7478 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
PAYLOAD_PUBLIC_SITE_URL=http://localhost:3000
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:8000
MONGODB_URI=mongodb://localhost/form-builder-example
PAYLOAD_SECRET=ENTER-STRING-HERE

View File

@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['@payloadcms'],
}

5
examples/form-builder/cms/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
build
dist
node_modules
package-lock.json
.env

View File

@@ -0,0 +1 @@
legacy-peer-deps=true

View File

@@ -0,0 +1,8 @@
module.exports = {
printWidth: 100,
parser: "typescript",
semi: false,
singleQuote: true,
trailingComma: "all",
arrowParens: "avoid",
};

View File

@@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Learn with Jason CMS",
"program": "${workspaceFolder}/src/server.ts",
"preLaunchTask": "npm: build:server",
"env": {
"PAYLOAD_CONFIG_PATH": "${workspaceFolder}/src/payload.config.ts"
},
// "outFiles": [
// "${workspaceFolder}/dist/**/*.js"
// ]
},
]
}

View File

@@ -0,0 +1,26 @@
# Form Builder Example CMS
This is an example repo for a CMS built with [Payload](https://payloadcms.com). This repo showcases how to utilize Payload's [Form Builder Plugin](https://github.com/payloadcms/plugin-form-builder).
## Getting Started
1. Clone this repo
2. `cd` into the directory and run `yarn` or `npm install`
3. Copy (`cp`) the `.env.example` file to an `.env` file
4. Run `yarn dev` or `npm run dev` to start the development server
5. Visit `http://localhost:8000/admin` to access the admin panel
6. Login with the following credentials:
- Email: `dev@payloadcms.com`
- Password: `test`
## Frontend Development
Clone the [frontend](https://github.com/payloadcms/form-builder-example-website) and follow the instructions there to get started. You can use this repo as a backend for the frontend and see for yourself how it all works together.
## Usage
Once booted up, a `Basic Form` will be immediately available to view on the home page along with a few other forms on their corresponding pages.
- These forms are seeded into the `forms` collection.
- A few pages have also been seeded in on start up and utilize a layout building block called `Form Block` that is wired up to use the different forms from the `forms` collection.
- This is done by adding a `relationship` field in the form-block config and setting its `relationTo` field to the `forms` collection.

View File

@@ -0,0 +1,4 @@
{
"ext": "ts",
"exec": "ts-node src/server.ts"
}

View File

@@ -0,0 +1,33 @@
{
"name": "form-builder-example-cms",
"description": "The CMS that utilizes Payload's form builder plugin.",
"version": "1.0.0",
"main": "dist/server.js",
"license": "MIT",
"scripts": {
"dev": "cross-env PAYLOAD_SEED=true PAYLOAD_DROP_DATABASE=true PAYLOAD_CONFIG_PATH=src/payload.config.ts nodemon",
"build:payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload build",
"build:server": "tsc",
"build": "yarn copyfiles && yarn build:payload && yarn build:server",
"serve": "cross-env PAYLOAD_CONFIG_PATH=dist/payload.config.js NODE_ENV=production node dist/server.js",
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png}\" dist/",
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
"generate:graphQLSchema": "PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:graphQLSchema"
},
"dependencies": {
"@faceless-ui/modal": "^2.0.1",
"@payloadcms/plugin-form-builder": "^1.0.12",
"@payloadcms/plugin-seo": "^1.0.8",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"payload": "^1.6.19"
},
"devDependencies": {
"@types/express": "^4.17.9",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
"nodemon": "^2.0.6",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
}

View File

@@ -0,0 +1,11 @@
import { Access } from 'payload/config';
export const publishedOnly: Access = ({ req: { user } }) => {
if (user) return true;
return {
_status: {
equals: 'published',
},
};
};

View File

@@ -0,0 +1,33 @@
import { Block } from 'payload/types';
import richText from '../../fields/richText';
export const FormBlock: Block = {
slug: 'formBlock',
labels: {
singular: 'Form Block',
plural: 'Form Blocks',
},
graphQL: {
singularName: 'FormBlock',
},
fields: [
{
name: 'form',
type: 'relationship',
relationTo: 'forms',
required: true,
},
{
name: 'enableIntro',
label: 'Enable Intro Content',
type: 'checkbox',
},
richText({
name: 'introContent',
label: 'Intro Content',
admin: {
condition: (_, { enableIntro }) => Boolean(enableIntro),
},
}),
],
};

View File

@@ -0,0 +1,44 @@
import { CollectionConfig } from 'payload/types';
import { publishedOnly } from '../access/publishedOnly';
import { FormBlock } from '../blocks/Form';
import { slugField } from '../fields/slug';
export const Pages: CollectionConfig = {
slug: 'pages',
admin: {
useAsTitle: 'title',
defaultColumns: ['title', 'slug', 'updatedAt'],
},
versions: {
drafts: true,
},
access: {
read: publishedOnly,
},
fields: [
{
name: 'title',
type: 'text',
required: true,
},
{
type: 'tabs',
tabs: [
{
label: 'Content',
fields: [
{
name: 'layout',
type: 'blocks',
required: true,
blocks: [
FormBlock,
],
},
],
},
],
},
slugField(),
],
};

View File

@@ -0,0 +1,12 @@
import { CollectionConfig } from 'payload/types';
export const Users: CollectionConfig = {
slug: 'users',
auth: true,
admin: {
useAsTitle: 'email',
},
fields: [
// Don't need any user fields here
],
};

View File

@@ -0,0 +1,151 @@
import { Field } from 'payload/types';
import deepMerge from '../utilities/deepMerge';
export const appearanceOptions = {
primary: {
label: 'Primary Button',
value: 'primary',
},
secondary: {
label: 'Secondary Button',
value: 'secondary',
},
default: {
label: 'Default',
value: 'default',
},
};
export type LinkAppearances = 'primary' | 'secondary' | 'default'
type LinkType = (
options?: {
appearances?: LinkAppearances[] | false
disableLabel?: boolean
overrides?: Record<string, unknown>
}
) => Field;
const link: LinkType = ({
appearances,
disableLabel = false,
overrides = {},
} = {}) => {
const linkResult: Field = {
name: 'link',
type: 'group',
admin: {
hideGutter: true,
},
fields: [
{
type: 'row',
fields: [
{
name: 'type',
type: 'radio',
options: [
{
label: 'Internal link',
value: 'reference',
},
{
label: 'Custom URL',
value: 'custom',
},
],
defaultValue: 'reference',
admin: {
layout: 'horizontal',
width: '50%',
},
},
{
name: 'newTab',
label: 'Open in new tab',
type: 'checkbox',
admin: {
width: '50%',
style: {
alignSelf: 'flex-end',
},
},
},
],
},
],
};
const linkTypes: Field[] = [
{
name: 'reference',
label: 'Document to link to',
type: 'relationship',
relationTo: ['pages'],
required: true,
maxDepth: 1,
admin: {
condition: (_, siblingData) => siblingData?.type === 'reference',
},
},
{
name: 'url',
label: 'Custom URL',
type: 'text',
required: true,
admin: {
condition: (_, siblingData) => siblingData?.type === 'custom',
},
},
];
if (!disableLabel) {
linkTypes[0].admin.width = '50%';
linkTypes[1].admin.width = '50%';
linkResult.fields.push({
type: 'row',
fields: [
...linkTypes,
{
name: 'label',
label: 'Label',
type: 'text',
required: true,
admin: {
width: '50%',
},
},
],
});
} else {
linkResult.fields = [...linkResult.fields, ...linkTypes];
}
if (appearances !== false) {
let appearanceOptionsToUse = [
appearanceOptions.default,
appearanceOptions.primary,
appearanceOptions.secondary,
];
if (appearances) {
appearanceOptionsToUse = appearances.map((appearance) => appearanceOptions[appearance]);
}
linkResult.fields.push({
name: 'appearance',
type: 'select',
defaultValue: 'default',
options: appearanceOptionsToUse,
admin: {
description: 'Choose how the link should be rendered.',
},
});
}
return deepMerge(linkResult, overrides);
};
export default link;

View File

@@ -0,0 +1,13 @@
import { RichTextElement } from 'payload/dist/fields/config/types';
const elements: RichTextElement[] = [
'blockquote',
'h2',
'h3',
'h4',
'h5',
'h6',
'link',
];
export default elements;

View File

@@ -0,0 +1,94 @@
import { RichTextElement, RichTextField, RichTextLeaf } from 'payload/dist/fields/config/types';
import deepMerge from '../../utilities/deepMerge';
import elements from './elements';
import leaves from './leaves';
import link from '../link';
type RichText = (
overrides?: Partial<RichTextField>,
additions?: {
elements?: RichTextElement[]
leaves?: RichTextLeaf[]
}
) => RichTextField
const richText: RichText = (
overrides,
additions = {
elements: [],
leaves: [],
},
) => deepMerge<RichTextField, Partial<RichTextField>>(
{
name: 'richText',
type: 'richText',
required: true,
admin: {
upload: {
collections: {
media: {
fields: [
{
type: 'richText',
name: 'caption',
label: 'Caption',
admin: {
elements: [
...elements,
],
leaves: [
...leaves,
],
},
},
{
type: 'radio',
name: 'alignment',
label: 'Alignment',
options: [
{
label: 'Left',
value: 'left',
},
{
label: 'Center',
value: 'center',
},
{
label: 'Right',
value: 'right',
},
],
},
{
name: 'enableLink',
type: 'checkbox',
label: 'Enable Link',
},
link({
appearances: false,
disableLabel: true,
overrides: {
admin: {
condition: (_, data) => Boolean(data?.enableLink),
},
},
}),
],
},
},
},
elements: [
...elements,
...additions.elements || [],
],
leaves: [
...leaves,
...additions.leaves || [],
],
},
},
overrides,
);
export default richText;

View File

@@ -0,0 +1,9 @@
import { RichTextLeaf } from 'payload/dist/fields/config/types';
const defaultLeaves: RichTextLeaf[] = [
'bold',
'italic',
'underline',
];
export default defaultLeaves;

View File

@@ -0,0 +1,23 @@
import { Field } from 'payload/types';
import formatSlug from '../utilities/formatSlug';
import deepMerge from '../utilities/deepMerge';
type Slug = (fieldToUse?: string, overrides?: Partial<Field>) => Field
export const slugField: Slug = (fieldToUse = 'title', overrides) => deepMerge<Field, Partial<Field>>(
{
name: 'slug',
label: 'Slug',
type: 'text',
index: true,
admin: {
position: 'sidebar',
},
hooks: {
beforeValidate: [
formatSlug(fieldToUse),
],
},
},
overrides,
);

View File

@@ -0,0 +1,21 @@
import { GlobalConfig } from 'payload/types';
import link from '../fields/link';
export const MainMenu: GlobalConfig = {
slug: 'main-menu',
access: {
read: () => true,
},
fields: [
{
name: 'navItems',
type: 'array',
maxRows: 6,
fields: [
link({
appearances: false,
}),
],
},
],
};

View File

@@ -0,0 +1,202 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload CMS.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "main-menu".
*/
export interface MainMenu {
id: string;
navItems: {
link: {
type?: 'reference' | 'custom';
newTab?: boolean;
reference: {
value: string | Page;
relationTo: 'pages';
};
url: string;
label: string;
};
id?: string;
}[];
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "pages".
*/
export interface Page {
id: string;
title: string;
layout: {
form: string | Form;
enableIntro?: boolean;
introContent: {
[k: string]: unknown;
}[];
id?: string;
blockName?: string;
blockType: 'formBlock';
}[];
slug?: string;
_status?: 'draft' | 'published';
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "forms".
*/
export interface Form {
id: string;
title: string;
fields: (
| {
name: string;
label?: string;
width?: number;
defaultValue?: string;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'text';
}
| {
name: string;
label?: string;
width?: number;
defaultValue?: string;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'textarea';
}
| {
name: string;
label?: string;
width?: number;
defaultValue?: string;
options: {
label: string;
value: string;
id?: string;
}[];
required?: boolean;
id?: string;
blockName?: string;
blockType: 'select';
}
| {
name: string;
label?: string;
width?: number;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'email';
}
| {
name: string;
label?: string;
width?: number;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'state';
}
| {
name: string;
label?: string;
width?: number;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'country';
}
| {
name: string;
label?: string;
width?: number;
defaultValue?: number;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'number';
}
| {
name: string;
label?: string;
width?: number;
required?: boolean;
defaultValue?: boolean;
id?: string;
blockName?: string;
blockType: 'checkbox';
}
| {
message?: {
[k: string]: unknown;
}[];
id?: string;
blockName?: string;
blockType: 'message';
}
)[];
submitButtonLabel?: string;
confirmationType?: 'message' | 'redirect';
confirmationMessage: {
[k: string]: unknown;
}[];
redirect: {
url: string;
};
emails: {
emailTo: string;
bcc?: string;
replyTo?: string;
replyToName?: string;
emailFrom?: string;
emailFromName?: string;
subject: string;
message?: {
[k: string]: unknown;
}[];
id?: string;
}[];
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "form-submissions".
*/
export interface FormSubmission {
id: string;
form: string | Form;
submissionData: {
field: string;
value: string;
id?: string;
}[];
createdAt: string;
updatedAt: string;
}

View File

@@ -0,0 +1,31 @@
import { buildConfig } from 'payload/config';
import path from 'path';
import FormBuilder from '@payloadcms/plugin-form-builder';
import { Users } from './collections/Users';
import { Pages } from './collections/Pages';
import { MainMenu } from './globals/MainMenu';
export default buildConfig({
collections: [
Pages,
Users,
],
globals: [
MainMenu,
],
cors: [
'http://localhost:3000',
process.env.PAYLOAD_PUBLIC_SITE_URL,
],
typescript: {
outputFile: path.resolve(__dirname, 'payload-types.ts'),
},
plugins: [
FormBuilder({
fields: {
payment: false,
},
}),
],
});

View File

@@ -0,0 +1,23 @@
export const advanced = {
title: 'Advanced',
layout: [
{
form: '{{ADVANCED_FORM_ID}}',
enableIntro: true,
introContent: [
{
children: [
{
text: 'Advanced form:',
},
],
type: 'h4',
},
],
id: '63adc92568224b995af9df14',
blockType: 'formBlock',
},
],
slug: 'advanced',
_status: 'published',
};

View File

@@ -0,0 +1,118 @@
export const advancedForm = {
id: '63c0835134d40cef85cc11a2',
title: 'Advanced Form',
fields: [
{
name: 'first-name',
label: 'First Name',
width: 50,
required: true,
id: '63c081b169853127a8895312',
blockName: 'first-name',
blockType: 'text',
},
{
name: 'last-name',
label: 'Last Name',
width: 50,
required: true,
id: '63c081c669853127a8895313',
blockName: 'last-name',
blockType: 'text',
},
{
name: 'email',
label: 'Email',
width: 100,
required: true,
id: '63c081e869853127a8895314',
blockName: 'email',
blockType: 'email',
},
{
name: 'street-address',
label: 'Street Address',
width: 100,
required: true,
id: '63c081fe69853127a8895315',
blockName: 'street-address',
blockType: 'text',
},
{
name: 'street-address-two',
label: 'Street Address Line 2',
width: 100,
id: '63c0823169853127a8895316',
blockName: 'street-address-two',
blockType: 'text',
},
{
name: 'city',
label: 'City',
width: 50,
required: true,
id: '63c0825a69853127a8895317',
blockName: 'city',
blockType: 'text',
},
{
name: 'state',
label: 'State',
width: 50,
required: true,
id: '63c0826569853127a8895318',
blockName: 'state',
blockType: 'state',
},
{
name: 'zip-code',
label: 'Postal / Zip Code',
width: 50,
required: true,
id: '63c082bb69853127a889531a',
blockName: 'zip-code',
blockType: 'number',
},
{
name: 'county',
label: 'Country',
width: 50,
required: true,
id: '63c0829269853127a8895319',
blockName: 'country',
blockType: 'country',
},
],
submitButtonLabel: 'Submit',
confirmationType: 'message',
confirmationMessage: [
{
children: [
{
text: 'Your shipping information submission was successful.',
},
],
},
],
emails: [
{
emailTo: '{{email}}',
emailFrom: 'dev@payloadcms.com',
emailFromName: 'Payload Team',
subject: "You've received a new message.",
message: [
{
children: [
{
text: 'Your example shipping information form submission was received successfully.',
},
],
},
],
id: '63c0831869853127a889531b',
},
],
createdAt: '2023-01-12T22:01:53.023Z',
updatedAt: '2023-01-12T22:01:53.023Z',
redirect: {},
};

View File

@@ -0,0 +1,102 @@
export const basicForm = {
id: '63c0651b132c8e2783f8dcae',
updatedAt: '2023-01-12T21:25:41.113Z',
createdAt: '2022-12-28T20:48:53.181Z',
title: 'Basic Form',
fields: [
{
name: 'first-name',
label: 'First name',
width: 50,
required: true,
id: '63adaaba5236fe69ca8973f8',
blockName: 'first-name',
blockType: 'text',
},
{
name: 'last-name',
label: 'Last name',
width: 50,
required: true,
id: '63bf4b1fd69cef4f34272f9a',
blockName: 'last-name',
blockType: 'text',
},
{
name: 'email',
label: 'Email',
width: 100,
required: true,
id: '63c0953adc1cd2c2f6c2d30b',
blockName: 'email',
blockType: 'email',
},
{
name: 'coolest-project',
label: "What's the coolest project you've built with Payload so far?",
width: 100,
required: false,
id: '63adab96b65c28c168442316',
blockName: 'coolest-project',
blockType: 'textarea',
},
{
message: [
{
children: [
{
text: 'Have a great rest of your day!',
},
],
},
{
children: [
{
text: '',
},
],
},
{
children: [
{
text: 'Sincerely, \n\nPayload Team.',
},
],
},
],
id: '63adb90db65c28c168442322',
blockName: 'farewell',
blockType: 'message',
},
],
submitButtonLabel: 'Submit',
confirmationType: 'message',
confirmationMessage: [
{
children: [
{
text: 'The basic form has been submitted successfully.',
},
],
},
],
emails: [
{
emailTo: '{{email}}',
emailFrom: 'dev@payloadcms.com',
emailFromName: 'Payload',
subject: "You've received a new message.",
message: [
{
children: [
{
text: 'Your basic form submission was successfully received.',
},
],
},
],
id: '63acab72433ea1822764c538',
},
],
redirect: {},
};

View File

@@ -0,0 +1,23 @@
export const contact = {
title: 'Contact',
layout: [
{
form: '{{CONTACT_FORM_ID}}',
enableIntro: true,
introContent: [
{
children: [
{
text: 'Example contact form:',
},
],
type: 'h4',
},
],
id: '63adc92568224b995af9df13',
blockType: 'formBlock',
},
],
slug: 'contact',
_status: 'published',
};

View File

@@ -0,0 +1,74 @@
export const contactForm = {
id: '63c07ffd4cb6b574b4977573',
title: 'Contact Form',
fields: [
{
name: 'full-name',
label: 'Full Name',
width: 100,
required: true,
id: '63c07f4e69853127a889530c',
blockName: 'full-name',
blockType: 'text',
},
{
name: 'email',
label: 'Email',
width: 50,
required: true,
id: '63c07f7069853127a889530d',
blockName: 'email',
blockType: 'email',
},
{
name: 'phone',
label: 'Phone',
width: 50,
required: false,
id: '63c07f8169853127a889530e',
blockName: 'phone',
blockType: 'number',
},
{
name: 'message',
label: 'Message',
width: 100,
required: true,
id: '63c07f9d69853127a8895310',
blockName: 'message',
blockType: 'textarea',
},
],
submitButtonLabel: 'Submit',
confirmationType: 'message',
confirmationMessage: [
{
children: [
{
text: 'The contact form has been submitted successfully.',
},
],
},
],
emails: [
{
emailTo: '{{email}}',
emailFrom: 'dev@payloadcms.com',
emailFromName: 'Payload Team',
subject: "You've received a new message.",
message: [
{
children: [
{
text: 'Your contact form submission was successfully received.',
},
],
},
],
id: '63c07fcb69853127a8895311',
},
],
createdAt: '2023-01-12T21:47:41.374Z',
updatedAt: '2023-01-12T21:47:41.374Z',
redirect: {},
};

View File

@@ -0,0 +1,23 @@
export const home = {
title: 'Home',
layout: [
{
form: '{{BASIC_FORM_ID}}',
enableIntro: true,
introContent: [
{
children: [
{
text: 'Example basic form:',
},
],
type: 'h4',
},
],
id: '63adc92568224b995af9df12',
blockType: 'formBlock',
},
],
slug: 'home',
_status: 'published',
};

View File

@@ -0,0 +1,121 @@
import { Payload } from 'payload';
import { home } from './home';
import { contact } from './contact';
import { advanced } from './advanced';
import { signUp } from './signUp';
import { basicForm } from './basicForm';
import { contactForm } from './contactForm';
import { advancedForm } from './advancedForm';
import { signUpForm } from './signUpForm';
export const seed = async (payload: Payload) => {
await payload.create({
collection: 'users',
data: {
email: 'dev@payloadcms.com',
password: 'test',
},
});
const basicFormJSON = JSON.parse(JSON.stringify(basicForm));
const { id: basicFormID } = await payload.create({
collection: 'forms',
data: basicFormJSON,
});
const contactFormJSON = JSON.parse(JSON.stringify(contactForm));
const { id: contactFormID } = await payload.create({
collection: 'forms',
data: contactFormJSON,
});
const advancedFormJSON = JSON.parse(JSON.stringify(advancedForm));
const { id: advancedFormID } = await payload.create({
collection: 'forms',
data: advancedFormJSON,
});
const signUpFormJSON = JSON.parse(JSON.stringify(signUpForm));
const { id: signUpFormID } = await payload.create({
collection: 'forms',
data: signUpFormJSON,
});
const homePageJSON = JSON.parse(
JSON.stringify(home).replace(/{{BASIC_FORM_ID}}/g, basicFormID),
);
const contactPageJSON = JSON.parse(
JSON.stringify(contact).replace(/{{CONTACT_FORM_ID}}/g, contactFormID),
);
const advancedPageJSON = JSON.parse(
JSON.stringify(advanced).replace(/{{ADVANCED_FORM_ID}}/g, advancedFormID),
);
const signupPageJSON = JSON.parse(
JSON.stringify(signUp).replace(/{{SIGNUP_FORM_ID}}/g, signUpFormID),
);
await payload.create({
collection: 'pages',
data: homePageJSON,
});
const { id: contactPageID } = await payload.create({
collection: 'pages',
data: contactPageJSON,
});
const { id: advancedPageID } = await payload.create({
collection: 'pages',
data: advancedPageJSON,
});
const { id: signupPageID } = await payload.create({
collection: 'pages',
data: signupPageJSON,
});
await payload.updateGlobal({
slug: 'main-menu',
data: {
navItems: [
{
link: {
type: 'reference',
reference: {
relationTo: 'pages',
value: contactPageID,
},
label: 'Contact Form',
},
},
{
link: {
type: 'reference',
reference: {
relationTo: 'pages',
value: advancedPageID,
},
label: 'Advanced Form',
},
},
{
link: {
type: 'reference',
reference: {
relationTo: 'pages',
value: signupPageID,
},
label: 'Signup Form',
},
},
],
},
});
};

View File

@@ -0,0 +1,23 @@
export const signUp = {
title: 'Sign Up',
layout: [
{
form: '{{SIGNUP_FORM_ID}}',
enableIntro: true,
introContent: [
{
children: [
{
text: 'Example sign-up form:',
},
],
type: 'h4',
},
],
id: '63adc92568224b995af9df15',
blockType: 'formBlock',
},
],
slug: 'sign-up',
_status: 'published',
};

View File

@@ -0,0 +1,86 @@
export const signUpForm = {
id: '63c086c36955e39c4208aa8f',
title: 'Sign Up Form',
fields: [
{
name: 'full-name',
label: 'Full Name',
width: 100,
required: true,
id: '63c085ae69853127a889531e',
blockName: 'full-name',
blockType: 'text',
},
{
name: 'email',
label: 'Email',
width: 100,
required: true,
id: '63c085df69853127a889531f',
blockName: 'email',
blockType: 'email',
},
{
name: 'password',
label: 'Password',
width: 100,
required: true,
id: '63c0861869853127a8895321',
blockName: 'password',
blockType: 'text',
},
{
message: [
{
children: [
{
text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
},
],
},
],
id: '63c0865769853127a8895324',
blockType: 'message',
},
{
name: 'terms-and-conditions',
label: 'I agree to the terms and conditions',
required: true,
id: '63c086a469853127a8895325',
blockName: 'terms-and-conditions',
blockType: 'checkbox',
},
],
submitButtonLabel: 'Create Account',
confirmationType: 'message',
confirmationMessage: [
{
children: [
{
text: 'Your sign up submission was successful.',
},
],
},
],
emails: [
{
emailTo: '{{email}}',
emailFrom: 'dev@payloadcms.com',
emailFromName: 'Payload Team',
subject: "You've received a new message.",
message: [
{
children: [
{
text: 'Your sign up submissioin was received successfully.',
},
],
},
],
id: '63c0858f69853127a889531d',
},
],
createdAt: '2023-01-12T22:16:35.480Z',
updatedAt: '2023-01-12T22:16:35.480Z',
redirect: {},
};

View File

@@ -0,0 +1,40 @@
import path from 'path';
import express from 'express';
import payload from 'payload';
import { seed } from './seed';
// eslint-disable-next-line
require('dotenv').config({
path: path.resolve(__dirname, '../.env'),
});
const app = express();
app.get('/', (_, res) => {
res.redirect('/admin');
});
const start = async () => {
await payload.init({
secret: process.env.PAYLOAD_SECRET,
mongoURL: process.env.MONGODB_URI,
express: app,
email: {
fromName: 'Admin',
fromAddress: 'admin@example.com',
logMockCredentials: true,
},
onInit: () => {
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`);
},
});
if (process.env.PAYLOAD_SEED === 'true') {
payload.logger.info('---- SEEDING DATABASE ----');
await seed(payload);
}
app.listen(8000);
};
start();

View File

@@ -0,0 +1,32 @@
/**
* Simple object check.
* @param item
* @returns {boolean}
*/
export function isObject(item: unknown): boolean {
return (item && typeof item === 'object' && !Array.isArray(item));
}
/**
* Deep merge two objects.
* @param target
* @param ...sources
*/
export default function deepMerge<T, R>(target: T, source: R): T {
const output = { ...target };
if (isObject(target) && isObject(source)) {
Object.keys(source).forEach((key) => {
if (isObject(source[key])) {
if (!(key in target)) {
Object.assign(output, { [key]: source[key] });
} else {
output[key] = deepMerge(target[key], source[key]);
}
} else {
Object.assign(output, { [key]: source[key] });
}
});
}
return output;
}

View File

@@ -0,0 +1,21 @@
import { FieldHook } from 'payload/types';
const format = (val: string): string => val.replace(/ /g, '-').replace(/[^\w-]+/g, '').toLowerCase();
const formatSlug = (fallback: string): FieldHook => ({ operation, value, originalDoc, data }) => {
if (typeof value === 'string') {
return format(value);
}
if (operation === 'create') {
const fallbackData = (data && data[fallback]) || (originalDoc && originalDoc[fallback]);
if (fallbackData && typeof fallbackData === 'string') {
return format(fallbackData);
}
}
return value;
};
export default formatSlug;

View File

@@ -0,0 +1,30 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "./src",
"jsx": "react",
"sourceMap": true,
"resolveJsonModule": true
},
"include": [
"src"
],
"exclude": [
"node_modules",
"dist",
"build",
],
"ts-node": {
"transpileOnly": true
}
}

File diff suppressed because it is too large Load Diff