autosave builder changes

pull/105/head
Alex Turchyn 2 years ago
parent c9e255f589
commit a258ca6c79

@ -32,7 +32,8 @@ class SubmissionsController < ApplicationController
end end
end end
redirect_to template_submissions_path(@template), notice: "#{submissions.size} recepients added" redirect_to template_submissions_path(@template),
notice: "#{submissions.size} #{'recipient'.pluralize(submissions.size)} added"
end end
def destroy def destroy

@ -52,7 +52,7 @@ button[disabled] .enabled {
} }
.base-textarea { .base-textarea {
@apply textarea textarea-bordered bg-white; @apply textarea textarea-bordered bg-white rounded-3xl;
} }
.base-button { .base-button {

@ -24,6 +24,7 @@
:compact="true" :compact="true"
:menu-classes="'dropdown-content bg-white menu menu-xs p-2 shadow rounded-box w-52 rounded-t-none -left-[1px]'" :menu-classes="'dropdown-content bg-white menu menu-xs p-2 shadow rounded-box w-52 rounded-t-none -left-[1px]'"
:submitters="template.submitters" :submitters="template.submitters"
@update:model-value="save"
@click="selectedAreaRef.value = area" @click="selectedAreaRef.value = area"
/> />
<FieldType <FieldType
@ -31,7 +32,7 @@
:button-width="27" :button-width="27"
:button-classes="'px-1'" :button-classes="'px-1'"
:menu-classes="'bg-white rounded-t-none'" :menu-classes="'bg-white rounded-t-none'"
@update:model-value="maybeUpdateOptions" @update:model-value="[maybeUpdateOptions(), save()]"
@click="selectedAreaRef.value = area" @click="selectedAreaRef.value = area"
/> />
<span <span
@ -111,7 +112,7 @@ export default {
FieldSubmitter, FieldSubmitter,
IconX IconX
}, },
inject: ['template', 'selectedAreaRef'], inject: ['template', 'selectedAreaRef', 'save'],
props: { props: {
area: { area: {
type: Object, type: Object,
@ -127,6 +128,7 @@ export default {
data () { data () {
return { return {
isResize: false, isResize: false,
isDragged: false,
isNameFocus: false, isNameFocus: false,
dragFrom: { x: 0, y: 0 } dragFrom: { x: 0, y: 0 }
} }
@ -204,6 +206,8 @@ export default {
this.field.name = '' this.field.name = ''
this.$refs.name.innerText = this.defaultName this.$refs.name.innerText = this.defaultName
} }
this.save()
}, },
onNameEnter (e) { onNameEnter (e) {
this.$refs.name.blur() this.$refs.name.blur()
@ -216,6 +220,8 @@ export default {
}, },
drag (e) { drag (e) {
if (e.toElement.id === 'mask') { if (e.toElement.id === 'mask') {
this.isDragged = true
this.area.x = (e.layerX - this.dragFrom.x) / e.toElement.clientWidth this.area.x = (e.layerX - this.dragFrom.x) / e.toElement.clientWidth
this.area.y = (e.layerY - this.dragFrom.y) / e.toElement.clientHeight this.area.y = (e.layerY - this.dragFrom.y) / e.toElement.clientHeight
} }
@ -236,6 +242,12 @@ export default {
document.removeEventListener('mousemove', this.drag) document.removeEventListener('mousemove', this.drag)
document.removeEventListener('mouseup', this.stopDrag) document.removeEventListener('mouseup', this.stopDrag)
if (this.isDragged) {
this.save()
}
this.isDragged = false
this.$emit('stop-drag') this.$emit('stop-drag')
}, },
startResize () { startResize () {
@ -251,6 +263,8 @@ export default {
document.removeEventListener('mouseup', this.stopResize) document.removeEventListener('mouseup', this.stopResize)
this.$emit('stop-resize') this.$emit('stop-resize')
this.save()
} }
} }
} }

@ -17,24 +17,32 @@
</div> </div>
<div class="space-x-3 flex items-center"> <div class="space-x-3 flex items-center">
<a <a
:href="`/templates/${template.id}/submissions`" :href="`/templates/${template.id}/submissions/new`"
data-turbo-frame="modal"
class="btn btn-primary" class="btn btn-primary"
> >
<IconUsersPlus <IconUsersPlus
width="20" width="20"
class="mr-2 inline" class="inline"
/> />
Recipients Recipients
</a> </a>
<a <button
:href="`/`"
class="base-button" class="base-button"
:class="{ disabled: isSaving }"
v-bind="isSaving ? { disabled: true } : {}" v-bind="isSaving ? { disabled: true } : {}"
@click.prevent="onSaveClick" @click.prevent="onSaveClick"
><IconDeviceFloppy >
<IconInnerShadowTop
v-if="isSaving"
width="20" width="20"
class="mr-2" class="animate-spin"
/>Save</a> />
<IconDeviceFloppy
v-else
width="20"
/>Save
</button>
</div> </div>
</div> </div>
<div <div
@ -131,7 +139,7 @@ import Document from './document'
import Logo from './logo' import Logo from './logo'
import Contenteditable from './contenteditable' import Contenteditable from './contenteditable'
import DocumentPreview from './preview' import DocumentPreview from './preview'
import { IconUsersPlus, IconDeviceFloppy } from '@tabler/icons-vue' import { IconUsersPlus, IconDeviceFloppy, IconInnerShadowTop } from '@tabler/icons-vue'
import { v4 } from 'uuid' import { v4 } from 'uuid'
import i18n from './i18n' import i18n from './i18n'
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
@ -145,6 +153,7 @@ export default {
Fields, Fields,
Logo, Logo,
DocumentPreview, DocumentPreview,
IconInnerShadowTop,
Contenteditable, Contenteditable,
IconUsersPlus, IconUsersPlus,
IconDeviceFloppy IconDeviceFloppy
@ -152,6 +161,7 @@ export default {
provide () { provide () {
return { return {
template: this.template, template: this.template,
save: this.save,
selectedAreaRef: computed(() => this.selectedAreaRef) selectedAreaRef: computed(() => this.selectedAreaRef)
} }
}, },
@ -239,6 +249,8 @@ export default {
if (!field.areas.length) { if (!field.areas.length) {
this.template.fields.splice(this.template.fields.indexOf(field), 1) this.template.fields.splice(this.template.fields.indexOf(field), 1)
} }
this.save()
}, },
onDraw (area) { onDraw (area) {
if (this.drawField) { if (this.drawField) {
@ -281,6 +293,8 @@ export default {
} }
this.selectedAreaRef.value = area this.selectedAreaRef.value = area
this.save()
}, },
onDropfield (area) { onDropfield (area) {
const field = { const field = {
@ -343,6 +357,8 @@ export default {
this.selectedAreaRef.value = fieldArea this.selectedAreaRef.value = fieldArea
this.template.fields.push(field) this.template.fields.push(field)
this.save()
}, },
updateFromUpload ({ schema, documents }) { updateFromUpload ({ schema, documents }) {
this.template.schema.push(...schema) this.template.schema.push(...schema)
@ -387,7 +403,7 @@ export default {
this.isSaving = true this.isSaving = true
this.save().then(() => { this.save().then(() => {
// window.Turbo.visit('/') window.Turbo.visit(`/templates/${this.template.id}/submissions`)
}).finally(() => { }).finally(() => {
this.isSaving = false this.isSaving = false
}) })
@ -404,7 +420,14 @@ export default {
return fetch(`/api/templates/${this.template.id}`, { return fetch(`/api/templates/${this.template.id}`, {
method: 'PUT', method: 'PUT',
body: JSON.stringify({ template: this.template }), body: JSON.stringify({
template: {
name: this.template.name,
schema: this.template.schema,
submitters: this.template.submitters,
fields: this.template.fields
}
}),
headers: { 'Content-Type': 'application/json' } headers: { 'Content-Type': 'application/json' }
}).then((resp) => { }).then((resp) => {
console.log(resp) console.log(resp)

@ -14,7 +14,7 @@
<FieldType <FieldType
v-model="field.type" v-model="field.type"
:button-width="20" :button-width="20"
@update:model-value="maybeUpdateOptions" @update:model-value="[maybeUpdateOptions(), save()]"
@click="scrollToFirstArea" @click="scrollToFirstArea"
/> />
<Contenteditable <Contenteditable
@ -157,10 +157,11 @@
class="w-full input input-primary input-xs text-sm" class="w-full input input-primary input-xs text-sm"
type="text" type="text"
required required
@blur="save"
> >
<button <button
class="text-sm w-3.5" class="text-sm w-3.5"
@click="field.options.splice(index, 1)" @click="[field.options.splice(index, 1), save()]"
> >
&times; &times;
</button> </button>
@ -168,7 +169,7 @@
<button <button
v-if="field.options" v-if="field.options"
class="text-center text-sm w-full pb-1" class="text-center text-sm w-full pb-1"
@click="field.options.push('')" @click="[field.options.push(''), save()]"
> >
+ Add option + Add option
</button> </button>
@ -191,7 +192,7 @@ export default {
IconTrashX, IconTrashX,
FieldType FieldType
}, },
inject: ['template'], inject: ['template', 'save'],
props: { props: {
field: { field: {
type: Object, type: Object,
@ -250,9 +251,13 @@ export default {
} }
this.isNameFocus = false this.isNameFocus = false
this.save()
}, },
removeArea (area) { removeArea (area) {
this.field.areas.splice(this.field.areas.indexOf(area), 1) this.field.areas.splice(this.field.areas.indexOf(area), 1)
this.save()
} }
} }
} }

@ -26,6 +26,7 @@
class="cursor-text" class="cursor-text"
:icon-inline="true" :icon-inline="true"
:icon-width="18" :icon-width="18"
@update:model-value="$emit('name-change', selectedSubmitter)"
/> />
</div> </div>
<span> <span>
@ -116,7 +117,7 @@ export default {
default: 'dropdown-content menu p-2 shadow bg-base-100 rounded-box w-full z-10' default: 'dropdown-content menu p-2 shadow bg-base-100 rounded-box w-full z-10'
} }
}, },
emits: ['update:model-value', 'remove'], emits: ['update:model-value', 'remove', 'new-submitter', 'name-change'],
computed: { computed: {
colors () { colors () {
return [ return [
@ -158,6 +159,7 @@ export default {
this.submitters.push(newSubmitter) this.submitters.push(newSubmitter)
this.$emit('update:model-value', newSubmitter.uuid) this.$emit('update:model-value', newSubmitter.uuid)
this.$emit('new-submitter', newSubmitter)
}, },
closeDropdown () { closeDropdown () {
document.activeElement.blur() document.activeElement.blur()

@ -4,7 +4,9 @@
:model-value="selectedSubmitter.uuid" :model-value="selectedSubmitter.uuid"
class="w-full bg-base-100" class="w-full bg-base-100"
:submitters="submitters" :submitters="submitters"
@new-submitter="save"
@remove="removeSubmitter" @remove="removeSubmitter"
@name-change="save"
@update:model-value="$emit('change-submitter', submitters.find((s) => s.uuid === $event))" @update:model-value="$emit('change-submitter', submitters.find((s) => s.uuid === $event))"
/> />
</div> </div>
@ -79,6 +81,7 @@ export default {
Field, Field,
FieldSubmitter FieldSubmitter
}, },
inject: ['save'],
props: { props: {
fields: { fields: {
type: Array, type: Array,
@ -116,6 +119,8 @@ export default {
if (this.selectedSubmitter === submitter) { if (this.selectedSubmitter === submitter) {
this.$emit('change-submitter', this.submitters[0]) this.$emit('change-submitter', this.submitters[0])
} }
this.save()
}, },
move (field, direction) { move (field, direction) {
const currentIndex = this.submitterFields.indexOf(field) const currentIndex = this.submitterFields.indexOf(field)
@ -134,9 +139,13 @@ export default {
} else { } else {
this.fields.splice(fieldsIndex + direction, 0, field) this.fields.splice(fieldsIndex + direction, 0, field)
} }
this.save()
}, },
removeField (field) { removeField (field) {
this.fields.splice(this.fields.indexOf(field), 1) this.fields.splice(this.fields.indexOf(field), 1)
this.save()
}, },
addField (type, area = null) { addField (type, area = null) {
const field = { const field = {
@ -152,6 +161,8 @@ export default {
} }
this.fields.push(field) this.fields.push(field)
this.save()
} }
} }
} }

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class SubmitterMailer < ApplicationMailer class SubmitterMailer < ApplicationMailer
DEFAULT_MESSAGE = "You've been invited to submit documents." DEFAULT_MESSAGE = "You've been invited to submit the following documents:"
def invitation_email(submitter, message: DEFAULT_MESSAGE) def invitation_email(submitter, message: DEFAULT_MESSAGE)
@submitter = submitter @submitter = submitter

@ -32,12 +32,12 @@
<% if signature.signature_handler.signer_certificate.public_key.to_der == trusted_certs.first.public_key.to_der %> <% if signature.signature_handler.signer_certificate.public_key.to_der == trusted_certs.first.public_key.to_der %>
<%= svg_icon('circle_check', class: 'w-6 h-6 text-green-500') %> <%= svg_icon('circle_check', class: 'w-6 h-6 text-green-500') %>
<span> <span>
Signed with DocuSeal Certificate Signed with DocuSeal certificate
</span> </span>
<% else %> <% else %>
<%= svg_icon('x_circle', class: 'w-6 h-6 text-red-500') %> <%= svg_icon('x_circle', class: 'w-6 h-6 text-red-500') %>
<span> <span>
Signed with External Certificate Signed with external certificate
</span> </span>
<% end %> <% end %>
</p> </p>

@ -1,3 +1,4 @@
<!DOCTYPE html>
<html data-theme="docuseal"> <html data-theme="docuseal">
<head> <head>
<title> <title>
@ -12,5 +13,6 @@
<body> <body>
<% if flash.present? %><%= render 'shared/flash' %><% end %> <% if flash.present? %><%= render 'shared/flash' %><% end %>
<%= yield %> <%= yield %>
<turbo-frame id="modal"></turbo-frame>
</body> </body>
</html> </html>

@ -32,10 +32,10 @@
</div> </div>
</div> </div>
<div class="flex justify-between mb-4"> <div class="flex justify-between mb-4">
<h1 class="text-3xl font-bold">Recepients</h1> <h1 class="text-3xl font-bold">Recipients</h1>
<%= link_to new_template_submission_path(@template), class: 'btn btn-primary btn-sm gap-2', data: { turbo_frame: 'modal' } do %> <%= link_to new_template_submission_path(@template), class: 'btn btn-primary btn-sm gap-2', data: { turbo_frame: 'modal' } do %>
<%= svg_icon('plus', class: 'w-6 h-6') %> <%= svg_icon('plus', class: 'w-6 h-6') %>
<span class="hidden md:block">Add Recepients</span> <span class="hidden md:block">Add Recipients</span>
<% end %> <% end %>
</div> </div>
<div class="overflow-x-auto"> <div class="overflow-x-auto">

@ -1,4 +1,4 @@
<%= render 'shared/turbo_modal', title: 'New Recepients' do %> <%= render 'shared/turbo_modal', title: 'New Recipients' do %>
<%= form_for '', url: template_submissions_path(@template), html: { class: 'space-y-4' }, data: { turbo_frame: :_top } do |f| %> <%= form_for '', url: template_submissions_path(@template), html: { class: 'space-y-4' }, data: { turbo_frame: :_top } do |f| %>
<% if @template.submitters.size == 1 %> <% if @template.submitters.size == 1 %>
<div class="form-control"> <div class="form-control">
@ -11,14 +11,14 @@
<div class="card card-compact bg-base-200" data-targets="dynamic-list.items"> <div class="card card-compact bg-base-200" data-targets="dynamic-list.items">
<div class="card-body"> <div class="card-body">
<div class="absolute right-4 top-5"> <div class="absolute right-4 top-5">
<a href="#" data-action="click:dynamic-list#removeItem" class="block w-6 h-6 rounded-lg text-neutral-700 text-center bg-base-300 p-1 hidden hover:bg-neutral hover:text-white"> <a href="#" data-action="click:dynamic-list#removeItem" class="-top-3 relative block w-6 h-6 rounded-lg text-neutral-700 text-center bg-base-300 p-1 hidden hover:bg-neutral hover:text-white">
<%= svg_icon('trash', class: 'w-4 h-4') %> <%= svg_icon('trash', class: 'w-4 h-4') %>
</a> </a>
</div> </div>
<div class="grid md:grid-cols-2 gap-4"> <div class="grid md:grid-cols-2 gap-4">
<% @template.submitters.each do |item| %> <% @template.submitters.each do |item| %>
<div class="form-control"> <div class="form-control">
<label class="label"> <label class="label pt-0 pb-1 text-xs">
<span class="label-text"> <%= item['name'] %></span> <span class="label-text"> <%= item['name'] %></span>
</label> </label>
<input type="hidden" name="submission[1][submitters][][uuid]" value="<%= item['uuid'] %>" > <input type="hidden" name="submission[1][submitters][][uuid]" value="<%= item['uuid'] %>" >
@ -54,7 +54,7 @@
</div> </div>
</div> </div>
<div class="form-control"> <div class="form-control">
<%= f.button button_title(title: 'Confirm', disabled_with: 'Processing'), class: 'base-button' %> <%= f.button button_title(title: 'Add Recipients'), class: 'base-button' %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>

Loading…
Cancel
Save