chore(plugin-form-builder): eslint fix

This commit is contained in:
Elliot DeNolf
2023-10-26 23:07:08 -04:00
parent 22bd80b8c2
commit 87c58bc0ba
13 changed files with 322 additions and 314 deletions

View File

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

View File

@@ -1,7 +1,7 @@
import type { PluginConfig } from '../../../types'
const createCharge = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
const { operation, data } = beforeChangeData
const { data, operation } = beforeChangeData
let dataWithPaymentDetails = data

View File

@@ -1,14 +1,15 @@
import type { Email, FormattedEmail, PluginConfig } from '../../../types'
import { replaceDoubleCurlys } from '../../../utilities/replaceDoubleCurlys'
import { serialize } from '../../../utilities/serializeRichText'
const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
const { operation, data } = beforeChangeData
const { data, operation } = beforeChangeData
if (operation === 'create') {
const {
data: { id: formSubmissionID },
req: { payload, locale },
req: { locale, payload },
} = beforeChangeData
const { form: formID, submissionData } = data || {}
@@ -28,13 +29,13 @@ const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promi
const formattedEmails: FormattedEmail[] = emails.map(
(email: Email): FormattedEmail | null => {
const {
message,
subject,
emailTo,
cc: emailCC,
bcc: emailBCC,
cc: emailCC,
emailFrom,
emailTo,
message,
replyTo: emailReplyTo,
subject,
} = email
const to = replaceDoubleCurlys(emailTo, submissionData)
@@ -44,13 +45,13 @@ const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promi
const replyTo = replaceDoubleCurlys(emailReplyTo || emailFrom, submissionData)
return {
to,
from,
cc,
bcc,
cc,
from,
html: `<div>${serialize(message, submissionData)}</div>`,
replyTo,
subject: replaceDoubleCurlys(subject, submissionData),
html: `<div>${serialize(message, submissionData)}</div>`,
to,
}
},
)
@@ -64,7 +65,7 @@ const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promi
// const log = emailsToSend.map(({ html, ...rest }) => ({ ...rest }))
await Promise.all(
emailsToSend.map(async email => {
emailsToSend.map(async (email) => {
const { to } = email
try {
const emailPromise = await payload.sendEmail(email)

View File

@@ -1,6 +1,7 @@
import type { CollectionConfig } from 'payload/types'
import type { PluginConfig } from '../../types'
import createCharge from './hooks/createCharge'
import sendEmail from './hooks/sendEmail'
@@ -8,51 +9,41 @@ import sendEmail from './hooks/sendEmail'
export const generateSubmissionCollection = (formConfig: PluginConfig): CollectionConfig => {
const newConfig: CollectionConfig = {
...(formConfig?.formSubmissionOverrides || {}),
slug: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',
access: {
create: () => true,
update: () => false,
read: ({ req: { user } }) => !!user, // logged-in users,
update: () => false,
...(formConfig?.formSubmissionOverrides?.access || {}),
},
admin: {
...(formConfig?.formSubmissionOverrides?.admin || {}),
enableRichTextRelationship: false,
},
hooks: {
beforeChange: [
data => createCharge(data, formConfig),
data => sendEmail(data, formConfig),
...(formConfig?.formSubmissionOverrides?.hooks?.beforeChange || []),
],
...(formConfig?.formSubmissionOverrides?.hooks || {}),
},
fields: [
{
name: 'form',
type: 'relationship',
relationTo: formConfig?.formOverrides?.slug || 'forms',
required: true,
admin: {
readOnly: true,
},
relationTo: formConfig?.formOverrides?.slug || 'forms',
required: true,
type: 'relationship',
},
{
name: 'submissionData',
type: 'array',
admin: {
readOnly: true,
},
fields: [
{
name: 'field',
type: 'text',
required: true,
type: 'text',
},
{
name: 'value',
type: 'text',
required: true,
type: 'text',
validate: (value: unknown) => {
// TODO:
// create a validation function that dynamically
@@ -72,9 +63,19 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
},
},
],
type: 'array',
},
...(formConfig?.formSubmissionOverrides?.fields || []),
],
hooks: {
beforeChange: [
(data) => createCharge(data, formConfig),
(data) => sendEmail(data, formConfig),
...(formConfig?.formSubmissionOverrides?.hooks?.beforeChange || []),
],
...(formConfig?.formSubmissionOverrides?.hooks || {}),
},
slug: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',
}
const paymentFieldConfig = formConfig?.fields?.payment
@@ -82,7 +83,6 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
if (paymentFieldConfig) {
newConfig.fields.push({
name: 'payment',
type: 'group',
admin: {
readOnly: true,
},
@@ -99,10 +99,10 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
},
{
name: 'amount',
type: 'number',
admin: {
description: 'Amount in cents',
},
type: 'number',
},
{
name: 'paymentProcessor',
@@ -110,8 +110,6 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
},
{
name: 'creditCard',
label: 'Credit Card',
type: 'group',
fields: [
{
name: 'token',
@@ -129,8 +127,11 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
type: 'text',
},
],
label: 'Credit Card',
type: 'group',
},
],
type: 'group',
})
}

View File

@@ -1,12 +1,13 @@
'use client'
import React, { useEffect, useState } from 'react'
import type { TextField } from 'payload/dist/fields/config/types'
import { Select, useForm } from 'payload/components/forms'
import { TextField } from 'payload/dist/fields/config/types'
import React, { useEffect, useState } from 'react'
import { SelectFieldOption } from '../../types'
import type { SelectFieldOption } from '../../types'
export const DynamicFieldSelector: React.FC<TextField> = props => {
export const DynamicFieldSelector: React.FC<TextField> = (props) => {
const { fields, getDataByPath } = useForm()
const [options, setOptions] = useState<SelectFieldOption[]>([])
@@ -18,7 +19,7 @@ export const DynamicFieldSelector: React.FC<TextField> = props => {
if (fields) {
const allNonPaymentFields = fields
.map((block): SelectFieldOption | null => {
const { name, label, blockType } = block
const { name, blockType, label } = block
if (blockType !== 'payment') {
return {
@@ -29,7 +30,7 @@ export const DynamicFieldSelector: React.FC<TextField> = props => {
return null
})
.filter(Boolean) as SelectFieldOption[]
.filter(Boolean)
setOptions(allNonPaymentFields)
}
}, [fields, getDataByPath])

View File

@@ -1,20 +1,21 @@
'use client'
import React, { useEffect, useState } from 'react'
import type { Data } from 'payload/dist/admin/components/forms/Form/types'
import type { Props as TextFieldType } from 'payload/dist/admin/components/forms/field-types/Text/types'
import { Text, useWatchForm } from 'payload/components/forms'
import { useLocale } from 'payload/components/utilities'
import { Props as TextFieldType } from 'payload/dist/admin/components/forms/field-types/Text/types'
import { Data } from 'payload/dist/admin/components/forms/Form/types'
import React, { useEffect, useState } from 'react'
type FieldWithID = {
id: string
name: string
}
export const DynamicPriceSelector: React.FC<TextFieldType> = props => {
const { path, label } = props
export const DynamicPriceSelector: React.FC<TextFieldType> = (props) => {
const { label, path } = props
const { fields, getDataByPath, getData } = useWatchForm()
const { fields, getData, getDataByPath } = useWatchForm()
const locale = useLocale()

View File

@@ -1,21 +1,22 @@
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,
type: 'text',
}
const label: Field = {
name: 'label',
label: 'Label',
type: 'text',
localized: true,
type: 'text',
}
const required: Field = {
@@ -31,14 +32,8 @@ const width: Field = {
}
const Select: Block = {
slug: 'select',
labels: {
singular: 'Select',
plural: 'Select Fields',
},
fields: [
{
type: 'row',
fields: [
{
...name,
@@ -53,9 +48,9 @@ const Select: Block = {
},
},
],
type: 'row',
},
{
type: 'row',
fields: [
{
...width,
@@ -65,63 +60,63 @@ const Select: Block = {
},
{
name: 'defaultValue',
label: 'Default Value',
localized: true,
type: 'text',
admin: {
width: '50%',
},
label: 'Default Value',
localized: true,
type: 'text',
},
],
type: 'row',
},
{
name: 'options',
label: 'Select Attribute Options',
type: 'array',
labels: {
singular: 'Option',
plural: 'Options',
},
fields: [
{
type: 'row',
fields: [
{
name: 'label',
label: 'Label',
type: 'text',
required: true,
localized: true,
admin: {
width: '50%',
},
label: 'Label',
localized: true,
required: true,
type: 'text',
},
{
name: 'value',
label: 'Value',
type: 'text',
required: true,
admin: {
width: '50%',
},
label: 'Value',
required: true,
type: 'text',
},
],
type: 'row',
},
],
label: 'Select Attribute Options',
labels: {
plural: 'Options',
singular: 'Option',
},
type: 'array',
},
required,
],
labels: {
plural: 'Select Fields',
singular: 'Select',
},
slug: 'select',
}
const Text: Block = {
slug: 'text',
labels: {
singular: 'Text',
plural: 'Text Fields',
},
fields: [
{
type: 'row',
fields: [
{
...name,
@@ -136,9 +131,9 @@ const Text: Block = {
},
},
],
type: 'row',
},
{
type: 'row',
fields: [
{
...width,
@@ -148,28 +143,28 @@ const Text: Block = {
},
{
name: 'defaultValue',
label: 'Default Value',
type: 'text',
localized: true,
admin: {
width: '50%',
},
label: 'Default Value',
localized: true,
type: 'text',
},
],
type: 'row',
},
required,
],
labels: {
plural: 'Text Fields',
singular: 'Text',
},
slug: 'text',
}
const TextArea: Block = {
slug: 'textarea',
labels: {
singular: 'Text Area',
plural: 'Text Area Fields',
},
fields: [
{
type: 'row',
fields: [
{
...name,
@@ -184,9 +179,9 @@ const TextArea: Block = {
},
},
],
type: 'row',
},
{
type: 'row',
fields: [
{
...width,
@@ -196,28 +191,28 @@ const TextArea: Block = {
},
{
name: 'defaultValue',
admin: {
width: '50%',
},
label: 'Default Value',
localized: true,
type: 'text',
admin: {
width: '50%',
},
},
],
type: 'row',
},
required,
],
labels: {
plural: 'Text Area Fields',
singular: 'Text Area',
},
slug: 'textarea',
}
const Number: Block = {
slug: 'number',
labels: {
singular: 'Number',
plural: 'Number Fields',
},
fields: [
{
type: 'row',
fields: [
{
...name,
@@ -232,9 +227,9 @@ const Number: Block = {
},
},
],
type: 'row',
},
{
type: 'row',
fields: [
{
...width,
@@ -244,27 +239,27 @@ const Number: Block = {
},
{
name: 'defaultValue',
label: 'Default Value',
type: 'number',
admin: {
width: '50%',
},
label: 'Default Value',
type: 'number',
},
],
type: 'row',
},
required,
],
labels: {
plural: 'Number Fields',
singular: 'Number',
},
slug: 'number',
}
const Email: Block = {
slug: 'email',
labels: {
singular: 'Email',
plural: 'Email Fields',
},
fields: [
{
type: 'row',
fields: [
{
...name,
@@ -279,21 +274,21 @@ const Email: Block = {
},
},
],
type: 'row',
},
width,
required,
],
labels: {
plural: 'Email Fields',
singular: 'Email',
},
slug: 'email',
}
const State: Block = {
slug: 'state',
labels: {
singular: 'State',
plural: 'State Fields',
},
fields: [
{
type: 'row',
fields: [
{
...name,
@@ -308,21 +303,21 @@ const State: Block = {
},
},
],
type: 'row',
},
width,
required,
],
labels: {
plural: 'State Fields',
singular: 'State',
},
slug: 'state',
}
const Country: Block = {
slug: 'country',
labels: {
singular: 'Country',
plural: 'Country Fields',
},
fields: [
{
type: 'row',
fields: [
{
...name,
@@ -337,21 +332,21 @@ const Country: Block = {
},
},
],
type: 'row',
},
width,
required,
],
labels: {
plural: 'Country Fields',
singular: 'Country',
},
slug: 'country',
}
const Checkbox: Block = {
slug: 'checkbox',
labels: {
singular: 'Checkbox',
plural: 'Checkbox Fields',
},
fields: [
{
type: 'row',
fields: [
{
...name,
@@ -366,9 +361,9 @@ const Checkbox: Block = {
},
},
],
type: 'row',
},
{
type: 'row',
fields: [
{
...width,
@@ -383,6 +378,7 @@ const Checkbox: Block = {
},
},
],
type: 'row',
},
{
name: 'defaultValue',
@@ -390,29 +386,28 @@ const Checkbox: Block = {
type: 'checkbox',
},
],
labels: {
plural: 'Checkbox Fields',
singular: 'Checkbox',
},
slug: 'checkbox',
}
const Payment = (fieldConfig: PaymentFieldConfig): Block => {
let paymentProcessorField = null
if (fieldConfig?.paymentProcessor) {
paymentProcessorField = {
type: 'select',
options: [],
name: 'paymentProcessor',
label: 'Payment Processor',
options: [],
type: 'select',
...fieldConfig.paymentProcessor,
}
}
const fields = {
slug: 'payment',
labels: {
singular: 'Payment',
plural: 'Payment Fields',
},
fields: [
{
type: 'row',
fields: [
{
...name,
@@ -427,9 +422,9 @@ const Payment = (fieldConfig: PaymentFieldConfig): Block => {
},
},
],
type: 'row',
},
{
type: 'row',
fields: [
{
...width,
@@ -439,93 +434,87 @@ const Payment = (fieldConfig: PaymentFieldConfig): Block => {
},
{
name: 'basePrice',
type: 'number',
label: 'Base Price',
admin: {
width: '50%',
},
label: 'Base Price',
type: 'number',
},
],
type: 'row',
},
paymentProcessorField,
{
name: 'priceConditions',
labels: {
singular: 'Price Condition',
plural: 'Price Conditions',
},
type: 'array',
label: 'Price Conditions',
fields: [
{
name: 'fieldToUse',
type: 'text',
admin: {
components: {
Field: DynamicFieldSelector,
},
},
type: 'text',
},
{
name: 'condition',
label: 'Condition',
type: 'select',
defaultValue: 'hasValue',
label: 'Condition',
options: [
{
value: 'hasValue',
label: 'Has Any Value',
value: 'hasValue',
},
{
value: 'equals',
label: 'Equals',
value: 'equals',
},
{
value: 'notEquals',
label: 'Does Not Equal',
value: 'notEquals',
},
],
type: 'select',
},
{
name: 'valueForCondition',
label: 'Value',
type: 'text',
admin: {
condition: (_: any, { condition }: any) =>
condition === 'equals' || condition === 'notEquals',
},
label: 'Value',
type: 'text',
},
{
name: 'operator',
type: 'select',
defaultValue: 'add',
options: [
{
value: 'add',
label: 'Add',
value: 'add',
},
{
value: 'subtract',
label: 'Subtract',
value: 'subtract',
},
{
value: 'multiply',
label: 'Multiply',
value: 'multiply',
},
{
value: 'divide',
label: 'Divide',
value: 'divide',
},
],
type: 'select',
},
{
name: 'valueType',
label: 'Value Type',
type: 'radio',
admin: {
width: '100%',
},
defaultValue: 'static',
label: 'Value Type',
options: [
{
label: 'Static Value',
@@ -536,55 +525,67 @@ const Payment = (fieldConfig: PaymentFieldConfig): Block => {
value: 'valueOfField',
},
],
type: 'radio',
},
{
name: 'valueForOperator',
label: 'Value',
type: 'text',
admin: {
components: {
Field: DynamicPriceSelector,
},
},
label: 'Value',
type: 'text',
},
],
label: 'Price Conditions',
labels: {
plural: 'Price Conditions',
singular: 'Price Condition',
},
type: 'array',
},
required,
].filter(Boolean) as Field[],
labels: {
plural: 'Payment Fields',
singular: 'Payment',
},
slug: 'payment',
}
return fields
}
const Message: Block = {
slug: 'message',
labels: {
singular: 'Message',
plural: 'Message Blocks',
},
fields: [
{
name: 'message',
type: 'richText',
localized: true,
type: 'richText',
},
],
labels: {
plural: 'Message Blocks',
singular: 'Message',
},
slug: 'message',
}
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
export const fields = {
select: Select,
checkbox: Checkbox,
text: Text,
textarea: TextArea,
country: Country,
email: Email,
message: Message,
number: Number,
country: Country,
state: State,
payment: Payment,
select: Select,
state: State,
text: Text,
textarea: TextArea,
} as {
[key: string]: Block | ((fieldConfig?: boolean | FieldConfig) => Block)
[key: string]: ((fieldConfig?: FieldConfig | boolean) => Block) | Block
}
export default fields

View File

@@ -1,44 +1,49 @@
import merge from 'deepmerge'
import type { Block, CollectionConfig, Field } from 'payload/types'
import merge from 'deepmerge'
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',
admin: {
hideGutter: true,
condition: (_, siblingData) => siblingData?.confirmationType === 'redirect',
hideGutter: true,
},
fields: [
{
name: 'url',
label: 'URL to redirect to',
type: 'text',
required: true,
type: 'text',
},
],
type: 'group',
}
if (formConfig.redirectRelationships) {
redirect.fields.unshift({
name: 'reference',
label: 'Document to link to',
type: 'relationship',
relationTo: formConfig.redirectRelationships,
required: true,
maxDepth: 2,
admin: {
condition: (_, siblingData) => siblingData?.type === 'reference',
},
label: 'Document to link to',
maxDepth: 2,
relationTo: formConfig.redirectRelationships,
required: true,
type: 'relationship',
})
redirect.fields.unshift({
name: 'type',
type: 'radio',
admin: {
layout: 'horizontal',
},
defaultValue: 'reference',
options: [
{
label: 'Internal link',
@@ -49,10 +54,7 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
value: 'custom',
},
],
defaultValue: 'reference',
admin: {
layout: 'horizontal',
},
type: 'radio',
})
if (redirect.fields[2].type !== 'row') redirect.fields[2].label = 'Custom URL'
@@ -64,30 +66,28 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
const config: CollectionConfig = {
...(formConfig?.formOverrides || {}),
slug: formConfig?.formOverrides?.slug || 'forms',
admin: {
useAsTitle: 'title',
enableRichTextRelationship: false,
...(formConfig?.formOverrides?.admin || {}),
},
access: {
read: () => true,
...(formConfig?.formOverrides?.access || {}),
},
admin: {
enableRichTextRelationship: false,
useAsTitle: 'title',
...(formConfig?.formOverrides?.admin || {}),
},
fields: [
{
name: 'title',
type: 'text',
required: true,
type: 'text',
},
{
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]
const block = fields[fieldKey]
if (block === undefined && typeof fieldConfig === 'object') {
return fieldConfig
@@ -109,20 +109,21 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
return null
})
.filter(Boolean) as Block[],
type: 'blocks',
},
{
name: 'submitButtonLabel',
type: 'text',
localized: true,
type: 'text',
},
{
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.',
layout: 'horizontal',
},
defaultValue: 'message',
options: [
{
label: 'Message',
@@ -133,100 +134,101 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
value: 'redirect',
},
],
defaultValue: 'message',
type: 'radio',
},
{
name: 'confirmationMessage',
type: 'richText',
localized: true,
required: true,
admin: {
condition: (_, siblingData) => siblingData?.confirmationType === 'message',
},
localized: true,
required: true,
type: 'richText',
},
redirect,
{
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}}.",
},
fields: [
{
type: 'row',
fields: [
{
type: 'text',
name: 'emailTo',
label: 'Email To',
admin: {
width: '100%',
placeholder: '"Email Sender" <sender@email.com>',
width: '100%',
},
label: 'Email To',
type: 'text',
},
{
type: 'text',
name: 'cc',
label: 'CC',
admin: {
width: '50%',
},
label: 'CC',
type: 'text',
},
{
type: 'text',
name: 'bcc',
label: 'BCC',
admin: {
width: '50%',
},
label: 'BCC',
type: 'text',
},
],
type: 'row',
},
{
type: 'row',
fields: [
{
type: 'text',
name: 'replyTo',
label: 'Reply To',
admin: {
width: '50%',
placeholder: '"Reply To" <reply-to@email.com>',
width: '50%',
},
label: 'Reply To',
type: 'text',
},
{
type: 'text',
name: 'emailFrom',
label: 'Email From',
admin: {
width: '50%',
placeholder: '"Email From" <email-from@email.com>',
width: '50%',
},
label: 'Email From',
type: 'text',
},
],
type: 'row',
},
{
type: 'text',
name: 'subject',
label: 'Subject',
defaultValue: "You've received a new message.",
required: true,
label: 'Subject',
localized: true,
required: true,
type: 'text',
},
{
type: 'richText',
name: 'message',
label: 'Message',
localized: true,
admin: {
description: 'Enter the message that should be sent in this email.',
},
label: 'Message',
localized: true,
type: 'richText',
},
],
type: 'array',
},
...(formConfig?.formOverrides?.fields || []),
],
slug: formConfig?.formOverrides?.slug || 'forms',
}
return config

View File

@@ -1,9 +1,10 @@
import type { Config } from 'payload/config'
import { generateFormCollection } from './collections/Forms'
import { generateSubmissionCollection } from './collections/FormSubmissions'
import type { PluginConfig } from './types'
import { generateSubmissionCollection } from './collections/FormSubmissions'
import { generateFormCollection } from './collections/Forms'
export { fields } from './collections/Forms/fields'
export { getPaymentTotal } from './utilities/getPaymentTotal'
@@ -13,16 +14,16 @@ const FormBuilder =
const formConfig: PluginConfig = {
...incomingFormConfig,
fields: {
checkbox: true,
country: true,
email: true,
message: true,
number: true,
payment: false,
select: true,
state: true,
text: true,
textarea: true,
select: true,
email: true,
state: true,
country: true,
number: true,
checkbox: true,
message: true,
payment: false,
...incomingFormConfig.fields,
},
}

View File

@@ -14,7 +14,7 @@ export function isValidBlockConfig(blockConfig: BlockConfig | string): blockConf
}
export interface FieldValues {
[key: string]: string | number | boolean | null | undefined
[key: string]: boolean | null | number | string | undefined
}
export type PaymentFieldConfig = Partial<Field> & {
@@ -24,49 +24,49 @@ export type PaymentFieldConfig = Partial<Field> & {
export type FieldConfig = Partial<Field> | PaymentFieldConfig
export interface FieldsConfig {
select?: boolean | FieldConfig
text?: boolean | FieldConfig
textarea?: boolean | FieldConfig
email?: boolean | FieldConfig
state?: boolean | FieldConfig
country?: boolean | FieldConfig
checkbox?: boolean | FieldConfig
number?: boolean | FieldConfig
message?: boolean | FieldConfig
payment?: boolean | FieldConfig
[key: string]: boolean | FieldConfig | undefined
[key: string]: FieldConfig | boolean | undefined
checkbox?: FieldConfig | boolean
country?: FieldConfig | boolean
email?: FieldConfig | boolean
message?: FieldConfig | boolean
number?: FieldConfig | boolean
payment?: FieldConfig | boolean
select?: FieldConfig | boolean
state?: FieldConfig | boolean
text?: FieldConfig | boolean
textarea?: FieldConfig | boolean
}
export type BeforeEmail = (emails: FormattedEmail[]) => FormattedEmail[] | Promise<FormattedEmail[]>
export type HandlePayment = (data: any) => void
export interface PluginConfig {
fields?: FieldsConfig
formSubmissionOverrides?: Partial<CollectionConfig>
formOverrides?: Partial<CollectionConfig>
beforeEmail?: BeforeEmail
fields?: FieldsConfig
formOverrides?: Partial<CollectionConfig>
formSubmissionOverrides?: Partial<CollectionConfig>
handlePayment?: HandlePayment
redirectRelationships?: string[]
}
export interface TextField {
blockType: 'text'
blockName?: string
width?: number
name: string
label?: string
blockType: 'text'
defaultValue?: string
label?: string
name: string
required?: boolean
width?: number
}
export interface TextAreaField {
blockType: 'textarea'
blockName?: string
width?: number
name: string
label?: string
blockType: 'textarea'
defaultValue?: string
label?: string
name: string
required?: boolean
width?: number
}
export interface SelectFieldOption {
@@ -75,133 +75,133 @@ export interface SelectFieldOption {
}
export interface SelectField {
blockType: 'select'
blockName?: string
width?: number
name: string
label?: string
blockType: 'select'
defaultValue?: string
required?: boolean
label?: string
name: string
options: SelectFieldOption[]
required?: boolean
width?: number
}
export interface PriceCondition {
condition: 'equals' | 'hasValue' | 'notEquals'
fieldToUse: string
condition: 'equals' | 'notEquals' | 'hasValue'
operator: 'add' | 'divide' | 'multiply' | 'subtract'
valueForCondition: string
operator: 'add' | 'subtract' | 'multiply' | 'divide'
valueForOperator: number | string // TODO: make this a number, see ./collections/Forms/DynamicPriceSelector.tsx
valueType: 'static' | 'valueOfField'
valueForOperator: string | number // TODO: make this a number, see ./collections/Forms/DynamicPriceSelector.tsx
}
export interface PaymentField {
blockType: 'payment'
blockName?: string
width?: number
name: string
label?: string
defaultValue?: string
required?: boolean
paymentProcessor: string
basePrice: number
blockName?: string
blockType: 'payment'
defaultValue?: string
label?: string
name: string
paymentProcessor: string
priceConditions: PriceCondition[]
required?: boolean
width?: number
}
export interface EmailField {
blockType: 'email'
blockName?: string
width?: number
name: string
label?: string
blockType: 'email'
defaultValue?: string
label?: string
name: string
required?: boolean
width?: number
}
export interface StateField {
blockType: 'state'
blockName?: string
width?: number
name: string
label?: string
blockType: 'state'
defaultValue?: string
label?: string
name: string
required?: boolean
width?: number
}
export interface CountryField {
blockType: 'country'
blockName?: string
width?: number
name: string
label?: string
blockType: 'country'
defaultValue?: string
label?: string
name: string
required?: boolean
width?: number
}
export interface CheckboxField {
blockType: 'checkbox'
blockName?: string
width?: number
name: string
label?: string
blockType: 'checkbox'
defaultValue?: boolean
label?: string
name: string
required?: boolean
width?: number
}
export interface MessageField {
blockType: 'message'
blockName?: string
blockType: 'message'
message: unknown
}
export type FormFieldBlock =
| TextField
| TextAreaField
| SelectField
| EmailField
| StateField
| CountryField
| CheckboxField
| CountryField
| EmailField
| MessageField
| PaymentField
| SelectField
| StateField
| TextAreaField
| TextField
export interface Email {
emailTo: string
emailFrom: string
cc?: string
bcc?: string
cc?: string
emailFrom: string
emailTo: string
message?: any // TODO: configure rich text type
replyTo?: string
subject: string
message?: any // TODO: configure rich text type
}
export interface FormattedEmail {
to: string
cc?: string
bcc?: string
cc?: string
from: string
subject: string
html: string
replyTo: string
subject: string
to: string
}
export interface Redirect {
type: 'reference' | 'custom'
reference?: {
relationTo: string
value: string | unknown
}
type: 'custom' | 'reference'
url: string
}
export interface Form {
id: string
title: string
fields: FormFieldBlock[]
submitButtonLabel?: string
confirmationType: 'message' | 'redirect'
confirmationMessage?: any // TODO: configure rich text type
redirect?: Redirect
confirmationType: 'message' | 'redirect'
emails: Email[]
fields: FormFieldBlock[]
id: string
redirect?: Redirect
submitButtonLabel?: string
title: string
}
export interface SubmissionValue {
@@ -210,6 +210,6 @@ export interface SubmissionValue {
}
export interface FormSubmission {
form: string | Form
form: Form | string
submissionData: SubmissionValue[]
}

View File

@@ -5,13 +5,13 @@ export const getPaymentTotal = (
fieldValues: FieldValues
},
): number => {
const { basePrice = 0, priceConditions, fieldValues } = args
const { basePrice = 0, fieldValues, priceConditions } = args
let total = basePrice
if (Array.isArray(priceConditions) && priceConditions.length > 0) {
priceConditions.forEach((priceCondition: PriceCondition) => {
const { condition, valueForCondition, fieldToUse, operator, valueType, valueForOperator } =
const { condition, fieldToUse, operator, valueForCondition, valueForOperator, valueType } =
priceCondition
const valueOfField = fieldValues?.[fieldToUse]

View File

@@ -6,7 +6,7 @@ interface 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)

View File

@@ -5,11 +5,11 @@ import { replaceDoubleCurlys } from './replaceDoubleCurlys'
interface Node {
bold?: boolean
children?: Node[]
code?: boolean
italic?: boolean
type?: string
url?: string
children?: Node[]
}
export const serialize = (children?: Node[], submissionData?: any): string | undefined =>