Signature block (img) (#39)
* Signature block (img) * Singature input UI changes * Style the signature input Co-authored-by: Julien Nahum <jhumanj@MacBook-Pro-de-Julien.local>
This commit is contained in:
parent
9936cb3389
commit
07f44ec048
|
@ -124,6 +124,7 @@ class AnswerFormRequest extends FormRequest
|
||||||
switch ($property['type']) {
|
switch ($property['type']) {
|
||||||
case 'text':
|
case 'text':
|
||||||
case 'phone_number':
|
case 'phone_number':
|
||||||
|
case 'signature':
|
||||||
return ['string'];
|
return ['string'];
|
||||||
case 'number':
|
case 'number':
|
||||||
return ['numeric'];
|
return ['numeric'];
|
||||||
|
|
|
@ -41,7 +41,7 @@ class FormSubmissionResource extends JsonResource
|
||||||
$data = $this->data;
|
$data = $this->data;
|
||||||
$formFields = collect($this->form->properties)->concat(collect($this->form->removed_properties));
|
$formFields = collect($this->form->properties)->concat(collect($this->form->removed_properties));
|
||||||
$fileFields = $formFields->filter(function ($field) {
|
$fileFields = $formFields->filter(function ($field) {
|
||||||
return $field['type'] == 'files';
|
return in_array($field['type'], ['files', 'signature']);
|
||||||
});
|
});
|
||||||
foreach ($fileFields as $field) {
|
foreach ($fileFields as $field) {
|
||||||
if (isset($data[$field['id']]) && !empty($data[$field['id']])) {
|
if (isset($data[$field['id']]) && !empty($data[$field['id']])) {
|
||||||
|
|
|
@ -89,6 +89,11 @@ class StoreFormSubmissionJob implements ShouldQueue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For Singrature
|
||||||
|
if($this->form->is_pro && $field['type'] == 'signature') {
|
||||||
|
$finalData[$field['id']] = $this->storeSignature($answerValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $finalData;
|
return $finalData;
|
||||||
|
@ -130,6 +135,21 @@ class StoreFormSubmissionJob implements ShouldQueue
|
||||||
return $fileNameParser->getMovedFileName();
|
return $fileNameParser->getMovedFileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function storeSignature(?string $value)
|
||||||
|
{
|
||||||
|
if ($value == null || !isset(explode(',', $value)[1])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileName = 'sign_'.(string) Str::uuid().'.png';
|
||||||
|
$newPath = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $this->form->id);
|
||||||
|
$completeNewFilename = $newPath.'/'.$fileName;
|
||||||
|
|
||||||
|
Storage::disk('s3')->put($completeNewFilename, base64_decode(explode(',', $value)[1]));
|
||||||
|
|
||||||
|
return $fileName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds prefill from hidden fields
|
* Adds prefill from hidden fields
|
||||||
*
|
*
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"vue-plugin-load-script": "^1.3.2",
|
"vue-plugin-load-script": "^1.3.2",
|
||||||
"vue-prism-editor": "^1.2.2",
|
"vue-prism-editor": "^1.2.2",
|
||||||
"vue-router": "^3.5.2",
|
"vue-router": "^3.5.2",
|
||||||
|
"vue-signature-pad": "^2.0.5",
|
||||||
"vue-tailwind": "^2.5.0",
|
"vue-tailwind": "^2.5.0",
|
||||||
"vue2-editor": "^2.10.3",
|
"vue2-editor": "^2.10.3",
|
||||||
"vuedraggable": "^2.24.3",
|
"vuedraggable": "^2.24.3",
|
||||||
|
@ -10616,6 +10617,11 @@
|
||||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
|
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/merge-images": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-images/-/merge-images-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-hEGvgnTdXr08uzGvEArxRsKpy7WmozM73YaSi4s5IYF4LxrhANpqfHaz9CgBZ5+0+s2NsjPnPdStz3aCc0Yulw=="
|
||||||
|
},
|
||||||
"node_modules/merge-source-map": {
|
"node_modules/merge-source-map": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
|
||||||
|
@ -14291,6 +14297,11 @@
|
||||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/signature_pad": {
|
||||||
|
"version": "3.0.0-beta.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/signature_pad/-/signature_pad-3.0.0-beta.4.tgz",
|
||||||
|
"integrity": "sha512-cOf2NhVuTiuNqe2X/ycEmizvCDXk0DoemhsEpnkcGnA4kS5iJYTCqZ9As7tFBbsch45Q1EdX61833+6sjJ8rrw=="
|
||||||
|
},
|
||||||
"node_modules/slash": {
|
"node_modules/slash": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
|
||||||
|
@ -16364,6 +16375,19 @@
|
||||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.6.5.tgz",
|
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.6.5.tgz",
|
||||||
"integrity": "sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ=="
|
"integrity": "sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-signature-pad": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-signature-pad/-/vue-signature-pad-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-FLvJRmhSP/DVkg0W/tGcPZ4D0ZQlFxHgN1mjph6jt/59yLeTSv0zGGU133lfq9CkYMQ5DqN6rWujjL7Gnx7UPA==",
|
||||||
|
"dependencies": {
|
||||||
|
"merge-images": "^1.1.0",
|
||||||
|
"signature_pad": "^3.0.0-beta.3",
|
||||||
|
"vue": "^2.6.14"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-style-loader": {
|
"node_modules/vue-style-loader": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
|
||||||
|
@ -25446,6 +25470,11 @@
|
||||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
|
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"merge-images": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-images/-/merge-images-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-hEGvgnTdXr08uzGvEArxRsKpy7WmozM73YaSi4s5IYF4LxrhANpqfHaz9CgBZ5+0+s2NsjPnPdStz3aCc0Yulw=="
|
||||||
|
},
|
||||||
"merge-source-map": {
|
"merge-source-map": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
|
||||||
|
@ -28183,6 +28212,11 @@
|
||||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"signature_pad": {
|
||||||
|
"version": "3.0.0-beta.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/signature_pad/-/signature_pad-3.0.0-beta.4.tgz",
|
||||||
|
"integrity": "sha512-cOf2NhVuTiuNqe2X/ycEmizvCDXk0DoemhsEpnkcGnA4kS5iJYTCqZ9As7tFBbsch45Q1EdX61833+6sjJ8rrw=="
|
||||||
|
},
|
||||||
"slash": {
|
"slash": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
|
||||||
|
@ -29801,6 +29835,16 @@
|
||||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.6.5.tgz",
|
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.6.5.tgz",
|
||||||
"integrity": "sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ=="
|
"integrity": "sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ=="
|
||||||
},
|
},
|
||||||
|
"vue-signature-pad": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-signature-pad/-/vue-signature-pad-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-FLvJRmhSP/DVkg0W/tGcPZ4D0ZQlFxHgN1mjph6jt/59yLeTSv0zGGU133lfq9CkYMQ5DqN6rWujjL7Gnx7UPA==",
|
||||||
|
"requires": {
|
||||||
|
"merge-images": "^1.1.0",
|
||||||
|
"signature_pad": "^3.0.0-beta.3",
|
||||||
|
"vue": "^2.6.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"vue-style-loader": {
|
"vue-style-loader": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
"vue-plugin-load-script": "^1.3.2",
|
"vue-plugin-load-script": "^1.3.2",
|
||||||
"vue-prism-editor": "^1.2.2",
|
"vue-prism-editor": "^1.2.2",
|
||||||
"vue-router": "^3.5.2",
|
"vue-router": "^3.5.2",
|
||||||
|
"vue-signature-pad": "^2.0.5",
|
||||||
"vue-tailwind": "^2.5.0",
|
"vue-tailwind": "^2.5.0",
|
||||||
"vue2-editor": "^2.10.3",
|
"vue2-editor": "^2.10.3",
|
||||||
"vuedraggable": "^2.24.3",
|
"vuedraggable": "^2.24.3",
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
<template>
|
||||||
|
<div :class="wrapperClass">
|
||||||
|
<label v-if="label" :for="id?id:name"
|
||||||
|
:class="[theme.CodeInput.label,{'uppercase text-xs':uppercaseLabels, 'text-sm':!uppercaseLabels}]"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
<span v-if="required" class="text-red-500 required-dot">*</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<VueSignaturePad ref="signaturePad"
|
||||||
|
:class="[theme.default.input,{ 'ring-red-500 ring-2': hasValidation && form.errors.has(name), 'cursor-not-allowed bg-gray-200':disabled }]" height="150px"
|
||||||
|
:name="name"
|
||||||
|
:options="{ onEnd }"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="flex">
|
||||||
|
<small v-if="help" :class="theme.default.help" class="flex-grow">
|
||||||
|
<slot name="help"><span class="field-help" v-html="help" /></slot>
|
||||||
|
</small>
|
||||||
|
<small v-else class="flex-grow" />
|
||||||
|
<small :class="theme.default.help">
|
||||||
|
<a :class="theme.default.help" href="#" @click.prevent="clear">Clear</a>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<has-error v-if="hasValidation" :form="form" :field="name" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Vue from 'vue'
|
||||||
|
import VueSignaturePad from 'vue-signature-pad'
|
||||||
|
import inputMixin from '~/mixins/forms/input'
|
||||||
|
|
||||||
|
Vue.use(VueSignaturePad)
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SignatureInput',
|
||||||
|
|
||||||
|
components: {},
|
||||||
|
mixins: [inputMixin],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
clear () {
|
||||||
|
this.$refs.signaturePad.clearSignature()
|
||||||
|
this.onEnd()
|
||||||
|
},
|
||||||
|
onEnd () {
|
||||||
|
const { isEmpty, data } = this.$refs.signaturePad.saveSignature()
|
||||||
|
this.$set(this.form, this.name, (!isEmpty && data) ? data : null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -38,6 +38,7 @@ import ToggleSwitchInput from './ToggleSwitchInput'
|
||||||
})
|
})
|
||||||
|
|
||||||
// Lazy load some heavy component
|
// Lazy load some heavy component
|
||||||
|
Vue.component('SignatureInput', () => import('./SignatureInput'))
|
||||||
Vue.component('RichTextAreaInput', () => import('./RichTextAreaInput'))
|
Vue.component('RichTextAreaInput', () => import('./RichTextAreaInput'))
|
||||||
Vue.component('DateInput', () => import('./DateInput'))
|
Vue.component('DateInput', () => import('./DateInput'))
|
||||||
Vue.component('SimpleDateInput', () => import('./SimpleDateInput'))
|
Vue.component('SimpleDateInput', () => import('./SimpleDateInput'))
|
||||||
|
|
|
@ -348,6 +348,9 @@ export default {
|
||||||
if (field.type === 'checkbox' && field.use_toggle_switch) {
|
if (field.type === 'checkbox' && field.use_toggle_switch) {
|
||||||
return 'ToggleSwitchInput'
|
return 'ToggleSwitchInput'
|
||||||
}
|
}
|
||||||
|
if (field.type === 'signature') {
|
||||||
|
return 'SignatureInput'
|
||||||
|
}
|
||||||
if (field.type === 'date' && field.simple_date_input) {
|
if (field.type === 'date' && field.simple_date_input) {
|
||||||
return 'SimpleDateInput'
|
return 'SimpleDateInput'
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,19 @@
|
||||||
<p class="w-full text-xs text-gray-500 uppercase text-center font-semibold mb-4">File Input</p>
|
<p class="w-full text-xs text-gray-500 uppercase text-center font-semibold mb-4">File Input</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Signature Block -->
|
||||||
|
<div
|
||||||
|
class="bg-gray-50 border hover:bg-gray-100 dark:bg-gray-900 rounded-md dark:hover:bg-gray-800 p-2 flex flex-col"
|
||||||
|
role="button" @click.prevent="addBlock('signature')"
|
||||||
|
>
|
||||||
|
<div class="mx-auto py-4">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<p class="w-full text-xs text-gray-500 uppercase text-center font-semibold mb-4">Signature Input</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-gray-500 uppercase text-xs font-semibold mb-2 mt-6">Layout Blocks</p>
|
<p class="text-gray-500 uppercase text-xs font-semibold mb-2 mt-6">Layout Blocks</p>
|
||||||
|
@ -250,6 +263,7 @@ export default {
|
||||||
'select': 'Select',
|
'select': 'Select',
|
||||||
'multi_select': 'Multi Select',
|
'multi_select': 'Multi Select',
|
||||||
'files': 'Files',
|
'files': 'Files',
|
||||||
|
'signature': 'Signature',
|
||||||
'nf-text': 'Text Block',
|
'nf-text': 'Text Block',
|
||||||
'nf-page-break': 'Page Break',
|
'nf-page-break': 'Page Break',
|
||||||
'nf-divider': 'Divider',
|
'nf-divider': 'Divider',
|
||||||
|
@ -307,6 +321,8 @@ export default {
|
||||||
data.previous_btn_text = 'Previous'
|
data.previous_btn_text = 'Previous'
|
||||||
} else if (data.type === 'nf-code') {
|
} else if (data.type === 'nf-code') {
|
||||||
data.content = '<div class="text-blue-500 italic">This is a code block.</div>'
|
data.content = '<div class="text-blue-500 italic">This is a code block.</div>'
|
||||||
|
} else if (data.type === 'signature') {
|
||||||
|
data.help = 'Draw your signature above'
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
|
|
|
@ -143,6 +143,7 @@ export default {
|
||||||
url: OpenUrl,
|
url: OpenUrl,
|
||||||
email: OpenText,
|
email: OpenText,
|
||||||
phone_number: OpenText,
|
phone_number: OpenText,
|
||||||
|
signature: OpenFile,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue