| @@ -1,7 +1,8 @@ | |||
| import React from 'react' | |||
| import React, { useMemo } from 'react' | |||
| import { useAppForm } from '../..' | |||
| import BaseField from './field' | |||
| import type { BaseFormProps } from './types' | |||
| import { generateZodSchema } from './utils' | |||
| const BaseForm = <T,>({ | |||
| initialData, | |||
| @@ -9,11 +10,22 @@ const BaseForm = <T,>({ | |||
| onSubmit, | |||
| CustomActions, | |||
| }: BaseFormProps<T>) => { | |||
| const schema = useMemo(() => { | |||
| const schema = generateZodSchema<T>(configurations) | |||
| return schema | |||
| }, [configurations]) | |||
| const baseForm = useAppForm({ | |||
| defaultValues: initialData, | |||
| validators: { | |||
| onSubmit: ({ value }) => { | |||
| console.log('onSubmit', value) | |||
| onChange: ({ value }) => { | |||
| const result = schema.safeParse(value) | |||
| if (!result.success) { | |||
| const issues = result.error.issues | |||
| const firstIssue = issues[0].message | |||
| return firstIssue | |||
| } | |||
| return undefined | |||
| }, | |||
| }, | |||
| onSubmit: ({ value }) => { | |||
| @@ -0,0 +1,56 @@ | |||
| import type { ZodSchema, ZodString } from 'zod' | |||
| import { z } from 'zod' | |||
| import { type BaseConfiguration, BaseVarType } from './types' | |||
| export const generateZodSchema = <T>(fields: BaseConfiguration<T>[]) => { | |||
| const shape: Record<string, ZodSchema> = {} | |||
| fields.forEach((field) => { | |||
| let zodType | |||
| switch (field.type) { | |||
| case BaseVarType.textInput: | |||
| zodType = z.string() | |||
| break | |||
| case BaseVarType.numberInput: | |||
| zodType = z.number() | |||
| break | |||
| case BaseVarType.checkbox: | |||
| zodType = z.boolean() | |||
| break | |||
| case BaseVarType.select: | |||
| zodType = z.string() | |||
| break | |||
| default: | |||
| zodType = z.any() | |||
| break | |||
| } | |||
| if (field.required) { | |||
| if ([BaseVarType.textInput].includes(field.type)) | |||
| zodType = (zodType as ZodString).nonempty(`${field.label} is required`) | |||
| } | |||
| else { | |||
| zodType = zodType.optional() | |||
| } | |||
| if (field.maxLength) { | |||
| if ([BaseVarType.textInput].includes(field.type)) | |||
| zodType = (zodType as ZodString).max(field.maxLength, `${field.label} exceeds max length of ${field.maxLength}`) | |||
| } | |||
| if (field.min) { | |||
| if ([BaseVarType.numberInput].includes(field.type)) | |||
| zodType = (zodType as ZodString).min(field.min, `${field.label} must be at least ${field.min}`) | |||
| } | |||
| if (field.max) { | |||
| if ([BaseVarType.numberInput].includes(field.type)) | |||
| zodType = (zodType as ZodString).max(field.max, `${field.label} exceeds max value of ${field.max}`) | |||
| } | |||
| shape[field.variable] = zodType | |||
| }) | |||
| return z.object(shape) | |||
| } | |||
| @@ -1,16 +1,17 @@ | |||
| 'use client' | |||
| import InputFieldForm from '../components/base/form/form-scenarios/base' | |||
| import BaseForm from '../components/base/form/form-scenarios/base' | |||
| import { BaseVarType } from '../components/base/form/form-scenarios/base/types' | |||
| export default function Page() { | |||
| return ( | |||
| <div className='flex h-screen w-full items-center justify-center p-20'> | |||
| <div className='w-[400px] rounded-lg border border-components-panel-border bg-components-panel-bg'> | |||
| <InputFieldForm | |||
| <BaseForm | |||
| initialData={{ | |||
| type: 'option_1', | |||
| variable: 'test', | |||
| label: 'Test', | |||
| maxLength: 48, | |||
| required: true, | |||
| }} | |||
| configurations={[ | |||
| @@ -19,14 +20,18 @@ export default function Page() { | |||
| variable: 'variable', | |||
| label: 'Variable', | |||
| required: true, | |||
| showConditions: [{ | |||
| variable: 'type', | |||
| value: 'option_1', | |||
| }], | |||
| showConditions: [], | |||
| }, | |||
| { | |||
| type: BaseVarType.textInput, | |||
| variable: 'label', | |||
| label: 'Label', | |||
| required: true, | |||
| showConditions: [], | |||
| }, | |||
| { | |||
| type: BaseVarType.numberInput, | |||
| variable: 'max_length', | |||
| variable: 'maxLength', | |||
| label: 'Max Length', | |||
| required: true, | |||
| showConditions: [], | |||