import React, { useState, useEffect } from 'react'
import { Plus, Trash2, X } from 'lucide-react'
import { getFieldType } from '../extensions/registry'
// Fields that never carry a submitted value (the server skips them), so rules on them could never match.
const NO_VALUE_TYPES = new Set(['grid', 'section', 'static-content', 'html', 'image', 'submit', 'submit_button', 'promo-banner', 'trust-badges', 'faq-accordion', 'countdown-banner', 'captcha'])
const hasNoValue = (type) => NO_VALUE_TYPES.has(type) || Boolean(getFieldType(type)?.noValue)
/** Values a rule can compare against for fields with a fixed value list (matches what the storefront submits). */
export function ruleValueChoices(field) {
if (!field) return null
// Registered field types list their own values (`ruleValueChoices(field)` → [{ value, label }]).
const registered = getFieldType(field.type)
if (registered && typeof registered.ruleValueChoices === 'function') return registered.ruleValueChoices(field) || null
return null
}
const ConditionalLogic = ({
enableLogic = false,
setEnableLogic,
logicConditions = [],
setLogicConditions,
fields = [],
actionLabel = 'this item',
onSave,
onClose,
setIsDirty,
logicMatch = 'all',
setLogicMatch,
logicAction = 'show',
setLogicAction,
}) => {
const [action, setAction] = useState(logicAction || 'show')
// Helper function to get all fields including grid fields and nested fields
const getAllFieldsIncludingNested = (fieldsList = []) => {
const allFields = []
fieldsList.forEach((field) => {
// Include regular fields (not grid)
if (field.type !== 'grid') {
allFields.push({
...field,
displayName: field.label || field.name || 'Unnamed Field',
isNested: false,
})
}
// Include grid fields and their nested columns
if (field.type === 'grid') {
allFields.push({
...field,
displayName: `${field.label || field.name || 'Grid Section'} (Section)`,
isNested: false,
})
if (field.columns) {
Object.entries(field.columns).forEach(([columnKey, columnFields]) => {
if (Array.isArray(columnFields)) {
columnFields.forEach((nestedField) => {
const columnDisplayName = columnKey
.replace(/col-/i, 'Column ')
.replace(/column/i, 'Column ')
.replace(/(\d+)/, (m) => Number(m) + 1)
allFields.push({
...nestedField,
displayName: `${nestedField.label || nestedField.name || 'Unnamed Field'} (${field.label || field.name || 'Grid'} - ${columnDisplayName})`,
isNested: true,
parentFieldId: field.id,
parentFieldName: field.label || field.name || 'Grid',
columnKey: columnKey,
})
})
}
})
}
}
})
return allFields
}
// Sync action from props
useEffect(() => {
if (logicAction) {
setAction(logicAction)
}
}, [logicAction])
const handleEnableLogicChange = (checked) => {
if (setIsDirty) setIsDirty(true)
if (setEnableLogic) setEnableLogic(checked)
if (setLogicConditions) {
setLogicConditions(
checked
? logicConditions?.length
? logicConditions
: [{ field: '', operator: 'is', value: '' }]
: []
)
}
}
const findConditionField = (fieldId) => {
if (!fieldId) return null
for (const f of fields) {
if (f.id === fieldId) return f
if (f.type === 'grid' && f.columns) {
for (const colFields of Object.values(f.columns)) {
if (Array.isArray(colFields)) {
const nested = colFields.find((nf) => nf.id === fieldId)
if (nested) return nested
}
}
}
}
return null
}
return (
{/* Enable Conditional Logic Switch */}
{/* Conditional Logic Configuration */}
{enableLogic && (
{/* Action & Match Sentence Header */}
{actionLabel} if
of the following match:
{/* Conditions List */}
{Array.isArray(logicConditions) &&
logicConditions.map((condition, index) => {
const conditionField = findConditionField(condition.field || condition.fieldId)
return (
{/* Field Selector */}
{/* Operator Selector */}
{/* Dynamic Value Input / Dropdown */}
{!['is_empty', 'is_not_empty'].includes(condition.operator) && (
{(() => {
if (conditionField && conditionField.type === 'switch') {
return (
)
}
if (
conditionField &&
(['select', 'checkbox', 'radio', 'dropdown'].includes(conditionField.type) || getFieldType(conditionField.type)?.ruleOptions) &&
Array.isArray(conditionField.options) &&
conditionField.options.length > 0
) {
return (
)
}
const fixed = ruleValueChoices(conditionField)
if (fixed && fixed.length) {
return (
)
}
return (
{
if (setIsDirty) setIsDirty(true)
const updatedConditions = [...logicConditions]
updatedConditions[index] = {
...updatedConditions[index],
value: e.target.value,
}
if (setLogicConditions) setLogicConditions(updatedConditions)
}}
placeholder="Enter value..."
/>
)
})()}
)}
{/* Remove Condition Button */}
)
})}
{/* Add New Condition Button */}
)}
{/* Save and Close Footer if provided */}
{(onSave || onClose) && (
{onClose && (
)}
{onSave && (
)}
)}
)
}
export default ConditionalLogic