group form checkboxes into single step
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex cursor-pointer bg-red-100 absolute border"
|
||||
class="flex cursor-pointer bg-red-100 absolute border text-[1.5vw] lg:text-base"
|
||||
:style="computedStyle"
|
||||
:class="{ 'border-red-100 bg-opacity-70': !isActive, 'border-red-500 border-dashed bg-opacity-30 z-10': isActive }"
|
||||
:class="{ 'border-red-100': !isActive, 'bg-opacity-70': !isActive && !isValue, 'border-red-500 border-dashed z-10': isActive, 'bg-opacity-30': isActive || isValue }"
|
||||
>
|
||||
<div
|
||||
v-if="!isActive && !modelValue"
|
||||
v-if="!isActive && !isValue && field.type !== 'checkbox'"
|
||||
class="absolute top-0 bottom-0 right-0 left-0 items-center justify-center h-full w-full"
|
||||
>
|
||||
<span
|
||||
@@ -25,6 +25,9 @@
|
||||
class="absolute -top-7 rounded bg-base-content text-base-100 px-2 text-sm whitespace-nowrap"
|
||||
>
|
||||
{{ field.name || fieldNames[field.type] }}
|
||||
<template v-if="field.type === 'checkbox'">
|
||||
{{ fieldIndex + 1 }}
|
||||
</template>
|
||||
</div>
|
||||
<div
|
||||
v-if="isActive"
|
||||
@@ -33,39 +36,83 @@
|
||||
/>
|
||||
<img
|
||||
v-if="field.type === 'image' && image"
|
||||
class="object-contain"
|
||||
class="object-contain mx-auto"
|
||||
:src="image.url"
|
||||
>
|
||||
<img
|
||||
v-else-if="field.type === 'signature' && signature"
|
||||
class="object-contain"
|
||||
class="object-contain mx-auto"
|
||||
:src="signature.url"
|
||||
>
|
||||
<div v-else-if="field.type === 'attachment'">
|
||||
<div
|
||||
v-else-if="field.type === 'file'"
|
||||
class="px-0.5 flex items-center"
|
||||
>
|
||||
<a
|
||||
v-for="(attachment, index) in attachments"
|
||||
:key="index"
|
||||
target="_blank"
|
||||
:href="attachment.url"
|
||||
>
|
||||
<IconPaperclip
|
||||
class="inline w-[1.5vw] h-[1.5vw] lg:w-4 lg:h-4"
|
||||
/>
|
||||
{{ attachment.filename }}
|
||||
</a>
|
||||
</div>
|
||||
<span v-else>
|
||||
{{ modelValue }}
|
||||
</span>
|
||||
<div
|
||||
v-else-if="field.type === 'checkbox'"
|
||||
class="w-full p-[0.2vw] flex items-center justify-center"
|
||||
>
|
||||
<input
|
||||
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)"
|
||||
>
|
||||
</div>
|
||||
<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>
|
||||
<span v-else>
|
||||
{{ modelValue }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { IconTextSize, IconWriting, IconCalendarEvent, IconPhoto, IconCheckbox, IconPaperclip, IconSelect, IconCircleDot } from '@tabler/icons-vue'
|
||||
import { IconTextSize, IconWriting, IconCalendarEvent, IconPhoto, IconCheckbox, IconPaperclip, IconSelect, IconCircleDot, IconChecks } from '@tabler/icons-vue'
|
||||
|
||||
export default {
|
||||
name: 'FieldArea',
|
||||
components: {
|
||||
IconPaperclip
|
||||
},
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
step: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => []
|
||||
},
|
||||
values: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({})
|
||||
},
|
||||
modelValue: {
|
||||
type: [Array, String, Number, Object, Boolean],
|
||||
required: false,
|
||||
@@ -76,6 +123,11 @@ export default {
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
fieldIndex: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
attachmentsIndex: {
|
||||
type: Object,
|
||||
required: false,
|
||||
@@ -97,9 +149,13 @@ export default {
|
||||
file: 'File',
|
||||
select: 'Select',
|
||||
checkbox: 'Checkbox',
|
||||
radio: 'Radio'
|
||||
radio: 'Radio',
|
||||
multiple: 'Multiple Select'
|
||||
}
|
||||
},
|
||||
isValue () {
|
||||
return this.step.some((f) => ![null, undefined, ''].includes(this.values[f.uuid]))
|
||||
},
|
||||
fieldIcons () {
|
||||
return {
|
||||
text: IconTextSize,
|
||||
@@ -109,7 +165,8 @@ export default {
|
||||
file: IconPaperclip,
|
||||
select: IconSelect,
|
||||
checkbox: IconCheckbox,
|
||||
radio: IconCircleDot
|
||||
radio: IconCircleDot,
|
||||
multiple: IconChecks
|
||||
}
|
||||
},
|
||||
image () {
|
||||
@@ -126,8 +183,15 @@ export default {
|
||||
return null
|
||||
}
|
||||
},
|
||||
formattedDate () {
|
||||
if (this.field.type === 'date' && this.modelValue) {
|
||||
return new Intl.DateTimeFormat({ year: 'numeric', month: 'numeric', day: 'numeric' }).format(new Date(this.modelValue))
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
attachments () {
|
||||
if (this.field.type === 'attachment') {
|
||||
if (this.field.type === 'file') {
|
||||
return (this.modelValue || []).map((uuid) => this.attachmentsIndex[uuid])
|
||||
} else {
|
||||
return []
|
||||
|
||||
@@ -1,23 +1,31 @@
|
||||
<template>
|
||||
<template
|
||||
v-for="field in fields"
|
||||
:key="field.uuid"
|
||||
v-for="step in steps"
|
||||
:key="step[0].uuid"
|
||||
>
|
||||
<template
|
||||
v-for="(area, index) in field.areas"
|
||||
:key="index"
|
||||
v-for="(field, fieldIndex) in step"
|
||||
:key="field.uuid"
|
||||
>
|
||||
<Teleport :to="`#page-${area.attachment_uuid}-${area.page}`">
|
||||
<FieldArea
|
||||
:ref="setAreaRef"
|
||||
v-model="values[field.uuid]"
|
||||
:field="field"
|
||||
:area="area"
|
||||
:is-active="currentField === field"
|
||||
:attachments-index="attachmentsIndex"
|
||||
@click="$emit('focus-field', field)"
|
||||
/>
|
||||
</Teleport>
|
||||
<template
|
||||
v-for="(area, areaIndex) in field.areas"
|
||||
:key="areaIndex"
|
||||
>
|
||||
<Teleport :to="`#page-${area.attachment_uuid}-${area.page}`">
|
||||
<FieldArea
|
||||
:ref="setAreaRef"
|
||||
v-model="values[field.uuid]"
|
||||
:field="field"
|
||||
:values="values"
|
||||
:area="area"
|
||||
:field-index="fieldIndex"
|
||||
:step="step"
|
||||
:is-active="currentStep === step"
|
||||
:attachments-index="attachmentsIndex"
|
||||
@click="$emit('focus-step', step)"
|
||||
/>
|
||||
</Teleport>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
@@ -31,7 +39,7 @@ export default {
|
||||
FieldArea
|
||||
},
|
||||
props: {
|
||||
fields: {
|
||||
steps: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => []
|
||||
@@ -46,13 +54,13 @@ export default {
|
||||
required: false,
|
||||
default: () => ({})
|
||||
},
|
||||
currentField: {
|
||||
type: Object,
|
||||
currentStep: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => ({})
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
emits: ['focus-field'],
|
||||
emits: ['focus-step'],
|
||||
data () {
|
||||
return {
|
||||
areaRefs: []
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<FieldAreas
|
||||
ref="areas"
|
||||
:fields="submitterFields"
|
||||
:steps="stepFields"
|
||||
:values="values"
|
||||
:attachments-index="attachmentsIndex"
|
||||
:current-field="currentField"
|
||||
@focus-field="goToField($event, false, true)"
|
||||
:current-step="currentStepFields"
|
||||
@focus-step="goToStep($event, false, true)"
|
||||
/>
|
||||
<form
|
||||
v-if="!isCompleted"
|
||||
@@ -21,7 +21,7 @@
|
||||
:value="authenticityToken"
|
||||
>
|
||||
<input
|
||||
v-if="currentStep === submitterFields.length - 1"
|
||||
v-if="currentStep === stepFields.length - 1"
|
||||
type="hidden"
|
||||
name="completed"
|
||||
value="true"
|
||||
@@ -42,12 +42,12 @@
|
||||
<input
|
||||
:id="currentField.uuid"
|
||||
v-model="values[currentField.uuid]"
|
||||
autofocus
|
||||
class="base-input !text-2xl w-full"
|
||||
:required="currentField.required"
|
||||
placeholder="Type here..."
|
||||
type="text"
|
||||
:name="`values[${currentField.uuid}]`"
|
||||
@focus="$refs.areas.scrollIntoField(currentField)"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,15 +57,15 @@
|
||||
:for="currentField.uuid"
|
||||
class="label text-2xl mb-2"
|
||||
>{{ currentField.name }}</label>
|
||||
<div>
|
||||
<div class="text-center">
|
||||
<input
|
||||
:id="currentField.uuid"
|
||||
v-model="values[currentField.uuid]"
|
||||
class="base-input !text-2xl w-full text-center"
|
||||
autofocus
|
||||
class="base-input !text-2xl text-center w-full"
|
||||
:required="currentField.required"
|
||||
type="date"
|
||||
:name="`values[${currentField.uuid}]`"
|
||||
@focus="$refs.areas.scrollIntoField(currentField)"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,6 +81,7 @@
|
||||
class="select base-input !text-2xl w-full text-center font-normal"
|
||||
:name="`values[${currentField.uuid}]`"
|
||||
@change="values[currentField.uuid] = $event.target.value"
|
||||
@focus="$refs.areas.scrollIntoField(currentField)"
|
||||
>
|
||||
<option
|
||||
value=""
|
||||
@@ -98,63 +99,73 @@
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-else-if="currentField.type === 'radio' && currentField.options?.length">
|
||||
<div v-else-if="currentField.type === 'radio'">
|
||||
<label
|
||||
v-if="currentField.name"
|
||||
:for="currentField.uuid"
|
||||
class="label text-2xl mb-2"
|
||||
>{{ currentField.name }}</label>
|
||||
<div class="space-y-3.5">
|
||||
<div
|
||||
v-for="(option, index) in currentField.options"
|
||||
:key="index"
|
||||
>
|
||||
<label
|
||||
:for="currentField.uuid + option"
|
||||
class="flex items-center space-x-3"
|
||||
<div class="flex w-full">
|
||||
<div class="space-y-3.5 mx-auto">
|
||||
<div
|
||||
v-for="(option, index) in currentField.options"
|
||||
:key="index"
|
||||
>
|
||||
<input
|
||||
:id="currentField.uuid + option"
|
||||
v-model="values[currentField.uuid]"
|
||||
type="radio"
|
||||
class="base-radio !h-7 !w-7"
|
||||
:name="`values[${currentField.uuid}]`"
|
||||
:value="option"
|
||||
required
|
||||
<label
|
||||
:for="currentField.uuid + option"
|
||||
class="flex items-center space-x-3"
|
||||
>
|
||||
<span class="text-xl">
|
||||
{{ option }}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
:id="currentField.uuid + option"
|
||||
v-model="values[currentField.uuid]"
|
||||
type="radio"
|
||||
class="base-radio !h-7 !w-7"
|
||||
:name="`values[${currentField.uuid}]`"
|
||||
:value="option"
|
||||
required
|
||||
>
|
||||
<span class="text-xl">
|
||||
{{ option }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<CheckboxStep
|
||||
v-else-if="currentField.type === 'checkbox' && currentField.options?.length"
|
||||
<MultiSelectStep
|
||||
v-else-if="currentField.type === 'multiple'"
|
||||
v-model="values[currentField.uuid]"
|
||||
:field="currentField"
|
||||
/>
|
||||
<div v-else-if="['radio', 'checkbox'].includes(currentField.type)">
|
||||
<div class="flex justify-center">
|
||||
<label
|
||||
:for="currentField.uuid"
|
||||
class="flex items-center space-x-3"
|
||||
<div
|
||||
v-else-if="currentField.type === 'checkbox'"
|
||||
class="flex w-full"
|
||||
>
|
||||
<div
|
||||
class="space-y-3.5 mx-auto"
|
||||
>
|
||||
<div
|
||||
v-for="(field, index) in currentStepFields"
|
||||
:key="field.uuid"
|
||||
>
|
||||
<input
|
||||
:id="currentField.uuid"
|
||||
:model-value="values[currentField.uuid]"
|
||||
:type="currentField.type"
|
||||
:name="`values[${currentField.uuid}]`"
|
||||
:value="true"
|
||||
class="!h-7 !w-7"
|
||||
:class="{'base-radio' : currentField.type === 'radio', 'base-checkbox': currentField.type === 'checkbox'}"
|
||||
:checked="!!values[currentField.uuid]"
|
||||
@click="values[currentField.uuid] = !values[currentField.uuid]"
|
||||
<label
|
||||
:for="field.uuid"
|
||||
class="flex items-center space-x-3"
|
||||
>
|
||||
<span class="text-xl">
|
||||
{{ currentField.name || currentField.type }}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
:id="field.uuid"
|
||||
type="checkbox"
|
||||
:name="`values[${field.uuid}]`"
|
||||
:value="false"
|
||||
class="base-checkbox !h-7 !w-7"
|
||||
:checked="!!values[field.uuid]"
|
||||
@click="values[field.uuid] = !values[field.uuid]"
|
||||
>
|
||||
<span class="text-xl">
|
||||
{{ currentField.name || currentField.type + ' ' + (index + 1) }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ImageStep
|
||||
@@ -199,12 +210,12 @@
|
||||
<div class="flex justify-center">
|
||||
<div class="flex items-center mt-5 mb-1">
|
||||
<a
|
||||
v-for="(field, index) in submitterFields"
|
||||
:key="field.uuid"
|
||||
v-for="(step, index) in stepFields"
|
||||
:key="step[0].uuid"
|
||||
href="#"
|
||||
class="inline border border-base-300 h-3 w-3 rounded-full mx-1"
|
||||
:class="{ 'bg-base-200': index === currentStep, 'bg-base-content': index < currentStep, 'bg-white': index > currentStep }"
|
||||
@click.prevent="goToField(field, true)"
|
||||
@click.prevent="goToStep(step, true)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -220,7 +231,7 @@ import FieldAreas from './areas'
|
||||
import ImageStep from './image_step'
|
||||
import SignatureStep from './signature_step'
|
||||
import AttachmentStep from './attachment_step'
|
||||
import CheckboxStep from './checkbox_step'
|
||||
import MultiSelectStep from './multi_select_step'
|
||||
import FormCompleted from './completed'
|
||||
|
||||
export default {
|
||||
@@ -230,7 +241,7 @@ export default {
|
||||
ImageStep,
|
||||
SignatureStep,
|
||||
AttachmentStep,
|
||||
CheckboxStep,
|
||||
MultiSelectStep,
|
||||
FormCompleted
|
||||
},
|
||||
props: {
|
||||
@@ -270,12 +281,28 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentStepFields () {
|
||||
return this.stepFields[this.currentStep]
|
||||
},
|
||||
currentField () {
|
||||
return this.submitterFields[this.currentStep]
|
||||
return this.currentStepFields[0]
|
||||
},
|
||||
submitterFields () {
|
||||
return this.fields.filter((f) => f.submitter_uuid === this.submitterUuid)
|
||||
},
|
||||
stepFields () {
|
||||
return this.submitterFields.reduce((acc, f) => {
|
||||
const prevStep = acc[acc.length - 1]
|
||||
|
||||
if (f.type === 'checkbox' && Array.isArray(prevStep) && prevStep[0].type === 'checkbox') {
|
||||
prevStep.push(f)
|
||||
} else {
|
||||
acc.push([f])
|
||||
}
|
||||
|
||||
return acc
|
||||
}, [])
|
||||
},
|
||||
attachmentsIndex () {
|
||||
return this.attachments.reduce((acc, a) => {
|
||||
acc[a.uuid] = a
|
||||
@@ -289,17 +316,17 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.currentStep = Math.min(
|
||||
this.submitterFields.indexOf([...this.submitterFields].reverse().find((field) => !!this.values[field.uuid])) + 1,
|
||||
this.submitterFields.length - 1
|
||||
this.stepFields.indexOf([...this.stepFields].reverse().find((fields) => fields.some((f) => !!this.values[f.uuid]))) + 1,
|
||||
this.stepFields.length - 1
|
||||
)
|
||||
},
|
||||
methods: {
|
||||
goToField (field, scrollToArea = false, clickUpload = false) {
|
||||
this.currentStep = this.submitterFields.indexOf(field)
|
||||
goToStep (step, scrollToArea = false, clickUpload = false) {
|
||||
this.currentStep = this.stepFields.indexOf(step)
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (scrollToArea) {
|
||||
this.$refs.areas.scrollIntoField(field)
|
||||
this.$refs.areas.scrollIntoField(step[0])
|
||||
}
|
||||
|
||||
this.$refs.form.querySelector('input[type="date"], input[type="text"], select')?.focus()
|
||||
@@ -322,10 +349,10 @@ export default {
|
||||
method: 'POST',
|
||||
body: new FormData(this.$refs.form)
|
||||
}).then(response => {
|
||||
const nextField = this.submitterFields[this.currentStep + 1]
|
||||
const nextStep = this.stepFields[this.currentStep + 1]
|
||||
|
||||
if (nextField) {
|
||||
this.goToField(this.submitterFields[this.currentStep + 1], true)
|
||||
if (nextStep) {
|
||||
this.goToStep(this.stepFields[this.currentStep + 1], true)
|
||||
} else {
|
||||
this.isCompleted = true
|
||||
}
|
||||
|
||||
+24
-22
@@ -4,36 +4,38 @@
|
||||
:for="field.uuid"
|
||||
class="label text-2xl mb-2"
|
||||
>{{ field.name }}</label>
|
||||
<div class="space-y-3.5">
|
||||
<div
|
||||
v-for="(option, index) in field.options"
|
||||
:key="index"
|
||||
>
|
||||
<label
|
||||
:for="field.uuid + option"
|
||||
class="flex items-center space-x-3"
|
||||
<div class="flex w-full">
|
||||
<div class="space-y-3.5 mx-auto">
|
||||
<div
|
||||
v-for="(option, index) in field.options"
|
||||
:key="index"
|
||||
>
|
||||
<input
|
||||
:id="field.uuid + option"
|
||||
:ref="setInputRef"
|
||||
type="checkbox"
|
||||
:name="`values[${field.uuid}][]`"
|
||||
:value="option"
|
||||
class="base-checkbox !h-7 !w-7"
|
||||
:checked="modelValue.includes(option)"
|
||||
@change="onChange"
|
||||
<label
|
||||
:for="field.uuid + option"
|
||||
class="flex items-center space-x-3"
|
||||
>
|
||||
<span class="text-xl">
|
||||
{{ option }}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
:id="field.uuid + option"
|
||||
:ref="setInputRef"
|
||||
type="checkbox"
|
||||
:name="`values[${field.uuid}][]`"
|
||||
:value="option"
|
||||
class="base-checkbox !h-7 !w-7"
|
||||
:checked="modelValue.includes(option)"
|
||||
@change="onChange"
|
||||
>
|
||||
<span class="text-xl">
|
||||
{{ option }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SheckboxStep',
|
||||
name: 'MultiSelectStep',
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
@@ -35,7 +35,7 @@
|
||||
@click="selectedAreaRef.value = area"
|
||||
/>
|
||||
<span
|
||||
v-if="withName"
|
||||
v-if="field.type !== 'checkbox' || field.name"
|
||||
ref="name"
|
||||
contenteditable
|
||||
class="pr-1 cursor-text outline-none block"
|
||||
@@ -138,9 +138,6 @@ export default {
|
||||
'bg-purple-100'
|
||||
]
|
||||
},
|
||||
withName () {
|
||||
return !['checkbox', 'radio'].includes(this.field.type) || this.field.options
|
||||
},
|
||||
isSelected () {
|
||||
return this.selectedAreaRef.value === this.area
|
||||
},
|
||||
@@ -169,11 +166,11 @@ export default {
|
||||
}
|
||||
},
|
||||
maybeUpdateOptions () {
|
||||
if (!['radio', 'checkbox', 'select'].includes(this.field.type)) {
|
||||
if (!['radio', 'multiple', 'select'].includes(this.field.type)) {
|
||||
delete this.field.options
|
||||
}
|
||||
|
||||
if (this.field.type === 'select') {
|
||||
if (['select', 'multiple', 'radio'].includes(this.field.type)) {
|
||||
this.field.options ||= ['']
|
||||
}
|
||||
},
|
||||
|
||||
@@ -291,7 +291,7 @@ export default {
|
||||
required: true
|
||||
}
|
||||
|
||||
if (this.dragFieldType === 'select') {
|
||||
if (['select', 'multiple', 'radio'].includes(this.dragFieldType)) {
|
||||
field.options = ['']
|
||||
}
|
||||
|
||||
@@ -311,7 +311,7 @@ export default {
|
||||
} else if (previousField?.areas) {
|
||||
baseArea = previousField.areas[previousField.areas.length - 1]
|
||||
} else {
|
||||
if (['checkbox', 'radio'].includes(this.dragFieldType)) {
|
||||
if (['checkbox'].includes(this.dragFieldType)) {
|
||||
baseArea = {
|
||||
w: area.maskW / 30 / area.maskW,
|
||||
h: area.maskW / 30 / area.maskW * (area.maskW / area.maskH)
|
||||
|
||||
@@ -182,7 +182,9 @@ export default {
|
||||
defaultName () {
|
||||
const typeIndex = this.template.fields.filter((f) => f.type === this.field.type).indexOf(this.field)
|
||||
|
||||
return `${this.$t(this.field.type)} Field ${typeIndex + 1}`
|
||||
const suffix = { multiple: 'Select', radio: 'Group' }[this.field.type] || 'Field'
|
||||
|
||||
return `${this.$t(this.field.type)} ${suffix} ${typeIndex + 1}`
|
||||
},
|
||||
areas () {
|
||||
return this.field.areas || []
|
||||
@@ -203,11 +205,11 @@ export default {
|
||||
document.activeElement.blur()
|
||||
},
|
||||
maybeUpdateOptions () {
|
||||
if (!['radio', 'checkbox', 'select'].includes(this.field.type)) {
|
||||
if (!['radio', 'multiple', 'select'].includes(this.field.type)) {
|
||||
delete this.field.options
|
||||
}
|
||||
|
||||
if (this.field.type === 'select') {
|
||||
if (['radio', 'multiple', 'select'].includes(this.field.type)) {
|
||||
this.field.options ||= ['']
|
||||
}
|
||||
},
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { IconTextSize, IconWriting, IconCalendarEvent, IconPhoto, IconCheckbox, IconPaperclip, IconSelect, IconCircleDot } from '@tabler/icons-vue'
|
||||
import { IconTextSize, IconWriting, IconCalendarEvent, IconPhoto, IconCheckbox, IconPaperclip, IconSelect, IconCircleDot, IconChecks } from '@tabler/icons-vue'
|
||||
|
||||
export default {
|
||||
name: 'FiledTypeDropdown',
|
||||
@@ -77,6 +77,7 @@ export default {
|
||||
file: IconPaperclip,
|
||||
select: IconSelect,
|
||||
checkbox: IconCheckbox,
|
||||
multiple: IconChecks,
|
||||
radio: IconCircleDot
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<FieldSubmitter
|
||||
:model-value="selectedSubmitter.uuid"
|
||||
class="w-full"
|
||||
:submitters="submitters"
|
||||
@remove="removeSubmitter"
|
||||
@update:model-value="$emit('change-submitter', submitters.find((s) => s.uuid === $event))"
|
||||
/>
|
||||
<div class="sticky -top-1 bg-base-100 pt-1 -mt-1 z-10">
|
||||
<FieldSubmitter
|
||||
:model-value="selectedSubmitter.uuid"
|
||||
class="w-full bg-base-100"
|
||||
:submitters="submitters"
|
||||
@remove="removeSubmitter"
|
||||
@update:model-value="$emit('change-submitter', submitters.find((s) => s.uuid === $event))"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-1 mt-2">
|
||||
<Field
|
||||
v-for="field in submitterFields"
|
||||
@@ -19,7 +21,7 @@
|
||||
@set-draw="$emit('set-draw', $event)"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-1">
|
||||
<div class="grid grid-cols-3 gap-1 pb-2">
|
||||
<button
|
||||
v-for="(icon, type) in fieldIcons"
|
||||
:key="type"
|
||||
@@ -145,7 +147,7 @@ export default {
|
||||
type
|
||||
}
|
||||
|
||||
if (['select', 'checkbox', 'radio'].includes(type)) {
|
||||
if (['select', 'multiple', 'radio'].includes(type)) {
|
||||
field.options = ['']
|
||||
}
|
||||
|
||||
|
||||
@@ -6,5 +6,6 @@ export default {
|
||||
file: 'File',
|
||||
select: 'Select',
|
||||
checkbox: 'Checkbox',
|
||||
multiple: 'Multiple',
|
||||
radio: 'Radio'
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<% end %>
|
||||
<div class="text-center px-2">
|
||||
Powered by
|
||||
<a href="https://www.docuseal.co" class="underline">DocuSeal</a> - An open source documents software
|
||||
<a href="https://www.docuseal.co" class="underline">DocuSeal</a> - open source documents software
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed bottom-0 w-full h-0 z-20">
|
||||
|
||||
Reference in New Issue
Block a user