0351d front end linting (#377)

* feat: disable custom script for  trial users

* after lint fix

* frontend linting

---------

Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
Favour Olayinka
2024-04-15 18:39:03 +01:00
committed by GitHub
parent 8d35fc8b1a
commit bcd45ce8a6
228 changed files with 17036 additions and 8744 deletions

View File

@@ -1,18 +1,28 @@
<template>
<div id="new-features"
class="w-full bg-gray-50 dark:bg-gray-800 border rounded-lg mt-4"
<div
id="new-features"
class="w-full bg-gray-50 dark:bg-gray-800 border rounded-lg mt-4"
>
<div class="border-b">
<div v-track.new_in_notionforms_click
class="relative flex items-center cursor-pointer hover:bg-gray-100 p-4" role="button"
@click.prevent="showNewFeatures=!showNewFeatures"
<div
v-track.new_in_notionforms_click
class="relative flex items-center cursor-pointer hover:bg-gray-100 p-4"
role="button"
@click.prevent="showNewFeatures = !showNewFeatures"
>
<div class="text-gray-700 dark:text-gray-300 pr-4">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24"
stroke="currentColor" stroke-width="2"
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path stroke-linecap="round" stroke-linejoin="round"
d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"
/>
</svg>
</div>
@@ -26,26 +36,57 @@
</div>
</div>
<v-transition>
<ul v-if="showNewFeatures" class="list-disc list-inside border-t pt-2 p-4">
<li v-for="changelog in changelogEntries" :key="changelog.id" v-track.new_feature_click class="text-sm">
<a :href="changelog.url" target="_blank" class="text-gray-700 dark:text-gray-300">{{ changelog.title }}</a>
<ul
v-if="showNewFeatures"
class="list-disc list-inside border-t pt-2 p-4"
>
<li
v-for="changelog in changelogEntries"
:key="changelog.id"
v-track.new_feature_click
class="text-sm"
>
<a
:href="changelog.url"
target="_blank"
class="text-gray-700 dark:text-gray-300"
>{{ changelog.title }}</a>
</li>
<li v-track.new_feature_read_more_click class="text-sm">
<a class="text-gray-700 dark:text-gray-300" :href="changelogLink" target="_blank">Read more</a>
<li
v-track.new_feature_read_more_click
class="text-sm"
>
<a
class="text-gray-700 dark:text-gray-300"
:href="changelogLink"
target="_blank"
>Read more</a>
</li>
</ul>
</v-transition>
</div>
<div class="relative flex items-center cursor-pointer hover:bg-gray-100 p-4">
<a v-track.feature_request_click="{user_has_forms:user.has_forms}" :href="requestFeatureLink"
class="absolute inset-0" target="_blank"
<div
class="relative flex items-center cursor-pointer hover:bg-gray-100 p-4"
>
<a
v-track.feature_request_click="{ user_has_forms: user.has_forms }"
:href="requestFeatureLink"
class="absolute inset-0"
target="_blank"
/>
<div class="text-gray-700 dark:text-gray-300 pr-4">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"
stroke-width="2"
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path stroke-linecap="round" stroke-linejoin="round"
d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
/>
</svg>
</div>
@@ -62,45 +103,45 @@
</template>
<script>
import { computed } from 'vue'
import { useAuthStore } from '../../../stores/auth';
import VTransition from '~/components/global/transitions/VTransition.vue'
import { computed } from "vue"
import { useAuthStore } from "../../../stores/auth"
import VTransition from "~/components/global/transitions/VTransition.vue"
export default {
components: { VTransition },
props: {},
setup () {
setup() {
const authStore = useAuthStore()
return {
user : computed(() => authStore.user)
user: computed(() => authStore.user),
}
},
data: () => ({
changelogEntries: [],
showNewFeatures: false
showNewFeatures: false,
}),
mounted () {
computed: {
requestFeatureLink() {
return this.$config.links.feature_requests
},
changelogLink() {
return this.$config.links.changelog_url
},
},
mounted() {
this.loadChangelogEntries()
},
computed: {
requestFeatureLink () {
return this.$config.links.feature_requests
},
changelogLink () {
return this.$config.links.changelog_url
}
},
methods: {
loadChangelogEntries () {
opnFetch('/content/changelog/entries').then(data => {
loadChangelogEntries() {
opnFetch("/content/changelog/entries").then((data) => {
this.changelogEntries = data.splice(0, 3)
})
}
}
},
},
}
</script>

View File

@@ -1,18 +1,36 @@
<template>
<Modal :show="show" :closeable="!aiForm.busy" @close="$emit('close')">
<Modal
:show="show"
:closeable="!aiForm.busy"
@close="$emit('close')"
>
<template #icon>
<template v-if="state == 'default'">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-10 h-10 text-blue">
<path fill-rule="evenodd"
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-10 h-10 text-blue"
>
<path
fill-rule="evenodd"
d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z"
clip-rule="evenodd" />
clip-rule="evenodd"
/>
</svg>
</template>
<template v-else-if="state == 'ai'">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8 text-blue-500">
<path fill-rule="evenodd"
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-8 h-8 text-blue-500"
>
<path
fill-rule="evenodd"
d="M14.615 1.595a.75.75 0 01.359.852L12.982 9.75h7.268a.75.75 0 01.548 1.262l-10.5 11.25a.75.75 0 01-1.272-.71l1.992-7.302H3.75a.75.75 0 01-.548-1.262l10.5-11.25a.75.75 0 01.913-.143z"
clip-rule="evenodd" />
clip-rule="evenodd"
/>
</svg>
</template>
</template>
@@ -24,27 +42,54 @@
AI-powered form generator
</template>
</template>
<div v-if="state == 'default'" class="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-8">
<div v-track.select_form_base="{ base: 'contact-form' }" role="button"
class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50" @click="$emit('close')">
<div
v-if="state == 'default'"
class="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-8"
>
<div
v-track.select_form_base="{ base: 'contact-form' }"
role="button"
class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50"
@click="$emit('close')"
>
<div class="p-4">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8 text-blue-500">
<path d="M1.5 8.67v8.58a3 3 0 003 3h15a3 3 0 003-3V8.67l-8.928 5.493a3 3 0 01-3.144 0L1.5 8.67z" />
<path d="M22.5 6.908V6.75a3 3 0 00-3-3h-15a3 3 0 00-3 3v.158l9.714 5.978a1.5 1.5 0 001.572 0L22.5 6.908z" />
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-8 h-8 text-blue-500"
>
<path
d="M1.5 8.67v8.58a3 3 0 003 3h15a3 3 0 003-3V8.67l-8.928 5.493a3 3 0 01-3.144 0L1.5 8.67z"
/>
<path
d="M22.5 6.908V6.75a3 3 0 00-3-3h-15a3 3 0 00-3 3v.158l9.714 5.978a1.5 1.5 0 001.572 0L22.5 6.908z"
/>
</svg>
</div>
<p class="font-medium">
Start from a simple contact form
</p>
</div>
<div v-if="aiFeaturesEnabled" v-track.select_form_base="{ base: 'ai' }"
class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50" role="button"
@click="state = 'ai'">
<div
v-if="aiFeaturesEnabled"
v-track.select_form_base="{ base: 'ai' }"
class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50"
role="button"
@click="state = 'ai'"
>
<div class="p-4 relative">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8 text-blue-500">
<path fill-rule="evenodd"
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-8 h-8 text-blue-500"
>
<path
fill-rule="evenodd"
d="M14.615 1.595a.75.75 0 01.359.852L12.982 9.75h7.268a.75.75 0 01.548 1.262l-10.5 11.25a.75.75 0 01-1.272-.71l1.992-7.302H3.75a.75.75 0 01-.548-1.262l10.5-11.25a.75.75 0 01.913-.143z"
clip-rule="evenodd" />
clip-rule="evenodd"
/>
</svg>
</div>
<p class="font-medium text-blue-700">
@@ -52,32 +97,65 @@
</p>
<span class="text-xs text-gray-500">(1 min)</span>
</div>
<div class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50 relative">
<div
class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50 relative"
>
<div class="p-4 relative">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8 text-blue-500">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-8 h-8 text-blue-500"
>
<path
d="M11.25 5.337c0-.355-.186-.676-.401-.959a1.647 1.647 0 01-.349-1.003c0-1.036 1.007-1.875 2.25-1.875S15 2.34 15 3.375c0 .369-.128.713-.349 1.003-.215.283-.401.604-.401.959 0 .332.278.598.61.578 1.91-.114 3.79-.342 5.632-.676a.75.75 0 01.878.645 49.17 49.17 0 01.376 5.452.657.657 0 01-.66.664c-.354 0-.675-.186-.958-.401a1.647 1.647 0 00-1.003-.349c-1.035 0-1.875 1.007-1.875 2.25s.84 2.25 1.875 2.25c.369 0 .713-.128 1.003-.349.283-.215.604-.401.959-.401.31 0 .557.262.534.571a48.774 48.774 0 01-.595 4.845.75.75 0 01-.61.61c-1.82.317-3.673.533-5.555.642a.58.58 0 01-.611-.581c0-.355.186-.676.401-.959.221-.29.349-.634.349-1.003 0-1.035-1.007-1.875-2.25-1.875s-2.25.84-2.25 1.875c0 .369.128.713.349 1.003.215.283.401.604.401.959a.641.641 0 01-.658.643 49.118 49.118 0 01-4.708-.36.75.75 0 01-.645-.878c.293-1.614.504-3.257.629-4.924A.53.53 0 005.337 15c-.355 0-.676.186-.959.401-.29.221-.634.349-1.003.349-1.036 0-1.875-1.007-1.875-2.25s.84-2.25 1.875-2.25c.369 0 .713.128 1.003.349.283.215.604.401.959.401a.656.656 0 00.659-.663 47.703 47.703 0 00-.31-4.82.75.75 0 01.83-.832c1.343.155 2.703.254 4.077.294a.64.64 0 00.657-.642z" />
d="M11.25 5.337c0-.355-.186-.676-.401-.959a1.647 1.647 0 01-.349-1.003c0-1.036 1.007-1.875 2.25-1.875S15 2.34 15 3.375c0 .369-.128.713-.349 1.003-.215.283-.401.604-.401.959 0 .332.278.598.61.578 1.91-.114 3.79-.342 5.632-.676a.75.75 0 01.878.645 49.17 49.17 0 01.376 5.452.657.657 0 01-.66.664c-.354 0-.675-.186-.958-.401a1.647 1.647 0 00-1.003-.349c-1.035 0-1.875 1.007-1.875 2.25s.84 2.25 1.875 2.25c.369 0 .713-.128 1.003-.349.283-.215.604-.401.959-.401.31 0 .557.262.534.571a48.774 48.774 0 01-.595 4.845.75.75 0 01-.61.61c-1.82.317-3.673.533-5.555.642a.58.58 0 01-.611-.581c0-.355.186-.676.401-.959.221-.29.349-.634.349-1.003 0-1.035-1.007-1.875-2.25-1.875s-2.25.84-2.25 1.875c0 .369.128.713.349 1.003.215.283.401.604.401.959a.641.641 0 01-.658.643 49.118 49.118 0 01-4.708-.36.75.75 0 01-.645-.878c.293-1.614.504-3.257.629-4.924A.53.53 0 005.337 15c-.355 0-.676.186-.959.401-.29.221-.634.349-1.003.349-1.036 0-1.875-1.007-1.875-2.25s.84-2.25 1.875-2.25c.369 0 .713.128 1.003.349.283.215.604.401.959.401a.656.656 0 00.659-.663 47.703 47.703 0 00-.31-4.82.75.75 0 01.83-.832c1.343.155 2.703.254 4.077.294a.64.64 0 00.657-.642z"
/>
</svg>
</div>
<p class="font-medium">
Start from a template
</p>
<NuxtLink v-track.select_form_base="{ base: 'template' }" :to="{ name: 'templates' }" class="absolute inset-0" />
<NuxtLink
v-track.select_form_base="{ base: 'template' }"
:to="{ name: 'templates' }"
class="absolute inset-0"
/>
</div>
</div>
<div v-else-if="state == 'ai'">
<a class="absolute top-4 left-4" href="#" role="button" @click.prevent="state = 'default'">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-4 h-4 inline -mt-1">
<path fill-rule="evenodd"
<a
class="absolute top-4 left-4"
href="#"
role="button"
@click.prevent="state = 'default'"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-4 h-4 inline -mt-1"
>
<path
fill-rule="evenodd"
d="M7.72 12.53a.75.75 0 010-1.06l7.5-7.5a.75.75 0 111.06 1.06L9.31 12l6.97 6.97a.75.75 0 11-1.06 1.06l-7.5-7.5z"
clip-rule="evenodd" />
clip-rule="evenodd"
/>
</svg>
Back
</a>
<text-area-input label="Form Description" :disabled="loading ? true : null" :form="aiForm" name="form_prompt"
<text-area-input
label="Form Description"
:disabled="loading ? true : null"
:form="aiForm"
name="form_prompt"
help="Give us a description of the form you want to build (the more details the better)"
placeholder="A simple contact form, with a name, email and message field" />
<v-button class="w-full" :loading="loading" @click.prevent="generateForm">
placeholder="A simple contact form, with a name, email and message field"
/>
<v-button
class="w-full"
:loading="loading"
@click.prevent="generateForm"
>
Generate a form
</v-button>
<p class="text-gray-500 text-xs text-center mt-1">
@@ -89,28 +167,28 @@
<script>
export default {
emits: ['close', 'form-generated'],
props: {
show: { type: Boolean, required: true }
show: { type: Boolean, required: true },
},
emits: ["close", "form-generated"],
setup() {
return {
useAlert: useAlert(),
runtimeConfig: useRuntimeConfig()
runtimeConfig: useRuntimeConfig(),
}
},
data: () => ({
state: 'default',
state: "default",
aiForm: useForm({
form_prompt: ''
form_prompt: "",
}),
loading: false
loading: false,
}),
computed: {
aiFeaturesEnabled() {
return this.runtimeConfig.public.aiFeaturesEnabled
}
},
},
methods: {
@@ -118,39 +196,47 @@ export default {
if (this.loading) return
this.loading = true
this.aiForm.post('/forms/ai/generate').then(response => {
this.useAlert.success(response.message)
this.fetchGeneratedForm(response.ai_form_completion_id)
}).catch(error => {
console.error(error)
this.loading = false
this.state = 'ai'
})
this.aiForm
.post("/forms/ai/generate")
.then((response) => {
this.useAlert.success(response.message)
this.fetchGeneratedForm(response.ai_form_completion_id)
})
.catch((error) => {
console.error(error)
this.loading = false
this.state = "ai"
})
},
fetchGeneratedForm(generationId) {
// check every 4 seconds if form is generated
setTimeout(() => {
opnFetch('/forms/ai/' + generationId).then(data => {
if (data.ai_form_completion.status === 'completed') {
this.useAlert.success(data.message)
this.$emit('form-generated', JSON.parse(data.ai_form_completion.result))
this.$emit('close')
} else if (data.ai_form_completion.status === 'failed') {
this.useAlert.error('Something went wrong, please try again.')
this.state = 'default'
opnFetch("/forms/ai/" + generationId)
.then((data) => {
if (data.ai_form_completion.status === "completed") {
this.useAlert.success(data.message)
this.$emit(
"form-generated",
JSON.parse(data.ai_form_completion.result),
)
this.$emit("close")
} else if (data.ai_form_completion.status === "failed") {
this.useAlert.error("Something went wrong, please try again.")
this.state = "default"
this.loading = false
} else {
this.fetchGeneratedForm(generationId)
}
})
.catch((error) => {
if (error?.data?.message) {
this.useAlert.error(error.data.message)
}
this.state = "default"
this.loading = false
} else {
this.fetchGeneratedForm(generationId)
}
}).catch(error => {
if (error?.data?.message) {
this.useAlert.error(error.data.message)
}
this.state = 'default'
this.loading = false
})
})
}, 4000)
}
}
},
},
}
</script>

View File

@@ -1,14 +1,27 @@
<template>
<div>
<h3 class="font-semibold text-xl">Embed</h3>
<h3 class="font-semibold text-xl">
Embed
</h3>
<p>Embed your form on your website by copying the HTML code below.</p>
<copy-content :content="embedCode" buttonText="Copy Code">
<copy-content
:content="embedCode"
button-text="Copy Code"
>
<template #icon>
<svg class="h-4 w-4 -mt-1 text-blue-600 inline mr-1" viewBox="0 0 18 18" fill="none"
xmlns="http://www.w3.org/2000/svg">
<svg
class="h-4 w-4 -mt-1 text-blue-600 inline mr-1"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.0833 11.5L13.5833 9L11.0833 6.5M6.91667 6.5L4.41667 9L6.91667 11.5M5.5 16.5H12.5C13.9001 16.5 14.6002 16.5 15.135 16.2275C15.6054 15.9878 15.9878 15.6054 16.2275 15.135C16.5 14.6002 16.5 13.9001 16.5 12.5V5.5C16.5 4.09987 16.5 3.3998 16.2275 2.86502C15.9878 2.39462 15.6054 2.01217 15.135 1.77248C14.6002 1.5 13.9001 1.5 12.5 1.5H5.5C4.09987 1.5 3.3998 1.5 2.86502 1.77248C2.39462 2.01217 2.01217 2.39462 1.77248 2.86502C1.5 3.3998 1.5 4.09987 1.5 5.5V12.5C1.5 13.9001 1.5 14.6002 1.77248 15.135C2.01217 15.6054 2.39462 15.9878 2.86502 16.2275C3.3998 16.5 4.09987 16.5 5.5 16.5Z"
stroke="currentColor" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
stroke="currentColor"
stroke-width="1.66667"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</template>
Copy Code
@@ -17,38 +30,48 @@
</template>
<script>
import CopyContent from '../../../open/forms/components/CopyContent.vue'
import {appUrl} from "~/lib/utils.js";
/* eslint-disable */
import CopyContent from "../../../open/forms/components/CopyContent.vue"
import { appUrl } from "~/lib/utils.js"
export default {
name: 'EmbedCode',
components: {CopyContent},
name: "EmbedCode",
components: { CopyContent },
props: {
form: {type: Object, required: true},
extraQueryParam: {type: String, default: ''}
form: { type: Object, required: true },
extraQueryParam: { type: String, default: "" },
},
data: () => ({
autoresizeIframe: false
autoresizeIframe: false,
}),
computed: {
embedCode() {
// eslint-disable no-useless-escape
return `
<script type="text/javascript" src="${appUrl('/widgets/iframeResize.min.js')}"><\/script>
<script type="text/javascript" src="${appUrl("/widgets/iframeResize.min.js")}"><\/script>
${this.iframeCode}
<script type="text/javascript">iFrameResize({log: false, checkOrigin: false}, "#${this.iframeId}");<\/script>
`
},
iframeCode() {
const share_url = (this.extraQueryParam) ? this.form.share_url + "?" + this.extraQueryParam : this.form.share_url + this.extraQueryParam
return '<iframe style="border:none;width:100%;" id="' + this.iframeId + '" src="' + share_url + '"></iframe>'
const share_url = this.extraQueryParam
? this.form.share_url + "?" + this.extraQueryParam
: this.form.share_url + this.extraQueryParam
return (
'<iframe style="border:none;width:100%;" id="' +
this.iframeId +
'" src="' +
share_url +
'"></iframe>'
)
},
iframeId() {
return 'form-' + this.form.slug
}
return "form-" + this.form.slug
},
},
methods: {}
methods: {},
}
</script>

View File

@@ -1,24 +1,47 @@
<template>
<div>
<v-button
v-track.share_embed_form_popup_click="{form_id:form.id, form_slug:form.slug}"
v-track.share_embed_form_popup_click="{
form_id: form.id,
form_slug: form.slug,
}"
class="w-full"
color="light-gray"
@click="showEmbedFormAsPopupModal=true"
@click="showEmbedFormAsPopupModal = true"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-2 text-blue-600 inline" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round"
d="M2.25 12.76c0 1.6 1.123 2.994 2.707 3.227 1.068.157 2.148.279 3.238.364.466.037.893.281 1.153.671L12 21l2.652-3.978c.26-.39.687-.634 1.153-.67 1.09-.086 2.17-.208 3.238-.365 1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z"
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 mr-2 text-blue-600 inline"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M2.25 12.76c0 1.6 1.123 2.994 2.707 3.227 1.068.157 2.148.279 3.238.364.466.037.893.281 1.153.671L12 21l2.652-3.978c.26-.39.687-.634 1.153-.67 1.09-.086 2.17-.208 3.238-.365 1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z"
/>
</svg>
Embed as popup
</v-button>
<modal :show="showEmbedFormAsPopupModal" @close="onClose">
<modal
:show="showEmbedFormAsPopupModal"
@close="onClose"
>
<template #icon>
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 text-blue" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round"
d="M2.25 12.76c0 1.6 1.123 2.994 2.707 3.227 1.068.157 2.148.279 3.238.364.466.037.893.281 1.153.671L12 21l2.652-3.978c.26-.39.687-.634 1.153-.67 1.09-.086 2.17-.208 3.238-.365 1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z"
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-10 h-10 text-blue"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M2.25 12.76c0 1.6 1.123 2.994 2.707 3.227 1.068.157 2.148.279 3.238.364.466.037.893.281 1.153.671L12 21l2.652-3.978c.26-.39.687-.634 1.153-.67 1.09-.086 2.17-.208 3.238-.365 1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z"
/>
</svg>
</template>
@@ -31,14 +54,18 @@
Demo
</h3>
<p class="pb-6">
A live preview of your form popup was just added to this page. <span class="font-semibold text-blue-800">Click on the button on the bottom
A live preview of your form popup was just added to this page.
<span class="font-semibold text-blue-800">Click on the button on the bottom
{{ advancedOptions.position }} corner to try it</span>.
</p>
<h3 class="border-t text-xl font-semibold mb-2 pt-6">
How does it work?
</h3>
<p>Paste the following code snippet in the <b>&lt;head&gt;</b> section of your website.</p>
<p>
Paste the following code snippet in the <b>&lt;head&gt;</b> section of
your website.
</p>
<div
class="border border-nt-blue-light bg-blue-50 dark:bg-notion-dark-light rounded-md p-4 mb-5 w-full mx-auto mt-4 select-all"
@@ -47,19 +74,32 @@
<p class="select-all text-nt-blue flex-grow break-all">
{{ embedPopupCode }}
</p>
<div class="hover:bg-nt-blue-lighter rounded transition-colors cursor-pointer" @click="copyToClipboard">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-nt-blue" fill="none" viewBox="0 0 24 24"
stroke="currentColor"
<div
class="hover:bg-nt-blue-lighter rounded transition-colors cursor-pointer"
@click="copyToClipboard"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 text-nt-blue"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"
/>
</svg>
</div>
</div>
</div>
<collapse class="py-5 w-full border rounded-md px-4" :model-value="true">
<collapse
class="py-5 w-full border rounded-md px-4"
:model-value="true"
>
<template #title>
<div class="flex">
<h3 class="font-semibold block text-lg">
@@ -68,31 +108,52 @@
</div>
</template>
<div class="border-t mt-4 -mx-4" />
<toggle-switch-input v-model="advancedOptions.hide_title" name="hide_title" class="mt-4"
label="Hide Form Title"
:disabled="(form.hide_title===true)?true:null"
:help="hideTitleHelp"
<toggle-switch-input
v-model="advancedOptions.hide_title"
name="hide_title"
class="mt-4"
label="Hide Form Title"
:disabled="form.hide_title === true ? true : null"
:help="hideTitleHelp"
/>
<color-input v-model="advancedOptions.bgcolor" name="bgcolor" class="mt-4"
label="Circle Background Color"
<color-input
v-model="advancedOptions.bgcolor"
name="bgcolor"
class="mt-4"
label="Circle Background Color"
/>
<text-input v-model="advancedOptions.emoji" name="emoji" class="mt-4"
label="Emoji" :max-char-limit="2"
<text-input
v-model="advancedOptions.emoji"
name="emoji"
class="mt-4"
label="Emoji"
:max-char-limit="2"
/>
<flat-select-input v-model="advancedOptions.position" name="position" class="mt-4"
label="Position"
:options="[
{name:'Bottom Right',value:'right'},
{name:'Bottom Left',value:'left'},
]"
<flat-select-input
v-model="advancedOptions.position"
name="position"
class="mt-4"
label="Position"
:options="[
{ name: 'Bottom Right', value: 'right' },
{ name: 'Bottom Left', value: 'left' },
]"
/>
<text-input v-model="advancedOptions.width" name="width" class="mt-4"
label="Form pop max width (px)" native-type="number"
<text-input
v-model="advancedOptions.width"
name="width"
class="mt-4"
label="Form pop max width (px)"
native-type="number"
/>
</collapse>
<div class="flex justify-end mt-4">
<v-button color="gray" shade="light" @click="onClose">
<v-button
color="gray"
shade="light"
@click="onClose"
>
Close
</v-button>
</div>
@@ -102,48 +163,58 @@
</template>
<script setup>
import { ref, defineProps, computed } from 'vue'
import {appUrl} from "~/lib/utils.js";
import { ref, defineProps, computed } from "vue"
import { appUrl } from "~/lib/utils.js"
const { copy } = useClipboard()
const crisp = useCrisp()
const props = defineProps({
form: { type: Object, required: true }
form: { type: Object, required: true },
})
const embedScriptUrl = '/widgets/embed-min.js'
let showEmbedFormAsPopupModal = ref(false)
let advancedOptions = ref({
const embedScriptUrl = "/widgets/embed-min.js"
const showEmbedFormAsPopupModal = ref(false)
const advancedOptions = ref({
hide_title: false,
emoji: '💬',
position: 'right',
bgcolor: '#3B82F6',
width: '500'
emoji: "💬",
position: "right",
bgcolor: "#3B82F6",
width: "500",
})
let hideTitleHelp = computed(() => {
return props.form.hide_title ? 'This option is disabled because the form title is already hidden' : null
const hideTitleHelp = computed(() => {
return props.form.hide_title
? "This option is disabled because the form title is already hidden"
: null
})
let shareUrl = computed(() => {
return (advancedOptions.value.hide_title) ? props.form.share_url + '?hide_title=true' : props.form.share_url
const shareUrl = computed(() => {
return advancedOptions.value.hide_title
? props.form.share_url + "?hide_title=true"
: props.form.share_url
})
let embedPopupCode = computed(() => {
const embedPopupCode = computed(() => {
const nfData = {
formurl: shareUrl.value,
emoji: advancedOptions.value.emoji,
position: advancedOptions.value.position,
bgcolor: advancedOptions.value.bgcolor,
width: advancedOptions.value.width
width: advancedOptions.value.width,
}
previewPopup(nfData)
return '<script async data-nf=\'' + JSON.stringify(nfData) + '\' src=\'' + appUrl(embedScriptUrl) + '\'></scrip' + 't>'
return (
"<script async data-nf='" +
JSON.stringify(nfData) +
"' src='" +
appUrl(embedScriptUrl) +
"'></scrip" +
"t>"
)
})
onMounted(() => {
advancedOptions.value.bgcolor = props.form.color
})
const onClose = () => {
removePreview()
crisp.showChat()
@@ -152,15 +223,15 @@ const onClose = () => {
const copyToClipboard = () => {
if (import.meta.server) return
copy(embedPopupCode.value)
useAlert().success('Copied!')
useAlert().success("Copied!")
}
const removePreview = () => {
if (import.meta.server) return
const oldP = document.head.querySelector('#nf-popup-preview')
const oldP = document.head.querySelector("#nf-popup-preview")
if (oldP) {
oldP.remove()
}
const oldM = document.body.querySelector('.nf-main')
const oldM = document.body.querySelector(".nf-main")
if (oldM) {
oldM.remove()
}
@@ -178,11 +249,11 @@ const previewPopup = (nfData) => {
crisp.hideChat()
// Add new preview
const el = document.createElement('script')
el.id = 'nf-popup-preview'
const el = document.createElement("script")
el.id = "nf-popup-preview"
el.async = true
el.src = embedScriptUrl
el.setAttribute('data-nf', JSON.stringify(nfData))
el.setAttribute("data-nf", JSON.stringify(nfData))
document.head.appendChild(el)
}
</script>

View File

@@ -1,120 +1,278 @@
<template>
<div>
<div v-if="loadingDuplicate || loadingDelete" class="pr-4 pt-2">
<div
v-if="loadingDuplicate || loadingDelete"
class="pr-4 pt-2"
>
<Loader class="h-6 w-6 mx-auto" />
</div>
<dropdown v-else class="inline">
<dropdown
v-else
class="inline"
>
<template #trigger="{ toggle }">
<v-button color="white" @click="toggle">
<svg class="w-4 h-4 inline -mt-1" viewBox="0 0 16 4" fill="none" xmlns="http://www.w3.org/2000/svg">
<v-button
color="white"
@click="toggle"
>
<svg
class="w-4 h-4 inline -mt-1"
viewBox="0 0 16 4"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.00016 2.83366C8.4604 2.83366 8.8335 2.46056 8.8335 2.00033C8.8335 1.54009 8.4604 1.16699 8.00016 1.16699C7.53993 1.16699 7.16683 1.54009 7.16683 2.00033C7.16683 2.46056 7.53993 2.83366 8.00016 2.83366Z"
stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round" />
stroke="#344054"
stroke-width="1.66667"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M13.8335 2.83366C14.2937 2.83366 14.6668 2.46056 14.6668 2.00033C14.6668 1.54009 14.2937 1.16699 13.8335 1.16699C13.3733 1.16699 13.0002 1.54009 13.0002 2.00033C13.0002 2.46056 13.3733 2.83366 13.8335 2.83366Z"
stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round" />
stroke="#344054"
stroke-width="1.66667"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M2.16683 2.83366C2.62707 2.83366 3.00016 2.46056 3.00016 2.00033C3.00016 1.54009 2.62707 1.16699 2.16683 1.16699C1.70659 1.16699 1.3335 1.54009 1.3335 2.00033C1.3335 2.46056 1.70659 2.83366 2.16683 2.83366Z"
stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round" />
stroke="#344054"
stroke-width="1.66667"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</v-button>
</template>
<span v-if="isMainPage && form.visibility === 'draft'"
<span
v-if="isMainPage && form.visibility === 'draft'"
class="block px-4 py-2 text-md text-gray-700 cursor-pointer dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click="showDraftFormWarningNotification">
<svg class="w-4 h-4 mr-2" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12C23 12 19 20 12 20C5 20 1 12 1 12Z" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@click="showDraftFormWarningNotification"
>
<svg
class="w-4 h-4 mr-2"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12C23 12 19 20 12 20C5 20 1 12 1 12Z"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
View form
</span>
<a v-else-if="isMainPage" v-track.view_form_click="{ form_id: form.id, form_slug: form.slug }"
:href="form.share_url" target="_blank"
class="block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center">
<svg class="w-4 h-4 mr-2" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12C23 12 19 20 12 20C5 20 1 12 1 12Z" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<a
v-else-if="isMainPage"
v-track.view_form_click="{ form_id: form.id, form_slug: form.slug }"
:href="form.share_url"
target="_blank"
class="block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
>
<svg
class="w-4 h-4 mr-2"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12C23 12 19 20 12 20C5 20 1 12 1 12Z"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
View form
</a>
<nuxt-link v-if="isMainPage" v-track.edit_form_click="{ form_id: form.id, form_slug: form.slug }"
<nuxt-link
v-if="isMainPage"
v-track.edit_form_click="{ form_id: form.id, form_slug: form.slug }"
:to="{ name: 'forms-slug-edit', params: { slug: form.slug } }"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center">
<svg class="w-4 h-4 mr-2" width="18" height="17" viewBox="0 0 18 17" fill="none"
xmlns="http://www.w3.org/2000/svg">
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
>
<svg
class="w-4 h-4 mr-2"
width="18"
height="17"
viewBox="0 0 18 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.99998 15.6662H16.5M1.5 15.6662H2.89545C3.3031 15.6662 3.50693 15.6662 3.69874 15.6202C3.8688 15.5793 4.03138 15.512 4.1805 15.4206C4.34869 15.3175 4.49282 15.1734 4.78107 14.8852L15.25 4.4162C15.9404 3.72585 15.9404 2.60656 15.25 1.9162C14.5597 1.22585 13.4404 1.22585 12.75 1.9162L2.28105 12.3852C1.9928 12.6734 1.84867 12.8175 1.7456 12.9857C1.65422 13.1348 1.58688 13.2974 1.54605 13.4675C1.5 13.6593 1.5 13.8631 1.5 14.2708V15.6662Z"
stroke="currentColor" stroke-width="1.67" stroke-linecap="round" stroke-linejoin="round" />
stroke="currentColor"
stroke-width="1.67"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
Edit
</nuxt-link>
<a v-if="isMainPage" href="#"
<a
v-if="isMainPage"
href="#"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click.prevent="copyLink">
<svg class="w-4 h-4 mr-2" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
@click.prevent="copyLink"
>
<svg
class="w-4 h-4 mr-2"
viewBox="0 0 16 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.00016 8.33317H4.66683C2.82588 8.33317 1.3335 6.84079 1.3335 4.99984C1.3335 3.15889 2.82588 1.6665 4.66683 1.6665H6.00016M10.0002 8.33317H11.3335C13.1744 8.33317 14.6668 6.84079 14.6668 4.99984C14.6668 3.15889 13.1744 1.6665 11.3335 1.6665H10.0002M4.66683 4.99984L11.3335 4.99984"
stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
Copy link to share
</a>
<a v-track.duplicate_form_click="{ form_id: form.id, form_slug: form.slug }" href="#"
<a
v-track.duplicate_form_click="{
form_id: form.id,
form_slug: form.slug,
}"
href="#"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click.prevent="duplicateForm">
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2" />
@click.prevent="duplicateForm"
>
<svg
class="w-4 h-4 mr-2"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2"
/>
</svg>
Duplicate form
</a>
<a v-if="!isMainPage" v-track.create_template_click="{ form_id: form.id, form_slug: form.slug }" href="#"
<a
v-if="!isMainPage"
v-track.create_template_click="{
form_id: form.id,
form_slug: form.slug,
}"
href="#"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click.prevent="showFormTemplateModal = true">
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round"
d="M17 14v6m-3-3h6M6 10h2a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2zm10 0h2a2 2 0 002-2V6a2 2 0 00-2-2h-2a2 2 0 00-2 2v2a2 2 0 002 2zM6 20h2a2 2 0 002-2v-2a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2z" />
@click.prevent="showFormTemplateModal = true"
>
<svg
class="w-4 h-4 mr-2"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M17 14v6m-3-3h6M6 10h2a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2zm10 0h2a2 2 0 002-2V6a2 2 0 00-2-2h-2a2 2 0 00-2 2v2a2 2 0 002 2zM6 20h2a2 2 0 002-2v-2a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2z"
/>
</svg>
Create Template
</a>
<a v-track.change_workspace_click="{ form_id: form.id, form_slug: form.slug }" href="#"
<a
v-track.change_workspace_click="{
form_id: form.id,
form_slug: form.slug,
}"
href="#"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click.prevent="showFormWorkspaceModal = true">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="w-4 h-4 mr-2">
<path stroke-linecap="round" stroke-linejoin="round"
d="M2.25 21h19.5m-18-18v18m10.5-18v18m6-13.5V21M6.75 6.75h.75m-.75 3h.75m-.75 3h.75m3-6h.75m-.75 3h.75m-.75 3h.75M6.75 21v-3.375c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21M3 3h12m-.75 4.5H21m-3.75 3.75h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Z" />
@click.prevent="showFormWorkspaceModal = true"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4 mr-2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M2.25 21h19.5m-18-18v18m10.5-18v18m6-13.5V21M6.75 6.75h.75m-.75 3h.75m-.75 3h.75m3-6h.75m-.75 3h.75m-.75 3h.75M6.75 21v-3.375c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21M3 3h12m-.75 4.5H21m-3.75 3.75h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Z"
/>
</svg>
Change workspace
</a>
<a v-track.delete_form_click="{ form_id: form.id, form_slug: form.slug }" href="#"
<a
v-track.delete_form_click="{ form_id: form.id, form_slug: form.slug }"
href="#"
class="block block px-4 py-2 text-md text-red-600 hover:bg-red-50 flex items-center"
@click.prevent="showDeleteFormModal = true">
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
@click.prevent="showDeleteFormModal = true"
>
<svg
class="w-4 h-4 mr-2"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
Delete form
</a>
</dropdown>
<!-- Delete Form Modal -->
<modal :show="showDeleteFormModal" icon-color="red" max-width="sm" @close="showDeleteFormModal = false">
<modal
:show="showDeleteFormModal"
icon-color="red"
max-width="sm"
@close="showDeleteFormModal = false"
>
<template #icon>
<svg class="w-10 h-10" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
<svg
class="w-10 h-10"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</template>
<template #title>
@@ -122,83 +280,111 @@
</template>
<div class="p-3">
<p>
If you want to permanently delete this form and all of its data, you can do so below.
If you want to permanently delete this form and all of its data, you
can do so below.
</p>
<div class="flex mt-4">
<v-button class="sm:w-1/2 mr-4" color="white" @click.prevent="showDeleteFormModal = false">
<v-button
class="sm:w-1/2 mr-4"
color="white"
@click.prevent="showDeleteFormModal = false"
>
Cancel
</v-button>
<v-button class="sm:w-1/2" color="red" :loading="loadingDelete" @click.prevent="deleteForm">
<v-button
class="sm:w-1/2"
color="red"
:loading="loadingDelete"
@click.prevent="deleteForm"
>
Yes, delete it
</v-button>
</div>
</div>
</modal>
<form-template-modal v-if="!isMainPage && user" :form="form" :show="showFormTemplateModal"
@close="showFormTemplateModal = false" />
<form-workspace-modal v-if="user" :form="form" :show="showFormWorkspaceModal"
@close="showFormWorkspaceModal = false" />
<form-template-modal
v-if="!isMainPage && user"
:form="form"
:show="showFormTemplateModal"
@close="showFormTemplateModal = false"
/>
<form-workspace-modal
v-if="user"
:form="form"
:show="showFormWorkspaceModal"
@close="showFormWorkspaceModal = false"
/>
</div>
</template>
<script setup>
import { ref, defineProps, computed } from 'vue'
import Dropdown from '~/components/global/Dropdown.vue'
import FormTemplateModal from '../../../open/forms/components/templates/FormTemplateModal.vue'
import FormWorkspaceModal from '../../../open/forms/components/FormWorkspaceModal.vue'
import { ref, defineProps, computed } from "vue"
import Dropdown from "~/components/global/Dropdown.vue"
import FormTemplateModal from "../../../open/forms/components/templates/FormTemplateModal.vue"
import FormWorkspaceModal from "../../../open/forms/components/FormWorkspaceModal.vue"
const { copy } = useClipboard()
const router = useRouter()
const props = defineProps({
form: { type: Object, required: true },
isMainPage: { type: Boolean, required: false, default: false }
isMainPage: { type: Boolean, required: false, default: false },
})
const authStore = useAuthStore()
const formsStore = useFormsStore()
const formEndpoint = '/open/forms/{id}'
let user = computed(() => authStore.user)
const formEndpoint = "/open/forms/{id}"
const user = computed(() => authStore.user)
let loadingDuplicate = ref(false)
let loadingDelete = ref(false)
let showDeleteFormModal = ref(false)
let showFormTemplateModal = ref(false)
let showFormWorkspaceModal = ref(false)
const loadingDuplicate = ref(false)
const loadingDelete = ref(false)
const showDeleteFormModal = ref(false)
const showFormTemplateModal = ref(false)
const showFormWorkspaceModal = ref(false)
const copyLink = () => {
copy(props.form.share_url)
useAlert().success('Copied!')
useAlert().success("Copied!")
}
const duplicateForm = () => {
if (loadingDuplicate.value) return
loadingDuplicate.value = true
opnFetch(formEndpoint.replace('{id}', props.form.id) + '/duplicate', { method: 'POST' }).then((data) => {
formsStore.save(data.new_form)
router.push({ name: 'forms-slug-show', params: { slug: data.new_form.slug } })
useAlert().success(data.message)
loadingDuplicate.value = false
}).catch((error) => {
useAlert().error(error.data.message)
loadingDuplicate.value = false
opnFetch(formEndpoint.replace("{id}", props.form.id) + "/duplicate", {
method: "POST",
})
.then((data) => {
formsStore.save(data.new_form)
router.push({
name: "forms-slug-show",
params: { slug: data.new_form.slug },
})
useAlert().success(data.message)
loadingDuplicate.value = false
})
.catch((error) => {
useAlert().error(error.data.message)
loadingDuplicate.value = false
})
}
const deleteForm = () => {
if (loadingDelete.value) return
loadingDelete.value = true
opnFetch(formEndpoint.replace('{id}', props.form.id), { method: 'DELETE' }).then((data) => {
formsStore.remove(props.form)
router.push({ name: 'home' })
useAlert().success(data.message)
loadingDelete.value = false
}).catch((error) => {
useAlert().error(error.data.message)
loadingDelete.value = false
})
opnFetch(formEndpoint.replace("{id}", props.form.id), { method: "DELETE" })
.then((data) => {
formsStore.remove(props.form)
router.push({ name: "home" })
useAlert().success(data.message)
loadingDelete.value = false
})
.catch((error) => {
useAlert().error(error.data.message)
loadingDelete.value = false
})
}
const showDraftFormWarningNotification = () => {
useAlert().warning('This form is currently in Draft mode and is not publicly accessible, You can change the form status on the edit form page.')
useAlert().warning(
"This form is currently in Draft mode and is not publicly accessible, You can change the form status on the edit form page.",
)
}
</script>

View File

@@ -1,46 +1,93 @@
<template>
<v-transition>
<div v-if="hasCleanings && !hideWarning" class="border border-gray-300 dark:border-gray-600 rounded-md bg-white p-2"
:class="{'hover:bg-yellow-50 dark:hover:bg-yellow-900':!collapseOpened}"
<div
v-if="hasCleanings && !hideWarning"
class="border border-gray-300 dark:border-gray-600 rounded-md bg-white p-2"
:class="{
'hover:bg-yellow-50 dark:hover:bg-yellow-900': !collapseOpened,
}"
>
<collapse v-model="collapseOpened">
<template #title>
<p class="text-yellow-500 dark:text-yellow-400 font-semibold text-sm p-1 pr-4">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6 inline"
<p
class="text-yellow-500 dark:text-yellow-400 font-semibold text-sm p-1 pr-4"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6 inline"
>
<path stroke-linecap="round" stroke-linejoin="round"
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
/>
</svg>
Some features that are included in our {{ form.is_pro ? 'Enterprise' : 'Pro' }} plan are disabled when
publicly sharing this form<span v-if="specifyFormOwner"> (only owners of this form can see this)</span>.
Some features that are included in our
{{ form.is_pro ? "Enterprise" : "Pro" }} plan are disabled when
publicly sharing this form<span v-if="specifyFormOwner">
(only owners of this form can see this)</span>.
</p>
</template>
<div class="border-t mt-1 p-4 pb-2 -mx-2">
<p class="text-gray-500 text-sm" v-html="cleaningContent" />
<p
class="text-gray-500 text-sm"
v-html="cleaningContent"
/>
<p class="text-gray-500 text-sm mb-4 font-semibold">
<NuxtLink :to="{name:'pricing'}">
{{ form.is_pro ? 'Upgrade your OpnForms plan today' : 'Start your free OpnForms trial' }}
<NuxtLink :to="{ name: 'pricing' }">
{{
form.is_pro
? "Upgrade your OpnForms plan today"
: "Start your free OpnForms trial"
}}
</NuxtLink>
to unlock all of our features and build powerful forms.
</p>
<div class="flex flex-wrap items-end w-full">
<div class="flex-grow flex pr-2">
<v-button v-track.upgrade_from_form_cleanings_click size="small" class="inline-block" :to="{name:'pricing'}">
{{ form.is_pro ? 'Upgrade plan' : 'Start free trial' }}
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-4 h-4 inline -mt-[2px]"
<v-button
v-track.upgrade_from_form_cleanings_click
size="small"
class="inline-block"
:to="{ name: 'pricing' }"
>
{{ form.is_pro ? "Upgrade plan" : "Start free trial" }}
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4 inline -mt-[2px]"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3" />
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3"
/>
</svg>
</v-button>
<v-button color="white" size="small" class="ml-2" @click.prevent="openCrisp">
<v-button
color="white"
size="small"
class="ml-2"
@click.prevent="openCrisp"
>
Contact us
</v-button>
</div>
<v-button v-if="hideable" color="white" size="small" class="mt-2" @click.prevent="hideWarning=true">
<v-button
v-if="hideable"
color="white"
size="small"
class="mt-2"
@click.prevent="hideWarning = true"
>
Hide warning
</v-button>
</div>
@@ -50,57 +97,58 @@
</v-transition>
</template>
<script>
import Collapse from '~/components/global/Collapse.vue'
import VButton from '~/components/global/VButton.vue'
import VTransition from '~/components/global/transitions/VTransition.vue'
import Collapse from "~/components/global/Collapse.vue"
import VButton from "~/components/global/VButton.vue"
import VTransition from "~/components/global/transitions/VTransition.vue"
export default {
name: 'FormCleanings',
name: "FormCleanings",
components: { VTransition, VButton, Collapse },
props: {
form: { type: Object, required: true },
specifyFormOwner: { type: Boolean, default: false },
hideable: { type: Boolean, default: false }
hideable: { type: Boolean, default: false },
},
data () {
data() {
return {
collapseOpened: false,
hideWarning: false
hideWarning: false,
}
},
computed: {
hasCleanings () {
hasCleanings() {
return this.form.cleanings && Object.keys(this.form.cleanings).length > 0
},
cleanings () {
cleanings() {
return this.form.cleanings
},
cleaningContent () {
let message = ''
cleaningContent() {
let message = ""
Object.keys(this.cleanings).forEach((key) => {
let fieldName = key.charAt(0).toUpperCase() + key.slice(1)
if (fieldName !== 'Form') {
if (fieldName !== "Form") {
fieldName = '"' + fieldName + '" field'
}
let fieldInfo = '<span class="font-semibold">' + fieldName + '</span><br/><ul class=\'list-disc list-inside\'>'
let fieldInfo =
'<span class="font-semibold">' +
fieldName +
"</span><br/><ul class='list-disc list-inside'>"
this.cleanings[key].forEach((msg) => {
fieldInfo = fieldInfo + '<li>' + msg + '</li>'
fieldInfo = fieldInfo + "<li>" + msg + "</li>"
})
if (fieldInfo) {
message = message + fieldInfo + '<ul/><br/>'
message = message + fieldInfo + "<ul/><br/>"
}
})
return message
}
},
},
watch: {},
mounted () {
},
mounted() {},
methods: {
openCrisp () {
openCrisp() {
useCrisp().openAndShowChat()
}
}
},
},
}
</script>

View File

@@ -1,50 +1,58 @@
<template>
<div>
<h3 class="font-semibold text-xl">QR Code</h3>
<h3 class="font-semibold text-xl">
QR Code
</h3>
<p>Scan the QR code to open the form (Right click to copy the image)</p>
<div class="flex items-center">
<img v-if="QrUrl" :src="QrUrl" class="m-auto" />
<img
v-if="QrUrl"
:src="QrUrl"
class="m-auto"
>
</div>
</div>
</template>
<script>
import QRCode from 'qrcode'
import QRCode from "qrcode"
export default {
name: 'FormQrCode',
name: "FormQrCode",
props: {
form: { type: Object, required: true },
extraQueryParam: { type: String, default: '' }
extraQueryParam: { type: String, default: "" },
},
data () {
data() {
return {
QrUrl: null
QrUrl: null,
}
},
computed: {
shareUrl () {
return (this.extraQueryParam) ? this.form.share_url + "?" + this.extraQueryParam : this.form.share_url + this.extraQueryParam
}
shareUrl() {
return this.extraQueryParam
? this.form.share_url + "?" + this.extraQueryParam
: this.form.share_url + this.extraQueryParam
},
},
watch: {
shareUrl () {
shareUrl() {
this.generateQR()
}
},
},
mounted () {
mounted() {
this.generateQR()
},
methods: {
generateQR () {
QRCode.toDataURL(this.shareUrl).then(url => {
generateQR() {
QRCode.toDataURL(this.shareUrl).then((url) => {
this.QrUrl = url
})
}
}
},
},
}
</script>

View File

@@ -1,27 +1,49 @@
<template>
<div>
<v-button
v-track.regenerate_form_link_click="{
form_id: form.id,
form_slug: form.slug,
}"
class="w-full"
color="light-gray"
v-track.regenerate_form_link_click="{form_id:form.id, form_slug:form.slug}"
@click="showGenerateFormLinkModal=true"
@click="showGenerateFormLinkModal = true"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-2 text-blue-600 inline" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 mr-2 text-blue-600 inline"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
/>
</svg>
Regenerate link
</v-button>
<!-- Regenerate form link modal -->
<modal :show="showGenerateFormLinkModal" @close="showGenerateFormLinkModal=false">
<modal
:show="showGenerateFormLinkModal"
@close="showGenerateFormLinkModal = false"
>
<template #icon>
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 text-blue-600" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-10 h-10 text-blue-600"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
/>
</svg>
</template>
@@ -31,19 +53,26 @@
<div class="p-4">
<p>
You can choose between two different URL formats for your form.
<span class="font-semibold">Be careful, changing your form URL is not a reversible operation</span>.
Make sure to udpate your form URL everywhere where it's used.
<span class="font-semibold">Be careful, changing your form URL is not a reversible
operation</span>. Make sure to udpate your form URL everywhere where it's used.
</p>
<div class="border-t py-4 mt-4">
<h3 class="text-xl text-gray-700 font-semibold">
Human Readable URL
</h3>
<p>If your users are going to see this url, you might want to make nice and readable. Example:</p>
<p>
If your users are going to see this url, you might want to make nice
and readable. Example:
</p>
<p class="text-gray-600 border p-4 bg-gray-50 rounded-md mt-4">
https://opnform.com/forms/contact
</p>
<div class="text-center mt-4">
<v-button :loading="loadingNewLink" color="outline-blue" @click="regenerateLink('slug')">
<v-button
:loading="loadingNewLink"
color="outline-blue"
@click="regenerateLink('slug')"
>
Generate a Human Readable URL
</v-button>
</div>
@@ -53,41 +82,43 @@
Random ID URL
</h3>
<p>
If your user are not going to see your form url (if it's embedded), and if you prefer to have a random
non-guessable URL. Example:
If your user are not going to see your form url (if it's embedded),
and if you prefer to have a random non-guessable URL. Example:
</p>
<p class="text-gray-600 p-4 border bg-gray-50 rounded-md mt-4">
https://opnform.com/forms/b4417f9c-34ae-4421-8006-832ee47786e7
</p>
<div class="text-center mt-4">
<v-button :loading="loadingNewLink" color="outline-blue" @click="regenerateLink('uuid')">
<v-button
:loading="loadingNewLink"
color="outline-blue"
@click="regenerateLink('uuid')"
>
Generate a Random ID URL
</v-button>
</div>
</div>
</div>
</modal>
</div>
</template>
<script>
import { computed } from 'vue'
import { useFormsStore } from '../../../../stores/forms'
import { useFormsStore } from "../../../../stores/forms"
export default {
name: 'RegenerateFormLink',
name: "RegenerateFormLink",
components: {},
props: {
form: { type: Object, required: true }
form: { type: Object, required: true },
},
setup () {
const formsStore = useFormsStore()
return {
formsStore
}
},
setup() {
const formsStore = useFormsStore()
return {
formsStore,
}
},
data: () => ({
loadingNewLink: false,
@@ -95,22 +126,32 @@ export default {
}),
computed: {
formEndpoint: () => '/open/forms/{id}',
formEndpoint: () => "/open/forms/{id}",
},
methods: {
regenerateLink(option) {
if (this.loadingNewLink) return
this.loadingNewLink = true
opnFetch(this.formEndpoint.replace('{id}', this.form.id) + '/regenerate-link/' + option, {method:'PUT'}).then((data) => {
this.formsStore.save(data.form)
this.$router.push({name: 'forms-slug-show-share', params: {slug: data.form.slug}})
useAlert().success(data.message)
this.loadingNewLink = false
}).finally(() => {
this.showGenerateFormLinkModal = false
})
opnFetch(
this.formEndpoint.replace("{id}", this.form.id) +
"/regenerate-link/" +
option,
{ method: "PUT" },
)
.then((data) => {
this.formsStore.save(data.form)
this.$router.push({
name: "forms-slug-show-share",
params: { slug: data.form.slug },
})
useAlert().success(data.message)
this.loadingNewLink = false
})
.finally(() => {
this.showGenerateFormLinkModal = false
})
},
}
},
}
</script>

View File

@@ -1,44 +1,58 @@
<template>
<div>
<h3 class="font-semibold text-xl">Share Link</h3>
<p>Your form is now published and ready to be shared with the world! Copy this link to share your form
on social media, messaging apps or via email.</p>
<copy-content :content="share_url" :is-draft="form.visibility=='draft'">
<template #icon>
<svg class="h-4 w-4 -mt-1 text-blue-600 inline mr-1" viewBox="0 0 20 10" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M7.49984 9.16634H5.83317C3.53198 9.16634 1.6665 7.30086 1.6665 4.99967C1.6665 2.69849 3.53198 0.833008 5.83317 0.833008H7.49984M12.4998 9.16634H14.1665C16.4677 9.16634 18.3332 7.30086 18.3332 4.99967C18.3332 2.69849 16.4677 0.833008 14.1665 0.833008H12.4998M5.83317 4.99967L14.1665 4.99968"
stroke="currentColor" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</template>
Copy Link
</copy-content>
<h3 class="font-semibold text-xl">
Share Link
</h3>
<p>
Your form is now published and ready to be shared with the world! Copy
this link to share your form on social media, messaging apps or via email.
</p>
<copy-content
:content="share_url"
:is-draft="form.visibility == 'draft'"
>
<template #icon>
<svg
class="h-4 w-4 -mt-1 text-blue-600 inline mr-1"
viewBox="0 0 20 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M7.49984 9.16634H5.83317C3.53198 9.16634 1.6665 7.30086 1.6665 4.99967C1.6665 2.69849 3.53198 0.833008 5.83317 0.833008H7.49984M12.4998 9.16634H14.1665C16.4677 9.16634 18.3332 7.30086 18.3332 4.99967C18.3332 2.69849 16.4677 0.833008 14.1665 0.833008H12.4998M5.83317 4.99967L14.1665 4.99968"
stroke="currentColor"
stroke-width="1.66667"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</template>
Copy Link
</copy-content>
</div>
</template>
<script>
import CopyContent from '../../../open/forms/components/CopyContent.vue'
import CopyContent from "../../../open/forms/components/CopyContent.vue"
export default {
name: 'ShareLink',
components: { CopyContent },
props: {
form: { type: Object, required: true },
extraQueryParam: { type: String, default: '' }
name: "ShareLink",
components: { CopyContent },
props: {
form: { type: Object, required: true },
extraQueryParam: { type: String, default: "" },
},
data: () => ({}),
computed: {
share_url() {
return this.extraQueryParam
? this.form.share_url + "?" + this.extraQueryParam
: this.form.share_url + this.extraQueryParam
},
},
data: () => ({
}),
computed: {
share_url () {
return (this.extraQueryParam) ? this.form.share_url + '?' + this.extraQueryParam : this.form.share_url + this.extraQueryParam
}
},
methods: {}
methods: {},
}
</script>

View File

@@ -1,25 +1,48 @@
<template>
<div class="flex">
<v-button
v-track.url_form_prefill_click="{
form_id: form.id,
form_slug: form.slug,
}"
class="w-full"
color="light-gray"
v-track.url_form_prefill_click="{form_id:form.id, form_slug:form.slug}"
@click="showUrlFormPrefillModal=true"
@click="showUrlFormPrefillModal = true"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-2 text-blue-600 inline" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17 16v2a2 2 0 01-2 2H5a2 2 0 01-2-2v-7a2 2 0 012-2h2m3-4H9a2 2 0 00-2 2v7a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-1m-1 4l-3 3m0 0l-3-3m3 3V3"
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 mr-2 text-blue-600 inline"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17 16v2a2 2 0 01-2 2H5a2 2 0 01-2-2v-7a2 2 0 012-2h2m3-4H9a2 2 0 00-2 2v7a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-1m-1 4l-3 3m0 0l-3-3m3 3V3"
/>
</svg>
Url pre-fill
</v-button>
<modal :show="showUrlFormPrefillModal" @close="showUrlFormPrefillModal=false">
<modal
:show="showUrlFormPrefillModal"
@close="showUrlFormPrefillModal = false"
>
<template #icon>
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 text-blue" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17 16v2a2 2 0 01-2 2H5a2 2 0 01-2-2v-7a2 2 0 012-2h2m3-4H9a2 2 0 00-2 2v7a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-1m-1 4l-3 3m0 0l-3-3m3 3V3"
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-10 h-10 text-blue"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17 16v2a2 2 0 01-2 2H5a2 2 0 01-2-2v-7a2 2 0 012-2h2m3-4H9a2 2 0 00-2 2v7a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-1m-1 4l-3 3m0 0l-3-3m3 3V3"
/>
</svg>
</template>
@@ -27,10 +50,15 @@
<span>Url Form Prefill</span>
</template>
<div class="p-4" ref="content">
<div
ref="content"
class="p-4"
>
<p>
Create dynamic links when sharing your form (whether it's embedded or not), that allows you to prefill
your form fields. You can use this to personalize the form when sending it to multiple contacts for instance.
Create dynamic links when sharing your form (whether it's embedded or
not), that allows you to prefill your form fields. You can use this to
personalize the form when sending it to multiple contacts for
instance.
</p>
<h3 class="mt-6 border-t text-xl font-semibold mb-4 pt-6">
@@ -38,13 +66,25 @@
</h3>
<p>
Complete your form below and fill only the fields you want to prefill. You can even leave the required fields empty.
Complete your form below and fill only the fields you want to prefill.
You can even leave the required fields empty.
</p>
<div class="rounded-lg p-5 bg-gray-100 dark:bg-gray-900 mt-4">
<open-form v-if="form" :theme="theme" :loading="false" :show-hidden="true" :form="form" :fields="form.properties" @submit="generateUrl">
<template #submit-btn="{submitForm}">
<v-button class="mt-2 px-8 mx-1" @click.prevent="submitForm">
<open-form
v-if="form"
:theme="theme"
:loading="false"
:show-hidden="true"
:form="form"
:fields="form.properties"
@submit="generateUrl"
>
<template #submit-btn="{ submitForm }">
<v-button
class="mt-2 px-8 mx-1"
@click.prevent="submitForm"
>
Generate Pre-filled URL
</v-button>
</template>
@@ -55,26 +95,28 @@
<h3 class="mt-6 text-xl font-semibold mb-4 pt-6">
Your Prefill url
</h3>
<form-url-prefill :form="form" :form-data="prefillFormData" :extra-query-param="extraQueryParam" />
<form-url-prefill
:form="form"
:form-data="prefillFormData"
:extra-query-param="extraQueryParam"
/>
</template>
</div>
</modal>
</div>
</template>
<script>
import FormUrlPrefill from '../../../open/forms/components/FormUrlPrefill.vue'
import ProTag from '~/components/global/ProTag.vue'
import OpenForm from '../../../open/forms/OpenForm.vue'
import { themes } from '~/lib/forms/form-themes.js'
import FormUrlPrefill from "../../../open/forms/components/FormUrlPrefill.vue"
import OpenForm from "../../../open/forms/OpenForm.vue"
import { themes } from "~/lib/forms/form-themes.js"
export default {
name: 'UrlFormPrefill',
components: { FormUrlPrefill, ProTag, OpenForm },
name: "UrlFormPrefill",
components: { FormUrlPrefill, OpenForm },
props: {
form: { type: Object, required: true },
extraQueryParam: { type: String, default: '' }
extraQueryParam: { type: String, default: "" },
},
data: () => ({
@@ -86,14 +128,15 @@ export default {
computed: {},
methods: {
generateUrl (formData, onFailure) {
generateUrl(formData) {
this.prefillFormData = formData
this.$nextTick().then(() => {
if (this.$refs.content) {
this.$refs.content.parentElement.parentElement.parentElement.scrollTop = this.$refs.content.offsetHeight
this.$refs.content.parentElement.parentElement.parentElement.scrollTop =
this.$refs.content.offsetHeight
}
})
}
}
},
},
}
</script>