Manually upload signature (#521)

* Manually upload signature

* Signature upload UI changes

* fix signature on clear

---------

Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
Chirag Chhatrala 2024-08-16 20:19:23 +05:30 committed by GitHub
parent 1ac71ecf8b
commit 5049ba7fb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 116 additions and 2 deletions

View File

@ -216,6 +216,10 @@ class StoreFormSubmissionJob implements ShouldQueue
private function storeSignature(?string $value)
{
if ($value && preg_match('/^[\/\w\-. ]+$/', $value)) { // If it's filename
return $this->storeFile($value);
}
if ($value == null || !isset(explode(',', $value)[1])) {
return null;
}

View File

@ -4,7 +4,42 @@
<slot name="label" />
</template>
<div
v-if="loading || file"
:class="[
theme.SignatureInput.input,
theme.SignatureInput.spacing.horizontal,
theme.SignatureInput.spacing.vertical,
theme.SignatureInput.fontSize,
theme.SignatureInput.borderRadius,
{
'!ring-red-500 !ring-2 !border-transparent': hasError,
'!cursor-not-allowed !bg-gray-200': disabled,
},
]"
class="flex flex-wrap items-center justify-center gap-4"
>
<div
v-if="loading"
class="text-gray-600 dark:text-gray-400"
>
<Loader class="mx-auto h-6 w-6" />
<p class="mt-2 text-center text-sm text-gray-500">
Uploading your file...
</p>
</div>
<uploaded-file
v-else
:key="file.url"
:file="file"
:theme="theme"
:show-remove="false"
/>
</div>
<VueSignaturePad
v-else
ref="signaturePad"
:class="[
theme.SignatureInput.input,
@ -23,6 +58,26 @@
/>
<template #bottom_after_help>
<small
v-if="!file"
:class="theme.default.help"
class="flex-auto"
>
<input
ref="actual-input"
class="hidden"
:multiple="false"
type="file"
accept=".pdf,.png,.jpg,.jpeg"
@change="manualFileUpload"
>
<a
:class="theme.default.help"
href="#"
@click.prevent="openFileUpload"
>Upload file instead</a>
</small>
<small :class="theme.default.help">
<a
:class="theme.default.help"
@ -42,6 +97,7 @@
import { inputProps, useFormInput } from "./useFormInput.js"
import InputWrapper from "./components/InputWrapper.vue"
import { VueSignaturePad } from "vue-signature-pad"
import { storeFile } from "~/lib/file-uploads.js"
export default {
name: "SignatureInput",
@ -57,12 +113,31 @@ export default {
}
},
data: () => ({
file: null,
loading: false
}),
watch: {
file: {
handler(file) {
this.compVal = file?.url || null
}
}
},
methods: {
clear() {
this.$refs.signaturePad.clearSignature()
this.file = null
this.$refs.signaturePad?.clearSignature()
this.onEnd()
},
onEnd() {
if (!this.$refs.signaturePad) {
this.form[this.name] = null
return
}
if (this.disabled) {
this.$refs.signaturePad.clearSignature()
} else {
@ -71,6 +146,39 @@ export default {
this.form[this.name] = !isEmpty && data ? data : null
}
},
openFileUpload() {
if (this.disabled || !this.$refs['actual-input']) return
this.$refs['actual-input'].click()
},
manualFileUpload(e) {
const files = e.target.files
for (let i = 0; i < files.length; i++) {
this.uploadFileToServer(files.item(i))
}
},
uploadFileToServer(file) {
if (this.disabled) return
this.loading = true
storeFile(file)
.then((response) => {
this.file = {
file: file,
url: file.name.split('.').slice(0, -1).join('.') + '_' + response.uuid + '.' + response.extension,
src: this.getFileSrc(file)
}
this.loading = false
})
.catch((error) => {
this.loading = false
this.file = null
})
},
getFileSrc(file) {
if (file.type && file.type.split('/')[0] === 'image') {
return URL.createObjectURL(file)
}
return null
}
},
}
</script>

View File

@ -37,6 +37,7 @@
{{ file.file.name }}
</p>
<a
v-if="showRemove"
href="javascript:void(0);"
class="flex text-gray-400 rounded hover:bg-neutral-50 hover:text-red-500 dark:text-gray-600 p-1"
role="button"
@ -69,7 +70,8 @@ export default {
name: "UploadedFile",
props: {
file: { type:Object, default: null },
file: { type: Object, default: null },
showRemove: { type: Boolean, default: true },
theme: {
type: Object, default: () => {
const theme = inject("theme", null)