/** * Checkout Field Editor Configuration * * Types, interfaces, and default values for the checkout field editor */ // Field types available in the editor export type FieldType = | 'text' | 'number' | 'hidden' | 'password' | 'email' | 'tel' | 'radio' | 'textarea' | 'select' | 'multiselect' | 'checkbox' | 'checkbox_group' | 'datetime-local' | 'date' | 'month' | 'time' | 'week' | 'url' | 'heading' | 'label' | 'paragraph' | 'file' | 'datepicker' | 'timepicker' | 'country' | 'state' // Field type definitions with metadata export interface FieldTypeDefinition { type: FieldType label: string icon: string category: 'basic' | 'advanced' | 'content' | 'datetime' | 'wc_native' hasOptions: boolean hasPlaceholder: boolean hasDefaultValue: boolean hasValidation: boolean isPro: boolean // Whether this field type requires Pro } export const fieldTypeDefinitions: FieldTypeDefinition[] = [ // Basic fields - FREE { type: 'text', label: 'Text', icon: 'Type', category: 'basic', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: false }, { type: 'number', label: 'Number', icon: 'Hash', category: 'basic', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: false }, { type: 'email', label: 'Email', icon: 'Mail', category: 'basic', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: false }, { type: 'tel', label: 'Phone', icon: 'Phone', category: 'basic', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: false }, { type: 'password', label: 'Password', icon: 'Lock', category: 'basic', hasOptions: false, hasPlaceholder: true, hasDefaultValue: false, hasValidation: true, isPro: false }, { type: 'hidden', label: 'Hidden', icon: 'EyeOff', category: 'basic', hasOptions: false, hasPlaceholder: false, hasDefaultValue: true, hasValidation: false, isPro: false }, { type: 'url', label: 'URL', icon: 'Link', category: 'basic', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: false }, { type: 'textarea', label: 'Textarea', icon: 'AlignLeft', category: 'basic', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: false }, // Selection fields - PRO (require options management) { type: 'select', label: 'Select', icon: 'ChevronDown', category: 'advanced', hasOptions: true, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'multiselect', label: 'Multi Select', icon: 'ListChecks', category: 'advanced', hasOptions: true, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'radio', label: 'Radio', icon: 'Circle', category: 'advanced', hasOptions: true, hasPlaceholder: false, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'checkbox', label: 'Checkbox', icon: 'CheckSquare', category: 'advanced', hasOptions: false, hasPlaceholder: false, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'checkbox_group', label: 'Checkbox Group', icon: 'CheckCircle', category: 'advanced', hasOptions: true, hasPlaceholder: false, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'file', label: 'File Upload', icon: 'Upload', category: 'advanced', hasOptions: false, hasPlaceholder: false, hasDefaultValue: false, hasValidation: true, isPro: true }, // Date/Time fields - PRO (advanced functionality) { type: 'date', label: 'Date', icon: 'Calendar', category: 'datetime', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'time', label: 'Time', icon: 'Clock', category: 'datetime', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'datetime-local', label: 'Date & Time', icon: 'CalendarClock', category: 'datetime', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'month', label: 'Month', icon: 'CalendarDays', category: 'datetime', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'week', label: 'Week', icon: 'CalendarRange', category: 'datetime', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'datepicker', label: 'Date Picker', icon: 'CalendarCheck', category: 'datetime', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: true }, { type: 'timepicker', label: 'Time Picker', icon: 'Timer', category: 'datetime', hasOptions: false, hasPlaceholder: true, hasDefaultValue: true, hasValidation: true, isPro: true }, // Content fields - PRO (advanced layout) { type: 'heading', label: 'Heading', icon: 'Heading', category: 'content', hasOptions: false, hasPlaceholder: false, hasDefaultValue: false, hasValidation: false, isPro: true }, { type: 'label', label: 'Label', icon: 'Tag', category: 'content', hasOptions: false, hasPlaceholder: false, hasDefaultValue: false, hasValidation: false, isPro: true }, { type: 'paragraph', label: 'Paragraph', icon: 'FileText', category: 'content', hasOptions: false, hasPlaceholder: false, hasDefaultValue: false, hasValidation: false, isPro: true }, // WooCommerce-native field types — not user-creatable, but used by core billing/shipping // country/state fields so the editor UI can resolve their icon, label, and properties. { type: 'country', label: 'Country', icon: 'Globe', category: 'wc_native', hasOptions: false, hasPlaceholder: true, hasDefaultValue: false, hasValidation: true, isPro: false }, { type: 'state', label: 'State / Region', icon: 'MapPin', category: 'wc_native', hasOptions: false, hasPlaceholder: true, hasDefaultValue: false, hasValidation: true, isPro: false }, ] // Helper to check if a field type is Pro export function isProFieldType(type: FieldType): boolean { const fieldDef = fieldTypeDefinitions.find(f => f.type === type) return fieldDef?.isPro ?? false } // Get free field types only export function getFreeFieldTypes(): FieldTypeDefinition[] { return fieldTypeDefinitions.filter(f => !f.isPro) } // Get pro field types only export function getProFieldTypes(): FieldTypeDefinition[] { return fieldTypeDefinitions.filter(f => f.isPro) } // Field option for select, radio, checkbox groups export interface FieldOption { value: string label: string isDefault?: boolean } // Validation rules export interface ValidationRules { required: boolean minLength?: number maxLength?: number min?: number max?: number pattern?: string patternMessage?: string customValidation?: string } // Conditional logic operators export type ConditionalOperator = | 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with' | 'is_empty' | 'is_not_empty' | 'greater_than' | 'less_than' | 'greater_equal' | 'less_equal' | 'in' | 'not_in' | 'checked' | 'unchecked' export interface ConditionalRule { id: string field: string operator: ConditionalOperator value: string } export interface ConditionalLogic { enabled: boolean action: 'show' | 'hide' | 'enable' | 'disable' logic: 'all' | 'any' rules: ConditionalRule[] } // Checkout section export type CheckoutSection = 'billing' | 'shipping' | 'order' | 'additional' // Single checkout field export interface CheckoutField { id: string key: string type: FieldType label: string placeholder?: string description?: string defaultValue?: string cssClass?: string options?: FieldOption[] validation: ValidationRules conditionalLogic?: ConditionalLogic section: CheckoutSection priority: number enabled: boolean isCore: boolean // Whether it's a WooCommerce default field width: 'full' | 'half' | 'third' // Additional properties autocomplete?: string inputMask?: string prefix?: string suffix?: string rows?: number // For textarea allowedFileTypes?: string[] // For file upload maxFileSize?: number // In MB dateFormat?: string timeFormat?: string minDate?: string maxDate?: string } // Section configuration export interface SectionConfig { id: CheckoutSection title: string enabled: boolean collapsed: boolean customTitle?: string description?: string } // Global settings export interface FieldEditorSettings { enabled: boolean overrideAddressFields: boolean showFieldLabels: boolean showPlaceholders: boolean showDescriptions: boolean requiredIndicator: string requiredIndicatorPosition: 'before' | 'after' enableConditionalLogic: boolean enableCustomValidation: boolean validateOnBlur: boolean validateOnSubmit: boolean showErrorsInline: boolean errorPosition: 'above' | 'below' scrollToError: boolean highlightErrorFields: boolean // File upload settings fileUploadPath: string maxTotalUploadSize: number // Address override settings allowBillingOverride: boolean allowShippingOverride: boolean syncBillingShipping: boolean } // Complete field editor state export interface FieldEditorState { settings: FieldEditorSettings sections: SectionConfig[] fields: CheckoutField[] } // Default WooCommerce billing fields export const defaultBillingFields: CheckoutField[] = [ { id: 'billing_first_name', key: 'billing_first_name', type: 'text', label: 'First name', placeholder: '', section: 'billing', priority: 10, enabled: true, isCore: true, width: 'half', autocomplete: 'given-name', validation: { required: true } }, { id: 'billing_last_name', key: 'billing_last_name', type: 'text', label: 'Last name', placeholder: '', section: 'billing', priority: 20, enabled: true, isCore: true, width: 'half', autocomplete: 'family-name', validation: { required: true } }, { id: 'billing_company', key: 'billing_company', type: 'text', label: 'Company name', placeholder: '', section: 'billing', priority: 30, enabled: true, isCore: true, width: 'full', autocomplete: 'organization', validation: { required: false } }, { id: 'billing_country', key: 'billing_country', type: 'country', label: 'Country / Region', placeholder: 'Select a country / region…', section: 'billing', priority: 40, enabled: true, isCore: true, width: 'full', autocomplete: 'country', validation: { required: true } }, { id: 'billing_address_1', key: 'billing_address_1', type: 'text', label: 'Street address', placeholder: 'House number and street name', section: 'billing', priority: 50, enabled: true, isCore: true, width: 'full', autocomplete: 'address-line1', validation: { required: true } }, { id: 'billing_address_2', key: 'billing_address_2', type: 'text', label: 'Apartment, suite, unit, etc.', placeholder: 'Apartment, suite, unit, etc. (optional)', section: 'billing', priority: 60, enabled: true, isCore: true, width: 'full', autocomplete: 'address-line2', validation: { required: false } }, { id: 'billing_city', key: 'billing_city', type: 'text', label: 'Town / City', placeholder: '', section: 'billing', priority: 70, enabled: true, isCore: true, width: 'full', autocomplete: 'address-level2', validation: { required: true } }, { id: 'billing_state', key: 'billing_state', type: 'state', label: 'State / County', placeholder: 'Select an option…', section: 'billing', priority: 80, enabled: true, isCore: true, width: 'full', autocomplete: 'address-level1', validation: { required: true } }, { id: 'billing_postcode', key: 'billing_postcode', type: 'text', label: 'Postcode / ZIP', placeholder: '', section: 'billing', priority: 90, enabled: true, isCore: true, width: 'full', autocomplete: 'postal-code', validation: { required: true } }, { id: 'billing_phone', key: 'billing_phone', type: 'tel', label: 'Phone', placeholder: '', section: 'billing', priority: 100, enabled: true, isCore: true, width: 'full', autocomplete: 'tel', validation: { required: true } }, { id: 'billing_email', key: 'billing_email', type: 'email', label: 'Email address', placeholder: '', section: 'billing', priority: 110, enabled: true, isCore: true, width: 'full', autocomplete: 'email', validation: { required: true } } ] // Default WooCommerce shipping fields export const defaultShippingFields: CheckoutField[] = [ { id: 'shipping_first_name', key: 'shipping_first_name', type: 'text', label: 'First name', placeholder: '', section: 'shipping', priority: 10, enabled: true, isCore: true, width: 'half', autocomplete: 'given-name', validation: { required: true } }, { id: 'shipping_last_name', key: 'shipping_last_name', type: 'text', label: 'Last name', placeholder: '', section: 'shipping', priority: 20, enabled: true, isCore: true, width: 'half', autocomplete: 'family-name', validation: { required: true } }, { id: 'shipping_company', key: 'shipping_company', type: 'text', label: 'Company name', placeholder: '', section: 'shipping', priority: 30, enabled: true, isCore: true, width: 'full', autocomplete: 'organization', validation: { required: false } }, { id: 'shipping_country', key: 'shipping_country', type: 'country', label: 'Country / Region', placeholder: 'Select a country / region…', section: 'shipping', priority: 40, enabled: true, isCore: true, width: 'full', autocomplete: 'country', validation: { required: true } }, { id: 'shipping_address_1', key: 'shipping_address_1', type: 'text', label: 'Street address', placeholder: 'House number and street name', section: 'shipping', priority: 50, enabled: true, isCore: true, width: 'full', autocomplete: 'address-line1', validation: { required: true } }, { id: 'shipping_address_2', key: 'shipping_address_2', type: 'text', label: 'Apartment, suite, unit, etc.', placeholder: 'Apartment, suite, unit, etc. (optional)', section: 'shipping', priority: 60, enabled: true, isCore: true, width: 'full', autocomplete: 'address-line2', validation: { required: false } }, { id: 'shipping_city', key: 'shipping_city', type: 'text', label: 'Town / City', placeholder: '', section: 'shipping', priority: 70, enabled: true, isCore: true, width: 'full', autocomplete: 'address-level2', validation: { required: true } }, { id: 'shipping_state', key: 'shipping_state', type: 'state', label: 'State / County', placeholder: 'Select an option…', section: 'shipping', priority: 80, enabled: true, isCore: true, width: 'full', autocomplete: 'address-level1', validation: { required: true } }, { id: 'shipping_postcode', key: 'shipping_postcode', type: 'text', label: 'Postcode / ZIP', placeholder: '', section: 'shipping', priority: 90, enabled: true, isCore: true, width: 'full', autocomplete: 'postal-code', validation: { required: true } } ] // Default order notes field export const defaultOrderFields: CheckoutField[] = [ { id: 'order_comments', key: 'order_comments', type: 'textarea', label: 'Order notes', placeholder: 'Notes about your order, e.g. special notes for delivery.', section: 'order', priority: 10, enabled: true, isCore: true, width: 'full', rows: 4, validation: { required: false } } ] // Default section configurations export const defaultSections: SectionConfig[] = [ { id: 'billing', title: 'Billing details', enabled: true, collapsed: false }, { id: 'shipping', title: 'Ship to a different address?', enabled: true, collapsed: true }, { id: 'additional', title: 'Additional information', enabled: true, collapsed: false }, { id: 'order', title: 'Order notes', enabled: true, collapsed: false } ] // Default settings export const defaultSettings: FieldEditorSettings = { enabled: true, overrideAddressFields: false, showFieldLabels: true, showPlaceholders: true, showDescriptions: true, requiredIndicator: '*', requiredIndicatorPosition: 'after', enableConditionalLogic: true, enableCustomValidation: true, validateOnBlur: true, validateOnSubmit: true, showErrorsInline: true, errorPosition: 'below', scrollToError: true, highlightErrorFields: true, fileUploadPath: 'checkout-uploads', maxTotalUploadSize: 10, allowBillingOverride: true, allowShippingOverride: true, syncBillingShipping: false } // Get all default fields combined export const getDefaultFields = (): CheckoutField[] => { return [ ...defaultBillingFields, ...defaultShippingFields, ...defaultOrderFields ] } // Field categories for the toolbox export const fieldCategories = [ { id: 'basic', label: 'Basic Fields', icon: 'Type' }, { id: 'advanced', label: 'Advanced Fields', icon: 'Settings' }, { id: 'datetime', label: 'Date & Time', icon: 'Calendar' }, { id: 'content', label: 'Content', icon: 'FileText' } ] // Width options export const widthOptions = [ { value: 'full', label: 'Full Width (100%)' }, { value: 'half', label: 'Half Width (50%)' }, { value: 'third', label: 'Third Width (33%)' } ] // Conditional operators export const conditionalOperators: { value: ConditionalOperator; label: string }[] = [ { value: 'equals', label: 'Equals' }, { value: 'not_equals', label: 'Does not equal' }, { value: 'contains', label: 'Contains' }, { value: 'not_contains', label: 'Does not contain' }, { value: 'starts_with', label: 'Starts with' }, { value: 'ends_with', label: 'Ends with' }, { value: 'is_empty', label: 'Is empty' }, { value: 'is_not_empty', label: 'Is not empty' }, { value: 'greater_than', label: 'Greater than' }, { value: 'less_than', label: 'Less than' }, { value: 'greater_equal', label: 'Greater than or equal' }, { value: 'less_equal', label: 'Less than or equal' }, { value: 'in', label: 'Is one of' }, { value: 'not_in', label: 'Is not one of' }, { value: 'checked', label: 'Is checked' }, { value: 'unchecked', label: 'Is unchecked' } ] // Operators that don't require a value input export const noValueOperators: ConditionalOperator[] = [ 'is_empty', 'is_not_empty', 'checked', 'unchecked' ] // Get operators appropriate for a given field type export function getOperatorsForFieldType(fieldType: FieldType): ConditionalOperator[] { switch (fieldType) { case 'checkbox': return ['checked', 'unchecked'] case 'number': return ['equals', 'not_equals', 'greater_than', 'less_than', 'greater_equal', 'less_equal', 'is_empty', 'is_not_empty'] case 'select': case 'radio': case 'country': case 'state': return ['equals', 'not_equals', 'in', 'not_in', 'is_empty', 'is_not_empty'] case 'multiselect': case 'checkbox_group': return ['contains', 'not_contains', 'in', 'not_in', 'is_empty', 'is_not_empty'] default: return ['equals', 'not_equals', 'contains', 'not_contains', 'starts_with', 'ends_with', 'is_empty', 'is_not_empty'] } } // Generate unique rule ID export const generateRuleId = (): string => { return `rule_${Date.now()}_${Math.random().toString(36).substr(2, 6)}` } // Validation patterns export const validationPatterns = [ { value: '', label: 'None' }, { value: '[a-zA-Z]+', label: 'Letters only' }, { value: '[0-9]+', label: 'Numbers only' }, { value: '[a-zA-Z0-9]+', label: 'Alphanumeric' }, { value: '^[A-Z][0-9][A-Z] [0-9][A-Z][0-9]$', label: 'Canadian postal code' }, { value: '^[0-9]{5}(-[0-9]{4})?$', label: 'US ZIP code' }, { value: '^[A-Z]{1,2}[0-9][0-9A-Z]?\\s?[0-9][A-Z]{2}$', label: 'UK postcode' }, { value: 'custom', label: 'Custom pattern' } ] // Generate unique field ID export const generateFieldId = (): string => { return `field_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` } // Generate unique field key export const generateFieldKey = (label: string, section: CheckoutSection): string => { const cleanLabel = label.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '') return `${section}_${cleanLabel}_${Math.random().toString(36).substr(2, 5)}` }