Files
docuseal/app/javascript/template_builder/fields.vue
T

281 lines
7.9 KiB
Vue
Raw Normal View History

2023-05-21 17:59:36 +03:00
<template>
2023-08-19 21:05:54 +03:00
<div :class="withStickySubmitters ? 'sticky top-0 z-10' : ''">
2023-06-16 00:04:05 +03:00
<FieldSubmitter
:model-value="selectedSubmitter.uuid"
2023-08-19 21:05:54 +03:00
class="w-full rounded-lg"
:class="{ 'bg-base-100': withStickySubmitters }"
2023-06-16 00:04:05 +03:00
:submitters="submitters"
2023-12-17 16:10:17 +02:00
:editable="editable && !defaultSubmitters.length"
2023-06-24 16:17:07 +03:00
@new-submitter="save"
2023-06-16 00:04:05 +03:00
@remove="removeSubmitter"
2023-06-24 16:17:07 +03:00
@name-change="save"
2023-06-16 00:04:05 +03:00
@update:model-value="$emit('change-submitter', submitters.find((s) => s.uuid === $event))"
/>
</div>
2023-11-04 14:06:59 +02:00
<div
class="mb-1 mt-2"
@dragover.prevent="onFieldDragover"
@drop="save"
>
2023-05-21 17:59:36 +03:00
<Field
2023-06-07 01:16:43 +03:00
v-for="field in submitterFields"
2023-05-21 17:59:36 +03:00
:key="field.uuid"
2023-11-04 14:06:59 +02:00
:data-uuid="field.uuid"
2023-05-21 17:59:36 +03:00
:field="field"
2023-06-03 00:53:46 +03:00
:type-index="fields.filter((f) => f.type === field.type).indexOf(field)"
2023-11-04 14:06:59 +02:00
:editable="editable && !dragField"
2023-11-27 20:24:58 +02:00
:default-field="defaultFields.find((f) => f.name === field.name)"
2023-11-04 14:06:59 +02:00
:draggable="editable"
@dragstart="dragField = field"
@dragend="dragField = null"
2023-06-07 01:16:43 +03:00
@remove="removeField"
2023-06-03 00:53:46 +03:00
@scroll-to="$emit('scroll-to-area', $event)"
2023-05-21 17:59:36 +03:00
@set-draw="$emit('set-draw', $event)"
/>
</div>
2023-11-11 23:36:03 +02:00
<div v-if="submitterDefaultFields.length">
<hr class="mb-2">
<template
v-for="field in submitterDefaultFields"
:key="field.name"
>
<div
:style="{ backgroundColor: backgroundColor }"
draggable="true"
class="border border-base-300 rounded rounded-tr-none relative group mb-2"
@dragstart="onDragstart({ type: 'text', ...field })"
@dragend="$emit('drag-end')"
>
<div class="flex items-center justify-between relative cursor-grab">
<div class="flex items-center p-1 space-x-1">
<IconDrag />
<FieldType
:model-value="field.type || 'text'"
:editable="false"
:button-width="20"
/>
<span class="block pl-0.5">
{{ field.name }}
</span>
</div>
</div>
</div>
</template>
</div>
2023-11-04 01:19:32 +02:00
<div
v-if="editable"
class="grid grid-cols-3 gap-1 pb-2"
>
2023-09-05 01:00:21 +03:00
<template
2023-06-04 01:08:45 +03:00
v-for="(icon, type) in fieldIcons"
:key="type"
2023-05-23 00:03:26 +03:00
>
2023-09-05 01:00:21 +03:00
<button
2023-12-14 21:22:26 +02:00
v-if="(withPhone || type != 'phone') && (withPayment || type != 'payment')"
2023-09-05 01:00:21 +03:00
draggable="true"
2023-11-21 23:08:59 +02:00
class="group flex items-center justify-center border border-dashed border-base-300 hover:border-base-content/20 w-full rounded relative"
2023-09-05 01:00:21 +03:00
:style="{ backgroundColor: backgroundColor }"
2023-11-11 23:36:03 +02:00
@dragstart="onDragstart({ type: type })"
2023-09-05 01:00:21 +03:00
@dragend="$emit('drag-end')"
@click="addField(type)"
>
2023-11-21 23:08:59 +02:00
<div class="flex items-console group-hover:bg-base-200/50 transition-all cursor-grab h-full absolute left-0">
<IconDrag class=" my-auto" />
2023-09-05 01:00:21 +03:00
</div>
<div class="flex items-center flex-col px-2 py-2">
<component :is="icon" />
<span class="text-xs mt-1">
{{ fieldNames[type] }}
</span>
</div>
</button>
<div
2023-12-14 21:22:26 +02:00
v-else-if="type == 'phone'"
2023-09-20 00:13:14 +03:00
class="tooltip tooltip-bottom-end flex"
2023-09-05 01:00:21 +03:00
data-tip="Unlock SMS-verified phone number field with paid plan. Use text field for phone numbers without verification."
>
<a
href="https://www.docuseal.co/pricing"
target="_blank"
class="opacity-50 flex items-center justify-center border border-dashed border-base-300 w-full rounded relative"
:style="{ backgroundColor: backgroundColor }"
>
<div class="w-0 absolute left-0">
<IconLock
width="18"
height="18"
stroke-width="1.5"
/>
</div>
<div class="flex items-center flex-col px-2 py-2">
<component :is="icon" />
<span class="text-xs mt-1">
{{ fieldNames[type] }}
</span>
</div>
</a>
2023-06-03 00:53:46 +03:00
</div>
2023-09-05 01:00:21 +03:00
</template>
2023-06-03 00:53:46 +03:00
</div>
2023-07-08 17:07:07 +03:00
<div
2023-11-04 01:19:32 +02:00
v-if="fields.length < 4 && editable"
2023-07-08 17:07:07 +03:00
class="text-xs p-2 border border-base-200 rounded"
>
2023-07-12 23:56:42 +03:00
<ul class="list-disc list-outside ml-3">
2023-07-08 17:07:07 +03:00
<li>
Draw a text field on the page with a mouse
</li>
<li>
Drag &amp; drop any other field type on the page
</li>
<li>
Click on the field type above to add it to the form without drawing it on the document
</li>
2023-07-12 23:56:42 +03:00
</ul>
2023-07-08 17:07:07 +03:00
</div>
2023-05-21 17:59:36 +03:00
</template>
<script>
import Field from './field'
import { v4 } from 'uuid'
2023-06-04 01:08:45 +03:00
import FieldType from './field_type'
2023-06-07 01:16:43 +03:00
import FieldSubmitter from './field_submitter'
2023-09-05 01:00:21 +03:00
import { IconLock } from '@tabler/icons-vue'
2023-11-11 23:36:03 +02:00
import IconDrag from './icon_drag'
2023-05-21 17:59:36 +03:00
export default {
2023-05-31 23:19:20 +03:00
name: 'TemplateFields',
2023-05-21 17:59:36 +03:00
components: {
2023-06-07 01:16:43 +03:00
Field,
2023-11-11 23:36:03 +02:00
FieldType,
2023-09-05 01:00:21 +03:00
FieldSubmitter,
2023-11-11 23:36:03 +02:00
IconDrag,
2023-09-05 01:00:21 +03:00
IconLock
2023-05-21 17:59:36 +03:00
},
2023-12-14 21:22:26 +02:00
inject: ['save', 'backgroundColor', 'withPhone', 'withPayment'],
2023-05-21 17:59:36 +03:00
props: {
fields: {
type: Array,
required: true
2023-06-07 01:16:43 +03:00
},
2023-11-04 01:19:32 +02:00
editable: {
type: Boolean,
required: false,
default: true
},
2023-11-11 23:36:03 +02:00
defaultFields: {
type: Array,
required: false,
default: () => []
},
2023-12-17 16:10:17 +02:00
defaultSubmitters: {
type: Array,
required: false,
default: () => []
},
2023-08-19 21:05:54 +03:00
withStickySubmitters: {
type: Boolean,
required: false,
default: true
},
2023-06-07 01:16:43 +03:00
submitters: {
type: Array,
required: true
},
selectedSubmitter: {
type: Object,
required: true
2023-05-21 17:59:36 +03:00
}
},
2023-06-07 01:16:43 +03:00
emits: ['set-draw', 'set-drag', 'drag-end', 'scroll-to-area', 'change-submitter'],
2023-11-04 14:06:59 +02:00
data () {
return {
dragField: null
}
},
2023-05-21 17:59:36 +03:00
computed: {
2023-06-27 00:57:29 +03:00
fieldNames: FieldType.computed.fieldNames,
2023-06-07 01:16:43 +03:00
fieldIcons: FieldType.computed.fieldIcons,
submitterFields () {
return this.fields.filter((f) => f.submitter_uuid === this.selectedSubmitter.uuid)
2023-11-11 23:36:03 +02:00
},
submitterDefaultFields () {
return this.defaultFields.filter((f) => {
2023-11-24 17:34:57 +02:00
return !this.submitterFields.find((field) => field.name === f.name) && (!f.role || f.role === this.selectedSubmitter.name)
2023-11-11 23:36:03 +02:00
})
2023-06-07 01:16:43 +03:00
}
2023-05-21 17:59:36 +03:00
},
methods: {
2023-11-11 23:36:03 +02:00
onDragstart (field) {
this.$emit('set-drag', field)
2023-05-23 00:03:26 +03:00
},
2023-11-04 14:06:59 +02:00
onFieldDragover (e) {
const targetFieldUuid = e.target.closest('[data-uuid]')?.dataset?.uuid
if (this.dragField && targetFieldUuid && this.dragField.uuid !== targetFieldUuid) {
const field = this.fields.find((f) => f.uuid === targetFieldUuid)
const currentIndex = this.fields.indexOf(this.dragField)
const targetIndex = this.fields.indexOf(field)
if (currentIndex < targetIndex) {
this.fields.splice(targetIndex + 1, 0, this.dragField)
this.fields.splice(currentIndex, 1)
} else {
this.fields.splice(targetIndex, 0, this.dragField)
this.fields.splice(currentIndex + 1, 1)
}
}
},
2023-06-07 01:16:43 +03:00
removeSubmitter (submitter) {
[...this.fields].forEach((field) => {
if (field.submitter_uuid === submitter.uuid) {
this.removeField(field)
}
})
this.submitters.splice(this.submitters.indexOf(submitter), 1)
if (this.selectedSubmitter === submitter) {
this.$emit('change-submitter', this.submitters[0])
}
2023-06-24 16:17:07 +03:00
this.save()
2023-06-07 01:16:43 +03:00
},
removeField (field) {
this.fields.splice(this.fields.indexOf(field), 1)
2023-06-24 16:17:07 +03:00
this.save()
2023-06-07 01:16:43 +03:00
},
2023-05-23 00:03:26 +03:00
addField (type, area = null) {
2023-05-21 17:59:36 +03:00
const field = {
2023-06-04 01:08:45 +03:00
name: '',
2023-05-21 17:59:36 +03:00
uuid: v4(),
2023-07-22 20:00:28 +03:00
required: type !== 'checkbox',
areas: [],
2023-06-07 01:16:43 +03:00
submitter_uuid: this.selectedSubmitter.uuid,
2023-05-21 17:59:36 +03:00
type
}
2023-06-16 00:04:05 +03:00
if (['select', 'multiple', 'radio'].includes(type)) {
2023-11-13 01:46:28 +02:00
field.options = [{ value: '', uuid: v4() }]
2023-05-21 17:59:36 +03:00
}
2023-12-17 23:32:05 +02:00
if (type === 'date') {
field.preferences = {
format: Intl.DateTimeFormat().resolvedOptions().locale.endsWith('-US') ? 'MM/DD/YYYY' : 'DD/MM/YYYY'
}
}
2023-05-21 17:59:36 +03:00
this.fields.push(field)
2023-06-24 16:17:07 +03:00
2023-11-21 23:08:59 +02:00
if (['signature', 'initials', 'cells'].includes(type)) {
this.$emit('set-draw', { field })
}
2023-06-24 16:17:07 +03:00
this.save()
2023-05-21 17:59:36 +03:00
}
}
}
</script>