diff --git a/app/javascript/application.js b/app/javascript/application.js index dc2df889..a23ce174 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -90,6 +90,7 @@ window.customElements.define('template-builder', class extends HTMLElement { withLogo: this.dataset.withLogo !== 'false', editable: this.dataset.editable !== 'false', withPayment: this.dataset.withPayment === 'true', + withFormula: this.dataset.withFormula === 'true', currencies: (this.dataset.currencies || '').split(',').filter(Boolean), acceptFileTypes: this.dataset.acceptFileTypes, isDirectUpload: this.dataset.isDirectUpload === 'true' diff --git a/app/javascript/submission_form/form.vue b/app/javascript/submission_form/form.vue index 3a5d6c84..89324a80 100644 --- a/app/javascript/submission_form/form.vue +++ b/app/javascript/submission_form/form.vue @@ -8,6 +8,11 @@ :current-step="currentStepFields" @focus-step="[saveStep(), goToStep($event, false, true), currentField.type !== 'checkbox' ? isFormVisible = true : '']" /> + + {{ t('required') }} +
  • + +
  • + + + @@ -366,7 +407,8 @@ import Contenteditable from './contenteditable' import FieldType from './field_type' import PaymentSettings from './payment_settings' -import { IconShape, IconNewSection, IconTrashX, IconCopy, IconSettings } from '@tabler/icons-vue' +import FormulaModal from './formula_modal' +import { IconMathFunction, IconShape, IconNewSection, IconTrashX, IconCopy, IconSettings } from '@tabler/icons-vue' import { v4 } from 'uuid' export default { @@ -377,11 +419,13 @@ export default { IconShape, PaymentSettings, IconNewSection, + FormulaModal, IconTrashX, + IconMathFunction, IconCopy, FieldType }, - inject: ['template', 'save', 'backgroundColor', 'selectedAreaRef', 't'], + inject: ['template', 'save', 'backgroundColor', 'selectedAreaRef', 't', 'withFormula'], props: { field: { type: Object, @@ -403,11 +447,15 @@ export default { return { isNameFocus: false, showPaymentModal: false, + isShowFormulaModal: false, renderDropdown: false } }, computed: { fieldNames: FieldType.computed.fieldNames, + modalContainerEl () { + return this.$el.getRootNode().querySelector('#docuseal_modal_container') + }, dateFormats () { return [ 'MM/DD/YYYY', @@ -422,22 +470,7 @@ export default { ] }, defaultName () { - if (this.field.type === 'payment' && this.field.preferences?.price) { - const { price, currency } = this.field.preferences || {} - - const formattedPrice = new Intl.NumberFormat([], { - style: 'currency', - currency - }).format(price) - - return `${this.fieldNames[this.field.type]} ${formattedPrice}` - } else { - const typeIndex = this.template.fields.filter((f) => f.type === this.field.type).indexOf(this.field) - - const suffix = { multiple: this.t('select'), radio: this.t('group') }[this.field.type] || this.t('field') - - return `${this.fieldNames[this.field.type]} ${suffix} ${typeIndex + 1}` - } + return this.buildDefaultName(this.field, this.template.fields) }, areas () { return this.field.areas || [] @@ -452,6 +485,24 @@ export default { } }, methods: { + buildDefaultName (field, fields) { + if (field.type === 'payment' && field.preferences?.price) { + const { price, currency } = field.preferences || {} + + const formattedPrice = new Intl.NumberFormat([], { + style: 'currency', + currency + }).format(price) + + return `${this.fieldNames[field.type]} ${formattedPrice}` + } else { + const typeIndex = fields.filter((f) => f.type === field.type).indexOf(field) + + const suffix = { multiple: this.t('select'), radio: this.t('group') }[field.type] || this.t('field') + + return `${this.fieldNames[field.type]} ${suffix} ${typeIndex + 1}` + } + }, formatDate (date, format) { const monthFormats = { M: 'numeric', diff --git a/app/javascript/template_builder/formula_modal.vue b/app/javascript/template_builder/formula_modal.vue new file mode 100644 index 00000000..144750e2 --- /dev/null +++ b/app/javascript/template_builder/formula_modal.vue @@ -0,0 +1,216 @@ +