You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/app/javascript/template_builder/field_context_menu.vue

1000 lines
30 KiB

<template>
<div>
<div
v-if="!isShowFormulaModal && !isShowFontModal && !isShowConditionsModal && !isShowDescriptionModal && !isShowCustomValidationModal && !isShowLengthValidationModal && !isShowNumberRangeModal && !isShowPriceModal && !isShowPaymentLinkModal"
ref="menu"
class="fixed z-50 p-1 bg-white shadow-lg rounded-lg border border-neutral-200 cursor-default"
style="min-width: 170px"
:style="menuStyle"
@mousedown.stop
@pointerdown.stop
>
<label
v-if="showRequired"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click.stop
>
<input
:checked="isRequired"
type="checkbox"
class="toggle toggle-xs"
:disabled="!editable || (defaultField && [true, false].includes(defaultField.required))"
@change="handleToggleRequired($event.target.checked)"
@click.stop
>
<span>{{ t('required') }}</span>
</label>
<label
v-if="showReadOnly"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click.stop
>
<input
:checked="isReadOnly"
type="checkbox"
class="toggle toggle-xs"
:disabled="!editable || (defaultField && [true, false].includes(defaultField.readonly))"
@change="handleToggleReadOnly($event.target.checked)"
@click.stop
>
<span>{{ t('read_only') }}</span>
</label>
<label
v-if="showPrefillable"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click.stop
>
<input
:checked="field.prefillable"
type="checkbox"
class="toggle toggle-xs"
:disabled="!editable || (defaultField && [true, false].includes(defaultField.prefillable))"
@change="handleTogglePrefillable($event.target.checked)"
@click.stop
>
<span>{{ t('prefillable') }}</span>
</label>
<label
v-if="showSetSigningDate"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click.stop
>
<input
:checked="field.readonly && field.default_value === '{{date}}'"
type="checkbox"
class="toggle toggle-xs"
@change="handleToggleSetSigningDate($event.target.checked)"
@click.stop
>
<span>{{ t('set_signing_date') }}</span>
</label>
<label
v-if="showWithLogo"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click.stop
>
<input
:checked="field.preferences?.with_logo !== false"
type="checkbox"
class="toggle toggle-xs"
@change="handleToggleWithLogo($event.target.checked)"
@click.stop
>
<span>{{ t('with_logo') }}</span>
</label>
<label
v-if="showSignatureId"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click.stop
>
<input
:checked="field.preferences?.with_signature_id"
type="checkbox"
class="toggle toggle-xs"
:disabled="!editable || (defaultField && [true, false].includes(defaultField.required))"
@change="handleToggleSignatureId($event.target.checked)"
@click.stop
>
<span>{{ t('signature_id') }}</span>
</label>
<label
v-if="showChecked"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click.stop
>
<input
:checked="field.default_value"
type="checkbox"
class="toggle toggle-xs"
@change="handleToggleChecked($event.target.checked)"
@click.stop
>
<span>{{ t('checked') }}</span>
</label>
<ContextSubmenu
v-if="showVerificationMethod"
:icon="IconId"
:label="t('method')"
:options="methodOptions"
:model-value="currentVerificationMethod"
@select="handleSelectVerificationMethod"
/>
<hr
v-if="showRequired || showReadOnly || showPrefillable || showSetSigningDate || showWithLogo || showSignatureId"
class="my-1 border-neutral-200"
>
<ContextSubmenu
v-if="showFormatSubmenu"
:icon="IconAdjustmentsHorizontal"
:label="t('format')"
:options="formatOptions"
:model-value="currentFormat"
@select="handleSelectFormat"
/>
<ContextSubmenu
v-if="showValidationSubmenu && field.type !== 'number'"
:icon="IconInputCheck"
:label="t('validation')"
:options="validationMenuItems.map(k => ({ value: k, label: t(k) }))"
:model-value="currentValidationKey"
@select="handleSelectValidation"
/>
<button
v-if="field.type === 'number'"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm"
@click.stop="openNumberRangeModal"
>
<IconInputCheck class="w-4 h-4" />
<span>{{ t('validation') }}</span>
</button>
<ContextSubmenu
v-if="showPaymentSettings"
:icon="IconCash"
:label="t('currency')"
:options="currencyOptions"
:model-value="currentCurrency"
@select="handleSelectCurrency"
/>
<ContextSubmenu
v-if="showPaymentSettings"
:icon="IconCoins"
:label="t('price')"
:options="priceTypeOptions"
:model-value="currentPriceType"
@select="handleSelectPriceType"
/>
<button
v-if="showFont"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm"
@click.stop="openFontModal"
>
<IconTypography class="w-4 h-4" />
<span>{{ t('font') }}</span>
</button>
<button
v-if="showDescription"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm"
@click.stop="openDescriptionModal"
>
<IconInfoCircle class="w-4 h-4" />
<span>{{ t('description') }}</span>
</button>
<button
v-if="showCondition"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center justify-between text-sm"
@click.stop="openConditionModal"
>
<span class="flex items-center space-x-2">
<IconRouteAltLeft class="w-4 h-4" />
<span>{{ t('condition') }}</span>
</span>
<span
v-if="field.conditions?.length"
class="bg-neutral-200 rounded px-1 leading-3"
style="font-size: 9px;"
>{{ field.conditions.length }}</span>
</button>
<button
v-if="showFormula"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm"
@click.stop="openFormulaModal"
>
<IconMathFunction class="w-4 h-4" />
<span>{{ t('formula') }}</span>
</button>
<hr
v-if="(showFont || showDescription || showCondition || showFormula || showPaymentSettings)"
class="my-1 border-neutral-200"
>
<button
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center justify-between text-sm"
@click.stop="$emit('copy')"
>
<span class="flex items-center space-x-2">
<IconCopy class="w-4 h-4" />
<span>{{ t('copy') }}</span>
</span>
<span class="text-xs text-base-content/60 ml-4">{{ isMac ? '⌘C' : 'Ctrl+C' }}</span>
</button>
<button
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center justify-between text-sm text-red-600"
@click.stop="$emit('delete')"
>
<span class="flex items-center space-x-2">
<IconTrashX class="w-4 h-4" />
<span>{{ t('remove') }}</span>
</span>
<span class="text-xs text-base-content/60 ml-4">Del</span>
</button>
<ContextSubmenu
v-if="showMoreSubmenu"
:icon="IconDots"
:label="t('more')"
>
<button
v-if="showDrawNewArea"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click="handleMoreSelect('draw_new_area')"
>
<IconNewSection class="w-4 h-4" />
<span class="whitespace-nowrap">{{ t('draw_new_area') }}</span>
</button>
<button
v-if="showCopyToAllPages"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click="handleMoreSelect('copy_to_all_pages')"
>
<IconCopy class="w-4 h-4" />
<span class="whitespace-nowrap">{{ t('copy_to_all_pages') }}</span>
</button>
<button
v-if="showSaveAsCustom"
class="w-full px-2 py-1 rounded-md hover:bg-neutral-100 flex items-center space-x-2 text-sm cursor-pointer"
@click="handleMoreSelect('save_as_custom')"
>
<IconForms class="w-4 h-4" />
<span class="whitespace-nowrap">{{ t('save_as_custom_field') }}</span>
</button>
</ContextSubmenu>
</div>
<Teleport
v-if="isShowFormulaModal"
:to="modalContainerEl"
>
<FormulaModal
:field="field"
:editable="editable"
:build-default-name="buildDefaultName"
@close="closeModal"
/>
</Teleport>
<Teleport
v-if="isShowFontModal"
:to="modalContainerEl"
>
<FontModal
:field="field"
:area="contextMenu.area"
:editable="editable"
:build-default-name="buildDefaultName"
@close="closeModal"
/>
</Teleport>
<Teleport
v-if="isShowConditionsModal"
:to="modalContainerEl"
>
<ConditionsModal
:item="field"
:build-default-name="buildDefaultName"
@close="closeModal"
/>
</Teleport>
<Teleport
v-if="isShowDescriptionModal"
:to="modalContainerEl"
>
<DescriptionModal
:field="field"
:editable="editable"
:build-default-name="buildDefaultName"
@close="closeModal"
/>
</Teleport>
<ContextModal
v-if="isShowCustomValidationModal"
:title="`${t('custom_validation')} - ${modalFieldName}`"
:modal-container-el="modalContainerEl"
@close="closeValidationModal"
@save="saveCustomValidation"
>
<div class="space-y-1 mb-1">
<div>
<label
dir="auto"
class="label text-sm"
for="custom_validation_pattern"
>
{{ t('regexp_validation') }}
</label>
<input
id="custom_validation_pattern"
v-model="customValidationPattern"
dir="auto"
type="text"
class="base-input !text-base w-full"
:placeholder="t('regexp_validation')"
>
</div>
<div>
<label
dir="auto"
class="label text-sm"
for="custom_validation_message"
>
{{ t('error_message') }}
</label>
<input
id="custom_validation_message"
v-model="customValidationMessage"
dir="auto"
:placeholder="t('error_message')"
class="base-input !text-base w-full"
>
</div>
</div>
</ContextModal>
<ContextModal
v-if="isShowLengthValidationModal"
:title="`${t('length_validation')} - ${modalFieldName}`"
:modal-container-el="modalContainerEl"
@close="closeValidationModal"
@save="saveLengthValidation"
>
<div class="flex space-x-3">
<div class="flex-1">
<label
dir="auto"
class="label text-sm"
for="length_validation_min"
>
{{ t('min') }}
</label>
<input
id="length_validation_min"
v-model="lengthValidationMin"
dir="auto"
type="number"
min="0"
class="base-input !text-base w-full"
:placeholder="t('min')"
>
</div>
<div class="flex-1">
<label
dir="auto"
class="label text-sm"
for="length_validation_max"
>
{{ t('max') }}
</label>
<input
id="length_validation_max"
v-model="lengthValidationMax"
dir="auto"
type="number"
min="1"
class="base-input !text-base w-full"
:placeholder="t('max')"
>
</div>
</div>
</ContextModal>
<ContextModal
v-if="isShowNumberRangeModal"
:title="`${t('number_range')} - ${modalFieldName}`"
:modal-container-el="modalContainerEl"
@close="closeValidationModal"
@save="saveNumberRange"
>
<div class="flex space-x-3">
<div class="flex-1">
<label
dir="auto"
class="label text-sm"
for="number_range_min"
>
{{ t('min') }}
</label>
<input
id="number_range_min"
v-model="numberRangeMin"
dir="auto"
type="number"
class="base-input !text-base w-full"
:placeholder="t('min')"
>
</div>
<div class="flex-1">
<label
dir="auto"
class="label text-sm"
for="number_range_max"
>
{{ t('max') }}
</label>
<input
id="number_range_max"
v-model="numberRangeMax"
dir="auto"
type="number"
class="base-input !text-base w-full"
:placeholder="t('max')"
>
</div>
</div>
</ContextModal>
<ContextModal
v-if="isShowPriceModal"
:title="`${t('price')} - ${modalFieldName}`"
:modal-container-el="modalContainerEl"
@close="closeValidationModal"
@save="savePrice"
>
<div>
<input
id="price_value"
v-model="priceValue"
dir="auto"
type="number"
class="base-input !text-base w-full"
:placeholder="t('price')"
>
</div>
</ContextModal>
<ContextModal
v-if="isShowPaymentLinkModal"
:title="`${t('payment_link')} - ${modalFieldName}`"
:modal-container-el="modalContainerEl"
@close="closeValidationModal"
@save="savePaymentLink"
>
<div>
<input
id="payment_link_value"
v-model="paymentLinkValue"
dir="auto"
type="text"
class="base-input !text-base w-full"
placeholder="plink_XXXXX"
>
</div>
</ContextModal>
</div>
</template>
<script>
import { IconCopy, IconTrashX, IconTypography, IconInfoCircle, IconRouteAltLeft, IconMathFunction, IconAdjustmentsHorizontal, IconInputCheck, IconDots, IconNewSection, IconForms, IconId, IconCash, IconCoins } from '@tabler/icons-vue'
import FormulaModal from './formula_modal'
import FontModal from './font_modal'
import ConditionsModal from './conditions_modal'
import DescriptionModal from './description_modal'
import Field from './field'
import FieldType from './field_type.vue'
import FieldSettings from './field_settings.vue'
import ContextSubmenu from './field_context_submenu.vue'
import ContextModal from './field_context_modal.vue'
export default {
name: 'FieldContextMenu',
components: {
IconCopy,
IconTrashX,
IconTypography,
IconInfoCircle,
IconRouteAltLeft,
IconMathFunction,
IconInputCheck,
IconNewSection,
IconForms,
FormulaModal,
FontModal,
ConditionsModal,
DescriptionModal,
ContextSubmenu,
ContextModal
},
inject: ['t', 'getFieldTypeIndex', 'template', 'withCustomFields', 'currencies'],
props: {
contextMenu: {
type: Object,
required: true
},
field: {
type: Object,
required: true
},
editable: {
type: Boolean,
default: true
},
withPrefillable: {
type: Boolean,
default: false
},
withSignatureId: {
type: Boolean,
default: null
},
withRequired: {
type: Boolean,
default: true
},
withCondition: {
type: Boolean,
default: true
},
withCopyToAllPages: {
type: Boolean,
default: true
},
defaultField: {
type: Object,
required: false,
default: null
}
},
emits: ['copy', 'delete', 'close', 'set-draw', 'add-custom-field', 'scroll-to', 'save'],
data () {
return {
isShowFormulaModal: false,
isShowFontModal: false,
isShowConditionsModal: false,
isShowDescriptionModal: false,
isShowCustomValidationModal: false,
isShowLengthValidationModal: false,
isShowNumberRangeModal: false,
isShowPriceModal: false,
isShowPaymentLinkModal: false,
customValidationPattern: '',
customValidationMessage: '',
lengthValidationMin: '',
lengthValidationMax: '',
numberRangeMin: '',
numberRangeMax: '',
priceValue: '',
paymentLinkValue: ''
}
},
computed: {
fieldNames: FieldType.computed.fieldNames,
fieldLabels: FieldType.computed.fieldLabels,
validationOptions: FieldSettings.computed.validations,
dateFormats: FieldSettings.computed.dateFormats,
numberFormats: FieldSettings.computed.numberFormats,
prefillableFieldTypes: FieldSettings.computed.prefillableFieldTypes,
verificationMethods: FieldSettings.computed.verificationMethods,
modalContainerEl () {
return this.$el.getRootNode().querySelector('#docuseal_modal_container')
},
modalFieldName () {
return (this.defaultField ? (this.defaultField.title || this.field.title || this.field.name) : this.field.name) || this.buildDefaultName(this.field)
},
isMac () {
return (navigator.userAgentData?.platform || navigator.platform)?.toLowerCase()?.includes('mac')
},
menuStyle () {
return {
left: this.contextMenu.x + 'px',
top: this.contextMenu.y + 'px'
}
},
showFont () {
return ['text', 'number', 'date', 'select', 'heading', 'cells'].includes(this.field.type)
},
showDescription () {
return !['stamp', 'heading', 'strikethrough'].includes(this.field.type)
},
showCondition () {
return this.withCondition && !['stamp', 'heading'].includes(this.field.type)
},
showFormula () {
return this.field.type === 'number' || this.field.type === 'payment'
},
showRequired () {
return this.withRequired && !['phone', 'stamp', 'verification', 'strikethrough', 'heading'].includes(this.field.type)
},
showReadOnly () {
return ['text', 'number', 'radio', 'multiple', 'select'].includes(this.field.type)
},
isRequired () {
return this.field.required || false
},
isReadOnly () {
return this.field.readonly || false
},
showFormatSubmenu () {
return ['date', 'number', 'signature'].includes(this.field.type)
},
showValidationSubmenu () {
return ['text', 'cells', 'number'].includes(this.field.type)
},
showPrefillable () {
return this.withPrefillable && this.prefillableFieldTypes.includes(this.field.type)
},
showSetSigningDate () {
return this.field.type === 'date'
},
showWithLogo () {
return this.field.type === 'stamp'
},
showSignatureId () {
return [true, false].includes(this.withSignatureId) && this.field.type === 'signature'
},
showChecked () {
return this.field.type === 'checkbox'
},
showVerificationMethod () {
return this.field.type === 'verification'
},
lengthValidation () {
return this.parseLengthPattern(this.field.validation?.pattern)
},
currentValidationKey () {
if (!this.field.validation?.pattern) return 'none'
if (this.lengthValidation) return 'length'
const matchedKey = Object.keys(this.validationOptions).find(
key => this.validationOptions[key] !== 'length' && key === this.field.validation.pattern
)
if (matchedKey) return this.validationOptions[matchedKey]
return 'custom'
},
validationMenuItems () {
return ['none', ...Object.values(this.validationOptions), 'custom']
},
signatureFormats () {
return ['any', ...FieldSettings.computed.signatureFormats.call(this)]
},
currentDateFormat () {
return this.field.preferences?.format || 'MM/DD/YYYY'
},
currentNumberFormat () {
return this.field.preferences?.format || 'none'
},
currentSignatureFormat () {
return this.field.preferences?.format || 'any'
},
currentVerificationMethod () {
return this.field.preferences?.method || 'qes'
},
methodOptions () {
return this.verificationMethods.map(m => ({ value: m.toLowerCase(), label: m }))
},
formatOptions () {
switch (this.field.type) {
case 'date': return this.dateFormats.map(f => ({ value: f, label: this.formatDate(new Date(), f) }))
case 'number': return this.numberFormats.map(f => ({ value: f, label: this.formatNumber(123456789.567, f) }))
case 'signature': return this.signatureFormats.map(f => ({ value: f, label: this.t(f) }))
default: return []
}
},
currentFormat () {
switch (this.field.type) {
case 'date': return this.currentDateFormat
case 'number': return this.currentNumberFormat
case 'signature': return this.currentSignatureFormat
default: return null
}
},
showPaymentSettings () {
return this.field.type === 'payment'
},
defaultCurrencies () {
return ['USD', 'EUR', 'GBP', 'CAD', 'AUD']
},
currenciesList () {
return this.currencies?.length ? this.currencies : this.defaultCurrencies
},
currencyOptions () {
return this.currenciesList.map(c => ({ value: c, label: c }))
},
currentCurrency () {
return this.field.preferences?.currency || 'USD'
},
priceTypeOptions () {
return [
{ value: 'one_off', label: this.t('fixed') },
{ value: 'formula', label: this.t('formula') },
{ value: 'payment_link', label: this.t('payment_link') }
]
},
currentPriceType () {
if (this.field.preferences?.formula) {
return 'formula'
}
if ('payment_link_id' in (this.field.preferences || {})) {
return 'payment_link'
}
if (this.field.preferences?.price) {
return 'one_off'
}
return ''
},
showDrawNewArea () {
return !this.field.areas?.length || !['radio', 'multiple'].includes(this.field.type)
},
showCopyToAllPages () {
return this.withCopyToAllPages && this.field.areas?.length === 1 && ['date', 'signature', 'initials', 'text', 'cells', 'stamp'].includes(this.field.type)
},
showSaveAsCustom () {
return this.withCustomFields
},
showMoreSubmenu () {
return this.showDrawNewArea || this.showCopyToAllPages || this.showSaveAsCustom
}
},
mounted () {
document.addEventListener('keydown', this.onKeyDown)
document.addEventListener('mousedown', this.handleClickOutside)
this.$nextTick(() => {
this.checkMenuPosition()
})
},
beforeUnmount () {
document.removeEventListener('keydown', this.onKeyDown)
document.removeEventListener('mousedown', this.handleClickOutside)
},
methods: {
IconAdjustmentsHorizontal,
IconInputCheck,
IconDots,
IconId,
IconCash,
IconCoins,
buildDefaultName: Field.methods.buildDefaultName,
formatNumber: FieldSettings.methods.formatNumber,
formatDate: FieldSettings.methods.formatDate,
parseLengthPattern: FieldSettings.methods.parseLengthPattern,
checkMenuPosition () {
if (this.$refs.menu) {
const rect = this.$refs.menu.getBoundingClientRect()
const overflow = rect.bottom - window.innerHeight
if (overflow > 0) {
this.contextMenu.y = this.contextMenu.y - overflow - 4
}
}
},
handleToggleRequired (value) {
this.field.required = value
this.$emit('save')
},
handleToggleReadOnly (value) {
this.field.readonly = value
this.$emit('save')
},
onKeyDown (event) {
if (event.key === 'Escape') {
event.preventDefault()
event.stopPropagation()
this.$emit('close')
}
},
handleClickOutside (event) {
if (this.$refs.menu && !this.$refs.menu.contains(event.target)) {
this.$emit('close')
}
},
openFontModal () {
this.isShowFontModal = true
},
openDescriptionModal () {
this.isShowDescriptionModal = true
},
openConditionModal () {
this.isShowConditionsModal = true
},
openFormulaModal () {
this.isShowFormulaModal = true
},
closeModal () {
this.isShowFormulaModal = false
this.isShowFontModal = false
this.isShowConditionsModal = false
this.isShowDescriptionModal = false
this.$emit('close')
},
handleSelectValidation (key) {
if (key === 'none') {
delete this.field.validation
} else if (key === 'custom') {
this.customValidationPattern = this.field.validation?.pattern || ''
this.customValidationMessage = this.field.validation?.message || ''
this.isShowCustomValidationModal = true
return
} else if (key === 'length') {
const existingLength = this.lengthValidation
this.lengthValidationMin = existingLength?.min || ''
this.lengthValidationMax = existingLength?.max || ''
this.isShowLengthValidationModal = true
return
} else {
this.field.validation ||= {}
this.field.validation.pattern = Object.keys(this.validationOptions).find(k => this.validationOptions[k] === key)
delete this.field.validation.message
}
this.$emit('save')
this.$emit('close')
},
handleSelectFormat (format) {
this.field.preferences ||= {}
this.field.preferences.format = format
this.$emit('save')
this.$emit('close')
},
handleTogglePrefillable (value) {
this.field.prefillable = value
this.$emit('save')
},
handleToggleSetSigningDate (value) {
this.field.default_value = value ? '{{date}}' : null
this.field.readonly = value
this.$emit('save')
},
handleToggleWithLogo (value) {
this.field.preferences ||= {}
this.field.preferences.with_logo = value
this.$emit('save')
},
handleToggleSignatureId (value) {
this.field.preferences ||= {}
this.field.preferences.with_signature_id = value
this.$emit('save')
},
handleToggleChecked (value) {
this.field.default_value = value
this.field.readonly = value
this.$emit('save')
},
handleSelectVerificationMethod (method) {
this.field.preferences ||= {}
this.field.preferences.method = method
this.$emit('save')
this.$emit('close')
},
openNumberRangeModal () {
this.numberRangeMin = this.field.validation?.min || ''
this.numberRangeMax = this.field.validation?.max || ''
this.isShowNumberRangeModal = true
},
saveCustomValidation () {
this.field.validation = {
pattern: this.customValidationPattern,
message: this.customValidationMessage
}
this.isShowCustomValidationModal = false
this.$emit('save')
this.$emit('close')
},
saveLengthValidation () {
const min = this.lengthValidationMin || '0'
const max = this.lengthValidationMax || ''
this.field.validation = { pattern: `.{${min},${max}}` }
this.isShowLengthValidationModal = false
this.$emit('save')
this.$emit('close')
},
saveNumberRange () {
this.field.validation ||= {}
if (this.numberRangeMin) {
this.field.validation.min = this.numberRangeMin
} else {
delete this.field.validation.min
}
if (this.numberRangeMax) {
this.field.validation.max = this.numberRangeMax
} else {
delete this.field.validation.max
}
this.isShowNumberRangeModal = false
this.$emit('save')
this.$emit('close')
},
closeValidationModal () {
this.isShowCustomValidationModal = false
this.isShowLengthValidationModal = false
this.isShowNumberRangeModal = false
this.isShowPriceModal = false
this.isShowPaymentLinkModal = false
},
handleSelectCurrency (currency) {
this.field.preferences ||= {}
this.field.preferences.currency = currency
this.$emit('save')
this.$emit('close')
},
handleSelectPriceType (type) {
this.field.preferences ||= {}
if (type === 'one_off') {
this.priceValue = this.field.preferences.price || ''
this.isShowPriceModal = true
} else if (type === 'payment_link') {
this.paymentLinkValue = this.field.preferences.payment_link_id || ''
this.isShowPaymentLinkModal = true
} else if (type === 'formula') {
this.openFormulaModal()
}
},
savePrice () {
this.field.preferences ||= {}
this.field.preferences.price = this.priceValue
delete this.field.preferences.payment_link_id
delete this.field.preferences.formula
this.isShowPriceModal = false
this.$emit('save')
this.$emit('close')
},
savePaymentLink () {
this.field.preferences ||= {}
this.field.preferences.payment_link_id = this.paymentLinkValue
delete this.field.preferences.price
delete this.field.preferences.formula
this.isShowPaymentLinkModal = false
this.$emit('save')
this.$emit('close')
},
handleMoreSelect (value) {
if (value === 'draw_new_area') {
this.$emit('set-draw', { field: this.field })
this.$emit('close')
} else if (value === 'save_as_custom') {
this.$emit('add-custom-field', this.field)
this.$emit('close')
} else if (value === 'copy_to_all_pages') {
this.copyToAllPages(this.field)
this.$emit('close')
}
},
copyToAllPages: FieldSettings.methods.copyToAllPages
}
}
</script>