Fixed form creation

This commit is contained in:
Julien Nahum
2023-12-20 16:10:32 +01:00
parent b598a16406
commit af5656ce81
34 changed files with 363 additions and 356 deletions

View File

@@ -16,11 +16,11 @@
<script>
import { computed } from 'vue'
import Form from 'vform'
import { useFormsStore } from '../../stores/forms'
import { useWorkingFormStore } from '../../stores/working_form'
import { useWorkspacesStore } from '../../stores/workspaces'
import { useFormsStore } from '../../../stores/forms.js'
import { useWorkingFormStore } from '../../../stores/working_form.js'
import { useWorkspacesStore } from '../../../stores/workspaces.js'
import Breadcrumb from '~/components/global/Breadcrumb.vue'
import SeoMeta from '../../mixins/seo-meta.js'
import SeoMeta from '../../../mixins/seo-meta.js'
const loadForms = function () {
const formsStore = useFormsStore()

View File

@@ -133,15 +133,15 @@
<script>
import { computed } from 'vue'
import Form from 'vform'
import { useAuthStore } from '../../../stores/auth'
import { useFormsStore } from '../../../stores/forms'
import { useWorkingFormStore } from '../../../stores/working_form'
import { useWorkspacesStore } from '../../../stores/workspaces'
import { useAuthStore } from '../../../../stores/auth.js'
import { useFormsStore } from '../../../../stores/forms.js'
import { useWorkingFormStore } from '../../../../stores/working_form.js'
import { useWorkspacesStore } from '../../../../stores/workspaces.js'
import ProTag from '~/components/global/ProTag.vue'
import VButton from '~/components/global/VButton.vue'
import ExtraMenu from '../../../components/pages/forms/show/ExtraMenu.vue'
import SeoMeta from '../../../mixins/seo-meta.js'
import FormCleanings from '../../../components/pages/forms/show/FormCleanings.vue'
import ExtraMenu from '../../../../components/pages/forms/show/ExtraMenu.vue'
import SeoMeta from '../../../../mixins/seo-meta.js'
import FormCleanings from '../../../../components/pages/forms/show/FormCleanings.vue'
const loadForms = function () {
const formsStore = useFormsStore()
@@ -263,7 +263,7 @@ export default {
this.$router.push({ name: 'home' })
},
openEdit () {
this.$router.push({ name: 'forms-edit', params: { slug: this.form.slug } })
this.$router.push({ name: 'forms-slug-edit', params: { slug: this.form.slug } })
}
}
}

View File

@@ -19,14 +19,14 @@
</template>
<script>
import ShareLink from '../../../components/pages/forms/show/ShareLink.vue'
import EmbedCode from '../../../components/pages/forms/show/EmbedCode.vue'
import FormQrCode from '../../../components/pages/forms/show/FormQrCode.vue'
import UrlFormPrefill from '../../../components/pages/forms/show/UrlFormPrefill.vue'
import RegenerateFormLink from '../../../components/pages/forms/show/RegenerateFormLink.vue'
import SeoMeta from '../../../mixins/seo-meta.js'
import AdvancedFormUrlSettings from '../../../components/open/forms/components/AdvancedFormUrlSettings.vue'
import EmbedFormAsPopupModal from '../../../components/pages/forms/show/EmbedFormAsPopupModal.vue'
import ShareLink from '../../../../components/pages/forms/show/ShareLink.vue'
import EmbedCode from '../../../../components/pages/forms/show/EmbedCode.vue'
import FormQrCode from '../../../../components/pages/forms/show/FormQrCode.vue'
import UrlFormPrefill from '../../../../components/pages/forms/show/UrlFormPrefill.vue'
import RegenerateFormLink from '../../../../components/pages/forms/show/RegenerateFormLink.vue'
import SeoMeta from '../../../../mixins/seo-meta.js'
import AdvancedFormUrlSettings from '../../../../components/open/forms/components/AdvancedFormUrlSettings.vue'
import EmbedFormAsPopupModal from '../../../../components/pages/forms/show/EmbedFormAsPopupModal.vue'
export default {
components: {

View File

@@ -8,8 +8,8 @@
</template>
<script>
import FormStats from '../../../components/open/forms/components/FormStats.vue'
import SeoMeta from '../../../mixins/seo-meta.js'
import FormStats from '../../../../components/open/forms/components/FormStats.vue'
import SeoMeta from '../../../../mixins/seo-meta.js'
export default {
name: 'Stats',

View File

@@ -5,8 +5,8 @@
</template>
<script>
import FormSubmissions from '../../../components/open/forms/components/FormSubmissions.vue'
import SeoMeta from '../../../mixins/seo-meta.js'
import FormSubmissions from '../../../../components/open/forms/components/FormSubmissions.vue'
import SeoMeta from '../../../../mixins/seo-meta.js'
export default {
components: {FormSubmissions},

View File

@@ -1,164 +0,0 @@
<template>
<div class="flex flex-wrap flex-col">
<transition v-if="stateReady" name="fade" mode="out-in">
<div key="2">
<create-form-base-modal :show="showInitialFormModal" @form-generated="formGenerated"
@close="showInitialFormModal=false"
/>
<form-editor v-if="!workspacesLoading" ref="editor"
class="w-full flex flex-grow"
:error="error"
@on-save="formInitialHash=null"
/>
<div v-else class="text-center mt-4 py-6">
<Loader class="h-6 w-6 text-nt-blue mx-auto" />
</div>
</div>
</transition>
</div>
</template>
<script>
import Form from 'vform'
import { computed } from 'vue'
import { useAuthStore } from '../../stores/auth'
import { useTemplatesStore } from '../../stores/templates'
import { useWorkingFormStore } from '../../stores/working_form'
import { useWorkspacesStore } from '../../stores/workspaces'
import initForm from '../../mixins/form_editor/initForm.js'
import SeoMeta from '../../mixins/seo-meta.js'
import CreateFormBaseModal from '../../components/pages/forms/create/CreateFormBaseModal.vue'
const loadTemplates = function () {
const templatesStore = useTemplatesStore()
templatesStore.startLoading()
templatesStore.loadIfEmpty().then(() => {
templatesStore.stopLoading()
})
}
export default {
name: 'CreateForm',
components: { CreateFormBaseModal },
mixins: [initForm, SeoMeta],
middleware: 'auth',
beforeRouteEnter (to, from, next) {
loadTemplates()
next()
},
beforeRouteLeave (to, from, next) {
if (this.isDirty()) {
return this.alertConfirm('Changes you made may not be saved. Are you sure want to leave?', () => {
window.onbeforeunload = null
next()
}, () => {})
}
next()
},
setup () {
const authStore = useAuthStore()
const templatesStore = useTemplatesStore()
const workingFormStore = useWorkingFormStore()
const workspacesStore = useWorkspacesStore()
return {
templatesStore,
workingFormStore,
workspacesStore,
user: computed(() => authStore.user),
workspaces : computed(() => workspacesStore.content),
workspacesLoading : computed(() => workspacesStore.loading)
}
},
data () {
return {
metaTitle: 'Create a new Form',
stateReady: false,
loading: false,
error: '',
showInitialFormModal: false,
formInitialHash: null
}
},
computed: {
form: {
get () {
return this.workingFormStore.content
},
/* We add a setter */
set (value) {
this.workingFormStore.set(value)
}
},
workspace () {
return this.workspacesStore.getCurrent()
}
},
watch: {
workspace () {
if (this.workspace) {
this.form.workspace_id = this.workspace.id
}
},
user () {
this.stateReady = true
}
},
mounted () {
window.onbeforeunload = () => {
if (this.isDirty()) {
return false
}
}
this.initForm()
this.formInitialHash = this.hashString(JSON.stringify(this.form.data()))
if (this.$route.query.template !== undefined && this.$route.query.template) {
const template = this.templatesStore.getByKey(this.$route.query.template)
if (template && template.structure) {
this.form = new Form({ ...this.form.data(), ...template.structure })
}
} else {
// No template loaded, ask how to start
this.showInitialFormModal = true
}
this.closeAlert()
this.workspacesStore.loadIfEmpty()
this.stateReady = this.user !== null
},
created () {},
unmounted () {},
methods: {
formGenerated (form) {
this.form = new Form({ ...this.form.data(), ...form })
},
isDirty () {
return !this.loading && this.formInitialHash && this.formInitialHash !== this.hashString(JSON.stringify(this.form.data()))
},
hashString (str, seed = 0) {
let h1 = 0xdeadbeef ^ seed
let h2 = 0x41c6ce57 ^ seed
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i)
h1 = Math.imul(h1 ^ ch, 2654435761)
h2 = Math.imul(h2 ^ ch, 1597334677)
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909)
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909)
return 4294967296 * (2097151 & h2) + (h1 >>> 0)
}
}
}
</script>

View File

@@ -0,0 +1,117 @@
<template>
<div class="flex flex-wrap flex-col">
<transition name="fade" mode="out-in">
<div key="2">
<create-form-base-modal :show="showInitialFormModal" @form-generated="formGenerated"
@close="showInitialFormModal=false"
/>
<form-editor v-if="form && !workspacesLoading" ref="editor"
class="w-full flex flex-grow"
:error="error"
@on-save="formInitialHash=null"
/>
<div v-else class="text-center mt-4 py-6">
<Loader class="h-6 w-6 text-nt-blue mx-auto"/>
</div>
</div>
</transition>
</div>
</template>
<script setup>
import {watch} from 'vue'
import {initForm} from "~/composables/forms/initForm.js"
import FormEditor from "~/components/open/forms/components/FormEditor.vue"
import CreateFormBaseModal from '../../../components/pages/forms/create/CreateFormBaseModal.vue'
// metaTitle: 'Create a new Form',
// beforeRouteLeave (to, from, next) {
// if (this.isDirty()) {
// return this.alertConfirm('Changes you made may not be saved. Are you sure want to leave?', () => {
// window.onbeforeunload = null
// next()
// }, () => {})
// }
// next()
// },
const route = useRoute()
const authStore = useAuthStore()
const templatesStore = useTemplatesStore()
const workingFormStore = useWorkingFormStore()
const workspacesStore = useWorkspacesStore()
const formStore = useFormsStore()
const {
getCurrent: workspace,
getAll: workspaces,
workspacesLoading: workspacesLoading
} = storeToRefs(workspacesStore)
const {content: form} = storeToRefs(workingFormStore)
// State
const loading = ref(false)
const error = ref('')
const showInitialFormModal = ref(false)
const formInitialHash = ref(null)
watch(() => workspace, () => {
if (workspace) {
form.workspace_id = workspace.value.id
}
})
onMounted(() => {
if (process.client) {
// window.onbeforeunload = () => {
if (isDirty()) {
return false
}
}
if (!formStore.allLoaded) {
formStore.load(workspace.value.id)
}
form.value = initForm({workspace_id: workspace.value?.id})
formInitialHash.value = hashString(JSON.stringify(form.value.data()))
// if (this.$route.query.template !== undefined && this.$route.query.template) {
// const template = this.templatesStore.getByKey(this.$route.query.template)
// if (template && template.structure) {
// this.form = new Form({...this.form.data(), ...template.structure})
// }
// } else {
// // No template loaded, ask how to start
// this.showInitialFormModal = true
// }
// this.closeAlert()
// this.workspacesStore.loadIfEmpty()
})
// Methods
const formGenerated = (newForm) => {
form.value = useForm({...form.value.data(), ...newForm})
}
const isDirty = () => {
return !loading.value && formInitialHash.value && formInitialHash.value !== hashString(JSON.stringify(form.value.data()))
}
const hashString = (str, seed = 0) => {
let h1 = 0xdeadbeef ^ seed
let h2 = 0x41c6ce57 ^ seed
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i)
h1 = Math.imul(h1 ^ ch, 2654435761)
h2 = Math.imul(h2 ^ ch, 1597334677)
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909)
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909)
return 4294967296 * (2097151 & h2) + (h1 >>> 0)
}
</script>

View File

@@ -133,14 +133,18 @@ definePageMeta({
const authStore = useAuthStore()
const formsStore = useFormsStore()
formsStore.startLoading()
const workspacesStore = useWorkspacesStore()
onMounted(() => {
formsStore.load(workspacesStore.currentId)
if (!formsStore.allLoaded) {
console.log('starting to load')
formsStore.load(workspacesStore.currentId)
}
})
// State
const {getAll: forms, loading: formsLoading} = storeToRefs(formsStore)
const {getAll: forms, loading: formsLoading, allTags} = storeToRefs(formsStore)
const showEditFormModal = ref(false)
const selectedForm = ref(null)
const search = ref('')
@@ -167,15 +171,7 @@ const viewForm = (form) => {
const isFilteringForms = computed(() => {
return (search.value !== '' && search.value !== null) || selectedTags.value.size > 0
})
const allTags = computed(() => {
let tags = []
forms.value.forEach((form) => {
if (form.tags && form.tags.length) {
tags = tags.concat(form.tags.split(','))
}
})
return [...new Set(tags)]
})
const enrichedForms = computed(() => {
let enrichedForms = forms.value.map((form) => {
form.workspace = workspacesStore.getByKey(form.workspace_id)