feat: builds demo

This commit is contained in:
Jacob Fletcher
2022-02-17 13:57:13 -05:00
parent 92fa206fa4
commit f05462efd3
15 changed files with 11372 additions and 173 deletions

View File

@@ -0,0 +1,10 @@
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
max_line_length = null

View File

@@ -1 +1,2 @@
node_modules
node_modules
.env

View File

@@ -0,0 +1,2 @@
MONGODB_URI=mongodb://localhost/payload-form-builder-demo
PAYLOAD_SECRET=kajsnfkjhabndsfgseaniluanbsrkdgbhyasfg

View File

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

View File

@@ -0,0 +1,27 @@
{
"name": "payload-starter-typescript",
"description": "Blank template - no collections",
"version": "1.0.0",
"main": "dist/server.js",
"license": "MIT",
"scripts": {
"dev": "cross-env 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 build:payload && yarn build:server",
"serve": "cross-env PAYLOAD_CONFIG_PATH=dist/payload.config.js NODE_ENV=production node dist/server.js",
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types"
},
"dependencies": {
"payload": "^0.14.0",
"dotenv": "^8.2.0",
"express": "^4.17.1"
},
"devDependencies": {
"@types/express": "^4.17.9",
"cross-env": "^7.0.3",
"nodemon": "^2.0.6",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
}

View File

@@ -0,0 +1,21 @@
// const payload = require('payload');
import { CollectionConfig } from 'payload/types';
export const Pages: CollectionConfig = {
slug: 'pages',
labels: {
singular: 'Page',
plural: 'Pages',
},
admin: {
useAsTitle: 'title',
},
fields: [
{
name: 'title',
label: 'Title',
type: 'text',
required: true,
}
],
};

View File

@@ -0,0 +1,16 @@
import { CollectionConfig } from 'payload/types';
export const Users: CollectionConfig = {
slug: 'users',
auth: true,
admin: {
useAsTitle: 'email',
},
access: {
read: () => true,
},
fields: [
// Email added by default
// Add more fields as needed
],
};

View File

@@ -0,0 +1,42 @@
import { buildConfig } from 'payload/config';
import path from 'path';
import formBuilderPlugin from '../../src';
import { Users } from './collections/Users';
import { Pages } from './collections/Pages';
export default buildConfig({
serverURL: 'http://localhost:3000',
admin: {
user: Users.slug,
},
collections: [
Users,
Pages
],
plugins: [
formBuilderPlugin({
redirectRelationships: [
'pages'
],
fields: {
payment: true,
// payment: {
// paymentProcessor: {
// options: [
// {
// label: 'Stripe',
// value: 'stripe'
// },
// ],
// defaultValue: 'stripe',
// },
// },
// handlePayment: handleFormPayments,
// beforeEmail: prepareFormEmails,
},
}),
],
typescript: {
outputFile: path.resolve(__dirname, 'payload-types.ts')
},
});

View File

@@ -0,0 +1,24 @@
import express from 'express';
import payload from 'payload';
require('dotenv').config();
const app = express();
// Redirect root to Admin panel
app.get('/', (_, res) => {
res.redirect('/admin');
});
// Initialize Payload
payload.init({
secret: process.env.PAYLOAD_SECRET,
mongoURL: process.env.MONGODB_URI,
express: app,
onInit: () => {
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`);
},
});
// Add your own express routes here
app.listen(3000);

View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "../",
"jsx": "react",
},
"ts-node": {
"transpileOnly": true
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,14 +3,14 @@ import { FormConfig } from '../../types';
import deepMerge from '../../utilities/deepMerge';
import sendEmail from './hooks/sendEmail';
import createCharge from './hooks/createCharge';
import loggedInUsers from '../../../../collections/User/access/loggedInUsers';
// all settings can be overridden by the config
export const generateSubmissionCollection = (formConfig: FormConfig): CollectionConfig => deepMerge({
slug: formConfig?.formsOverrides?.slug || 'formSubmissions',
slug: formConfig?.formSubmissionOverrides?.slug || 'formSubmissions',
access: {
create: () => true,
update: () => false,
read: loggedInUsers
read: ({ req: { user } }) => !!user // logged-in users
},
admin: {
enableRichTextRelationship: false
@@ -127,4 +127,4 @@ export const generateSubmissionCollection = (formConfig: FormConfig): Collection
]
}
],
}, formConfig.formSubmissionsOverrides || {});
}, formConfig.formSubmissionOverrides || {});

View File

@@ -340,177 +340,183 @@ const Checkbox: Block = {
],
};
const Payment = (fieldConfig: FieldConfig): Block => ({
slug: 'payment',
labels: {
singular: 'Payment',
plural: 'Payment Fields',
},
fields: [
{
type: 'row',
fields: [
{
...label,
admin: {
width: '50%',
},
},
{
...width,
admin: {
width: '50%',
},
},
],
const Payment = (fieldConfig: FieldConfig): Block => {
let paymentProcessorField = null;
if (fieldConfig?.paymentProcessor) {
paymentProcessorField = {
type: 'select',
options: [],
name: 'paymentProcessor',
label: 'Payment Processor',
...fieldConfig.paymentProcessor,
}
}
return ({
slug: 'payment',
labels: {
singular: 'Payment',
plural: 'Payment Fields',
},
{
type: 'row',
fields: [
{
name: 'paymentProcessor',
type: 'select',
options: [],
admin: {
width: '100%',
},
...fieldConfig?.paymentProcessor || {}
},
{
name: 'priceType',
label: 'Price Type',
type: 'radio',
admin: {
width: '100%',
},
defaultValue: 'static',
options: [
{
label: 'Static Price',
value: 'static'
fields: [
{
type: 'row',
fields: [
{
...label,
admin: {
width: '50%',
},
{
label: 'Dynamic Price',
value: 'dynamic'
}
]
},
{
name: 'staticPrice',
type: 'number',
label: 'Price',
admin: {
condition: (_, { priceType }) => priceType === 'static'
},
},
{
name: 'dynamicPrice',
labels: {
singular: 'Condition',
plural: 'Conditions',
{
...width,
admin: {
width: '50%',
},
},
type: 'array',
label: 'Price',
admin: {
condition: (_, { priceType }) => priceType === 'dynamic'
},
fields: [
{
name: 'fieldToUse',
type: 'text',
admin: {
components: {
Field: DynamicFieldSelector,
},
],
},
{
type: 'row',
fields: [
paymentProcessorField,
{
name: 'priceType',
label: 'Price Type',
type: 'radio',
admin: {
width: '100%',
},
defaultValue: 'static',
options: [
{
label: 'Static Price',
value: 'static'
},
},
{
name: 'condition',
label: 'Condition',
type: 'select',
defaultValue: 'hasValue',
options: [
{
value: 'hasValue',
label: 'Has Any Value'
},
{
value: 'equals',
label: 'Equals'
},
{
value: 'notEquals',
label: 'Does Not Equal'
}
]
},
{
name: 'valueForCondition',
label: 'Value',
type: 'text',
admin: {
condition: (_, { condition }) => condition === 'equals' || condition === 'notEquals'
{
label: 'Dynamic Price',
value: 'dynamic'
}
]
},
{
name: 'staticPrice',
type: 'number',
label: 'Price',
admin: {
condition: (_, { priceType }) => priceType === 'static'
},
{
name: 'operator',
type: 'select',
defaultValue: 'add',
options: [
{
value: 'add',
label: 'Add'
},
{
value: 'subtract',
label: 'Subtract'
},
{
value: 'multiply',
label: 'Multiply'
},
{
value: 'divide',
label: 'Divide'
}
]
},
{
name: 'dynamicPrice',
labels: {
singular: 'Condition',
plural: 'Conditions',
},
{
name: 'valueType',
label: 'Value Type',
type: 'radio',
admin: {
width: '100%',
},
defaultValue: 'static',
options: [
{
label: 'Static Value',
value: 'static'
},
{
label: 'Dynamic Value',
value: 'dynamic'
}
]
type: 'array',
label: 'Price',
admin: {
condition: (_, { priceType }) => priceType === 'dynamic'
},
{
name: 'valueForOperator',
label: 'Value',
type: 'text',
admin: {
components: {
Field: DynamicPriceSelector,
fields: [
{
name: 'fieldToUse',
type: 'text',
admin: {
components: {
Field: DynamicFieldSelector,
},
},
},
},
]
},
],
},
required,
],
});
{
name: 'condition',
label: 'Condition',
type: 'select',
defaultValue: 'hasValue',
options: [
{
value: 'hasValue',
label: 'Has Any Value'
},
{
value: 'equals',
label: 'Equals'
},
{
value: 'notEquals',
label: 'Does Not Equal'
}
]
},
{
name: 'valueForCondition',
label: 'Value',
type: 'text',
admin: {
condition: (_, { condition }) => condition === 'equals' || condition === 'notEquals'
}
},
{
name: 'operator',
type: 'select',
defaultValue: 'add',
options: [
{
value: 'add',
label: 'Add'
},
{
value: 'subtract',
label: 'Subtract'
},
{
value: 'multiply',
label: 'Multiply'
},
{
value: 'divide',
label: 'Divide'
}
]
},
{
name: 'valueType',
label: 'Value Type',
type: 'radio',
admin: {
width: '100%',
},
defaultValue: 'static',
options: [
{
label: 'Static Value',
value: 'static'
},
{
label: 'Dynamic Value',
value: 'dynamic'
}
]
},
{
name: 'valueForOperator',
label: 'Value',
type: 'text',
admin: {
components: {
Field: DynamicPriceSelector,
},
},
},
]
},
].filter(Boolean),
},
required,
]
})
};
const Message: Block = {
slug: 'message',

View File

@@ -3,8 +3,9 @@ import { FormConfig } from '../../types';
import fields from './fields';
import deepMerge from '../../utilities/deepMerge';
// all settings can be overridden by the config
export const generateFormCollection = (formConfig: FormConfig): CollectionConfig => deepMerge({
slug: formConfig?.formsOverrides?.slug || 'forms',
slug: formConfig?.formOverrides?.slug || 'forms',
admin: {
useAsTitle: 'title',
enableRichTextRelationship: false,
@@ -95,7 +96,7 @@ export const generateFormCollection = (formConfig: FormConfig): CollectionConfig
name: 'reference',
label: 'Document to link to',
type: 'relationship',
relationTo: ['pages', 'posts', 'housing'],
relationTo: formConfig.redirectRelationships || [],
required: true,
maxDepth: 2,
admin: {
@@ -182,4 +183,4 @@ export const generateFormCollection = (formConfig: FormConfig): CollectionConfig
],
},
],
}, formConfig.formsOverrides || {});
}, formConfig.formOverrides || {});

View File

@@ -1,4 +1,3 @@
import { RichText } from '@trbl/hope-types';
import { Block, CollectionConfig, Field } from 'payload/types';
export type BlockConfig = {
@@ -34,10 +33,11 @@ export type HandlePayment = (data) => void;
export type FormConfig = {
fields?: FieldsConfig
formSubmissionsOverrides?: CollectionConfig
formsOverrides?: CollectionConfig
formSubmissionOverrides?: Partial<CollectionConfig>
formOverrides?: Partial<CollectionConfig>
beforeEmail?: BeforeEmail
handlePayment?: HandlePayment
redirectRelationships?: string[]
}
export type TextField = {
@@ -120,7 +120,7 @@ export type Email = {
bcc?: string
replyTo?: string
subject: string
message?: RichText
message?: any // TODO: configure rich text type
}
export type FormattedEmail = {
@@ -144,7 +144,7 @@ export type Form = {
fields: FormFieldBlock[]
submitButtonLabel?: string
confirmationType: 'message' | 'redirect'
confirmationMessage?: RichText
confirmationMessage?: any // TODO: configure rich text type
redirect?: Redirect
emails: Email[]
}