From 07f44ec048929cd09f45ae14e4d44e81e851bf79 Mon Sep 17 00:00:00 2001 From: Chirag <103994754+chiragnotionforms@users.noreply.github.com> Date: Thu, 22 Dec 2022 16:23:33 +0530 Subject: [PATCH] Signature block (img) (#39) * Signature block (img) * Singature input UI changes * Style the signature input Co-authored-by: Julien Nahum --- app/Http/Requests/AnswerFormRequest.php | 1 + app/Http/Resources/FormSubmissionResource.php | 2 +- app/Jobs/Form/StoreFormSubmissionJob.php | 20 +++++++ package-lock.json | 44 +++++++++++++++ package.json | 1 + .../js/components/forms/SignatureInput.vue | 53 +++++++++++++++++++ resources/js/components/forms/index.js | 1 + .../js/components/open/forms/OpenForm.vue | 3 ++ .../form-components/AddFormBlockModal.vue | 16 ++++++ .../js/components/open/tables/OpenTable.vue | 1 + 10 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 resources/js/components/forms/SignatureInput.vue diff --git a/app/Http/Requests/AnswerFormRequest.php b/app/Http/Requests/AnswerFormRequest.php index 999586f..e45f506 100644 --- a/app/Http/Requests/AnswerFormRequest.php +++ b/app/Http/Requests/AnswerFormRequest.php @@ -124,6 +124,7 @@ class AnswerFormRequest extends FormRequest switch ($property['type']) { case 'text': case 'phone_number': + case 'signature': return ['string']; case 'number': return ['numeric']; diff --git a/app/Http/Resources/FormSubmissionResource.php b/app/Http/Resources/FormSubmissionResource.php index ab3fbfe..9c59516 100644 --- a/app/Http/Resources/FormSubmissionResource.php +++ b/app/Http/Resources/FormSubmissionResource.php @@ -41,7 +41,7 @@ class FormSubmissionResource extends JsonResource $data = $this->data; $formFields = collect($this->form->properties)->concat(collect($this->form->removed_properties)); $fileFields = $formFields->filter(function ($field) { - return $field['type'] == 'files'; + return in_array($field['type'], ['files', 'signature']); }); foreach ($fileFields as $field) { if (isset($data[$field['id']]) && !empty($data[$field['id']])) { diff --git a/app/Jobs/Form/StoreFormSubmissionJob.php b/app/Jobs/Form/StoreFormSubmissionJob.php index 33a5c90..b335b5d 100644 --- a/app/Jobs/Form/StoreFormSubmissionJob.php +++ b/app/Jobs/Form/StoreFormSubmissionJob.php @@ -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; @@ -130,6 +135,21 @@ class StoreFormSubmissionJob implements ShouldQueue 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 * diff --git a/package-lock.json b/package-lock.json index 4497d61..628b89b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "vue-plugin-load-script": "^1.3.2", "vue-prism-editor": "^1.2.2", "vue-router": "^3.5.2", + "vue-signature-pad": "^2.0.5", "vue-tailwind": "^2.5.0", "vue2-editor": "^2.10.3", "vuedraggable": "^2.24.3", @@ -10616,6 +10617,11 @@ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", "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": { "version": "1.1.0", "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==", "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": { "version": "1.0.0", "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", "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": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", @@ -25446,6 +25470,11 @@ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", "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": { "version": "1.1.0", "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==", "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": { "version": "1.0.0", "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", "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": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", diff --git a/package.json b/package.json index d858269..23b3c82 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "vue-plugin-load-script": "^1.3.2", "vue-prism-editor": "^1.2.2", "vue-router": "^3.5.2", + "vue-signature-pad": "^2.0.5", "vue-tailwind": "^2.5.0", "vue2-editor": "^2.10.3", "vuedraggable": "^2.24.3", diff --git a/resources/js/components/forms/SignatureInput.vue b/resources/js/components/forms/SignatureInput.vue new file mode 100644 index 0000000..f272bdf --- /dev/null +++ b/resources/js/components/forms/SignatureInput.vue @@ -0,0 +1,53 @@ + + + diff --git a/resources/js/components/forms/index.js b/resources/js/components/forms/index.js index 352a3cf..2bcd4ef 100644 --- a/resources/js/components/forms/index.js +++ b/resources/js/components/forms/index.js @@ -38,6 +38,7 @@ import ToggleSwitchInput from './ToggleSwitchInput' }) // Lazy load some heavy component +Vue.component('SignatureInput', () => import('./SignatureInput')) Vue.component('RichTextAreaInput', () => import('./RichTextAreaInput')) Vue.component('DateInput', () => import('./DateInput')) Vue.component('SimpleDateInput', () => import('./SimpleDateInput')) diff --git a/resources/js/components/open/forms/OpenForm.vue b/resources/js/components/open/forms/OpenForm.vue index 5a27981..330aa57 100644 --- a/resources/js/components/open/forms/OpenForm.vue +++ b/resources/js/components/open/forms/OpenForm.vue @@ -348,6 +348,9 @@ export default { if (field.type === 'checkbox' && field.use_toggle_switch) { return 'ToggleSwitchInput' } + if (field.type === 'signature') { + return 'SignatureInput' + } if (field.type === 'date' && field.simple_date_input) { return 'SimpleDateInput' } diff --git a/resources/js/components/open/forms/components/form-components/AddFormBlockModal.vue b/resources/js/components/open/forms/components/form-components/AddFormBlockModal.vue index 9284700..b522183 100644 --- a/resources/js/components/open/forms/components/form-components/AddFormBlockModal.vue +++ b/resources/js/components/open/forms/components/form-components/AddFormBlockModal.vue @@ -143,6 +143,19 @@

File Input

+ +
+
+ + + +
+

Signature Input

+
+

Layout Blocks

@@ -250,6 +263,7 @@ export default { 'select': 'Select', 'multi_select': 'Multi Select', 'files': 'Files', + 'signature': 'Signature', 'nf-text': 'Text Block', 'nf-page-break': 'Page Break', 'nf-divider': 'Divider', @@ -307,6 +321,8 @@ export default { data.previous_btn_text = 'Previous' } else if (data.type === 'nf-code') { data.content = '
This is a code block.
' + } else if (data.type === 'signature') { + data.help = 'Draw your signature above' } return data }, diff --git a/resources/js/components/open/tables/OpenTable.vue b/resources/js/components/open/tables/OpenTable.vue index d4f3a7e..bfde54f 100644 --- a/resources/js/components/open/tables/OpenTable.vue +++ b/resources/js/components/open/tables/OpenTable.vue @@ -143,6 +143,7 @@ export default { url: OpenUrl, email: OpenText, phone_number: OpenText, + signature: OpenFile, } }, },