Skip to content
This repository has been archived by the owner on Dec 13, 2023. It is now read-only.

wip: strictly types fields #43

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions demo/src/payload.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ export default buildConfig({
fields: {
payment: true,
colorField,
newFieldBlock: {
slug: 'custom-text-field',
fields: [],
},
text: {
...fields.text,
labels: {
Expand Down
10 changes: 4 additions & 6 deletions src/collections/Forms/fields.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Block, Field } from 'payload/types'

import type { FieldConfig, PaymentFieldConfig } from '../../types'
import type { FunctionThatReturnsBlock } from '../../types'
import { DynamicFieldSelector } from './DynamicFieldSelector'
import { DynamicPriceSelector } from './DynamicPriceSelector'

Expand Down Expand Up @@ -392,9 +392,10 @@ const Checkbox: Block = {
],
}

const Payment = (fieldConfig: PaymentFieldConfig): Block => {
const Payment: FunctionThatReturnsBlock = fieldConfig => {
let paymentProcessorField = null
if (fieldConfig?.paymentProcessor) {

if (fieldConfig && typeof fieldConfig === 'object' && 'paymentProcessor' in fieldConfig) {
paymentProcessorField = {
type: 'select',
options: [],
Expand Down Expand Up @@ -571,7 +572,6 @@ const Message: Block = {
],
}

// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
export const fields = {
select: Select,
checkbox: Checkbox,
Expand All @@ -583,8 +583,6 @@ export const fields = {
country: Country,
state: State,
payment: Payment,
} as {
[key: string]: Block | ((fieldConfig?: boolean | FieldConfig) => Block)
}

export default fields
38 changes: 22 additions & 16 deletions src/collections/Forms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import merge from 'deepmerge'
import type { Block, CollectionConfig, Field } from 'payload/types'

import type { FieldConfig, PluginConfig } from '../../types'
import { fields } from './fields'
import { fields as baseFields } from './fields'

// all settings can be overridden by the config
export const generateFormCollection = (formConfig: PluginConfig): CollectionConfig => {
Expand Down Expand Up @@ -86,27 +86,33 @@ export const generateFormCollection = (formConfig: PluginConfig): CollectionConf
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 (typeof fieldConfig === 'boolean' && fieldConfig === false) {
return null
}

if (block === undefined && typeof fieldConfig === 'object') {
return fieldConfig
}
let baseField = baseFields?.[fieldKey as keyof typeof baseFields]

if (typeof block === 'object' && typeof fieldConfig === 'object') {
return merge<FieldConfig>(block, fieldConfig, {
arrayMerge: (_, sourceArray) => sourceArray,
})
}
// this is a new, custom block that does not have a default
// it is of `Block` type, so we can just return it
if (baseField === undefined && typeof fieldConfig === 'object') {
return fieldConfig
}

if (typeof block === 'function') {
return block(fieldConfig)
}
// this is a partial field, so merge it into the default block
if (typeof baseField === 'object' && typeof fieldConfig === 'object') {
return merge<FieldConfig>(baseField, fieldConfig, {
arrayMerge: (_, sourceArray) => sourceArray,
})
}

return block
// this is a custom block that has a default
// it is a function so they can use their own merge strategy
if (typeof baseField === 'function' && typeof fieldConfig === 'object') {
return baseField(fieldConfig)
}

return null
// do nothing, return the default block as is with no modifications
return baseField
})
.filter(Boolean) as Block[],
},
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const FormBuilder =
checkbox: true,
message: true,
payment: false,
...incomingFormConfig.fields,
...(incomingFormConfig?.fields || {}),
},
}

Expand Down
27 changes: 14 additions & 13 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Block, CollectionConfig, Field } from 'payload/types'

import type formFields from './collections/Forms/fields'

export interface BlockConfig {
block: Block
validate?: (value: unknown) => boolean | string
Expand All @@ -21,23 +23,22 @@ export type PaymentFieldConfig = Partial<Field> & {
paymentProcessor: Partial<SelectField>
}

export type FieldConfig = Partial<Field> | PaymentFieldConfig
export interface FunctionThatReturnsBlock {
(fieldConfig?: boolean | Partial<Field> | PaymentFieldConfig): Block
}

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
export type FieldsConfig = {
[key in keyof typeof formFields]: boolean | Partial<Field>
} & {
payment: boolean | PaymentFieldConfig
} & {
[key: string]: Block | FunctionThatReturnsBlock
}

export type FieldConfig = FieldsConfig[keyof FieldsConfig]

export type BeforeEmail = (emails: FormattedEmail[]) => FormattedEmail[] | Promise<FormattedEmail[]>

export type HandlePayment = (data: any) => void

export interface PluginConfig {
Expand Down