mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
259 lines
7.5 KiB
259 lines
7.5 KiB
<template>
|
|
<div id="form_completed" class="mx-auto max-w-md flex flex-col completed-form" dir="auto">
|
|
<div class="font-medium text-2xl flex items-center space-x-1.5 mx-auto">
|
|
<IconCircleCheck class="inline text-green-600" :width="30" :height="30" />
|
|
<span class="completed-form-message-title">
|
|
{{ completedMessage.title || (hasSignatureFields ? (hasMultipleDocuments ? t("documents_have_been_signed") : t("document_has_been_signed")) : t("form_has_been_completed")) }}
|
|
</span>
|
|
</div>
|
|
<div v-if="completedMessage.body" class="mt-2 completed-form-message-body">
|
|
<MarkdownContent :string="completedMessage.body" />
|
|
</div>
|
|
<div class="space-y-3 mt-5">
|
|
<a v-if="completedButton.url" :href="sanitizeUrl(completedButton.url)" rel="noopener noreferrer nofollow" class="white-button flex items-center w-full completed-form-completed-button">
|
|
<span>
|
|
{{ completedButton.title || "Back to Website" }}
|
|
</span>
|
|
</a>
|
|
<button
|
|
v-if="canSendEmail && !isDemo && withSendCopyButton"
|
|
class="white-button !h-auto flex items-center space-x-1 w-full completed-form-send-copy-button"
|
|
:disabled="isSendingCopy"
|
|
@click.prevent="sendCopyToEmail"
|
|
>
|
|
<IconInnerShadowTop v-if="isSendingCopy" class="animate-spin" />
|
|
<IconMail v-else />
|
|
<span>
|
|
{{ t("send_copy_via_email") }}
|
|
</span>
|
|
</button>
|
|
<button v-if="!isWebView && withDownloadButton" class="base-button flex items-center space-x-1 w-full completed-form-download-button" :disabled="isDownloading" @click.prevent="download">
|
|
<IconInnerShadowTop v-if="isDownloading" class="animate-spin" />
|
|
<IconDownload v-else />
|
|
<span>
|
|
{{ t("download") }}
|
|
</span>
|
|
</button>
|
|
<a v-if="isDemo" target="_blank" :href="brandGithubUrl" class="white-button flex items-center space-x-1 w-full">
|
|
<IconBrandGithub />
|
|
<span> Star on Github </span>
|
|
</a>
|
|
<a v-if="isDemo" :href="brandWebsiteUrl" class="white-button flex items-center space-x-1 w-full">
|
|
<IconLogin />
|
|
<span>
|
|
{{ t("create_a_free_account") }}
|
|
</span>
|
|
</a>
|
|
</div>
|
|
<div v-if="attribution" class="text-center mt-4">
|
|
{{ t("powered_by") }}
|
|
<a :href="brandWebsiteUrl" target="_blank" class="underline">{{ brandName }}</a> - {{ t("open_source_documents_software") }}
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { IconCircleCheck, IconBrandGithub, IconMail, IconDownload, IconInnerShadowTop, IconLogin } from "@tabler/icons-vue";
|
|
import MarkdownContent from "./markdown_content";
|
|
import { sanitizeUrl } from "@braintree/sanitize-url";
|
|
|
|
export default {
|
|
name: "FormCompleted",
|
|
components: {
|
|
MarkdownContent,
|
|
IconCircleCheck,
|
|
IconInnerShadowTop,
|
|
IconBrandGithub,
|
|
IconMail,
|
|
IconLogin,
|
|
IconDownload,
|
|
},
|
|
inject: ["baseUrl", "t"],
|
|
props: {
|
|
submitterSlug: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
isDemo: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
attribution: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: true,
|
|
},
|
|
hasSignatureFields: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
hasMultipleDocuments: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
withDownloadButton: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: true,
|
|
},
|
|
withSendCopyButton: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: true,
|
|
},
|
|
withConfetti: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
canSendEmail: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
fetchOptions: {
|
|
type: Object,
|
|
required: false,
|
|
default: () => ({}),
|
|
},
|
|
completedButton: {
|
|
type: Object,
|
|
required: false,
|
|
default: () => ({}),
|
|
},
|
|
completedMessage: {
|
|
type: Object,
|
|
required: false,
|
|
default: () => ({}),
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
isSendingCopy: false,
|
|
isDownloading: false,
|
|
};
|
|
},
|
|
computed: {
|
|
brandName() {
|
|
return document.querySelector('meta[name="brand-name"]')?.content || "Intébec";
|
|
},
|
|
brandWebsiteUrl() {
|
|
return document.querySelector('meta[name="brand-website-url"]')?.content || "/";
|
|
},
|
|
brandGithubUrl() {
|
|
return document.querySelector('meta[name="brand-github-url"]')?.content || "";
|
|
},
|
|
isWebView() {
|
|
return /webview|wv|ip((?!.*Safari)|(?=.*like Safari))/i.test(window.navigator.userAgent);
|
|
},
|
|
},
|
|
async mounted() {
|
|
if (this.withConfetti) {
|
|
const { default: confetti } = await import("canvas-confetti");
|
|
|
|
confetti({
|
|
particleCount: 50,
|
|
startVelocity: 30,
|
|
spread: 140,
|
|
});
|
|
}
|
|
|
|
document.querySelectorAll("#decline_button").forEach((button) => {
|
|
button.setAttribute("disabled", "true");
|
|
});
|
|
},
|
|
methods: {
|
|
sanitizeUrl,
|
|
sendCopyToEmail() {
|
|
this.isSendingCopy = true;
|
|
|
|
fetch(this.baseUrl + `/send_submission_email.json?submitter_slug=${this.submitterSlug}`, {
|
|
method: "POST",
|
|
})
|
|
.then(() => {
|
|
alert(this.t("email_has_been_sent"));
|
|
})
|
|
.finally(() => {
|
|
this.isSendingCopy = false;
|
|
});
|
|
},
|
|
download() {
|
|
this.isDownloading = true;
|
|
|
|
fetch(this.baseUrl + `/submitters/${this.submitterSlug}/download`, {
|
|
method: "GET",
|
|
...this.fetchOptions,
|
|
}).then(async (response) => {
|
|
if (response.ok) {
|
|
const urls = await response.json();
|
|
const isMobileSafariIos = "ontouchstart" in window && navigator.maxTouchPoints > 0 && /AppleWebKit/i.test(navigator.userAgent);
|
|
const isSafariIos = isMobileSafariIos || /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
|
|
|
if (isSafariIos && urls.length > 1) {
|
|
this.downloadSafariIos(urls);
|
|
} else {
|
|
this.downloadUrls(urls);
|
|
}
|
|
} else {
|
|
alert(this.t("failed_to_download_files"));
|
|
}
|
|
});
|
|
},
|
|
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);
|
|
});
|
|
};
|
|
});
|
|
|
|
fileRequests
|
|
.reduce((prevPromise, request) => prevPromise.then(() => request()), Promise.resolve())
|
|
.finally(() => {
|
|
this.isDownloading = false;
|
|
});
|
|
},
|
|
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;
|
|
});
|
|
});
|
|
|
|
Promise.all(fileRequests)
|
|
.then((links) => {
|
|
links.forEach((link, index) => {
|
|
setTimeout(() => {
|
|
link.click();
|
|
|
|
URL.revokeObjectURL(link.href);
|
|
}, index * 50);
|
|
});
|
|
})
|
|
.finally(() => {
|
|
this.isDownloading = false;
|
|
});
|
|
},
|
|
},
|
|
};
|
|
</script>
|