Stuck at changing routes
This commit is contained in:
parent
358bf0e4d0
commit
3d3759c58c
|
@ -23,6 +23,6 @@ configureCompat({
|
||||||
})
|
})
|
||||||
|
|
||||||
router.app = app
|
router.app = app
|
||||||
app.mount('#app')
|
router.isReady().then(() => app.mount('#app'))
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
<template>
|
|
||||||
<Dropdown v-if="Object.keys(locales).length > 1"
|
|
||||||
dropdown-class="origin-top-right absolute right-0 mt-2 w-20 rounded-md shadow-lg bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5">
|
|
||||||
<template #trigger="{toggle}">
|
|
||||||
<a class="text-gray-300 hover:text-gray-800 dark:hover:text-white px-3 py-2 rounded-md text-sm font-medium" href="#" role="button" @click.prevent="toggle"
|
|
||||||
>
|
|
||||||
{{ locales[locale] }}
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<a v-for="(value, key) in locales" :key="key" class="block block text-center px-4 py-2 text-md text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center z-10" href="#"
|
|
||||||
@click.prevent="setLocale(key)"
|
|
||||||
>
|
|
||||||
{{ value }}
|
|
||||||
</a>
|
|
||||||
</Dropdown>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapGetters } from 'vuex'
|
|
||||||
import { loadMessages } from '~/plugins/i18n.js'
|
|
||||||
import Dropdown from './common/Dropdown.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: { Dropdown },
|
|
||||||
computed: mapGetters({
|
|
||||||
locale: 'lang/locale',
|
|
||||||
locales: 'lang/locales'
|
|
||||||
}),
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
setLocale (locale) {
|
|
||||||
if (this.$i18n.locale !== locale) {
|
|
||||||
loadMessages(locale)
|
|
||||||
|
|
||||||
this.$store.dispatch('lang/setLocale', { locale })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,11 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<v-button v-if="githubAuth" color="gray" type="button" @click="login">
|
<v-button v-if="githubAuth" color="gray" type="button" @click="login">
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
{{ $t('login_with') }}
|
Login with
|
||||||
<svg class="w-6 h-6 text-white ml-2" xmlns="http://www.w3.org/2000/svg"
|
<svg class="w-6 h-6 text-white ml-2" xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 24 24">
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
<path
|
<path
|
||||||
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</v-button>
|
</v-button>
|
||||||
|
@ -24,13 +26,13 @@ export default {
|
||||||
window.addEventListener('message', this.onMessage, false)
|
window.addEventListener('message', this.onMessage, false)
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy () {
|
beforeUnmount () {
|
||||||
window.removeEventListener('message', this.onMessage)
|
window.removeEventListener('message', this.onMessage)
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async login () {
|
async login () {
|
||||||
const newWindow = openWindow('', this.$t('login'))
|
const newWindow = openWindow('', 'Login')
|
||||||
|
|
||||||
const url = await this.$store.dispatch('auth/fetchOauthUrl', {
|
const url = await this.$store.dispatch('auth/fetchOauthUrl', {
|
||||||
provider: 'github'
|
provider: 'github'
|
||||||
|
|
|
@ -128,7 +128,7 @@ export default {
|
||||||
|
|
||||||
document.addEventListener('keydown', closeOnEscape)
|
document.addEventListener('keydown', closeOnEscape)
|
||||||
|
|
||||||
this.$once('hook:destroyed', () => {
|
this.$once('hook:unmounted', () => {
|
||||||
document.removeEventListener('keydown', closeOnEscape)
|
document.removeEventListener('keydown', closeOnEscape)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,34 +10,37 @@
|
||||||
>
|
>
|
||||||
{{ appName }}</span>
|
{{ appName }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
<workspace-dropdown class="ml-6"/>
|
<workspace-dropdown class="ml-6" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showAuth" class="hidden md:block ml-auto relative">
|
<div v-if="showAuth" class="hidden md:block ml-auto relative">
|
||||||
<router-link :to="{name:'templates'}" v-if="$route.name !== 'templates'"
|
<router-link v-if="$route.name !== 'templates'" :to="{name:'templates'}"
|
||||||
class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1 mr-8">
|
class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1 mr-8"
|
||||||
|
>
|
||||||
Templates
|
Templates
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link :to="{name:'aiformbuilder'}" v-if="$route.name !== 'aiformbuilder'"
|
<router-link v-if="$route.name !== 'aiformbuilder'" :to="{name:'aiformbuilder'}"
|
||||||
class="text-sm text-gray-600 dark:text-white hidden lg:inline hover:text-gray-800 cursor-pointer mt-1 mr-8">
|
class="text-sm text-gray-600 dark:text-white hidden lg:inline hover:text-gray-800 cursor-pointer mt-1 mr-8"
|
||||||
|
>
|
||||||
AI Form Builder
|
AI Form Builder
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link :to="{name:'pricing'}" v-if="paidPlansEnabled && (user===null || (user && workspace && !workspace.is_pro)) && $route.name !== 'pricing'"
|
<router-link v-if="paidPlansEnabled && (user===null || (user && workspace && !workspace.is_pro)) && $route.name !== 'pricing'" :to="{name:'pricing'}"
|
||||||
class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1 mr-8">
|
class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1 mr-8"
|
||||||
|
>
|
||||||
<span v-if="user">Upgrade</span>
|
<span v-if="user">Upgrade</span>
|
||||||
<span v-else>Pricing</span>
|
<span v-else>Pricing</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
<a href="#" class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1"
|
<a v-if="hasCrisp" href="#"
|
||||||
@click.prevent="openCrisp" v-if="hasCrisp"
|
class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1" @click.prevent="openCrisp"
|
||||||
>
|
>
|
||||||
Help
|
Help
|
||||||
</a>
|
</a>
|
||||||
<a :href="helpUrl" class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1"
|
<a v-else :href="helpUrl"
|
||||||
target="_blank" v-else
|
class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1" target="_blank"
|
||||||
>
|
>
|
||||||
Help
|
Help
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showAuth" class="hidden md:block pl-5 border-gray-300 border-r h-5"></div>
|
<div v-if="showAuth" class="hidden md:block pl-5 border-gray-300 border-r h-5" />
|
||||||
<div v-if="showAuth" class="block">
|
<div v-if="showAuth" class="block">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="ml-3 mr-4 relative">
|
<div class="ml-3 mr-4 relative">
|
||||||
|
@ -90,7 +93,7 @@
|
||||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
{{ $t('settings') }}
|
Settings
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<a href="#"
|
<a href="#"
|
||||||
|
@ -104,21 +107,20 @@
|
||||||
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
|
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
{{ $t('logout') }}
|
Logout
|
||||||
</a>
|
</a>
|
||||||
</dropdown>
|
</dropdown>
|
||||||
<div class="flex gap-2" v-else>
|
<div v-else class="flex gap-2">
|
||||||
<router-link v-if="$route.name !== 'login'" :to="{ name: 'login' }"
|
<router-link v-if="$route.name !== 'login'" :to="{ name: 'login' }"
|
||||||
class="text-gray-600 dark:text-white hover:text-gray-800 dark:hover:text-white px-0 sm:px-3 py-2 rounded-md text-sm"
|
class="text-gray-600 dark:text-white hover:text-gray-800 dark:hover:text-white px-0 sm:px-3 py-2 rounded-md text-sm"
|
||||||
active-class="text-gray-800 dark:text-white"
|
active-class="text-gray-800 dark:text-white"
|
||||||
>
|
>
|
||||||
{{ $t('login') }}
|
Login
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<v-button size="small" :to="{ name: 'forms.create.guest' }" color="outline-blue" v-track.nav_create_form_click :arrow="true">
|
<v-button v-track.nav_create_form_click size="small" :to="{ name: 'forms.create.guest' }" color="outline-blue" :arrow="true">
|
||||||
Create a form
|
Create a form
|
||||||
</v-button>
|
</v-button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -130,7 +132,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapGetters} from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import Dropdown from './common/Dropdown.vue'
|
import Dropdown from './common/Dropdown.vue'
|
||||||
import WorkspaceDropdown from './WorkspaceDropdown.vue'
|
import WorkspaceDropdown from './WorkspaceDropdown.vue'
|
||||||
|
|
||||||
|
@ -141,13 +143,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
appName: window.config.appName,
|
appName: window.config.appName
|
||||||
}),
|
}),
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
githubUrl: () => window.config.links.github_url,
|
githubUrl: () => window.config.links.github_url,
|
||||||
helpUrl: () => window.config.links.help_url,
|
helpUrl: () => window.config.links.help_url,
|
||||||
form() {
|
form () {
|
||||||
if (this.$route.name && this.$route.name.startsWith('forms.show_public')) {
|
if (this.$route.name && this.$route.name.startsWith('forms.show_public')) {
|
||||||
return this.$store.getters['open/forms/getBySlug'](this.$route.params.slug)
|
return this.$store.getters['open/forms/getBySlug'](this.$route.params.slug)
|
||||||
}
|
}
|
||||||
|
@ -156,13 +158,13 @@ export default {
|
||||||
workspace () {
|
workspace () {
|
||||||
return this.$store.getters['open/workspaces/getCurrent']()
|
return this.$store.getters['open/workspaces/getCurrent']()
|
||||||
},
|
},
|
||||||
paidPlansEnabled() {
|
paidPlansEnabled () {
|
||||||
return window.config.paid_plans_enabled
|
return window.config.paid_plans_enabled
|
||||||
},
|
},
|
||||||
showAuth() {
|
showAuth () {
|
||||||
return this.$route.name && !this.$route.name.startsWith('forms.show_public')
|
return this.$route.name && !this.$route.name.startsWith('forms.show_public')
|
||||||
},
|
},
|
||||||
hasNavbar() {
|
hasNavbar () {
|
||||||
if (this.isIframe) return false
|
if (this.isIframe) return false
|
||||||
|
|
||||||
if (this.$route.name && this.$route.name.startsWith('forms.show_public')) {
|
if (this.$route.name && this.$route.name.startsWith('forms.show_public')) {
|
||||||
|
@ -177,22 +179,22 @@ export default {
|
||||||
}
|
}
|
||||||
return !this.$root.navbarHidden
|
return !this.$root.navbarHidden
|
||||||
},
|
},
|
||||||
isIframe() {
|
isIframe () {
|
||||||
return window.location !== window.parent.location || window.frameElement
|
return window.location !== window.parent.location || window.frameElement
|
||||||
},
|
},
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
user: 'auth/user'
|
user: 'auth/user'
|
||||||
}),
|
}),
|
||||||
userOnboarded() {
|
userOnboarded () {
|
||||||
return this.user && this.user.workspaces_count > 0
|
return this.user && this.user.workspaces_count > 0
|
||||||
},
|
},
|
||||||
hasCrisp() {
|
hasCrisp () {
|
||||||
return window.config.crisp_website_id
|
return window.config.crisp_website_id
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async logout() {
|
async logout () {
|
||||||
// Log out the user.
|
// Log out the user.
|
||||||
await this.$store.dispatch('auth/logout')
|
await this.$store.dispatch('auth/logout')
|
||||||
|
|
||||||
|
@ -201,7 +203,7 @@ export default {
|
||||||
this.$store.dispatch('open/forms/resetState')
|
this.$store.dispatch('open/forms/resetState')
|
||||||
|
|
||||||
// Redirect to login.
|
// Redirect to login.
|
||||||
this.$router.push({name: 'login'})
|
this.$router.push({ name: 'login' })
|
||||||
},
|
},
|
||||||
openCrisp () {
|
openCrisp () {
|
||||||
window.$crisp.push(['do', 'chat:show'])
|
window.$crisp.push(['do', 'chat:show'])
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
<template>
|
|
||||||
<transition enter-active-class="linear duration-500 overflow-hidden"
|
|
||||||
enter-from-class="max-h-0 opacity-0"
|
|
||||||
enter-to-class="max-h-screen opacity-100"
|
|
||||||
leave-active-class="linear duration-500 overflow-hidden"
|
|
||||||
leave-from-class="max-h-screen opacity-100"
|
|
||||||
leave-to-class="max-h-0 opacity-0"
|
|
||||||
>
|
|
||||||
<div :class="alertClasses" class="border shadow-sm p-2 flex items-center rounded-md">
|
|
||||||
<div class="flex-grow">
|
|
||||||
<p class="mb-0 py-2 px-4" :class="textClasses" v-html="message" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="justify-end">
|
|
||||||
<v-button v-if="type == 'error'" color="red" shade="light" @click="close">
|
|
||||||
Close
|
|
||||||
</v-button>
|
|
||||||
<v-button v-if="type == 'success'" color="green" shade="light" @click="close">
|
|
||||||
OK
|
|
||||||
</v-button>
|
|
||||||
<v-button v-if="type == 'warning'" color="yellow" shade="light" @click="close">
|
|
||||||
OK
|
|
||||||
</v-button>
|
|
||||||
<v-button v-if="type == 'confirmation'" class="mr-1 mb-1" @click="confirm">
|
|
||||||
Yes
|
|
||||||
</v-button>
|
|
||||||
<v-button v-if="type == 'confirmation'" color="gray" shade="light" @click="cancel">
|
|
||||||
No, cancel
|
|
||||||
</v-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'Alert',
|
|
||||||
props: ['type', 'message', 'autoClose', 'confirmationProceed', 'confirmationCancel'],
|
|
||||||
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
timeout: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
alertClasses () {
|
|
||||||
if (this.type === 'error') return 'bg-red-100 border-red-500'
|
|
||||||
if (this.type === 'success') return 'bg-green-100 border-green-500'
|
|
||||||
if (this.type === 'warning') return 'bg-yellow-100 border-yellow-500'
|
|
||||||
return 'bg-blue-50 border-nt-blue-light'
|
|
||||||
},
|
|
||||||
textClasses () {
|
|
||||||
if (this.type === 'error') return 'text-red-600'
|
|
||||||
if (this.type === 'success') return 'text-green-600'
|
|
||||||
if (this.type === 'warning') return 'text-yellow-600'
|
|
||||||
return 'text-nt-blue'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
|
||||||
if (this.autoClose) {
|
|
||||||
this.timeout = setTimeout(() => {
|
|
||||||
this.close()
|
|
||||||
}, this.autoClose)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
/**
|
|
||||||
* Close the modal.
|
|
||||||
*/
|
|
||||||
close () {
|
|
||||||
clearTimeout(this.timeout)
|
|
||||||
this.$emit('close')
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Confirm and close the modal.
|
|
||||||
*/
|
|
||||||
confirm () {
|
|
||||||
this.confirmationProceed()
|
|
||||||
this.close()
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Cancel and close the modal.
|
|
||||||
*/
|
|
||||||
cancel () {
|
|
||||||
if (this.confirmationCancel) {
|
|
||||||
this.confirmationCancel()
|
|
||||||
}
|
|
||||||
this.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -60,19 +60,19 @@ export default {
|
||||||
const scrollContainerObserver = newResizeObserver(this.toggleShadow)
|
const scrollContainerObserver = newResizeObserver(this.toggleShadow)
|
||||||
if (scrollContainerObserver) {
|
if (scrollContainerObserver) {
|
||||||
scrollContainerObserver.observe(this.$refs.scrollContainer)
|
scrollContainerObserver.observe(this.$refs.scrollContainer)
|
||||||
// Cleanup when the component is destroyed.
|
// Cleanup when the component is unmounted.
|
||||||
this.$once('hook:destroyed', () => scrollContainerObserver.disconnect())
|
this.$once('hook:unmounted', () => scrollContainerObserver.disconnect())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculate the container dimensions when the wrapper is resized.
|
// Recalculate the container dimensions when the wrapper is resized.
|
||||||
const wrapObserver = newResizeObserver(this.calcDimensions)
|
const wrapObserver = newResizeObserver(this.calcDimensions)
|
||||||
if (wrapObserver) {
|
if (wrapObserver) {
|
||||||
wrapObserver.observe(this.$el)
|
wrapObserver.observe(this.$el)
|
||||||
// Cleanup when the component is destroyed.
|
// Cleanup when the component is unmounted.
|
||||||
this.$once('hook:destroyed', () => wrapObserver.disconnect())
|
this.$once('hook:unmounted', () => wrapObserver.disconnect())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destroyed () {
|
unmounted () {
|
||||||
window.removeEventListener('resize', this.calcDimensions)
|
window.removeEventListener('resize', this.calcDimensions)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -55,21 +55,21 @@
|
||||||
Please create this form on a device with a larger screen. That will allow you to preview your form changes.
|
Please create this form on a device with a larger screen. That will allow you to preview your form changes.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form-information/>
|
<form-information />
|
||||||
<form-structure/>
|
<form-structure />
|
||||||
<form-customization/>
|
<form-customization />
|
||||||
<form-about-submission/>
|
<form-about-submission />
|
||||||
<form-notifications/>
|
<form-notifications />
|
||||||
<form-security-privacy/>
|
<form-security-privacy />
|
||||||
<form-custom-seo />
|
<form-custom-seo />
|
||||||
<form-custom-code/>
|
<form-custom-code />
|
||||||
<form-integrations/>
|
<form-integrations />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form-editor-preview/>
|
<form-editor-preview />
|
||||||
|
|
||||||
<form-field-edit-sidebar/>
|
<form-field-edit-sidebar />
|
||||||
<add-form-block-sidebar/>
|
<add-form-block-sidebar />
|
||||||
|
|
||||||
<!-- Form Error Modal -->
|
<!-- Form Error Modal -->
|
||||||
<form-error-modal
|
<form-error-modal
|
||||||
|
@ -80,12 +80,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="flex justify-center items-center">
|
<div v-else class="flex justify-center items-center">
|
||||||
<loader class="w-6 h-6"/>
|
<loader class="w-6 h-6" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapGetters} from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import AddFormBlockSidebar from './form-components/AddFormBlockSidebar.vue'
|
import AddFormBlockSidebar from './form-components/AddFormBlockSidebar.vue'
|
||||||
import FormFieldEditSidebar from '../fields/FormFieldEditSidebar.vue'
|
import FormFieldEditSidebar from '../fields/FormFieldEditSidebar.vue'
|
||||||
import FormErrorModal from './form-components/FormErrorModal.vue'
|
import FormErrorModal from './form-components/FormErrorModal.vue'
|
||||||
|
@ -143,7 +143,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
showFormErrorModal: false,
|
showFormErrorModal: false,
|
||||||
validationErrorResponse: null,
|
validationErrorResponse: null,
|
||||||
|
@ -157,21 +157,21 @@ export default {
|
||||||
user: 'auth/user'
|
user: 'auth/user'
|
||||||
}),
|
}),
|
||||||
form: {
|
form: {
|
||||||
get() {
|
get () {
|
||||||
return this.$store.state['open/working_form'].content
|
return this.$store.state['open/working_form'].content
|
||||||
},
|
},
|
||||||
/* We add a setter */
|
/* We add a setter */
|
||||||
set(value) {
|
set (value) {
|
||||||
this.$store.commit('open/working_form/set', value)
|
this.$store.commit('open/working_form/set', value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createdForm() {
|
createdForm () {
|
||||||
return this.$store.getters['open/forms/getById'](this.createdFormId)
|
return this.$store.getters['open/forms/getById'](this.createdFormId)
|
||||||
},
|
},
|
||||||
workspace() {
|
workspace () {
|
||||||
return this.$store.getters['open/workspaces/getCurrent']()
|
return this.$store.getters['open/workspaces/getCurrent']()
|
||||||
},
|
},
|
||||||
steps() {
|
steps () {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
target: '#v-step-0',
|
target: '#v-step-0',
|
||||||
|
@ -211,12 +211,12 @@ export default {
|
||||||
|
|
||||||
watch: {},
|
watch: {},
|
||||||
|
|
||||||
mounted() {
|
mounted () {
|
||||||
this.$emit('mounted')
|
this.$emit('mounted')
|
||||||
this.$root.hideNavbar()
|
this.$root.hideNavbar()
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy () {
|
beforeUnmount () {
|
||||||
this.$root.hideNavbar(false)
|
this.$root.hideNavbar(false)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -225,12 +225,12 @@ export default {
|
||||||
window.$crisp.push(['do', 'chat:show'])
|
window.$crisp.push(['do', 'chat:show'])
|
||||||
window.$crisp.push(['do', 'chat:open'])
|
window.$crisp.push(['do', 'chat:open'])
|
||||||
},
|
},
|
||||||
showValidationErrors() {
|
showValidationErrors () {
|
||||||
this.showFormErrorModal = true
|
this.showFormErrorModal = true
|
||||||
},
|
},
|
||||||
saveForm() {
|
saveForm () {
|
||||||
this.form.properties = this.validateFieldsLogic(this.form.properties)
|
this.form.properties = this.validateFieldsLogic(this.form.properties)
|
||||||
if(this.isGuest) {
|
if (this.isGuest) {
|
||||||
this.saveFormGuest()
|
this.saveFormGuest()
|
||||||
} else if (this.isEdit) {
|
} else if (this.isEdit) {
|
||||||
this.saveFormEdit()
|
this.saveFormEdit()
|
||||||
|
@ -238,7 +238,7 @@ export default {
|
||||||
this.saveFormCreate()
|
this.saveFormCreate()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveFormEdit() {
|
saveFormEdit () {
|
||||||
if (this.updateFormLoading) return
|
if (this.updateFormLoading) return
|
||||||
|
|
||||||
this.updateFormLoading = true
|
this.updateFormLoading = true
|
||||||
|
@ -247,8 +247,8 @@ export default {
|
||||||
const data = response.data
|
const data = response.data
|
||||||
this.$store.commit('open/forms/addOrUpdate', data.form)
|
this.$store.commit('open/forms/addOrUpdate', data.form)
|
||||||
this.$emit('on-save')
|
this.$emit('on-save')
|
||||||
this.$router.push({name: 'forms.show', params: {slug: this.form.slug}})
|
this.$router.push({ name: 'forms.show', params: { slug: this.form.slug } })
|
||||||
this.$logEvent('form_saved', {form_id: this.form.id, form_slug: this.form.slug})
|
this.$logEvent('form_saved', { form_id: this.form.id, form_slug: this.form.slug })
|
||||||
this.displayFormModificationAlert(data)
|
this.displayFormModificationAlert(data)
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
if (error.response.status === 422) {
|
if (error.response.status === 422) {
|
||||||
|
@ -259,7 +259,7 @@ export default {
|
||||||
this.updateFormLoading = false
|
this.updateFormLoading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
saveFormCreate() {
|
saveFormCreate () {
|
||||||
if (this.updateFormLoading) return
|
if (this.updateFormLoading) return
|
||||||
this.form.workspace_id = this.workspace.id
|
this.form.workspace_id = this.workspace.id
|
||||||
this.validationErrorResponse = null
|
this.validationErrorResponse = null
|
||||||
|
@ -270,7 +270,7 @@ export default {
|
||||||
this.$emit('on-save')
|
this.$emit('on-save')
|
||||||
this.createdFormId = response.data.form.id
|
this.createdFormId = response.data.form.id
|
||||||
|
|
||||||
this.$logEvent('form_created', {form_id: response.data.form.id, form_slug: response.data.form.slug})
|
this.$logEvent('form_created', { form_id: response.data.form.id, form_slug: response.data.form.slug })
|
||||||
this.$crisp.push(['set', 'session:event', [[['form_created', {
|
this.$crisp.push(['set', 'session:event', [[['form_created', {
|
||||||
form_id: response.data.form.id,
|
form_id: response.data.form.id,
|
||||||
form_slug: response.data.form.slug
|
form_slug: response.data.form.slug
|
||||||
|
@ -292,7 +292,7 @@ export default {
|
||||||
this.updateFormLoading = false
|
this.updateFormLoading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
saveFormGuest() {
|
saveFormGuest () {
|
||||||
this.$emit('openRegister')
|
this.$emit('openRegister')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,71 +7,72 @@
|
||||||
:class="{'absolute': data.length !== 0}"
|
:class="{'absolute': data.length !== 0}"
|
||||||
style="will-change: transform; transform: translate3d(0px, 0px, 0px)"
|
style="will-change: transform; transform: translate3d(0px, 0px, 0px)"
|
||||||
>
|
>
|
||||||
<tr class="n-table-row overflow-x-hidden">
|
<tr class="n-table-row overflow-x-hidden">
|
||||||
<resizable-th v-for="col, index in form.properties" :id="'table-head-cell-' + col.id" :key="col.id"
|
<resizable-th v-for="col, index in form.properties" :id="'table-head-cell-' + col.id" :key="col.id"
|
||||||
scope="col" :allow-resize="allowResize" :width="(col.cell_width ? col.cell_width + 'px':'auto')"
|
scope="col" :allow-resize="allowResize" :width="(col.cell_width ? col.cell_width + 'px':'auto')"
|
||||||
class="n-table-cell p-0 relative"
|
class="n-table-cell p-0 relative"
|
||||||
@resize-width="resizeCol(col, $event)"
|
@resize-width="resizeCol(col, $event)"
|
||||||
>
|
|
||||||
<p
|
|
||||||
:class="{'border-r': index < form.properties.length - 1 || hasActions}"
|
|
||||||
class="bg-gray-50 dark:bg-notion-dark truncate sticky top-0 border-b border-gray-200 dark:border-gray-800 px-4 py-2 text-gray-500 font-semibold tracking-wider uppercase text-xs"
|
|
||||||
>
|
>
|
||||||
{{ col.name }}
|
<p
|
||||||
</p>
|
:class="{'border-r': index < form.properties.length - 1 || hasActions}"
|
||||||
</resizable-th>
|
class="bg-gray-50 dark:bg-notion-dark truncate sticky top-0 border-b border-gray-200 dark:border-gray-800 px-4 py-2 text-gray-500 font-semibold tracking-wider uppercase text-xs"
|
||||||
<th v-if="hasActions" class="n-table-cell p-0 relative" style="width: 100px">
|
>
|
||||||
<p
|
{{ col.name }}
|
||||||
class="bg-gray-50 dark:bg-notion-dark truncate sticky top-0 border-b border-gray-200 dark:border-gray-800 px-4 py-2 text-gray-500 font-semibold tracking-wider uppercase text-xs">
|
</p>
|
||||||
Actions
|
</resizable-th>
|
||||||
</p>
|
<th v-if="hasActions" class="n-table-cell p-0 relative" style="width: 100px">
|
||||||
</th>
|
<p
|
||||||
</tr>
|
class="bg-gray-50 dark:bg-notion-dark truncate sticky top-0 border-b border-gray-200 dark:border-gray-800 px-4 py-2 text-gray-500 font-semibold tracking-wider uppercase text-xs"
|
||||||
|
>
|
||||||
|
Actions
|
||||||
|
</p>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-if="data.length > 0" class="n-table-body bg-white dark:bg-notion-dark-light">
|
<tbody v-if="data.length > 0" class="n-table-body bg-white dark:bg-notion-dark-light">
|
||||||
<tr v-if="$slots.hasOwnProperty('actions')"
|
<tr v-if="$slots.hasOwnProperty('actions')"
|
||||||
:id="'table-actions-'+tableHash"
|
:id="'table-actions-'+tableHash"
|
||||||
ref="actions-row"
|
ref="actions-row"
|
||||||
class="action-row absolute w-full"
|
class="action-row absolute w-full"
|
||||||
style="will-change: transform; transform: translate3d(0px, 32px, 0px)"
|
style="will-change: transform; transform: translate3d(0px, 32px, 0px)"
|
||||||
>
|
>
|
||||||
<td :colspan="form.properties.length" class="p-1">
|
<td :colspan="form.properties.length" class="p-1">
|
||||||
<slot name="actions"/>
|
<slot name="actions" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="row, index in data" :key="index" class="n-table-row" :class="{'first':index===0}">
|
<tr v-for="row, index in data" :key="index" class="n-table-row" :class="{'first':index===0}">
|
||||||
<td v-for="col, colIndex in form.properties"
|
<td v-for="col, colIndex in form.properties"
|
||||||
:key="col.id"
|
:key="col.id"
|
||||||
:style="{width: col.cell_width + 'px'}"
|
:style="{width: col.cell_width + 'px'}"
|
||||||
class="n-table-cell border-gray-100 dark:border-gray-900 text-sm p-2 overflow-hidden"
|
class="n-table-cell border-gray-100 dark:border-gray-900 text-sm p-2 overflow-hidden"
|
||||||
:class="[{'border-b': index !== data.length - 1, 'border-r': colIndex !== form.properties.length - 1 || hasActions},
|
:class="[{'border-b': index !== data.length - 1, 'border-r': colIndex !== form.properties.length - 1 || hasActions},
|
||||||
colClasses(col)]"
|
colClasses(col)]"
|
||||||
>
|
>
|
||||||
<component :is="fieldComponents[col.type]" class="border-gray-100 dark:border-gray-900"
|
<component :is="fieldComponents[col.type]" class="border-gray-100 dark:border-gray-900"
|
||||||
:property="col" :value="row[col.id]"
|
:property="col" :value="row[col.id]"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td v-if="hasActions" class="n-table-cell border-gray-100 dark:border-gray-900 text-sm p-2 border-b"
|
<td v-if="hasActions" class="n-table-cell border-gray-100 dark:border-gray-900 text-sm p-2 border-b"
|
||||||
style="width: 100px"
|
style="width: 100px"
|
||||||
>
|
>
|
||||||
<record-operations :form="form" :structure="form.properties" :rowid="row.id" @deleted="$emit('deleted')" />
|
<record-operations :form="form" :structure="form.properties" :rowid="row.id" @deleted="$emit('deleted')" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="loading" class="n-table-row border-t bg-gray-50 dark:bg-gray-900">
|
<tr v-if="loading" class="n-table-row border-t bg-gray-50 dark:bg-gray-900">
|
||||||
<td :colspan="form.properties.length" class="p-8 w-full">
|
<td :colspan="form.properties.length" class="p-8 w-full">
|
||||||
<loader class="w-4 h-4 mx-auto"/>
|
<loader class="w-4 h-4 mx-auto" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tbody v-else key="body-content" class="n-table-body">
|
<tbody v-else key="body-content" class="n-table-body">
|
||||||
<tr class="n-table-row loader w-full">
|
<tr class="n-table-row loader w-full">
|
||||||
<td :colspan="form.properties.length" class="n-table-cell w-full p-8">
|
<td :colspan="form.properties.length" class="n-table-cell w-full p-8">
|
||||||
<loader v-if="loading" class="w-4 h-4 mx-auto"/>
|
<loader v-if="loading" class="w-4 h-4 mx-auto" />
|
||||||
<p v-else class="text-gray-500 text-center">
|
<p v-else class="text-gray-500 text-center">
|
||||||
No data found.
|
No data found.
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</template>
|
</template>
|
||||||
|
@ -101,7 +102,7 @@ const cyrb53 = function (str, seed = 0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {ResizableTh, RecordOperations},
|
components: { ResizableTh, RecordOperations },
|
||||||
props: {
|
props: {
|
||||||
data: {
|
data: {
|
||||||
type: Array,
|
type: Array,
|
||||||
|
@ -115,10 +116,10 @@ export default {
|
||||||
required: false,
|
required: false,
|
||||||
default: true,
|
default: true,
|
||||||
type: Boolean
|
type: Boolean
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
tableHash: null,
|
tableHash: null,
|
||||||
skip: false
|
skip: false
|
||||||
|
@ -127,18 +128,18 @@ export default {
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
form: {
|
form: {
|
||||||
get() {
|
get () {
|
||||||
return this.$store.state['open/working_form'].content
|
return this.$store.state['open/working_form'].content
|
||||||
},
|
},
|
||||||
set(value) {
|
set (value) {
|
||||||
this.$store.commit('open/working_form/set', value)
|
this.$store.commit('open/working_form/set', value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hasActions() {
|
hasActions () {
|
||||||
// In future if want to hide based on condition
|
// In future if want to hide based on condition
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
fieldComponents() {
|
fieldComponents () {
|
||||||
return {
|
return {
|
||||||
text: OpenText,
|
text: OpenText,
|
||||||
number: OpenText,
|
number: OpenText,
|
||||||
|
@ -150,35 +151,35 @@ export default {
|
||||||
url: OpenUrl,
|
url: OpenUrl,
|
||||||
email: OpenText,
|
email: OpenText,
|
||||||
phone_number: OpenText,
|
phone_number: OpenText,
|
||||||
signature: OpenFile,
|
signature: OpenFile
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
'form.properties': {
|
'form.properties': {
|
||||||
handler() {
|
handler () {
|
||||||
this.onStructureChange()
|
this.onStructureChange()
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.handleScroll()
|
this.handleScroll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted () {
|
||||||
const parent = document.getElementById('table-page')
|
const parent = document.getElementById('table-page')
|
||||||
this.tableHash = cyrb53(JSON.stringify(this.form.properties))
|
this.tableHash = cyrb53(JSON.stringify(this.form.properties))
|
||||||
parent.addEventListener('scroll', this.handleScroll, {passive: true})
|
parent.addEventListener('scroll', this.handleScroll, { passive: true })
|
||||||
window.addEventListener('resize', this.handleScroll)
|
window.addEventListener('resize', this.handleScroll)
|
||||||
this.onStructureChange()
|
this.onStructureChange()
|
||||||
this.handleScroll()
|
this.handleScroll()
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeUnmount () {
|
||||||
const parent = document.getElementById('table-page')
|
const parent = document.getElementById('table-page')
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent.removeEventListener('scroll', this.handleScroll)
|
parent.removeEventListener('scroll', this.handleScroll)
|
||||||
|
@ -187,7 +188,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
colClasses(col) {
|
colClasses (col) {
|
||||||
let colAlign, colColor, colFontWeight, colWrap
|
let colAlign, colColor, colFontWeight, colWrap
|
||||||
|
|
||||||
// Column align
|
// Column align
|
||||||
|
@ -212,7 +213,7 @@ export default {
|
||||||
|
|
||||||
return [colAlign, colColor, colWrap, colFontWeight]
|
return [colAlign, colColor, colWrap, colFontWeight]
|
||||||
},
|
},
|
||||||
onStructureChange() {
|
onStructureChange () {
|
||||||
if (this.form && this.form.properties) {
|
if (this.form && this.form.properties) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.form.properties.forEach(col => {
|
this.form.properties.forEach(col => {
|
||||||
|
@ -226,7 +227,7 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resizeCol(col, width) {
|
resizeCol (col, width) {
|
||||||
if (!this.form) return
|
if (!this.form) return
|
||||||
const columns = clonedeep(this.form.properties)
|
const columns = clonedeep(this.form.properties)
|
||||||
const index = this.form.properties.findIndex(c => c.id === col.id)
|
const index = this.form.properties.findIndex(c => c.id === col.id)
|
||||||
|
@ -236,7 +237,7 @@ export default {
|
||||||
this.$emit('resize')
|
this.$emit('resize')
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
handleScroll() {
|
handleScroll () {
|
||||||
const parent = document.getElementById('table-page')
|
const parent = document.getElementById('table-page')
|
||||||
const posTop = parent.getBoundingClientRect().top
|
const posTop = parent.getBoundingClientRect().top
|
||||||
const tablePosition = Math.max(0, posTop - this.$refs.table.getBoundingClientRect().top)
|
const tablePosition = Math.max(0, posTop - this.$refs.table.getBoundingClientRect().top)
|
||||||
|
@ -264,7 +265,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,49 +2,20 @@
|
||||||
<div class="main-layout min-h-screen flex flex-col">
|
<div class="main-layout min-h-screen flex flex-col">
|
||||||
<navbar />
|
<navbar />
|
||||||
|
|
||||||
<div class="w-full md:w-4/5 lg:w-3/5 md:mx-auto md:max-w-4xl px-4">
|
|
||||||
<alert v-if="alert.type"
|
|
||||||
class="my-4"
|
|
||||||
:message="alert.message"
|
|
||||||
:type="alert.type"
|
|
||||||
:auto-close="alert.autoClose"
|
|
||||||
:confirmation-proceed="alert.confirmationProceed"
|
|
||||||
:confirmation-cancel="alert.confirmationCancel"
|
|
||||||
@close="closeAlert"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<child class="flex-grow" />
|
<child class="flex-grow" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Navbar from '~/components/Navbar.vue'
|
import Navbar from '~/components/Navbar.vue'
|
||||||
import Alert from '../components/common/Alert.vue'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MainLayout',
|
name: 'MainLayout',
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
Navbar, Alert
|
Navbar
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {}
|
||||||
alert () {
|
|
||||||
return this.$root.alert
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
closeAlert () {
|
|
||||||
this.$root.alert = {
|
|
||||||
type: null,
|
|
||||||
autoClose: 0,
|
|
||||||
message: '',
|
|
||||||
confirmationProceed: null,
|
|
||||||
confirmationCancel: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import store from '~/store'
|
|
||||||
import { loadMessages } from '~/plugins/i18n'
|
|
||||||
|
|
||||||
export default async (to, from, next) => {
|
|
||||||
await loadMessages(store.getters['lang/locale'])
|
|
||||||
|
|
||||||
next()
|
|
||||||
}
|
|
|
@ -2,35 +2,39 @@
|
||||||
<div>
|
<div>
|
||||||
<forgot-password-modal :show="showForgotModal" @close="showForgotModal=false" />
|
<forgot-password-modal :show="showForgotModal" @close="showForgotModal=false" />
|
||||||
|
|
||||||
<form @submit.prevent="login" @keydown="form.onKeydown($event)" class="mt-4">
|
<form class="mt-4" @submit.prevent="login" @keydown="form.onKeydown($event)">
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<text-input name="email" :form="form" :label="$t('email')" :required="true" placeholder="Your email address" />
|
<text-input name="email" :form="form" label="Email" :required="true" placeholder="Your email address" />
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<text-input native-type="password" placeholder="Your password"
|
<text-input native-type="password" placeholder="Your password"
|
||||||
name="password" :form="form" :label="$t('password')" :required="true"
|
name="password" :form="form" label="Password" :required="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Remember Me -->
|
<!-- Remember Me -->
|
||||||
<div class="relative flex items-center my-5">
|
<div class="relative flex items-center my-5">
|
||||||
<v-checkbox v-model="remember" class="w-full md:w-1/2" name="remember" size="small">
|
<v-checkbox v-model="remember" class="w-full md:w-1/2" name="remember" size="small">
|
||||||
{{ $t('remember_me') }}
|
Remember me
|
||||||
</v-checkbox>
|
</v-checkbox>
|
||||||
|
|
||||||
<div class="w-full md:w-1/2 text-right">
|
<div class="w-full md:w-1/2 text-right">
|
||||||
<a href="#" @click.prevent="showForgotModal=true" class="text-xs hover:underline text-gray-500 sm:text-sm hover:text-gray-700">
|
<a href="#" class="text-xs hover:underline text-gray-500 sm:text-sm hover:text-gray-700" @click.prevent="showForgotModal=true">
|
||||||
Forgot your password?
|
Forgot your password?
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<v-button dusk="btn_login" :loading="form.busy">Log in to continue</v-button>
|
<v-button dusk="btn_login" :loading="form.busy">
|
||||||
|
Log in to continue
|
||||||
|
</v-button>
|
||||||
|
|
||||||
<p class="text-gray-500 mt-4">
|
<p class="text-gray-500 mt-4">
|
||||||
Don't have an account?
|
Don't have an account?
|
||||||
<a href="#" v-if="isQuick" @click.prevent="$emit('openRegister')" class="font-semibold ml-1">Sign Up</a>
|
<a v-if="isQuick" href="#" class="font-semibold ml-1" @click.prevent="$emit('openRegister')">Sign Up</a>
|
||||||
<router-link v-else :to="{name:'register'}" class="font-semibold ml-1">Sign Up</router-link>
|
<router-link v-else :to="{name:'register'}" class="font-semibold ml-1">
|
||||||
|
Sign Up
|
||||||
|
</router-link>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,7 +60,7 @@ export default {
|
||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
form: new Form({
|
form: new Form({
|
||||||
|
@ -86,7 +90,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
redirect () {
|
redirect () {
|
||||||
if(this.isQuick){
|
if (this.isQuick) {
|
||||||
this.$emit('afterQuickLogin')
|
this.$emit('afterQuickLogin')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<form @submit.prevent="register" @keydown="form.onKeydown($event)" class="mt-4">
|
<form class="mt-4" @submit.prevent="register" @keydown="form.onKeydown($event)">
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<text-input name="name" :form="form" :label="$t('name')" placeholder="Your name" :required="true" />
|
<text-input name="name" :form="form" label="Name" placeholder="Your name" :required="true" />
|
||||||
|
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<text-input name="email" :form="form" :label="$t('email')" :required="true" placeholder="Your email address" />
|
<text-input name="email" :form="form" label="Email" :required="true" placeholder="Your email address" />
|
||||||
|
|
||||||
<select-input name="hear_about_us" :options="hearAboutUsOptions" :form="form" placeholder="Select option"
|
<select-input name="hear_about_us" :options="hearAboutUsOptions" :form="form" placeholder="Select option"
|
||||||
label="How did you hear about us?" :required="true"
|
label="How did you hear about us?" :required="true"
|
||||||
|
@ -13,27 +13,35 @@
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<text-input native-type="password" placeholder="Enter password"
|
<text-input native-type="password" placeholder="Enter password"
|
||||||
name="password" :form="form" :label="$t('password')" :required="true"
|
name="password" :form="form" label="Password" :required="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Password Confirmation-->
|
<!-- Password Confirmation-->
|
||||||
<text-input native-type="password" :form="form" :required="true" placeholder="Enter confirm password"
|
<text-input native-type="password" :form="form" :required="true" placeholder="Enter confirm password"
|
||||||
name="password_confirmation" :label="$t('confirm_password')"
|
name="password_confirmation" label="Confirm Password"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<checkbox-input :form="form" name="agree_terms" :required="true">
|
<checkbox-input :form="form" name="agree_terms" :required="true">
|
||||||
<template #label>
|
<template #label>
|
||||||
I agree with the <router-link :to="{name:'terms-conditions'}" target="_blank">Terms and conditions</router-link> and <router-link :to="{name:'privacy-policy'}" target="_blank">Privacy policy</router-link> of the website and I accept them.
|
I agree with the <router-link :to="{name:'terms-conditions'}" target="_blank">
|
||||||
|
Terms and conditions
|
||||||
|
</router-link> and <router-link :to="{name:'privacy-policy'}" target="_blank">
|
||||||
|
Privacy policy
|
||||||
|
</router-link> of the website and I accept them.
|
||||||
</template>
|
</template>
|
||||||
</checkbox-input>
|
</checkbox-input>
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<v-button :loading="form.busy">Create an account</v-button>
|
<v-button :loading="form.busy">
|
||||||
|
Create an account
|
||||||
|
</v-button>
|
||||||
|
|
||||||
<p class="text-gray-500 mt-4">
|
<p class="text-gray-500 mt-4">
|
||||||
Already have an account?
|
Already have an account?
|
||||||
<a href="#" v-if="isQuick" @click.prevent="$emit('openLogin')" class="font-semibold ml-1">Log In</a>
|
<a v-if="isQuick" href="#" class="font-semibold ml-1" @click.prevent="$emit('openLogin')">Log In</a>
|
||||||
<router-link v-else :to="{name:'login'}" class="font-semibold ml-1">Log In</router-link>
|
<router-link v-else :to="{name:'login'}" class="font-semibold ml-1">
|
||||||
|
Log In
|
||||||
|
</router-link>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- GitHub Register Button -->
|
<!-- GitHub Register Button -->
|
||||||
|
@ -52,7 +60,7 @@ export default {
|
||||||
name: 'RegisterForm',
|
name: 'RegisterForm',
|
||||||
components: {
|
components: {
|
||||||
SelectInput,
|
SelectInput,
|
||||||
LoginWithGithub,
|
LoginWithGithub
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
isQuick: {
|
isQuick: {
|
||||||
|
@ -111,14 +119,14 @@ export default {
|
||||||
|
|
||||||
// Track event
|
// Track event
|
||||||
this.$logEvent('register', { source: this.form.hear_about_us })
|
this.$logEvent('register', { source: this.form.hear_about_us })
|
||||||
|
|
||||||
initCrisp(data)
|
initCrisp(data)
|
||||||
this.$crisp.push(['set', 'session:event', [[['register', {}, 'blue']]]])
|
this.$crisp.push(['set', 'session:event', [[['register', {}, 'blue']]]])
|
||||||
|
|
||||||
// Redirect
|
// Redirect
|
||||||
if(this.isQuick){
|
if (this.isQuick) {
|
||||||
this.$emit('afterQuickLogin')
|
this.$emit('afterQuickLogin')
|
||||||
}else{
|
} else {
|
||||||
this.$router.push({ name: 'forms.create' })
|
this.$router.push({ name: 'forms.create' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,17 @@
|
||||||
<div class="flex mt-6 mb-10">
|
<div class="flex mt-6 mb-10">
|
||||||
<div class="w-full md:w-2/3 md:mx-auto md:max-w-md px-4">
|
<div class="w-full md:w-2/3 md:mx-auto md:max-w-md px-4">
|
||||||
<h1 class="my-6">
|
<h1 class="my-6">
|
||||||
{{ $t('reset_password') }}
|
Reset password
|
||||||
</h1>
|
</h1>
|
||||||
<form @submit.prevent="send" @keydown="form.onKeydown($event)">
|
<form @submit.prevent="send" @keydown="form.onKeydown($event)">
|
||||||
<alert-success :form="form" :message="status" class="mb-4" />
|
<alert-success :form="form" :message="status" class="mb-4" />
|
||||||
|
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<text-input name="email" :form="form" :label="$t('email')" :required="true" />
|
<text-input name="email" :form="form" label="Email" :required="true" />
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<v-button class="w-full" :loading="form.busy">
|
<v-button class="w-full" :loading="form.busy">
|
||||||
{{ $t('send_password_reset_link') }}
|
Send Password Reset Link
|
||||||
</v-button>
|
</v-button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,12 +28,12 @@ import OpenFormFooter from '../../../components/pages/OpenFormFooter.vue'
|
||||||
import SeoMeta from '../../../mixins/seo-meta.js'
|
import SeoMeta from '../../../mixins/seo-meta.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
middleware: 'guest',
|
|
||||||
components: {
|
components: {
|
||||||
OpenFormFooter
|
OpenFormFooter
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [SeoMeta],
|
mixins: [SeoMeta],
|
||||||
|
middleware: 'guest',
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
metaTitle: 'Reset Password',
|
metaTitle: 'Reset Password',
|
||||||
|
|
|
@ -3,27 +3,27 @@
|
||||||
<div class="flex mt-6 mb-10">
|
<div class="flex mt-6 mb-10">
|
||||||
<div class="w-full md:w-2/3 md:mx-auto md:max-w-md px-4">
|
<div class="w-full md:w-2/3 md:mx-auto md:max-w-md px-4">
|
||||||
<h1 class="my-6">
|
<h1 class="my-6">
|
||||||
{{ $t('reset_password') }}
|
Reset Password
|
||||||
</h1>
|
</h1>
|
||||||
<form @submit.prevent="reset" @keydown="form.onKeydown($event)">
|
<form @submit.prevent="reset" @keydown="form.onKeydown($event)">
|
||||||
<alert-success class="mb-4" :form="form" :message="status" />
|
<alert-success class="mb-4" :form="form" :message="status" />
|
||||||
|
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<text-input name="email" :form="form" :label="$t('email')" :required="true" />
|
<text-input name="email" :form="form" label="Email" :required="true" />
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<text-input class="mt-8" native-type="password"
|
<text-input class="mt-8" native-type="password"
|
||||||
name="password" :form="form" :label="$t('password')" :required="true"
|
name="password" :form="form" label="Password" :required="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Password Confirmation-->
|
<!-- Password Confirmation-->
|
||||||
<text-input class="mt-8" native-type="password"
|
<text-input class="mt-8" native-type="password"
|
||||||
name="password_confirmation" :form="form" :label="$t('confirm_password')" :required="true"
|
name="password_confirmation" :form="form" label="Confirm Password" :required="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<v-button class="w-full" :loading="form.busy">
|
<v-button class="w-full" :loading="form.busy">
|
||||||
{{ $t('reset_password') }}
|
Reset Password
|
||||||
</v-button>
|
</v-button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,12 +38,12 @@ import OpenFormFooter from '../../../components/pages/OpenFormFooter.vue'
|
||||||
import SeoMeta from '../../../mixins/seo-meta.js'
|
import SeoMeta from '../../../mixins/seo-meta.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
middleware: 'guest',
|
|
||||||
components: {
|
components: {
|
||||||
OpenFormFooter
|
OpenFormFooter
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [SeoMeta],
|
mixins: [SeoMeta],
|
||||||
|
middleware: 'guest',
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
metaTitle: 'Reset Password',
|
metaTitle: 'Reset Password',
|
||||||
|
|
|
@ -2,19 +2,19 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-8 m-auto px-4">
|
<div class="col-lg-8 m-auto px-4">
|
||||||
<h1 class="my-6">
|
<h1 class="my-6">
|
||||||
{{ $t('verify_email') }}
|
Verify Email
|
||||||
</h1>
|
</h1>
|
||||||
<form @submit.prevent="send" @keydown="form.onKeydown($event)">
|
<form @submit.prevent="send" @keydown="form.onKeydown($event)">
|
||||||
<alert-success :form="form" :message="status" />
|
<alert-success :form="form" :message="status" />
|
||||||
|
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<text-input name="email" :form="form" :label="$t('email')" :required="true" />
|
<text-input name="email" :form="form" label="Email" :required="true" />
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-md-9 ml-md-auto">
|
<div class="col-md-9 ml-md-auto">
|
||||||
<v-button :loading="form.busy">
|
<v-button :loading="form.busy">
|
||||||
{{ $t('send_verification_link') }}
|
Send Verification Link
|
||||||
</v-button>
|
</v-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,9 +28,9 @@ import Form from 'vform'
|
||||||
import SeoMeta from '../../../mixins/seo-meta.js'
|
import SeoMeta from '../../../mixins/seo-meta.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
middleware: 'guest',
|
|
||||||
mixins: [SeoMeta],
|
mixins: [SeoMeta],
|
||||||
|
middleware: 'guest',
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
metaTitle: 'Verify Email',
|
metaTitle: 'Verify Email',
|
||||||
status: '',
|
status: '',
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-8 m-auto px-4">
|
<div class="col-lg-8 m-auto px-4">
|
||||||
<h1 class="my-6">
|
<h1 class="my-6">
|
||||||
{{ $t('verify_email') }}
|
Verify Email
|
||||||
</h1>
|
</h1>
|
||||||
<template v-if="success">
|
<template v-if="success">
|
||||||
<div class="alert alert-success" role="alert">
|
<div class="alert alert-success" role="alert">
|
||||||
|
@ -10,16 +10,16 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<router-link :to="{ name: 'login' }" class="btn btn-primary">
|
<router-link :to="{ name: 'login' }" class="btn btn-primary">
|
||||||
{{ $t('login') }}
|
Login
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">
|
||||||
{{ error || $t('failed_to_verify_email') }}
|
{{ error || 'Failed to verify email.' }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<router-link :to="{ name: 'verification.resend' }" class="small float-right">
|
<router-link :to="{ name: 'verification.resend' }" class="small float-right">
|
||||||
{{ $t('resend_verification_link') }}
|
Resend Verification Link?
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,6 +33,7 @@ import SeoMeta from '../../../mixins/seo-meta.js'
|
||||||
const qs = (params) => Object.keys(params).map(key => `${key}=${params[key]}`).join('&')
|
const qs = (params) => Object.keys(params).map(key => `${key}=${params[key]}`).join('&')
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [SeoMeta],
|
||||||
async beforeRouteEnter (to, from, next) {
|
async beforeRouteEnter (to, from, next) {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.post(`/api/email/verify/${to.params.id}?${qs(to.query)}`)
|
const { data } = await axios.post(`/api/email/verify/${to.params.id}?${qs(to.query)}`)
|
||||||
|
@ -48,8 +49,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
middleware: 'guest',
|
middleware: 'guest',
|
||||||
mixins: [SeoMeta],
|
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
metaTitle: 'Verify Email',
|
metaTitle: 'Verify Email',
|
||||||
error: '',
|
error: '',
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
<img alt="Nice plant as we have nothing else to show!" :src="asset('img/icons/plant.png')" class="w-56 mb-5">
|
<img alt="Nice plant as we have nothing else to show!" :src="asset('img/icons/plant.png')" class="w-56 mb-5">
|
||||||
|
|
||||||
<h1 class="mb-4 font-semibold text-3xl text-gray-900">
|
<h1 class="mb-4 font-semibold text-3xl text-gray-900">
|
||||||
{{ $t('page_not_found') }}
|
Page Not Found
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="links">
|
<div class="links">
|
||||||
<router-link :to="{ name: 'welcome' }" class="hover:underline text-gray-700">
|
<router-link :to="{ name: 'welcome' }" class="hover:underline text-gray-700">
|
||||||
{{ $t('go_home') }}
|
Go Home
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,34 +2,35 @@
|
||||||
<div class="flex flex-wrap flex-col">
|
<div class="flex flex-wrap flex-col">
|
||||||
<transition v-if="stateReady" name="fade" mode="out-in">
|
<transition v-if="stateReady" name="fade" mode="out-in">
|
||||||
<div key="2">
|
<div key="2">
|
||||||
<create-form-base-modal @form-generated="formGenerated" :show="showInitialFormModal"
|
<create-form-base-modal :show="showInitialFormModal" @form-generated="formGenerated"
|
||||||
@close="showInitialFormModal=false"/>
|
@close="showInitialFormModal=false"
|
||||||
|
/>
|
||||||
<form-editor v-if="!workspacesLoading" ref="editor"
|
<form-editor v-if="!workspacesLoading" ref="editor"
|
||||||
class="w-full flex flex-grow"
|
class="w-full flex flex-grow"
|
||||||
:error="error"
|
:error="error"
|
||||||
:isGuest="isGuest"
|
:is-guest="isGuest"
|
||||||
@openRegister="openRegister"
|
@openRegister="openRegister"
|
||||||
/>
|
/>
|
||||||
<div v-else class="text-center mt-4 py-6">
|
<div v-else class="text-center mt-4 py-6">
|
||||||
<loader class="h-6 w-6 text-nt-blue mx-auto"/>
|
<loader class="h-6 w-6 text-nt-blue mx-auto" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<quick-register :showRegisterModal="registerModal" @close="registerModal=false" @reopen="registerModal=true"
|
<quick-register :show-register-modal="registerModal" @close="registerModal=false" @reopen="registerModal=true"
|
||||||
@afterLogin="afterLogin"/>
|
@afterLogin="afterLogin"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import store from '~/store'
|
import store from '~/store'
|
||||||
import Form from 'vform'
|
import Form from 'vform'
|
||||||
import {mapState, mapActions} from 'vuex'
|
import { mapState, mapActions } from 'vuex'
|
||||||
import QuickRegister from '../auth/components/QuickRegister.vue'
|
import QuickRegister from '../auth/components/QuickRegister.vue'
|
||||||
import initForm from "../../mixins/form_editor/initForm.js"
|
import initForm from '../../mixins/form_editor/initForm.js'
|
||||||
import SeoMeta from '../../mixins/seo-meta.js'
|
import SeoMeta from '../../mixins/seo-meta.js'
|
||||||
import CreateFormBaseModal from "../../components/pages/forms/create/CreateFormBaseModal.vue"
|
import CreateFormBaseModal from '../../components/pages/forms/create/CreateFormBaseModal.vue'
|
||||||
|
|
||||||
const loadTemplates = function () {
|
const loadTemplates = function () {
|
||||||
store.commit('open/templates/startLoading')
|
store.commit('open/templates/startLoading')
|
||||||
|
@ -40,19 +41,19 @@ const loadTemplates = function () {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CreateFormGuest',
|
name: 'CreateFormGuest',
|
||||||
mixins: [initForm, SeoMeta],
|
|
||||||
components: {
|
components: {
|
||||||
QuickRegister, CreateFormBaseModal
|
QuickRegister, CreateFormBaseModal
|
||||||
},
|
},
|
||||||
|
mixins: [initForm, SeoMeta],
|
||||||
|
|
||||||
middleware: 'guest',
|
beforeRouteEnter (to, from, next) {
|
||||||
|
|
||||||
beforeRouteEnter(to, from, next) {
|
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
next()
|
next()
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
middleware: 'guest',
|
||||||
|
|
||||||
|
data () {
|
||||||
return {
|
return {
|
||||||
metaTitle: 'Create a new Form as Guest',
|
metaTitle: 'Create a new Form as Guest',
|
||||||
stateReady: false,
|
stateReady: false,
|
||||||
|
@ -67,35 +68,35 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
workspaces: state => state['open/workspaces'].content,
|
workspaces: state => state['open/workspaces'].content,
|
||||||
workspacesLoading: state => state['open/workspaces'].loading,
|
workspacesLoading: state => state['open/workspaces'].loading
|
||||||
}),
|
}),
|
||||||
form: {
|
form: {
|
||||||
get() {
|
get () {
|
||||||
return this.$store.state['open/working_form'].content
|
return this.$store.state['open/working_form'].content
|
||||||
},
|
},
|
||||||
/* We add a setter */
|
/* We add a setter */
|
||||||
set(value) {
|
set (value) {
|
||||||
this.$store.commit('open/working_form/set', value)
|
this.$store.commit('open/working_form/set', value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
workspace() {
|
workspace () {
|
||||||
return this.$store.getters['open/workspaces/getCurrent']()
|
return this.$store.getters['open/workspaces/getCurrent']()
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
workspace() {
|
workspace () {
|
||||||
if (this.workspace) {
|
if (this.workspace) {
|
||||||
this.form.workspace_id = this.workspace.id
|
this.form.workspace_id = this.workspace.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted () {
|
||||||
// Set as guest user
|
// Set as guest user
|
||||||
const guestWorkspace = {
|
const guestWorkspace = {
|
||||||
id: null,
|
id: null,
|
||||||
name: "Guest Workspace",
|
name: 'Guest Workspace',
|
||||||
is_enterprise: false,
|
is_enterprise: false,
|
||||||
is_pro: false
|
is_pro: false
|
||||||
}
|
}
|
||||||
|
@ -106,7 +107,7 @@ export default {
|
||||||
if (this.$route.query.template !== undefined && this.$route.query.template) {
|
if (this.$route.query.template !== undefined && this.$route.query.template) {
|
||||||
const template = this.$store.getters['open/templates/getBySlug'](this.$route.query.template)
|
const template = this.$store.getters['open/templates/getBySlug'](this.$route.query.template)
|
||||||
if (template && template.structure) {
|
if (template && template.structure) {
|
||||||
this.form = new Form({...this.form.data(), ...template.structure})
|
this.form = new Form({ ...this.form.data(), ...template.structure })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No template loaded, ask how to start
|
// No template loaded, ask how to start
|
||||||
|
@ -116,17 +117,17 @@ export default {
|
||||||
this.stateReady = true
|
this.stateReady = true
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {},
|
created () {},
|
||||||
destroyed() {},
|
unmounted () {},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions({
|
...mapActions({
|
||||||
loadWorkspaces: 'open/workspaces/load'
|
loadWorkspaces: 'open/workspaces/load'
|
||||||
}),
|
}),
|
||||||
openRegister() {
|
openRegister () {
|
||||||
this.registerModal = true
|
this.registerModal = true
|
||||||
},
|
},
|
||||||
afterLogin() {
|
afterLogin () {
|
||||||
this.registerModal = false
|
this.registerModal = false
|
||||||
this.isGuest = false
|
this.isGuest = false
|
||||||
this.loadWorkspaces()
|
this.loadWorkspaces()
|
||||||
|
@ -136,8 +137,8 @@ export default {
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
},
|
},
|
||||||
formGenerated(form) {
|
formGenerated (form) {
|
||||||
this.form = new Form({...this.form.data(), ...form})
|
this.form = new Form({ ...this.form.data(), ...form })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,16 @@
|
||||||
<div class="flex flex-wrap flex-col">
|
<div class="flex flex-wrap flex-col">
|
||||||
<transition v-if="stateReady" name="fade" mode="out-in">
|
<transition v-if="stateReady" name="fade" mode="out-in">
|
||||||
<div key="2">
|
<div key="2">
|
||||||
<create-form-base-modal @form-generated="formGenerated" :show="showInitialFormModal"
|
<create-form-base-modal :show="showInitialFormModal" @form-generated="formGenerated"
|
||||||
@close="showInitialFormModal=false"/>
|
@close="showInitialFormModal=false"
|
||||||
|
/>
|
||||||
<form-editor v-if="!workspacesLoading" ref="editor"
|
<form-editor v-if="!workspacesLoading" ref="editor"
|
||||||
class="w-full flex flex-grow"
|
class="w-full flex flex-grow"
|
||||||
:error="error"
|
:error="error"
|
||||||
@on-save="formInitialHash=null"
|
@on-save="formInitialHash=null"
|
||||||
/>
|
/>
|
||||||
<div v-else class="text-center mt-4 py-6">
|
<div v-else class="text-center mt-4 py-6">
|
||||||
<loader class="h-6 w-6 text-nt-blue mx-auto"/>
|
<loader class="h-6 w-6 text-nt-blue mx-auto" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
@ -20,10 +21,10 @@
|
||||||
<script>
|
<script>
|
||||||
import store from '~/store'
|
import store from '~/store'
|
||||||
import Form from 'vform'
|
import Form from 'vform'
|
||||||
import {mapState, mapActions} from 'vuex'
|
import { mapState, mapActions } from 'vuex'
|
||||||
import initForm from "../../mixins/form_editor/initForm.js";
|
import initForm from '../../mixins/form_editor/initForm.js'
|
||||||
import SeoMeta from '../../mixins/seo-meta.js'
|
import SeoMeta from '../../mixins/seo-meta.js'
|
||||||
import CreateFormBaseModal from "../../components/pages/forms/create/CreateFormBaseModal.vue"
|
import CreateFormBaseModal from '../../components/pages/forms/create/CreateFormBaseModal.vue'
|
||||||
|
|
||||||
const loadTemplates = function () {
|
const loadTemplates = function () {
|
||||||
store.commit('open/templates/startLoading')
|
store.commit('open/templates/startLoading')
|
||||||
|
@ -34,11 +35,11 @@ const loadTemplates = function () {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CreateForm',
|
name: 'CreateForm',
|
||||||
|
components: { CreateFormBaseModal },
|
||||||
|
|
||||||
mixins: [initForm, SeoMeta],
|
mixins: [initForm, SeoMeta],
|
||||||
components: {CreateFormBaseModal},
|
|
||||||
|
|
||||||
beforeRouteEnter(to, from, next) {
|
beforeRouteEnter (to, from, next) {
|
||||||
loadTemplates()
|
loadTemplates()
|
||||||
next()
|
next()
|
||||||
},
|
},
|
||||||
|
@ -55,7 +56,7 @@ export default {
|
||||||
|
|
||||||
middleware: 'auth',
|
middleware: 'auth',
|
||||||
|
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
metaTitle: 'Create a new Form',
|
metaTitle: 'Create a new Form',
|
||||||
stateReady: false,
|
stateReady: false,
|
||||||
|
@ -73,31 +74,31 @@ export default {
|
||||||
user: state => state.auth.user
|
user: state => state.auth.user
|
||||||
}),
|
}),
|
||||||
form: {
|
form: {
|
||||||
get() {
|
get () {
|
||||||
return this.$store.state['open/working_form'].content
|
return this.$store.state['open/working_form'].content
|
||||||
},
|
},
|
||||||
/* We add a setter */
|
/* We add a setter */
|
||||||
set(value) {
|
set (value) {
|
||||||
this.$store.commit('open/working_form/set', value)
|
this.$store.commit('open/working_form/set', value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
workspace() {
|
workspace () {
|
||||||
return this.$store.getters['open/workspaces/getCurrent']()
|
return this.$store.getters['open/workspaces/getCurrent']()
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
workspace() {
|
workspace () {
|
||||||
if (this.workspace) {
|
if (this.workspace) {
|
||||||
this.form.workspace_id = this.workspace.id
|
this.form.workspace_id = this.workspace.id
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
user() {
|
user () {
|
||||||
this.stateReady = true
|
this.stateReady = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted () {
|
||||||
window.onbeforeunload = () => {
|
window.onbeforeunload = () => {
|
||||||
if (this.isDirty()) {
|
if (this.isDirty()) {
|
||||||
return false
|
return false
|
||||||
|
@ -109,7 +110,7 @@ export default {
|
||||||
if (this.$route.query.template !== undefined && this.$route.query.template) {
|
if (this.$route.query.template !== undefined && this.$route.query.template) {
|
||||||
const template = this.$store.getters['open/templates/getBySlug'](this.$route.query.template)
|
const template = this.$store.getters['open/templates/getBySlug'](this.$route.query.template)
|
||||||
if (template && template.structure) {
|
if (template && template.structure) {
|
||||||
this.form = new Form({...this.form.data(), ...template.structure})
|
this.form = new Form({ ...this.form.data(), ...template.structure })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No template loaded, ask how to start
|
// No template loaded, ask how to start
|
||||||
|
@ -121,15 +122,15 @@ export default {
|
||||||
this.stateReady = this.user !== null
|
this.stateReady = this.user !== null
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {},
|
created () {},
|
||||||
destroyed() {},
|
unmounted () {},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions({
|
...mapActions({
|
||||||
loadWorkspaces: 'open/workspaces/loadIfEmpty'
|
loadWorkspaces: 'open/workspaces/loadIfEmpty'
|
||||||
}),
|
}),
|
||||||
formGenerated(form) {
|
formGenerated (form) {
|
||||||
this.form = new Form({...this.form.data(), ...form})
|
this.form = new Form({ ...this.form.data(), ...form })
|
||||||
},
|
},
|
||||||
isDirty () {
|
isDirty () {
|
||||||
return !this.loading && this.formInitialHash && this.formInitialHash !== this.hashString(JSON.stringify(this.form.data()))
|
return !this.loading && this.formInitialHash && this.formInitialHash !== this.hashString(JSON.stringify(this.form.data()))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full flex flex-col">
|
<div class="w-full flex flex-col">
|
||||||
<form-editor v-if="pageLoaded" ref="editor"
|
<form-editor v-if="pageLoaded" ref="editor"
|
||||||
:isEdit="true"
|
:is-edit="true"
|
||||||
@on-save="formInitialHash=null"
|
@on-save="formInitialHash=null"
|
||||||
/>
|
/>
|
||||||
<div v-else-if="!loading && error" class="mt-4 rounded-lg max-w-xl mx-auto p-6 bg-red-100 text-red-500">
|
<div v-else-if="!loading && error" class="mt-4 rounded-lg max-w-xl mx-auto p-6 bg-red-100 text-red-500">
|
||||||
|
@ -31,6 +31,7 @@ const loadForms = function () {
|
||||||
export default {
|
export default {
|
||||||
name: 'EditForm',
|
name: 'EditForm',
|
||||||
components: { Breadcrumb },
|
components: { Breadcrumb },
|
||||||
|
mixins: [SeoMeta],
|
||||||
|
|
||||||
beforeRouteEnter (to, from, next) {
|
beforeRouteEnter (to, from, next) {
|
||||||
if (!store.getters['open/forms/getBySlug'](to.params.slug)) {
|
if (!store.getters['open/forms/getBySlug'](to.params.slug)) {
|
||||||
|
@ -51,7 +52,6 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
middleware: 'auth',
|
middleware: 'auth',
|
||||||
mixins: [SeoMeta],
|
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
@ -82,7 +82,7 @@ export default {
|
||||||
},
|
},
|
||||||
metaTitle () {
|
metaTitle () {
|
||||||
return 'Edit ' + (this.form ? this.form.title : 'Your Form')
|
return 'Edit ' + (this.form ? this.form.title : 'Your Form')
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -92,7 +92,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
created () {},
|
created () {},
|
||||||
destroyed () {},
|
unmounted () {},
|
||||||
|
|
||||||
mounted () {
|
mounted () {
|
||||||
window.onbeforeunload = () => {
|
window.onbeforeunload = () => {
|
||||||
|
@ -109,11 +109,11 @@ export default {
|
||||||
this.formInitialHash = this.hashString(JSON.stringify(this.updatedForm.data()))
|
this.formInitialHash = this.hashString(JSON.stringify(this.updatedForm.data()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!this.updatedForm.notification_settings || Array.isArray(this.updatedForm.notification_settings)){
|
if (!this.updatedForm.notification_settings || Array.isArray(this.updatedForm.notification_settings)) {
|
||||||
this.updatedForm.notification_settings = {}
|
this.updatedForm.notification_settings = {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
isDirty () {
|
isDirty () {
|
||||||
return !this.loading && this.formInitialHash && this.formInitialHash !== this.hashString(JSON.stringify(this.updatedForm.data()))
|
return !this.loading && this.formInitialHash && this.formInitialHash !== this.hashString(JSON.stringify(this.updatedForm.data()))
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h3 class="font-semibold text-2xl text-gray-900">Password</h3>
|
<h3 class="font-semibold text-2xl text-gray-900">
|
||||||
|
Password
|
||||||
|
</h3>
|
||||||
<small class="text-gray-600">Manage your password.</small>
|
<small class="text-gray-600">Manage your password.</small>
|
||||||
|
|
||||||
<form @submit.prevent="update" @keydown="form.onKeydown($event)" class="mt-3">
|
<form class="mt-3" @submit.prevent="update" @keydown="form.onKeydown($event)">
|
||||||
<alert-success class="mb-5" :form="form" :message="$t('password_updated')" />
|
<alert-success class="mb-5" :form="form" message="Password updated." />
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<text-input native-type="password"
|
<text-input native-type="password"
|
||||||
name="password" :form="form" :label="$t('password')" :required="true"
|
name="password" :form="form" label="Password" :required="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Password Confirmation-->
|
<!-- Password Confirmation-->
|
||||||
<text-input native-type="password"
|
<text-input native-type="password"
|
||||||
name="password_confirmation" :form="form" :label="$t('confirm_password')" :required="true"
|
name="password_confirmation" :form="form" label="Confirm Password" :required="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<v-button :loading="form.busy" class="mt-4">Update password</v-button>
|
<v-button :loading="form.busy" class="mt-4">
|
||||||
|
Update password
|
||||||
|
</v-button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -27,8 +31,8 @@ import Form from 'vform'
|
||||||
import SeoMeta from '../../mixins/seo-meta.js'
|
import SeoMeta from '../../mixins/seo-meta.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
scrollToTop: false,
|
|
||||||
mixins: [SeoMeta],
|
mixins: [SeoMeta],
|
||||||
|
scrollToTop: false,
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
metaTitle: 'Password',
|
metaTitle: 'Password',
|
||||||
|
|
|
@ -1,19 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h3 class="font-semibold text-2xl text-gray-900">Profile details</h3>
|
<h3 class="font-semibold text-2xl text-gray-900">
|
||||||
|
Profile details
|
||||||
|
</h3>
|
||||||
<small class="text-gray-600">Update your username and manage your account details.</small>
|
<small class="text-gray-600">Update your username and manage your account details.</small>
|
||||||
|
|
||||||
<form @submit.prevent="update" @keydown="form.onKeydown($event)" class="mt-3">
|
<form class="mt-3" @submit.prevent="update" @keydown="form.onKeydown($event)">
|
||||||
<alert-success class="mb-5" :form="form" :message="$t('info_updated')" />
|
<alert-success class="mb-5" :form="form" message="Your info has been updated!" />
|
||||||
|
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<text-input name="name" :form="form" :label="$t('name')" :required="true" />
|
<text-input name="name" :form="form" label="Name" :required="true" />
|
||||||
|
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<text-input name="email" :form="form" :label="$t('email')" :required="true" />
|
<text-input name="email" :form="form" label="Email" :required="true" />
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<v-button :loading="form.busy" class="mt-4">Save changes</v-button>
|
<v-button :loading="form.busy" class="mt-4">
|
||||||
|
Save changes
|
||||||
|
</v-button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -24,8 +28,8 @@ import { mapGetters } from 'vuex'
|
||||||
import SeoMeta from '../../mixins/seo-meta.js'
|
import SeoMeta from '../../mixins/seo-meta.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
scrollToTop: false,
|
|
||||||
mixins: [SeoMeta],
|
mixins: [SeoMeta],
|
||||||
|
scrollToTop: false,
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
metaTitle: 'Profile',
|
metaTitle: 'Profile',
|
||||||
|
|
|
@ -22,9 +22,9 @@ import SeoMeta from '../../mixins/seo-meta.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { OpenFormFooter },
|
components: { OpenFormFooter },
|
||||||
|
mixins: [SeoMeta],
|
||||||
layout: 'default',
|
layout: 'default',
|
||||||
middleware: 'auth',
|
middleware: 'auth',
|
||||||
mixins: [SeoMeta],
|
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
metaTitle: 'Subscription Success',
|
metaTitle: 'Subscription Success',
|
||||||
|
@ -36,7 +36,7 @@ export default {
|
||||||
this.interval = setInterval(() => this.checkSubscription(), 5000)
|
this.interval = setInterval(() => this.checkSubscription(), 5000)
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy () {
|
beforeUnmount () {
|
||||||
clearInterval(this.interval)
|
clearInterval(this.interval)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ function hookLogEvent (binding) {
|
||||||
// Register directive to log event
|
// Register directive to log event
|
||||||
const registeredListeners = {}
|
const registeredListeners = {}
|
||||||
Vue.directive('track', {
|
Vue.directive('track', {
|
||||||
bind (el, binding, vnode) {
|
beforeMount (el, binding, vnode) {
|
||||||
registeredListeners[el] = () => {
|
registeredListeners[el] = () => {
|
||||||
hookLogEvent(binding)
|
hookLogEvent(binding)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import store from '~/store'
|
import store from '~/store'
|
||||||
import router from '~/router'
|
import router from '~/router'
|
||||||
import i18n from '~/plugins/i18n'
|
|
||||||
import Cookies from 'js-cookie'
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
function addPasswordToFormRequest (request) {
|
function addPasswordToFormRequest (request) {
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
import Vue from 'vue'
|
|
||||||
import store from '~/store'
|
|
||||||
import VueI18n from 'vue-i18n'
|
|
||||||
|
|
||||||
Vue.use(VueI18n)
|
|
||||||
|
|
||||||
const i18n = new VueI18n({
|
|
||||||
locale: 'en',
|
|
||||||
messages: {}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {String} locale
|
|
||||||
*/
|
|
||||||
export async function loadMessages (locale) {
|
|
||||||
if (Object.keys(i18n.getLocaleMessage(locale)).length === 0) {
|
|
||||||
if (locale) {
|
|
||||||
const langFiles = import.meta.glob('../lang/**.json', {eager: true})
|
|
||||||
const messages = langFiles[`../lang/${locale}.json`]
|
|
||||||
i18n.setLocaleMessage(locale, messages)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i18n.locale !== locale) {
|
|
||||||
i18n.locale = locale
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
;(async function () {
|
|
||||||
await loadMessages(store.getters['lang/locale'])
|
|
||||||
})()
|
|
||||||
|
|
||||||
export default i18n
|
|
|
@ -2,10 +2,11 @@ import routes from './routes'
|
||||||
import { createWebHistory, createRouter } from 'vue-router'
|
import { createWebHistory, createRouter } from 'vue-router'
|
||||||
import * as Sentry from '@sentry/vue'
|
import * as Sentry from '@sentry/vue'
|
||||||
import store from '../store'
|
import store from '../store'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
// import { nextTick } from '@vue/compat'
|
// import { nextTick } from '@vue/compat'
|
||||||
|
|
||||||
// The middleware for every page of the application.
|
// The middleware for every page of the application.
|
||||||
const globalMiddleware = ['locale', 'check-auth', 'notion-connection']
|
const globalMiddleware = ['check-auth', 'notion-connection']
|
||||||
|
|
||||||
// Load middleware modules dynamically.
|
// Load middleware modules dynamically.
|
||||||
const requireContext = import.meta.glob('../middleware/**/*.js', { eager: true })
|
const requireContext = import.meta.glob('../middleware/**/*.js', { eager: true })
|
||||||
|
@ -30,6 +31,13 @@ function createCustomRouter () {
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getMatchedComponents (to) {
|
||||||
|
return resolveComponents(to.matched.map((record) => {
|
||||||
|
const component = record.components.default
|
||||||
|
return typeof component === 'function' ? defineComponent(component) : component
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global router guard.
|
* Global router guard.
|
||||||
*
|
*
|
||||||
|
@ -54,9 +62,7 @@ async function beforeEach (to, from, next) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get the matched components and resolve them.
|
// Get the matched components and resolve them.
|
||||||
components = await resolveComponents(
|
components = await getMatchedComponents(to)
|
||||||
router.getMatchedComponents({ ...to })
|
|
||||||
)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (/^Loading( CSS)? chunk (\d)+ failed\./.test(error.message)) {
|
if (/^Loading( CSS)? chunk (\d)+ failed\./.test(error.message)) {
|
||||||
window.location.reload(true)
|
window.location.reload(true)
|
||||||
|
@ -78,15 +84,14 @@ async function beforeEach (to, from, next) {
|
||||||
|
|
||||||
// Call each middleware.
|
// Call each middleware.
|
||||||
callMiddleware(middleware, to, from, (...args) => {
|
callMiddleware(middleware, to, from, (...args) => {
|
||||||
console.log('in', store)
|
|
||||||
// Set the application layout only if "next()" was called with no args.
|
// Set the application layout only if "next()" was called with no args.
|
||||||
if (args.length === 0) {
|
if (args.length === 0) {
|
||||||
if (components[0].layout) {
|
if (components[0].layout) {
|
||||||
router.app.setLayout(components[0].layout)
|
store.commit('app/setLayout', components[0].layout)
|
||||||
} else if (components[0].default && components[0].default.layout) {
|
} else if (components[0].default && components[0].default.layout) {
|
||||||
router.app.setLayout(components[0].default.layout)
|
store.commit('app/setLayout', components[0].default.layout)
|
||||||
} else {
|
} else {
|
||||||
router.app.setLayout(null)
|
store.commit('app/setLayout', null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +223,7 @@ function scrollBehavior (to, from, savedPosition) {
|
||||||
return { selector: to.hash }
|
return { selector: to.hash }
|
||||||
}
|
}
|
||||||
|
|
||||||
const [component] = router.getMatchedComponents({ ...to }).slice(-1)
|
const [component] = getMatchedComponents(to)
|
||||||
|
|
||||||
if (component && component.scrollToTop === false) {
|
if (component && component.scrollToTop === false) {
|
||||||
return {}
|
return {}
|
||||||
|
@ -226,7 +231,7 @@ function scrollBehavior (to, from, savedPosition) {
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve({ x: 0, y: 0 })
|
resolve({ left: 0, top: 0 })
|
||||||
}, 190)
|
}, 190)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
import Cookies from 'js-cookie'
|
|
||||||
import * as types from '../mutation-types'
|
|
||||||
|
|
||||||
const { locale, locales } = window.config
|
|
||||||
|
|
||||||
// state
|
|
||||||
export const state = {
|
|
||||||
locale: getLocale(locales, locale),
|
|
||||||
locales: locales
|
|
||||||
}
|
|
||||||
|
|
||||||
// getters
|
|
||||||
export const getters = {
|
|
||||||
locale: state => state.locale,
|
|
||||||
locales: state => state.locales
|
|
||||||
}
|
|
||||||
|
|
||||||
// mutations
|
|
||||||
export const mutations = {
|
|
||||||
[types.SET_LOCALE] (state, { locale }) {
|
|
||||||
state.locale = locale
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// actions
|
|
||||||
export const actions = {
|
|
||||||
setLocale ({ commit }, { locale }) {
|
|
||||||
commit(types.SET_LOCALE, { locale })
|
|
||||||
|
|
||||||
Cookies.set('locale', locale, { expires: 365 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {String[]} locales
|
|
||||||
* @param {String} fallback
|
|
||||||
* @return {String}
|
|
||||||
*/
|
|
||||||
function getLocale (locales, fallback) {
|
|
||||||
const locale = Cookies.get('locale')
|
|
||||||
|
|
||||||
if (Object.prototype.hasOwnProperty.call(locales, locale)) {
|
|
||||||
return locale
|
|
||||||
} else if (locale) {
|
|
||||||
Cookies.remove('locale')
|
|
||||||
}
|
|
||||||
|
|
||||||
return fallback
|
|
||||||
}
|
|
Loading…
Reference in New Issue