Files
docuseal/app/javascript/submission_form/completed.vue
T

289 lines
7.2 KiB
Vue
Raw Normal View History

2023-05-25 22:47:52 +03:00
<template>
2024-01-08 20:10:55 +02:00
<div
2024-10-06 19:02:00 +03:00
id="form_completed"
2024-01-08 20:10:55 +02:00
class="mx-auto max-w-md flex flex-col"
dir="auto"
>
2024-04-05 16:16:30 +03:00
<div class="font-medium text-2xl flex items-center space-x-1.5 mx-auto">
2023-06-16 23:39:55 +03:00
<IconCircleCheck
class="inline text-green-600"
:width="30"
:height="30"
/>
2023-05-25 22:47:52 +03:00
<span>
2024-09-18 15:46:39 +03:00
{{ completedMessage.title || (hasSignatureFields ? (hasMultipleDocuments ? t('documents_have_been_signed') : t('document_has_been_signed')) : t('form_has_been_completed')) }}
2023-05-25 22:47:52 +03:00
</span>
2024-04-05 16:16:30 +03:00
</div>
<div
v-if="completedMessage.body"
class="mt-2"
>
<MarkdownContent
:string="completedMessage.body"
/>
</div>
2023-06-16 23:39:55 +03:00
<div class="space-y-3 mt-5">
2023-10-07 09:06:09 +03:00
<a
v-if="completedButton.url"
2024-03-13 11:09:18 +02:00
:href="sanitizeHref(completedButton.url)"
rel="noopener noreferrer nofollow"
2023-10-07 09:06:09 +03:00
class="white-button flex items-center w-full"
>
<span>
{{ completedButton.title || 'Back to Website' }}
</span>
</a>
2023-06-16 23:39:55 +03:00
<button
2023-12-17 16:10:17 +02:00
v-if="canSendEmail && !isDemo && withSendCopyButton"
2023-08-30 02:00:55 +03:00
class="white-button !h-auto flex items-center space-x-1 w-full"
2023-06-16 23:39:55 +03:00
:disabled="isSendingCopy"
@click.prevent="sendCopyToEmail"
>
<IconInnerShadowTop
v-if="isSendingCopy"
class="animate-spin"
/>
<IconMail v-else />
<span>
2023-08-30 02:00:55 +03:00
{{ t('send_copy_via_email') }}
2023-06-16 23:39:55 +03:00
</span>
</button>
<button
2023-12-17 16:10:17 +02:00
v-if="!isWebView && withDownloadButton"
2023-06-16 23:39:55 +03:00
class="base-button flex items-center space-x-1 w-full"
:disabled="isDownloading"
@click.prevent="download"
>
<IconInnerShadowTop
v-if="isDownloading"
class="animate-spin"
/>
<IconDownload v-else />
<span>
2023-08-30 02:00:55 +03:00
{{ t('download') }}
2023-06-16 23:39:55 +03:00
</span>
</button>
2023-07-12 01:24:25 +03:00
<a
v-if="isDemo"
target="_blank"
href="https://github.com/docusealco/docuseal"
class="white-button flex items-center space-x-1 w-full"
>
<IconBrandGithub />
<span>
Star on Github
</span>
</a>
2023-07-22 01:30:42 +03:00
<a
v-if="isDemo"
2024-10-26 09:54:41 +03:00
href="https://docuseal.com/sign_up"
2023-07-22 01:30:42 +03:00
class="white-button flex items-center space-x-1 w-full"
>
<IconLogin />
<span>
2023-08-30 02:00:55 +03:00
{{ t('create_a_free_account') }}
2023-07-22 01:30:42 +03:00
</span>
</a>
2023-06-16 23:39:55 +03:00
</div>
2023-09-03 20:44:54 +03:00
<div
v-if="attribution"
class="text-center mt-4"
>
2024-09-18 15:46:39 +03:00
{{ t('powered_by') }}
2023-07-08 16:36:12 +03:00
<a
2024-10-31 14:25:37 +02:00
href="https://www.docuseal.com/start"
2023-07-08 16:36:12 +03:00
target="_blank"
class="underline"
2023-08-30 02:00:55 +03:00
>DocuSeal</a> - {{ t('open_source_documents_software') }}
2023-07-08 16:36:12 +03:00
</div>
2023-05-25 22:47:52 +03:00
</div>
</template>
<script>
2023-07-22 01:30:42 +03:00
import { IconCircleCheck, IconBrandGithub, IconMail, IconDownload, IconInnerShadowTop, IconLogin } from '@tabler/icons-vue'
2024-04-05 16:16:30 +03:00
import MarkdownContent from './markdown_content'
2023-06-16 23:39:55 +03:00
2023-05-25 22:47:52 +03:00
export default {
name: 'FormCompleted',
2023-06-16 23:39:55 +03:00
components: {
2024-04-05 16:16:30 +03:00
MarkdownContent,
2023-06-16 23:39:55 +03:00
IconCircleCheck,
IconInnerShadowTop,
2023-07-12 01:24:25 +03:00
IconBrandGithub,
2023-06-16 23:39:55 +03:00
IconMail,
2023-07-22 01:30:42 +03:00
IconLogin,
2023-06-16 23:39:55 +03:00
IconDownload
},
2023-08-30 02:00:55 +03:00
inject: ['baseUrl', 't'],
2023-05-25 22:47:52 +03:00
props: {
2023-06-13 00:29:07 +03:00
submitterSlug: {
2023-05-25 22:47:52 +03:00
type: String,
required: true
2023-06-30 20:31:17 +03:00
},
2023-07-12 01:24:25 +03:00
isDemo: {
type: Boolean,
required: false,
default: false
},
2023-09-03 20:44:54 +03:00
attribution: {
type: Boolean,
required: false,
default: true
},
2024-09-18 15:46:39 +03:00
hasSignatureFields: {
type: Boolean,
required: false,
default: false
},
hasMultipleDocuments: {
type: Boolean,
required: false,
default: false
},
2023-12-17 16:10:17 +02:00
withDownloadButton: {
type: Boolean,
required: false,
default: true
},
withSendCopyButton: {
type: Boolean,
required: false,
default: true
},
2023-08-12 12:34:02 +03:00
withConfetti: {
type: Boolean,
required: false,
default: false
},
2023-06-30 20:31:17 +03:00
canSendEmail: {
type: Boolean,
required: false,
default: false
2023-09-29 01:24:39 +03:00
},
completedButton: {
type: Object,
required: false,
default: () => ({})
2024-04-05 16:16:30 +03:00
},
completedMessage: {
type: Object,
required: false,
default: () => ({})
2023-05-25 22:47:52 +03:00
}
},
data () {
return {
isSendingCopy: false,
isDownloading: false
}
},
2023-09-24 00:58:13 +03:00
computed: {
isWebView () {
return /webview|wv|ip((?!.*Safari)|(?=.*like Safari))/i.test(window.navigator.userAgent)
}
},
2023-06-24 18:31:12 +03:00
async mounted () {
2023-08-12 12:34:02 +03:00
if (this.withConfetti) {
const { default: confetti } = await import('canvas-confetti')
2023-06-24 18:31:12 +03:00
2023-08-12 12:34:02 +03:00
confetti({
particleCount: 50,
startVelocity: 30,
spread: 140
})
}
2024-08-21 20:03:33 +03:00
if (window.decline_button) {
window.decline_button.setAttribute('disabled', 'true')
}
2023-06-16 23:39:55 +03:00
},
2023-05-25 22:47:52 +03:00
methods: {
sendCopyToEmail () {
this.isSendingCopy = true
2023-08-12 12:34:02 +03:00
fetch(this.baseUrl + `/send_submission_email.json?submitter_slug=${this.submitterSlug}`, {
2023-05-25 22:47:52 +03:00
method: 'POST'
2023-06-16 23:39:55 +03:00
}).then(() => {
2023-09-05 22:28:50 +03:00
alert(this.t('email_has_been_sent'))
2023-05-25 22:47:52 +03:00
}).finally(() => {
this.isSendingCopy = false
})
},
download () {
this.isDownloading = true
2024-05-30 00:35:35 +03:00
fetch(this.baseUrl + `/submitters/${this.submitterSlug}/download`).then(async (response) => {
if (response.ok) {
const urls = await response.json()
2025-01-11 14:02:04 +02:00
const isMobileSafariIos = 'ontouchstart' in window && navigator.maxTouchPoints > 0 && /AppleWebKit/i.test(navigator.userAgent)
2025-01-10 21:49:30 +02:00
const isSafariIos = isMobileSafariIos || /iPhone|iPad|iPod/i.test(navigator.userAgent)
2023-05-25 22:47:52 +03:00
2024-05-30 00:35:35 +03:00
if (isSafariIos && urls.length > 1) {
this.downloadSafariIos(urls)
} else {
this.downloadUrls(urls)
}
2024-01-01 18:40:16 +02:00
} else {
2024-09-23 15:22:07 +03:00
alert(this.t('failed_to_download_files'))
2024-01-01 18:40:16 +02:00
}
})
},
downloadUrls (urls) {
const fileRequests = urls.map((url) => {
return () => {
return fetch(url).then(async (resp) => {
const blobUrl = URL.createObjectURL(await resp.blob())
const link = document.createElement('a')
link.href = blobUrl
link.setAttribute('download', decodeURI(url.split('/').pop()))
link.click()
URL.revokeObjectURL(blobUrl)
})
}
})
2023-05-25 22:47:52 +03:00
2024-01-01 18:40:16 +02:00
fileRequests.reduce(
(prevPromise, request) => prevPromise.then(() => request()),
Promise.resolve()
2024-03-31 18:31:09 +03:00
).finally(() => {
this.isDownloading = false
})
2024-01-01 18:40:16 +02:00
},
2024-03-13 11:09:18 +02:00
sanitizeHref (href) {
if (href && href.trim().match(/^((?:https?:\/\/)|\/)/)) {
return href.replace(/javascript:/g, '')
}
},
2024-01-01 18:40:16 +02:00
downloadSafariIos (urls) {
const fileRequests = urls.map((url) => {
return fetch(url).then(async (resp) => {
const blob = await resp.blob()
const blobUrl = URL.createObjectURL(blob.slice(0, blob.size, 'application/octet-stream'))
const link = document.createElement('a')
link.href = blobUrl
link.setAttribute('download', decodeURI(url.split('/').pop()))
return link
2023-06-16 23:39:55 +03:00
})
2024-01-01 18:40:16 +02:00
})
2023-06-22 01:31:39 +03:00
2024-01-01 18:40:16 +02:00
Promise.all(fileRequests).then((links) => {
links.forEach((link, index) => {
setTimeout(() => {
link.click()
2023-06-22 01:31:39 +03:00
2024-01-01 18:40:16 +02:00
URL.revokeObjectURL(link.href)
}, index * 50)
})
}).finally(() => {
2023-05-25 22:47:52 +03:00
this.isDownloading = false
})
}
}
}
</script>