Files
docuseal/app/javascript/submission_form/area.vue
T

257 lines
6.5 KiB
Vue
Raw Normal View History

2023-05-25 22:47:52 +03:00
<template>
<div
2023-06-16 23:39:55 +03:00
class="flex absolute text-[1.5vw] lg:text-base"
2023-05-25 22:47:52 +03:00
:style="computedStyle"
2023-06-16 23:39:55 +03:00
:class="{ 'cursor-default': !submittable, 'bg-red-100 border cursor-pointer ': submittable, 'border-red-100': !isActive && submittable, 'bg-opacity-70': !isActive && !isValueSet && submittable, 'border-red-500 border-dashed z-10': isActive && submittable, 'bg-opacity-30': (isActive || isValueSet) && submittable }"
2023-05-25 22:47:52 +03:00
>
2023-06-15 01:05:04 +03:00
<div
2023-06-16 23:39:55 +03:00
v-if="!isActive && !isValueSet && field.type !== 'checkbox' && submittable"
2023-06-15 01:05:04 +03:00
class="absolute top-0 bottom-0 right-0 left-0 items-center justify-center h-full w-full"
>
<span
v-if="field"
class="flex justify-center items-center h-full opacity-50"
>
<component
:is="fieldIcons[field.type]"
width="100%"
height="100%"
class="max-h-10 text-base-content"
/>
</span>
</div>
<div
2023-07-31 00:48:51 +03:00
v-if="isActive && withLabel"
2023-06-15 01:05:04 +03:00
class="absolute -top-7 rounded bg-base-content text-base-100 px-2 text-sm whitespace-nowrap"
>
{{ field.name || fieldNames[field.type] }}
2023-07-22 20:00:28 +03:00
<template v-if="field.type === 'checkbox' && !field.name">
2023-06-16 00:04:05 +03:00
{{ fieldIndex + 1 }}
</template>
2023-07-22 20:00:28 +03:00
<template v-else-if="!field.required && field.type !== 'checkbox'">
2023-06-20 00:24:39 +03:00
(optional)
</template>
2023-06-15 01:05:04 +03:00
</div>
<div
v-if="isActive"
ref="scrollToElem"
class="absolute -top-20"
/>
2023-05-25 22:47:52 +03:00
<img
v-if="field.type === 'image' && image"
2023-06-16 00:04:05 +03:00
class="object-contain mx-auto"
2023-05-25 22:47:52 +03:00
:src="image.url"
>
<img
v-else-if="field.type === 'signature' && signature"
2023-06-16 00:04:05 +03:00
class="object-contain mx-auto"
2023-05-25 22:47:52 +03:00
:src="signature.url"
>
2023-09-20 00:13:14 +03:00
<img
v-else-if="field.type === 'initials' && initials"
class="object-contain mx-auto"
:src="initials.url"
>
2023-06-16 00:04:05 +03:00
<div
v-else-if="field.type === 'file'"
2023-06-18 16:30:35 +03:00
class="px-0.5 flex flex-col justify-center"
2023-06-16 00:04:05 +03:00
>
2023-05-25 22:47:52 +03:00
<a
v-for="(attachment, index) in attachments"
:key="index"
2023-06-16 00:04:05 +03:00
target="_blank"
2023-05-25 22:47:52 +03:00
:href="attachment.url"
>
2023-06-16 00:04:05 +03:00
<IconPaperclip
class="inline w-[1.5vw] h-[1.5vw] lg:w-4 lg:h-4"
/>
2023-05-25 22:47:52 +03:00
{{ attachment.filename }}
</a>
</div>
2023-06-16 00:04:05 +03:00
<div
v-else-if="field.type === 'checkbox'"
class="w-full p-[0.2vw] flex items-center justify-center"
>
<input
2023-06-16 23:39:55 +03:00
v-if="submittable"
2023-06-16 00:04:05 +03:00
type="checkbox"
:value="false"
class="aspect-square base-checkbox"
:class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }"
:checked="!!modelValue"
@click="$emit('update:model-value', !modelValue)"
>
2023-06-18 16:30:35 +03:00
<IconCheck
v-else-if="modelValue"
2023-06-16 23:39:55 +03:00
class="aspect-square"
:class="{ '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }"
/>
2023-06-16 00:04:05 +03:00
</div>
2023-06-27 00:57:29 +03:00
<div
v-else-if="field.type === 'cells'"
class="w-full flex items-center"
>
<div
v-for="(char, index) in modelValue"
:key="index"
class="text-center flex-none"
:style="{ width: (area.cell_w / area.w * 100) + '%' }"
>
{{ char }}
</div>
</div>
2023-06-16 00:04:05 +03:00
<div
v-else
class="flex items-center px-0.5"
>
<span v-if="Array.isArray(modelValue)">
{{ modelValue.join(', ') }}
</span>
<span v-else-if="field.type === 'date'">
{{ formattedDate }}
</span>
2023-10-16 00:41:14 +03:00
<span
v-else
class="whitespace-pre-wrap"
>{{ modelValue }}</span>
2023-06-16 00:04:05 +03:00
</div>
2023-05-25 22:47:52 +03:00
</div>
</template>
<script>
2023-09-20 00:13:14 +03:00
import { IconTextSize, IconWritingSign, IconCalendarEvent, IconPhoto, IconCheckbox, IconPaperclip, IconSelect, IconCircleDot, IconChecks, IconCheck, IconColumns3, IconPhoneCheck, IconLetterCaseUpper } from '@tabler/icons-vue'
2023-06-15 01:05:04 +03:00
2023-05-25 22:47:52 +03:00
export default {
name: 'FieldArea',
2023-06-16 00:04:05 +03:00
components: {
2023-06-16 23:39:55 +03:00
IconPaperclip,
2023-06-18 16:30:35 +03:00
IconCheck
2023-06-16 00:04:05 +03:00
},
2023-05-25 22:47:52 +03:00
props: {
field: {
type: Object,
required: true
},
2023-06-16 23:39:55 +03:00
isValueSet: {
type: Boolean,
2023-06-16 00:04:05 +03:00
required: false,
2023-06-16 23:39:55 +03:00
default: false
2023-06-16 00:04:05 +03:00
},
2023-06-16 23:39:55 +03:00
submittable: {
type: Boolean,
2023-06-16 00:04:05 +03:00
required: false,
2023-06-16 23:39:55 +03:00
default: false
2023-06-16 00:04:05 +03:00
},
2023-06-15 01:05:04 +03:00
modelValue: {
type: [Array, String, Number, Object, Boolean],
2023-05-25 22:47:52 +03:00
required: false,
default: ''
},
2023-06-15 01:05:04 +03:00
isActive: {
type: Boolean,
required: false,
default: false
},
2023-07-31 00:48:51 +03:00
withLabel: {
type: Boolean,
required: false,
default: true
},
2023-06-16 00:04:05 +03:00
fieldIndex: {
type: Number,
required: false,
default: 0
},
2023-05-25 22:47:52 +03:00
attachmentsIndex: {
type: Object,
required: false,
default: () => ({})
},
area: {
type: Object,
required: true
}
},
2023-06-15 01:05:04 +03:00
emits: ['update:model-value'],
2023-05-25 22:47:52 +03:00
computed: {
2023-06-15 01:05:04 +03:00
fieldNames () {
return {
text: 'Text',
2023-06-27 00:57:29 +03:00
cells: 'Text',
2023-06-15 01:05:04 +03:00
signature: 'Signature',
date: 'Date',
image: 'Image',
2023-09-20 00:13:14 +03:00
initials: 'Initials',
2023-06-15 01:05:04 +03:00
file: 'File',
select: 'Select',
checkbox: 'Checkbox',
2023-06-16 00:04:05 +03:00
radio: 'Radio',
2023-09-05 01:00:21 +03:00
multiple: 'Multiple Select',
phone: 'Phone'
2023-06-15 01:05:04 +03:00
}
},
fieldIcons () {
return {
text: IconTextSize,
2023-06-24 17:15:36 +03:00
signature: IconWritingSign,
2023-06-15 01:05:04 +03:00
date: IconCalendarEvent,
image: IconPhoto,
2023-09-20 00:13:14 +03:00
initials: IconLetterCaseUpper,
2023-06-15 01:05:04 +03:00
file: IconPaperclip,
select: IconSelect,
checkbox: IconCheckbox,
2023-06-16 00:04:05 +03:00
radio: IconCircleDot,
2023-06-27 00:57:29 +03:00
cells: IconColumns3,
2023-09-05 01:00:21 +03:00
multiple: IconChecks,
phone: IconPhoneCheck
2023-06-15 01:05:04 +03:00
}
},
2023-05-25 22:47:52 +03:00
image () {
if (this.field.type === 'image') {
2023-06-15 01:05:04 +03:00
return this.attachmentsIndex[this.modelValue]
2023-05-25 22:47:52 +03:00
} else {
return null
}
},
signature () {
if (this.field.type === 'signature') {
2023-06-15 01:05:04 +03:00
return this.attachmentsIndex[this.modelValue]
2023-05-25 22:47:52 +03:00
} else {
return null
}
},
2023-09-20 00:13:14 +03:00
initials () {
if (this.field.type === 'initials') {
return this.attachmentsIndex[this.modelValue]
} else {
return null
}
},
2023-06-16 00:04:05 +03:00
formattedDate () {
if (this.field.type === 'date' && this.modelValue) {
2023-08-01 00:26:37 +03:00
return new Intl.DateTimeFormat([], { year: 'numeric', month: 'long', day: 'numeric', timeZone: 'UTC' }).format(new Date(this.modelValue))
2023-06-16 00:04:05 +03:00
} else {
return ''
}
},
2023-05-25 22:47:52 +03:00
attachments () {
2023-06-16 00:04:05 +03:00
if (this.field.type === 'file') {
2023-06-15 01:05:04 +03:00
return (this.modelValue || []).map((uuid) => this.attachmentsIndex[uuid])
2023-05-25 22:47:52 +03:00
} else {
return []
}
},
computedStyle () {
const { x, y, w, h } = this.area
return {
top: y * 100 + '%',
left: x * 100 + '%',
width: w * 100 + '%',
height: h * 100 + '%'
}
}
}
}
</script>