chore: eslint and prettier (#40)
This commit is contained in:
3
packages/plugin-form-builder/.eslintrc.js
Normal file
3
packages/plugin-form-builder/.eslintrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: ['@payloadcms'],
|
||||
}
|
||||
8
packages/plugin-form-builder/.prettierrc.js
Normal file
8
packages/plugin-form-builder/.prettierrc.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
printWidth: 100,
|
||||
parser: "typescript",
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
trailingComma: "all",
|
||||
arrowParens: "avoid",
|
||||
};
|
||||
@@ -20,6 +20,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.9",
|
||||
"@types/react": "^18.2.6",
|
||||
"cross-env": "^7.0.3",
|
||||
"nodemon": "^2.0.6",
|
||||
"ts-node": "^9.1.1",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// const payload = require('payload');
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
@@ -22,6 +21,6 @@ export const Pages: CollectionConfig = {
|
||||
label: 'Form',
|
||||
type: 'relationship',
|
||||
relationTo: 'forms',
|
||||
}
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
export const Users: CollectionConfig = {
|
||||
slug: 'users',
|
||||
@@ -13,4 +13,4 @@ export const Users: CollectionConfig = {
|
||||
// Email added by default
|
||||
// Add more fields as needed
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { buildConfig } from 'payload/config';
|
||||
import path from 'path';
|
||||
import path from 'path'
|
||||
import { buildConfig } from 'payload/config'
|
||||
import type { Block } from 'payload/types'
|
||||
|
||||
// import formBuilderPlugin from '../../dist';
|
||||
import formBuilderPlugin from '../../src';
|
||||
import { Users } from './collections/Users';
|
||||
import { Pages } from './collections/Pages';
|
||||
import { Block } from 'payload/types';
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import formBuilderPlugin from '../../src'
|
||||
import { Pages } from './collections/Pages'
|
||||
import { Users } from './collections/Users'
|
||||
|
||||
const colorField: Block = {
|
||||
slug: 'color',
|
||||
@@ -16,8 +18,8 @@ const colorField: Block = {
|
||||
{
|
||||
name: 'value',
|
||||
type: 'text',
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default buildConfig({
|
||||
@@ -28,34 +30,29 @@ export default buildConfig({
|
||||
},
|
||||
admin: {
|
||||
user: Users.slug,
|
||||
webpack: (config) => {
|
||||
webpack: config => {
|
||||
const newConfig = {
|
||||
...config,
|
||||
resolve: {
|
||||
...config.resolve,
|
||||
alias: {
|
||||
...config.resolve.alias,
|
||||
react: path.join(__dirname, "../node_modules/react"),
|
||||
"react-dom": path.join(__dirname, "../node_modules/react-dom"),
|
||||
"payload": path.join(__dirname, "../node_modules/payload"),
|
||||
react: path.join(__dirname, '../node_modules/react'),
|
||||
'react-dom': path.join(__dirname, '../node_modules/react-dom'),
|
||||
payload: path.join(__dirname, '../node_modules/payload'),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return newConfig;
|
||||
return newConfig
|
||||
},
|
||||
},
|
||||
collections: [
|
||||
Users,
|
||||
Pages
|
||||
],
|
||||
collections: [Users, Pages],
|
||||
plugins: [
|
||||
formBuilderPlugin({
|
||||
// handlePayment: handleFormPayments,
|
||||
// beforeEmail: prepareFormEmails,
|
||||
redirectRelationships: [
|
||||
'pages'
|
||||
],
|
||||
redirectRelationships: ['pages'],
|
||||
formOverrides: {
|
||||
// labels: {
|
||||
// singular: 'Contact Form',
|
||||
@@ -65,8 +62,8 @@ export default buildConfig({
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: {
|
||||
payment: true,
|
||||
@@ -86,6 +83,6 @@ export default buildConfig({
|
||||
}),
|
||||
],
|
||||
typescript: {
|
||||
outputFile: path.resolve(__dirname, 'payload-types.ts')
|
||||
outputFile: path.resolve(__dirname, 'payload-types.ts'),
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Payload } from 'payload';
|
||||
import type { Payload } from 'payload'
|
||||
|
||||
export const seed = async (payload: Payload) => {
|
||||
payload.logger.info('Seeding data...');
|
||||
export const seed = async (payload: Payload): Promise<any> => {
|
||||
payload.logger.info('Seeding data...')
|
||||
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: 'dev@payloadcms.com',
|
||||
password: 'test',
|
||||
}
|
||||
});
|
||||
},
|
||||
})
|
||||
|
||||
const { id: formID } = await payload.create({
|
||||
collection: 'forms',
|
||||
@@ -33,8 +33,8 @@ export const seed = async (payload: Payload) => {
|
||||
label: 'Email',
|
||||
name: 'email',
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
@@ -42,7 +42,7 @@ export const seed = async (payload: Payload) => {
|
||||
collection: 'pages',
|
||||
data: {
|
||||
title: 'Contact',
|
||||
form: formID
|
||||
form: formID,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import express from 'express';
|
||||
import payload from 'payload';
|
||||
import { seed } from './seed';
|
||||
import dotenv from 'dotenv'
|
||||
import express from 'express'
|
||||
import payload from 'payload'
|
||||
|
||||
require('dotenv').config();
|
||||
const app = express();
|
||||
import { seed } from './seed'
|
||||
|
||||
dotenv.config()
|
||||
const app = express()
|
||||
|
||||
// Redirect root to Admin panel
|
||||
app.get('/', (_, res) => {
|
||||
res.redirect('/admin');
|
||||
});
|
||||
res.redirect('/admin')
|
||||
})
|
||||
|
||||
// Initialize Payload
|
||||
const start = async () => {
|
||||
const start = async (): Promise<any> => {
|
||||
await payload.initAsync({
|
||||
secret: process.env.PAYLOAD_SECRET,
|
||||
mongoURL: process.env.MONGODB_URI,
|
||||
@@ -22,10 +24,10 @@ const start = async () => {
|
||||
})
|
||||
|
||||
if (process.env.PAYLOAD_SEED === 'true') {
|
||||
await seed(payload);
|
||||
await seed(payload)
|
||||
}
|
||||
|
||||
app.listen(3000);
|
||||
app.listen(3000)
|
||||
}
|
||||
|
||||
start();
|
||||
start()
|
||||
|
||||
@@ -1861,6 +1861,15 @@
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/react@^18.2.6":
|
||||
version "18.2.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.6.tgz#5cd53ee0d30ffc193b159d3516c8c8ad2f19d571"
|
||||
integrity sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/scheduler@*":
|
||||
version "0.16.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint --fix --ext .ts,.tsx src"
|
||||
},
|
||||
"keywords": [
|
||||
"payload",
|
||||
@@ -29,9 +31,27 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/escape-html": "^1.0.1",
|
||||
"@payloadcms/eslint-config": "^0.0.1",
|
||||
"@types/express": "^4.17.9",
|
||||
"@types/node": "18.11.3",
|
||||
"@types/react": "18.0.21",
|
||||
"@typescript-eslint/eslint-plugin": "^5.51.0",
|
||||
"@typescript-eslint/parser": "^5.51.0",
|
||||
"copyfiles": "^2.4.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.19.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-filenames": "^1.3.2",
|
||||
"eslint-plugin-import": "2.25.4",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"nodemon": "^2.0.6",
|
||||
"payload": "^1.3.0",
|
||||
"prettier": "^2.7.1",
|
||||
"react": "^18.0.0",
|
||||
"typescript": "^4.5.5"
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
import { PluginConfig } from "../../../types";
|
||||
import type { PluginConfig } from '../../../types'
|
||||
|
||||
const createCharge = async (beforeChangeData: any, formConfig: PluginConfig) => {
|
||||
const {
|
||||
operation,
|
||||
data
|
||||
} = beforeChangeData;
|
||||
const createCharge = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
|
||||
const { operation, data } = beforeChangeData
|
||||
|
||||
let dataWithPaymentDetails = data;
|
||||
let dataWithPaymentDetails = data
|
||||
|
||||
if (operation === 'create') {
|
||||
const {
|
||||
handlePayment
|
||||
} = formConfig || {};
|
||||
const { handlePayment } = formConfig || {}
|
||||
|
||||
if (typeof handlePayment === 'function') {
|
||||
dataWithPaymentDetails = await handlePayment(beforeChangeData);
|
||||
dataWithPaymentDetails = await handlePayment(beforeChangeData)
|
||||
}
|
||||
}
|
||||
|
||||
return dataWithPaymentDetails;
|
||||
};
|
||||
return dataWithPaymentDetails
|
||||
}
|
||||
|
||||
export default createCharge
|
||||
|
||||
@@ -1,111 +1,93 @@
|
||||
import { serialize } from '../../../utilities/serializeRichText';
|
||||
import { Email, FormattedEmail, PluginConfig } from '../../../types';
|
||||
import { replaceDoubleCurlys } from '../../../utilities/replaceDoubleCurlys';
|
||||
import type { Email, FormattedEmail, PluginConfig } from '../../../types'
|
||||
import { replaceDoubleCurlys } from '../../../utilities/replaceDoubleCurlys'
|
||||
import { serialize } from '../../../utilities/serializeRichText'
|
||||
|
||||
const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig) => {
|
||||
const {
|
||||
operation,
|
||||
data
|
||||
} = beforeChangeData;
|
||||
const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
|
||||
const { operation, data } = beforeChangeData
|
||||
|
||||
if (operation === 'create') {
|
||||
const {
|
||||
data: {
|
||||
id: formSubmissionID
|
||||
},
|
||||
req: {
|
||||
payload,
|
||||
locale
|
||||
}
|
||||
} = beforeChangeData;
|
||||
data: { id: formSubmissionID },
|
||||
req: { payload, locale },
|
||||
} = beforeChangeData
|
||||
|
||||
const {
|
||||
form: formID,
|
||||
submissionData
|
||||
} = data || {};
|
||||
const { form: formID, submissionData } = data || {}
|
||||
|
||||
const {
|
||||
beforeEmail,
|
||||
formOverrides
|
||||
} = formConfig || {};
|
||||
const { beforeEmail, formOverrides } = formConfig || {}
|
||||
|
||||
try {
|
||||
const form = await payload.findByID({
|
||||
id: formID,
|
||||
collection: formOverrides?.slug || 'forms',
|
||||
locale
|
||||
});
|
||||
locale,
|
||||
})
|
||||
|
||||
if (form) {
|
||||
const {
|
||||
emails,
|
||||
} = form;
|
||||
const { emails } = form
|
||||
|
||||
if (emails) {
|
||||
const formattedEmails: FormattedEmail[] = emails.map((email: Email): FormattedEmail | null => {
|
||||
const {
|
||||
message,
|
||||
subject,
|
||||
emailTo,
|
||||
cc: emailCC,
|
||||
bcc: emailBCC,
|
||||
emailFrom,
|
||||
replyTo: emailReplyTo,
|
||||
} = email;
|
||||
const formattedEmails: FormattedEmail[] = emails.map(
|
||||
(email: Email): FormattedEmail | null => {
|
||||
const {
|
||||
message,
|
||||
subject,
|
||||
emailTo,
|
||||
cc: emailCC,
|
||||
bcc: emailBCC,
|
||||
emailFrom,
|
||||
replyTo: emailReplyTo,
|
||||
} = email
|
||||
|
||||
const to = replaceDoubleCurlys(emailTo, submissionData);
|
||||
const cc = emailCC ? replaceDoubleCurlys(emailCC, submissionData) : '';
|
||||
const bcc = emailBCC ? replaceDoubleCurlys(emailBCC, submissionData) : '';
|
||||
const from = replaceDoubleCurlys(emailFrom, submissionData);
|
||||
const replyTo = replaceDoubleCurlys(emailReplyTo || emailFrom, submissionData);
|
||||
const to = replaceDoubleCurlys(emailTo, submissionData)
|
||||
const cc = emailCC ? replaceDoubleCurlys(emailCC, submissionData) : ''
|
||||
const bcc = emailBCC ? replaceDoubleCurlys(emailBCC, submissionData) : ''
|
||||
const from = replaceDoubleCurlys(emailFrom, submissionData)
|
||||
const replyTo = replaceDoubleCurlys(emailReplyTo || emailFrom, submissionData)
|
||||
|
||||
return ({
|
||||
to,
|
||||
from,
|
||||
cc,
|
||||
bcc,
|
||||
replyTo,
|
||||
subject: replaceDoubleCurlys(subject, submissionData),
|
||||
html: `<div>${serialize(message, submissionData)}</div>`
|
||||
});
|
||||
});
|
||||
return {
|
||||
to,
|
||||
from,
|
||||
cc,
|
||||
bcc,
|
||||
replyTo,
|
||||
subject: replaceDoubleCurlys(subject, submissionData),
|
||||
html: `<div>${serialize(message, submissionData)}</div>`,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
let emailsToSend = formattedEmails
|
||||
|
||||
if (typeof beforeEmail === 'function') {
|
||||
emailsToSend = await beforeEmail(formattedEmails);
|
||||
emailsToSend = await beforeEmail(formattedEmails)
|
||||
}
|
||||
|
||||
const log = emailsToSend.map(({ html, ...rest }) => ({ ...rest }))
|
||||
// const log = emailsToSend.map(({ html, ...rest }) => ({ ...rest }))
|
||||
|
||||
await Promise.all(
|
||||
emailsToSend.map(async (email) => {
|
||||
const { to } = email;
|
||||
emailsToSend.map(async email => {
|
||||
const { to } = email
|
||||
try {
|
||||
const emailPromise = await payload.sendEmail(email);
|
||||
return emailPromise;
|
||||
} catch (err: any) {
|
||||
console.error(`Error while sending email to address: ${to}. Email not sent.`);
|
||||
if (err?.response?.body?.errors) {
|
||||
const error = err.response.body.errors?.[0];
|
||||
console.log('%s: %s', error?.field, error?.message);
|
||||
} else {
|
||||
console.log(err);
|
||||
}
|
||||
const emailPromise = await payload.sendEmail(email)
|
||||
return emailPromise
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error({
|
||||
err: `Error while sending email to address: ${to}. Email not sent: ${err}`,
|
||||
})
|
||||
}
|
||||
})
|
||||
);
|
||||
}),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
console.log('No emails to send.')
|
||||
payload.logger.info({ msg: 'No emails to send.' })
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error while sending one or more emails in form submission id: ${formSubmissionID}.`);
|
||||
console.error(err);
|
||||
} catch (err: unknown) {
|
||||
const msg = `Error while sending one or more emails in form submission id: ${formSubmissionID}.`
|
||||
payload.logger.error({ err: msg })
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
return data
|
||||
}
|
||||
|
||||
export default sendEmail;
|
||||
export default sendEmail
|
||||
|
||||
@@ -1,30 +1,31 @@
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import { PluginConfig } from '../../types';
|
||||
import sendEmail from './hooks/sendEmail';
|
||||
import createCharge from './hooks/createCharge';
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import type { PluginConfig } from '../../types'
|
||||
import createCharge from './hooks/createCharge'
|
||||
import sendEmail from './hooks/sendEmail'
|
||||
|
||||
// all settings can be overridden by the config
|
||||
export const generateSubmissionCollection = (formConfig: PluginConfig): CollectionConfig => {
|
||||
const newConfig: CollectionConfig = {
|
||||
...formConfig?.formSubmissionOverrides || {},
|
||||
...(formConfig?.formSubmissionOverrides || {}),
|
||||
slug: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',
|
||||
access: {
|
||||
create: () => true,
|
||||
update: () => false,
|
||||
read: ({ req: { user } }) => !!user, // logged-in users,
|
||||
...formConfig?.formSubmissionOverrides?.access || {}
|
||||
...(formConfig?.formSubmissionOverrides?.access || {}),
|
||||
},
|
||||
admin: {
|
||||
...formConfig?.formSubmissionOverrides?.admin || {},
|
||||
enableRichTextRelationship: false
|
||||
...(formConfig?.formSubmissionOverrides?.admin || {}),
|
||||
enableRichTextRelationship: false,
|
||||
},
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
(data) => createCharge(data, formConfig),
|
||||
(data) => sendEmail(data, formConfig),
|
||||
...formConfig?.formSubmissionOverrides?.hooks?.beforeChange || []
|
||||
data => createCharge(data, formConfig),
|
||||
data => sendEmail(data, formConfig),
|
||||
...(formConfig?.formSubmissionOverrides?.hooks?.beforeChange || []),
|
||||
],
|
||||
...formConfig?.formSubmissionOverrides?.hooks || {}
|
||||
...(formConfig?.formSubmissionOverrides?.hooks || {}),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
@@ -33,14 +34,14 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
||||
relationTo: formConfig?.formOverrides?.slug || 'forms',
|
||||
required: true,
|
||||
admin: {
|
||||
readOnly: true
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'submissionData',
|
||||
type: 'array',
|
||||
admin: {
|
||||
readOnly: true
|
||||
readOnly: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
@@ -64,44 +65,44 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
||||
// Instead, might need to do all validation in a `beforeValidate` collection hook.
|
||||
|
||||
if (typeof value !== 'undefined') {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
return 'This field is required.';
|
||||
return 'This field is required.'
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
...formConfig?.formSubmissionOverrides?.fields || []
|
||||
...(formConfig?.formSubmissionOverrides?.fields || []),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const paymentFieldConfig = formConfig?.fields?.payment;
|
||||
const paymentFieldConfig = formConfig?.fields?.payment
|
||||
|
||||
if (paymentFieldConfig) {
|
||||
newConfig.fields.push({
|
||||
name: 'payment',
|
||||
type: 'group',
|
||||
admin: {
|
||||
readOnly: true
|
||||
readOnly: true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'field',
|
||||
label: 'Field',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
type: 'number',
|
||||
admin: {
|
||||
description: 'Amount in cents'
|
||||
}
|
||||
description: 'Amount in cents',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'paymentProcessor',
|
||||
@@ -115,23 +116,23 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
||||
{
|
||||
name: 'token',
|
||||
label: 'token',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'brand',
|
||||
label: 'Brand',
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'number',
|
||||
label: 'Number',
|
||||
type: 'text'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
return newConfig;
|
||||
return newConfig
|
||||
}
|
||||
|
||||
@@ -1,48 +1,36 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Select, useForm } from 'payload/components/forms';
|
||||
import { TextField } from 'payload/dist/fields/config/types';
|
||||
import { SelectFieldOption } from '../../types';
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { Select, useForm } from 'payload/components/forms'
|
||||
import { TextField } from 'payload/dist/fields/config/types'
|
||||
|
||||
export const DynamicFieldSelector: React.FC<TextField> = (props) => {
|
||||
const {
|
||||
fields,
|
||||
getDataByPath
|
||||
} = useForm();
|
||||
import { SelectFieldOption } from '../../types'
|
||||
|
||||
const [options, setOptions] = useState<SelectFieldOption[]>([]);
|
||||
export const DynamicFieldSelector: React.FC<TextField> = props => {
|
||||
const { fields, getDataByPath } = useForm()
|
||||
|
||||
const [options, setOptions] = useState<SelectFieldOption[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
// @ts-ignore
|
||||
const fields: any[] = getDataByPath('fields')
|
||||
|
||||
if (fields) {
|
||||
const allNonPaymentFields = fields.map((block): SelectFieldOption | null => {
|
||||
const {
|
||||
name,
|
||||
label,
|
||||
blockType
|
||||
} = block;
|
||||
const allNonPaymentFields = fields
|
||||
.map((block): SelectFieldOption | null => {
|
||||
const { name, label, blockType } = block
|
||||
|
||||
if (blockType !== 'payment') {
|
||||
return ({
|
||||
label,
|
||||
value: name
|
||||
})
|
||||
}
|
||||
if (blockType !== 'payment') {
|
||||
return {
|
||||
label,
|
||||
value: name,
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}).filter(Boolean) as SelectFieldOption[];
|
||||
setOptions(allNonPaymentFields);
|
||||
return null
|
||||
})
|
||||
.filter(Boolean) as SelectFieldOption[]
|
||||
setOptions(allNonPaymentFields)
|
||||
}
|
||||
}, [
|
||||
fields,
|
||||
getDataByPath
|
||||
]);
|
||||
}, [fields, getDataByPath])
|
||||
|
||||
return (
|
||||
<Select
|
||||
{...props}
|
||||
options={options}
|
||||
/>
|
||||
);
|
||||
};
|
||||
return <Select {...props} options={options} />
|
||||
}
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
import { Block, Field } from 'payload/types';
|
||||
import { FieldConfig, PaymentFieldConfig, TextField } from '../../types';
|
||||
import { DynamicFieldSelector } from './DynamicFieldSelector';
|
||||
import { DynamicPriceSelector } from './DynamicPriceSelector';
|
||||
import type { Block, Field } from 'payload/types'
|
||||
|
||||
import type { FieldConfig, PaymentFieldConfig } from '../../types'
|
||||
import { DynamicFieldSelector } from './DynamicFieldSelector'
|
||||
import { DynamicPriceSelector } from './DynamicPriceSelector'
|
||||
|
||||
const name: Field = {
|
||||
name: 'name',
|
||||
label: 'Name (lowercase, no special characters)',
|
||||
type: 'text',
|
||||
required: true,
|
||||
};
|
||||
}
|
||||
|
||||
const label: Field = {
|
||||
name: 'label',
|
||||
label: 'Label',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
};
|
||||
}
|
||||
|
||||
const required: Field = {
|
||||
name: 'required',
|
||||
label: 'Required',
|
||||
type: 'checkbox',
|
||||
};
|
||||
}
|
||||
|
||||
const width: Field = {
|
||||
name: 'width',
|
||||
label: 'Field Width (percentage)',
|
||||
type: 'number',
|
||||
};
|
||||
}
|
||||
|
||||
const Select: Block = {
|
||||
slug: 'select',
|
||||
@@ -110,7 +111,7 @@ const Select: Block = {
|
||||
},
|
||||
required,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const Text: Block = {
|
||||
slug: 'text',
|
||||
@@ -158,7 +159,7 @@ const Text: Block = {
|
||||
},
|
||||
required,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const TextArea: Block = {
|
||||
slug: 'textarea',
|
||||
@@ -206,7 +207,7 @@ const TextArea: Block = {
|
||||
},
|
||||
required,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const Number: Block = {
|
||||
slug: 'number',
|
||||
@@ -253,7 +254,7 @@ const Number: Block = {
|
||||
},
|
||||
required,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const Email: Block = {
|
||||
slug: 'email',
|
||||
@@ -282,7 +283,7 @@ const Email: Block = {
|
||||
width,
|
||||
required,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const State: Block = {
|
||||
slug: 'state',
|
||||
@@ -311,7 +312,7 @@ const State: Block = {
|
||||
width,
|
||||
required,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const Country: Block = {
|
||||
slug: 'country',
|
||||
@@ -340,7 +341,7 @@ const Country: Block = {
|
||||
width,
|
||||
required,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const Checkbox: Block = {
|
||||
slug: 'checkbox',
|
||||
@@ -389,11 +390,10 @@ const Checkbox: Block = {
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const Payment = (fieldConfig: PaymentFieldConfig): Block => {
|
||||
|
||||
let paymentProcessorField = null;
|
||||
let paymentProcessorField = null
|
||||
if (fieldConfig?.paymentProcessor) {
|
||||
paymentProcessorField = {
|
||||
type: 'select',
|
||||
@@ -474,25 +474,26 @@ const Payment = (fieldConfig: PaymentFieldConfig): Block => {
|
||||
options: [
|
||||
{
|
||||
value: 'hasValue',
|
||||
label: 'Has Any Value'
|
||||
label: 'Has Any Value',
|
||||
},
|
||||
{
|
||||
value: 'equals',
|
||||
label: 'Equals'
|
||||
label: 'Equals',
|
||||
},
|
||||
{
|
||||
value: 'notEquals',
|
||||
label: 'Does Not Equal'
|
||||
}
|
||||
]
|
||||
label: 'Does Not Equal',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'valueForCondition',
|
||||
label: 'Value',
|
||||
type: 'text',
|
||||
admin: {
|
||||
condition: (_: any, { condition }: any) => condition === 'equals' || condition === 'notEquals'
|
||||
}
|
||||
condition: (_: any, { condition }: any) =>
|
||||
condition === 'equals' || condition === 'notEquals',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'operator',
|
||||
@@ -501,21 +502,21 @@ const Payment = (fieldConfig: PaymentFieldConfig): Block => {
|
||||
options: [
|
||||
{
|
||||
value: 'add',
|
||||
label: 'Add'
|
||||
label: 'Add',
|
||||
},
|
||||
{
|
||||
value: 'subtract',
|
||||
label: 'Subtract'
|
||||
label: 'Subtract',
|
||||
},
|
||||
{
|
||||
value: 'multiply',
|
||||
label: 'Multiply'
|
||||
label: 'Multiply',
|
||||
},
|
||||
{
|
||||
value: 'divide',
|
||||
label: 'Divide'
|
||||
}
|
||||
]
|
||||
label: 'Divide',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'valueType',
|
||||
@@ -528,13 +529,13 @@ const Payment = (fieldConfig: PaymentFieldConfig): Block => {
|
||||
options: [
|
||||
{
|
||||
label: 'Static Value',
|
||||
value: 'static'
|
||||
value: 'static',
|
||||
},
|
||||
{
|
||||
label: 'Value Of Field',
|
||||
value: 'valueOfField'
|
||||
}
|
||||
]
|
||||
value: 'valueOfField',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'valueForOperator',
|
||||
@@ -546,14 +547,14 @@ const Payment = (fieldConfig: PaymentFieldConfig): Block => {
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
required,
|
||||
].filter(Boolean) as Field[]
|
||||
].filter(Boolean) as Field[],
|
||||
}
|
||||
|
||||
return fields
|
||||
};
|
||||
}
|
||||
|
||||
const Message: Block = {
|
||||
slug: 'message',
|
||||
@@ -568,8 +569,9 @@ const Message: Block = {
|
||||
localized: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
export default {
|
||||
select: Select,
|
||||
checkbox: Checkbox,
|
||||
@@ -580,7 +582,7 @@ export default {
|
||||
number: Number,
|
||||
country: Country,
|
||||
state: State,
|
||||
payment: Payment
|
||||
payment: Payment,
|
||||
} as {
|
||||
[key: string]: Block | ((fieldConfig?: boolean | FieldConfig) => Block)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Block, CollectionConfig, Field } from 'payload/types';
|
||||
import merge from 'deepmerge';
|
||||
import { FieldConfig, PluginConfig } from '../../types';
|
||||
import fields from './fields';
|
||||
import merge from 'deepmerge'
|
||||
import type { Block, CollectionConfig, Field } from 'payload/types'
|
||||
|
||||
import type { FieldConfig, PluginConfig } from '../../types'
|
||||
import fields from './fields'
|
||||
|
||||
// all settings can be overridden by the config
|
||||
export const generateFormCollection = (formConfig: PluginConfig): CollectionConfig => {
|
||||
|
||||
const redirect: Field = {
|
||||
name: 'redirect',
|
||||
type: 'group',
|
||||
@@ -21,7 +21,7 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
if (formConfig.redirectRelationships) {
|
||||
redirect.fields.unshift({
|
||||
@@ -34,7 +34,7 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
|
||||
admin: {
|
||||
condition: (_, siblingData) => siblingData?.type === 'reference',
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
redirect.fields.unshift({
|
||||
name: 'type',
|
||||
@@ -53,26 +53,26 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
|
||||
admin: {
|
||||
layout: 'horizontal',
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
if (redirect.fields[2].type !== 'row') redirect.fields[2].label = 'Custom URL';
|
||||
if (redirect.fields[2].type !== 'row') redirect.fields[2].label = 'Custom URL'
|
||||
|
||||
redirect.fields[2].admin = {
|
||||
condition: (_, siblingData) => siblingData?.type === 'custom',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const config: CollectionConfig = {
|
||||
...formConfig?.formOverrides || {},
|
||||
...(formConfig?.formOverrides || {}),
|
||||
slug: formConfig?.formOverrides?.slug || 'forms',
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
enableRichTextRelationship: false,
|
||||
...formConfig?.formOverrides?.admin || {},
|
||||
...(formConfig?.formOverrides?.admin || {}),
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
...formConfig?.formOverrides?.access || {}
|
||||
...(formConfig?.formOverrides?.access || {}),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
@@ -83,30 +83,32 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
|
||||
{
|
||||
name: 'fields',
|
||||
type: 'blocks',
|
||||
blocks: Object.entries(formConfig?.fields || {}).map(([fieldKey, fieldConfig]) => {
|
||||
// let the config enable/disable fields with either boolean values or objects
|
||||
if (fieldConfig !== false) {
|
||||
let block = fields[fieldKey];
|
||||
blocks: Object.entries(formConfig?.fields || {})
|
||||
.map(([fieldKey, fieldConfig]) => {
|
||||
// let the config enable/disable fields with either boolean values or objects
|
||||
if (fieldConfig !== false) {
|
||||
let block = fields[fieldKey]
|
||||
|
||||
if (block === undefined && typeof fieldConfig === 'object') {
|
||||
return fieldConfig
|
||||
if (block === undefined && typeof fieldConfig === 'object') {
|
||||
return fieldConfig
|
||||
}
|
||||
|
||||
if (typeof block === 'object' && typeof fieldConfig === 'object') {
|
||||
return merge<FieldConfig>(block, fieldConfig, {
|
||||
arrayMerge: (_, sourceArray) => sourceArray,
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof block === 'function') {
|
||||
return block(fieldConfig)
|
||||
}
|
||||
|
||||
return block
|
||||
}
|
||||
|
||||
if (typeof block === 'object' && typeof fieldConfig === 'object') {
|
||||
return merge<FieldConfig>(block, fieldConfig, {
|
||||
arrayMerge: (_, sourceArray) => sourceArray
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof block === 'function') {
|
||||
return block(fieldConfig);
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
return null;
|
||||
}).filter(Boolean) as Block[],
|
||||
return null
|
||||
})
|
||||
.filter(Boolean) as Block[],
|
||||
},
|
||||
{
|
||||
name: 'submitButtonLabel',
|
||||
@@ -117,7 +119,8 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
|
||||
name: 'confirmationType',
|
||||
type: 'radio',
|
||||
admin: {
|
||||
description: 'Choose whether to display an on-page message or redirect to a different page after they submit the form.',
|
||||
description:
|
||||
'Choose whether to display an on-page message or redirect to a different page after they submit the form.',
|
||||
layout: 'horizontal',
|
||||
},
|
||||
options: [
|
||||
@@ -146,7 +149,8 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
|
||||
name: 'emails',
|
||||
type: 'array',
|
||||
admin: {
|
||||
description: 'Send custom emails when the form submits. Use comma separated lists to send the same email to multiple recipients. To reference a value from this form, wrap that field\'s name with double curly brackets, i.e. {{firstName}}.',
|
||||
description:
|
||||
"Send custom emails when the form submits. Use comma separated lists to send the same email to multiple recipients. To reference a value from this form, wrap that field's name with double curly brackets, i.e. {{firstName}}.",
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
@@ -158,7 +162,7 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
|
||||
label: 'Email To',
|
||||
admin: {
|
||||
width: '100%',
|
||||
placeholder: '"Email Sender" <sender@email.com>'
|
||||
placeholder: '"Email Sender" <sender@email.com>',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -206,7 +210,7 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
|
||||
type: 'text',
|
||||
name: 'subject',
|
||||
label: 'Subject',
|
||||
defaultValue: 'You\'ve received a new message.',
|
||||
defaultValue: "You've received a new message.",
|
||||
required: true,
|
||||
localized: true,
|
||||
},
|
||||
@@ -221,9 +225,9 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
|
||||
},
|
||||
],
|
||||
},
|
||||
...formConfig?.formOverrides?.fields || []
|
||||
...(formConfig?.formOverrides?.fields || []),
|
||||
],
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -1,51 +1,54 @@
|
||||
import { Config } from 'payload/config';
|
||||
import { generateFormCollection } from './collections/Forms';
|
||||
import { generateSubmissionCollection } from './collections/FormSubmissions';
|
||||
import { PluginConfig } from './types';
|
||||
import type { Config } from 'payload/config'
|
||||
|
||||
import { generateFormCollection } from './collections/Forms'
|
||||
import { generateSubmissionCollection } from './collections/FormSubmissions'
|
||||
import type { PluginConfig } from './types'
|
||||
// import path from 'path';
|
||||
|
||||
export { getPaymentTotal } from './utilities/getPaymentTotal'
|
||||
|
||||
const FormBuilder = (incomingFormConfig: PluginConfig) => (config: Config): Config => {
|
||||
const formConfig: PluginConfig = {
|
||||
...incomingFormConfig,
|
||||
fields: {
|
||||
text: true,
|
||||
textarea: true,
|
||||
select: true,
|
||||
email: true,
|
||||
state: true,
|
||||
country: true,
|
||||
number: true,
|
||||
checkbox: true,
|
||||
message: true,
|
||||
payment: false,
|
||||
...incomingFormConfig.fields,
|
||||
},
|
||||
};
|
||||
const FormBuilder =
|
||||
(incomingFormConfig: PluginConfig) =>
|
||||
(config: Config): Config => {
|
||||
const formConfig: PluginConfig = {
|
||||
...incomingFormConfig,
|
||||
fields: {
|
||||
text: true,
|
||||
textarea: true,
|
||||
select: true,
|
||||
email: true,
|
||||
state: true,
|
||||
country: true,
|
||||
number: true,
|
||||
checkbox: true,
|
||||
message: true,
|
||||
payment: false,
|
||||
...incomingFormConfig.fields,
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
...config,
|
||||
// admin: {
|
||||
// ...config.admin,
|
||||
// webpack: (webpackConfig) => ({
|
||||
// ...webpackConfig,
|
||||
// resolve: {
|
||||
// ...webpackConfig.resolve,
|
||||
// alias: {
|
||||
// ...webpackConfig.resolve.alias,
|
||||
// [path.resolve(__dirname, 'collections/FormSubmissions/hooks/sendEmail.ts')]: path.resolve(__dirname, 'mocks/serverModule.js'),
|
||||
// [path.resolve(__dirname, 'collections/FormSubmissions/hooks/createCharge.ts')]: path.resolve(__dirname, 'mocks/serverModule.js'),
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
// },
|
||||
collections: [
|
||||
...config?.collections || [],
|
||||
generateFormCollection(formConfig),
|
||||
generateSubmissionCollection(formConfig),
|
||||
],
|
||||
};
|
||||
};
|
||||
return {
|
||||
...config,
|
||||
// admin: {
|
||||
// ...config.admin,
|
||||
// webpack: (webpackConfig) => ({
|
||||
// ...webpackConfig,
|
||||
// resolve: {
|
||||
// ...webpackConfig.resolve,
|
||||
// alias: {
|
||||
// ...webpackConfig.resolve.alias,
|
||||
// [path.resolve(__dirname, 'collections/FormSubmissions/hooks/sendEmail.ts')]: path.resolve(__dirname, 'mocks/serverModule.js'),
|
||||
// [path.resolve(__dirname, 'collections/FormSubmissions/hooks/createCharge.ts')]: path.resolve(__dirname, 'mocks/serverModule.js'),
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
// },
|
||||
collections: [
|
||||
...(config?.collections || []),
|
||||
generateFormCollection(formConfig),
|
||||
generateSubmissionCollection(formConfig),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
export default FormBuilder;
|
||||
export default FormBuilder
|
||||
|
||||
@@ -1 +1 @@
|
||||
export default {};
|
||||
export default {}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import { Block, CollectionConfig, Field } from 'payload/types';
|
||||
import type { Block, CollectionConfig, Field } from 'payload/types'
|
||||
|
||||
export type BlockConfig = {
|
||||
export interface BlockConfig {
|
||||
block: Block
|
||||
validate?: (value: unknown) => boolean | string
|
||||
}
|
||||
|
||||
export function isValidBlockConfig(blockConfig: BlockConfig | string): blockConfig is BlockConfig {
|
||||
return typeof blockConfig !== 'string'
|
||||
&& typeof blockConfig?.block?.slug === 'string'
|
||||
&& Array.isArray(blockConfig?.block?.fields);
|
||||
return (
|
||||
typeof blockConfig !== 'string' &&
|
||||
typeof blockConfig?.block?.slug === 'string' &&
|
||||
Array.isArray(blockConfig?.block?.fields)
|
||||
)
|
||||
}
|
||||
|
||||
export type FieldValues = {
|
||||
export interface FieldValues {
|
||||
[key: string]: string | number | boolean | null | undefined
|
||||
}
|
||||
|
||||
@@ -19,9 +21,9 @@ export type PaymentFieldConfig = Partial<Field> & {
|
||||
paymentProcessor: Partial<SelectField>
|
||||
}
|
||||
|
||||
export type FieldConfig = Partial<Field> | PaymentFieldConfig;
|
||||
export type FieldConfig = Partial<Field> | PaymentFieldConfig
|
||||
|
||||
export type FieldsConfig = {
|
||||
export interface FieldsConfig {
|
||||
select?: boolean | FieldConfig
|
||||
text?: boolean | FieldConfig
|
||||
textarea?: boolean | FieldConfig
|
||||
@@ -35,10 +37,10 @@ export type FieldsConfig = {
|
||||
[key: string]: boolean | FieldConfig | undefined
|
||||
}
|
||||
|
||||
export type BeforeEmail = (emails: FormattedEmail[]) => FormattedEmail[] | Promise<FormattedEmail[]>;
|
||||
export type HandlePayment = (data: any) => void;
|
||||
export type BeforeEmail = (emails: FormattedEmail[]) => FormattedEmail[] | Promise<FormattedEmail[]>
|
||||
export type HandlePayment = (data: any) => void
|
||||
|
||||
export type PluginConfig = {
|
||||
export interface PluginConfig {
|
||||
fields?: FieldsConfig
|
||||
formSubmissionOverrides?: Partial<CollectionConfig>
|
||||
formOverrides?: Partial<CollectionConfig>
|
||||
@@ -47,7 +49,7 @@ export type PluginConfig = {
|
||||
redirectRelationships?: string[]
|
||||
}
|
||||
|
||||
export type TextField = {
|
||||
export interface TextField {
|
||||
blockType: 'text'
|
||||
blockName?: string
|
||||
width?: string
|
||||
@@ -57,7 +59,7 @@ export type TextField = {
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
export type TextAreaField = {
|
||||
export interface TextAreaField {
|
||||
blockType: 'textarea'
|
||||
blockName?: string
|
||||
width?: string
|
||||
@@ -67,12 +69,12 @@ export type TextAreaField = {
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
export type SelectFieldOption = {
|
||||
export interface SelectFieldOption {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export type SelectField = {
|
||||
export interface SelectField {
|
||||
blockType: 'select'
|
||||
blockName?: string
|
||||
width?: string
|
||||
@@ -83,7 +85,7 @@ export type SelectField = {
|
||||
options: SelectFieldOption[]
|
||||
}
|
||||
|
||||
export type PriceCondition = {
|
||||
export interface PriceCondition {
|
||||
fieldToUse: string
|
||||
condition: 'equals' | 'notEquals' | 'hasValue'
|
||||
valueForCondition: string
|
||||
@@ -92,7 +94,7 @@ export type PriceCondition = {
|
||||
valueForOperator: string | number // TODO: make this a number, see ./collections/Forms/DynamicPriceSelector.tsx
|
||||
}
|
||||
|
||||
export type PaymentField = {
|
||||
export interface PaymentField {
|
||||
blockType: 'payment'
|
||||
blockName?: string
|
||||
width?: string
|
||||
@@ -100,12 +102,12 @@ export type PaymentField = {
|
||||
label?: string
|
||||
defaultValue?: string
|
||||
required?: boolean
|
||||
paymentProcessor: string,
|
||||
paymentProcessor: string
|
||||
basePrice: number
|
||||
priceConditions: PriceCondition[]
|
||||
}
|
||||
|
||||
export type EmailField = {
|
||||
export interface EmailField {
|
||||
blockType: 'email'
|
||||
blockName?: string
|
||||
width?: string
|
||||
@@ -115,7 +117,7 @@ export type EmailField = {
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
export type StateField = {
|
||||
export interface StateField {
|
||||
blockType: 'state'
|
||||
blockName?: string
|
||||
width?: string
|
||||
@@ -125,7 +127,7 @@ export type StateField = {
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
export type CountryField = {
|
||||
export interface CountryField {
|
||||
blockType: 'country'
|
||||
blockName?: string
|
||||
width?: string
|
||||
@@ -135,7 +137,7 @@ export type CountryField = {
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
export type CheckboxField = {
|
||||
export interface CheckboxField {
|
||||
blockType: 'checkbox'
|
||||
blockName?: string
|
||||
width?: string
|
||||
@@ -145,15 +147,24 @@ export type CheckboxField = {
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
export type MessageField = {
|
||||
export interface MessageField {
|
||||
blockType: 'message'
|
||||
blockName?: string
|
||||
message: unknown
|
||||
}
|
||||
|
||||
export type FormFieldBlock = TextField | TextAreaField | SelectField | EmailField | StateField | CountryField | CheckboxField | MessageField | PaymentField
|
||||
export type FormFieldBlock =
|
||||
| TextField
|
||||
| TextAreaField
|
||||
| SelectField
|
||||
| EmailField
|
||||
| StateField
|
||||
| CountryField
|
||||
| CheckboxField
|
||||
| MessageField
|
||||
| PaymentField
|
||||
|
||||
export type Email = {
|
||||
export interface Email {
|
||||
emailTo: string
|
||||
emailFrom: string
|
||||
cc?: string
|
||||
@@ -163,7 +174,7 @@ export type Email = {
|
||||
message?: any // TODO: configure rich text type
|
||||
}
|
||||
|
||||
export type FormattedEmail = {
|
||||
export interface FormattedEmail {
|
||||
to: string
|
||||
cc?: string
|
||||
bcc?: string
|
||||
@@ -173,7 +184,7 @@ export type FormattedEmail = {
|
||||
replyTo: string
|
||||
}
|
||||
|
||||
export type Redirect = {
|
||||
export interface Redirect {
|
||||
type: 'reference' | 'custom'
|
||||
reference?: {
|
||||
relationTo: string
|
||||
@@ -182,7 +193,7 @@ export type Redirect = {
|
||||
url: string
|
||||
}
|
||||
|
||||
export type Form = {
|
||||
export interface Form {
|
||||
id: string
|
||||
title: string
|
||||
fields: FormFieldBlock[]
|
||||
@@ -193,12 +204,12 @@ export type Form = {
|
||||
emails: Email[]
|
||||
}
|
||||
|
||||
export type SubmissionValue = {
|
||||
export interface SubmissionValue {
|
||||
field: string
|
||||
value: unknown
|
||||
}
|
||||
|
||||
export type FormSubmission = {
|
||||
export interface FormSubmission {
|
||||
form: string | Form
|
||||
submissionData: SubmissionValue[]
|
||||
}
|
||||
|
||||
@@ -1,61 +1,53 @@
|
||||
import { FieldValues, PaymentField, PriceCondition } from "../types";
|
||||
import type { FieldValues, PaymentField, PriceCondition } from '../types'
|
||||
|
||||
export const getPaymentTotal = (args: Partial<PaymentField> & {
|
||||
fieldValues: FieldValues
|
||||
}): number => {
|
||||
const {
|
||||
basePrice = 0,
|
||||
priceConditions,
|
||||
fieldValues
|
||||
} = args;
|
||||
export const getPaymentTotal = (
|
||||
args: Partial<PaymentField> & {
|
||||
fieldValues: FieldValues
|
||||
},
|
||||
): number => {
|
||||
const { basePrice = 0, priceConditions, fieldValues } = args
|
||||
|
||||
let total = basePrice;
|
||||
let total = basePrice
|
||||
|
||||
if (Array.isArray(priceConditions) && priceConditions.length > 0) {
|
||||
priceConditions.forEach((priceCondition: PriceCondition) => {
|
||||
const {
|
||||
condition,
|
||||
valueForCondition,
|
||||
fieldToUse,
|
||||
operator,
|
||||
valueType,
|
||||
valueForOperator
|
||||
} = priceCondition;
|
||||
const { condition, valueForCondition, fieldToUse, operator, valueType, valueForOperator } =
|
||||
priceCondition
|
||||
|
||||
const valueOfField = fieldValues?.[fieldToUse];
|
||||
const valueOfField = fieldValues?.[fieldToUse]
|
||||
|
||||
if (valueOfField) {
|
||||
if (
|
||||
condition === 'hasValue'
|
||||
|| condition === 'equals' && valueOfField === valueForCondition
|
||||
|| condition === 'notEquals' && valueOfField !== valueForCondition
|
||||
condition === 'hasValue' ||
|
||||
(condition === 'equals' && valueOfField === valueForCondition) ||
|
||||
(condition === 'notEquals' && valueOfField !== valueForCondition)
|
||||
) {
|
||||
const valueToUse = Number(valueType === 'valueOfField' ? valueOfField : valueForOperator);
|
||||
const valueToUse = Number(valueType === 'valueOfField' ? valueOfField : valueForOperator)
|
||||
switch (operator) {
|
||||
case 'add': {
|
||||
total += valueToUse;
|
||||
break;
|
||||
total += valueToUse
|
||||
break
|
||||
}
|
||||
case 'subtract': {
|
||||
total -= valueToUse;
|
||||
break;
|
||||
total -= valueToUse
|
||||
break
|
||||
}
|
||||
case 'multiply': {
|
||||
total *= valueToUse;
|
||||
break;
|
||||
total *= valueToUse
|
||||
break
|
||||
}
|
||||
case 'divide': {
|
||||
total /= valueToUse;
|
||||
break;
|
||||
total /= valueToUse
|
||||
break
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
return total;
|
||||
return total
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
type EmailVariable = {
|
||||
interface EmailVariable {
|
||||
field: string
|
||||
value: string
|
||||
}
|
||||
|
||||
type EmailVariables = EmailVariable[];
|
||||
type EmailVariables = EmailVariable[]
|
||||
|
||||
export const replaceDoubleCurlys = (str: string, variables?: EmailVariables): string => {
|
||||
const regex = /{{(.+?)}}/g;
|
||||
const regex = /{{(.+?)}}/g
|
||||
if (str && variables) {
|
||||
return str.replace(regex, (_, variable) => {
|
||||
const foundVariable = variables.find(({ field: fieldName }) => variable === fieldName);
|
||||
if (foundVariable) return foundVariable.value;
|
||||
return variable;
|
||||
const foundVariable = variables.find(({ field: fieldName }) => variable === fieldName)
|
||||
if (foundVariable) return foundVariable.value
|
||||
return variable
|
||||
})
|
||||
}
|
||||
return str;
|
||||
return str
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import escapeHTML from 'escape-html';
|
||||
import { Text } from 'slate';
|
||||
import { replaceDoubleCurlys } from './replaceDoubleCurlys';
|
||||
import escapeHTML from 'escape-html'
|
||||
import { Text } from 'slate'
|
||||
|
||||
type Node = {
|
||||
import { replaceDoubleCurlys } from './replaceDoubleCurlys'
|
||||
|
||||
interface Node {
|
||||
bold?: boolean
|
||||
code?: boolean
|
||||
italic?: boolean
|
||||
@@ -11,96 +12,100 @@ type Node = {
|
||||
children?: Node[]
|
||||
}
|
||||
|
||||
export const serialize = (children?: Node[], submissionData?: any): string | undefined => children?.map((node: Node, i) => {
|
||||
if (Text.isText(node)) {
|
||||
let text = `<span>${escapeHTML(replaceDoubleCurlys(node.text, submissionData))}</span>`;
|
||||
export const serialize = (children?: Node[], submissionData?: any): string | undefined =>
|
||||
children
|
||||
?.map((node: Node) => {
|
||||
if (Text.isText(node)) {
|
||||
let text = `<span>${escapeHTML(replaceDoubleCurlys(node.text, submissionData))}</span>`
|
||||
|
||||
if (node.bold) {
|
||||
text = (`
|
||||
if (node.bold) {
|
||||
text = `
|
||||
<strong>
|
||||
${text}
|
||||
</strong>
|
||||
`);
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
if (node.code) {
|
||||
text = (`
|
||||
if (node.code) {
|
||||
text = `
|
||||
<code>
|
||||
${text}
|
||||
</code>
|
||||
`);
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
if (node.italic) {
|
||||
text = (`
|
||||
if (node.italic) {
|
||||
text = `
|
||||
<em >
|
||||
${text}
|
||||
</em>
|
||||
`);
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
if (!node) {
|
||||
return null
|
||||
}
|
||||
|
||||
switch (node.type) {
|
||||
case 'h1':
|
||||
return (`
|
||||
switch (node.type) {
|
||||
case 'h1':
|
||||
return `
|
||||
<h1>
|
||||
${serialize(node.children, submissionData)}
|
||||
</h1>
|
||||
`);
|
||||
case 'h6':
|
||||
return (`
|
||||
`
|
||||
case 'h6':
|
||||
return `
|
||||
<h6>
|
||||
${serialize(node.children, submissionData)}
|
||||
</h6>
|
||||
`);
|
||||
case 'quote':
|
||||
return (`
|
||||
`
|
||||
case 'quote':
|
||||
return `
|
||||
<blockquote>
|
||||
${serialize(node.children, submissionData)}
|
||||
</blockquote>
|
||||
`);
|
||||
case 'ul':
|
||||
return (`
|
||||
`
|
||||
case 'ul':
|
||||
return `
|
||||
<ul>
|
||||
${serialize(node.children, submissionData)}
|
||||
</ul>
|
||||
`);
|
||||
case 'ol':
|
||||
return (`
|
||||
`
|
||||
case 'ol':
|
||||
return `
|
||||
<ol>
|
||||
${serialize(node.children, submissionData)}
|
||||
</ol>
|
||||
`);
|
||||
case 'li':
|
||||
return (`
|
||||
`
|
||||
case 'li':
|
||||
return `
|
||||
<li>
|
||||
${serialize(node.children, submissionData)}
|
||||
</li>
|
||||
`);
|
||||
case 'indent':
|
||||
return (`
|
||||
`
|
||||
case 'indent':
|
||||
return `
|
||||
<p style="padding-left: 20px">
|
||||
${serialize(node.children, submissionData)}
|
||||
</p>
|
||||
`);
|
||||
case 'link':
|
||||
return (`
|
||||
`
|
||||
case 'link':
|
||||
return `
|
||||
<a href={${escapeHTML(node.url)}}>
|
||||
${serialize(node.children, submissionData)}
|
||||
</a>
|
||||
`);
|
||||
`
|
||||
|
||||
default:
|
||||
return (`
|
||||
default:
|
||||
return `
|
||||
<p>
|
||||
${serialize(node.children, submissionData)}
|
||||
</p>
|
||||
`);
|
||||
}
|
||||
}).filter(Boolean).join('');
|
||||
`
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user