import { z } from "zod"; const fieldTypeEnum = z.enum([ "name", "text", "textarea", "number", "email", "phone", "address", "multiemail", "select", "multiselect", "checkbox", "radio", "radioInput", "boolean", ]); export const EditableSchema = z.enum([ "system", // Can't be deleted, can't be hidden, name can't be edited, can't be marked optional "system-but-optional", // Can't be deleted. Name can't be edited. But can be hidden or be marked optional "system-but-hidden", // Can't be deleted, name can't be edited, will be shown "user", // Fully editable "user-readonly", // All fields are readOnly. ]); export type ALL_VIEWS = "ALL_VIEWS"; const fieldSchema = z.object({ name: z.string(), // TODO: We should make at least one of `defaultPlaceholder` and `placeholder` required. Do the same for label. label: z.string().optional(), placeholder: z.string().optional(), /** * Supports translation */ defaultLabel: z.string().optional(), defaultPlaceholder: z.string().optional(), views: z .object({ label: z.string(), id: z.string(), description: z.string().optional(), }) .array() .optional(), type: fieldTypeEnum, options: z.array(z.object({ label: z.string(), value: z.string() })).optional(), /** * This is an alternate way to specify options when the options are stored elsewhere. Form Builder expects options to be present at `dataStore[getOptionsAt]` * This allows keeping a single source of truth in DB. */ getOptionsAt: z.string().optional(), optionsInputs: z .record( z.object({ // Support all types as needed // Must be a subset of `fieldTypeEnum`.TODO: Enforce it in TypeScript type: z.enum(["address", "phone", "text"]), required: z.boolean().optional(), placeholder: z.string().optional(), }) ) .optional(), /** * It is used to hide fields such as location when there are less than two options */ hideWhenJustOneOption: z.boolean().default(false).optional(), required: z.boolean().default(false).optional(), hidden: z.boolean().optional(), editable: EditableSchema .default("user") .optional(), sources: z .array( z.object({ // Unique ID for the `type`. If type is workflow, it's the workflow ID id: z.string(), type: z.union([z.literal("user"), z.literal("system"), z.string()]), label: z.string(), editUrl: z.string().optional(), // Mark if a field is required by this source or not. This allows us to set `field.required` based on all the sources' fieldRequired value fieldRequired: z.boolean().optional(), }) ) .optional(), }); export const fieldsSchema = z.array(fieldSchema);