Reworked workspaces store

This commit is contained in:
Julien Nahum 2023-12-19 18:57:31 +01:00
parent aac4d1da04
commit 5640f43b9d
17 changed files with 210 additions and 282 deletions

View File

@ -42,9 +42,6 @@
<script> <script>
import { computed } from 'vue' import { computed } from 'vue'
import { useAuthStore } from '../../stores/auth.js'
import { useFormsStore } from '../../stores/forms.js'
import { useWorkspacesStore } from '../../stores/workspaces.js'
import Dropdown from '~/components/global/Dropdown.vue' import Dropdown from '~/components/global/Dropdown.vue'
export default { export default {
@ -62,7 +59,7 @@ export default {
formsStore, formsStore,
workspacesStore, workspacesStore,
user: computed(() => authStore.user), user: computed(() => authStore.user),
workspaces: computed(() => workspacesStore.content), workspaces: computed(() => workspacesStore.getAll),
loading: computed(() => workspacesStore.loading) loading: computed(() => workspacesStore.loading)
} }
}, },
@ -83,8 +80,10 @@ export default {
switchWorkspace (workspace) { switchWorkspace (workspace) {
this.workspacesStore.setCurrentId(workspace.id) this.workspacesStore.setCurrentId(workspace.id)
this.$refs.dropdown.close() this.$refs.dropdown.close()
if (this.$route.name !== 'home') { const router = useRouter()
this.$router.push({ name: 'home' }) const route = useRoute()
if (route.name !== 'home') {
router.push({ name: 'home' })
} }
this.formsStore.load(workspace.id) this.formsStore.load(workspace.id)
}, },

View File

@ -42,7 +42,8 @@
<script> <script>
import ForgotPasswordModal from '../ForgotPasswordModal.vue' import ForgotPasswordModal from '../ForgotPasswordModal.vue'
import {opnFetch} from "~/composables/useOpnApi.js"; import {opnFetch} from "~/composables/useOpnApi.js"
import {fetchAllWorkspaces} from "~/stores/workspaces.js"
export default { export default {
name: 'LoginForm', name: 'LoginForm',
@ -58,9 +59,9 @@ export default {
}, },
setup () { setup () {
const authStore = useAuthStore()
return { return {
authStore authStore: useAuthStore(),
workspaceStore: useWorkspacesStore()
} }
}, },
@ -84,6 +85,9 @@ export default {
const userData = await opnFetch('user') const userData = await opnFetch('user')
this.authStore.setUser(userData) this.authStore.setUser(userData)
const workspaces = await fetchAllWorkspaces()
this.workspaceStore.set(workspaces.data.value)
// Redirect home. // Redirect home.
this.redirect() this.redirect()
}, },

View File

@ -23,12 +23,12 @@
</router-link> </router-link>
</div> </div>
<div v-if="templates.length > 0" <div v-if="sliderTemplates.length > 0"
class="w-full inline-flex flex-nowrap overflow-hidden [mask-image:_linear-gradient(to_right,transparent_0,_black_128px,_black_calc(100%-128px),transparent_100%)]" class="w-full inline-flex flex-nowrap overflow-hidden [mask-image:_linear-gradient(to_right,transparent_0,_black_128px,_black_calc(100%-128px),transparent_100%)]"
> >
<ul ref="templates-slider" class="flex justify-center md:justify-start animate-infinite-scroll"> <ul ref="templates-slider" class="flex justify-center md:justify-start animate-infinite-scroll">
<li v-for="(template, i) in sliderTemplates" :key="template.id" class="mx-4 w-72 h-auto"> <li v-for="(template, i) in sliderTemplates" :key="template.id" class="mx-4 w-72 h-auto">
<single-template :slug="template.slug" /> <single-template :template="template" />
</li> </li>
</ul> </ul>
</div> </div>
@ -37,29 +37,31 @@
<script> <script>
import { computed } from 'vue' import { computed } from 'vue'
import { useTemplatesStore } from '../../../stores/templates'
import SingleTemplate from '../templates/SingleTemplate.vue' import SingleTemplate from '../templates/SingleTemplate.vue'
export default { export default {
components: { SingleTemplate }, components: { SingleTemplate },
props: { },
setup () { setup () {
const templatesStore = useTemplatesStore() const templatesStore = useTemplatesStore()
templatesStore.initTypesAndIndustries()
onMounted(() => {
if (templatesStore.getAll.length < 10) {
opnFetch('templates',{query: {limit: 10}}).then((data) => {
templatesStore.set(data)
})
}
})
return { return {
templatesStore, templatesStore,
templates : computed(() => templatesStore.content) allLoaded: computed(() => templatesStore.allLoaded),
} sliderTemplates: computed(() => templatesStore.getAll.slice(0, 10))
},
data: () => ({}),
computed: {
sliderTemplates () {
return this.templates.slice(0, 20)
} }
}, },
watch: { watch: {
templates: { sliderTemplates: {
deep: true, deep: true,
handler () { handler () {
this.$nextTick(() => { this.$nextTick(() => {
@ -69,10 +71,6 @@ export default {
} }
}, },
mounted() {
this.templatesStore.loadAll({ limit: 20 })
},
methods: { methods: {
setInfinite () { setInfinite () {
const ul = this.$refs['templates-slider'] const ul = this.$refs['templates-slider']

View File

@ -17,12 +17,12 @@ export const useContentStore = (mapKey = 'id') => {
return content.value.get(key) return content.value.get(key)
} }
const length = computed(() => content.value.size)
// Actions // Actions
function set(items) { function set(items) {
content.value = new Map content.value = new Map
items.forEach((item) => { save(items)
content.value.set(item[mapKey], item)
})
} }
function save(items) { function save(items) {
@ -31,7 +31,6 @@ export const useContentStore = (mapKey = 'id') => {
content.value.set(item[mapKey], item) content.value.set(item[mapKey], item)
}) })
} }
function remove(item) { function remove(item) {
content.value.remove(item[mapKey]) content.value.remove(item[mapKey])
} }
@ -54,6 +53,7 @@ export const useContentStore = (mapKey = 'id') => {
loading, loading,
getAll, getAll,
getByKey, getByKey,
length,
set, set,
save, save,
remove, remove,

View File

@ -1,4 +1,4 @@
import {useWorkspacesStore} from "~/stores/workspaces.js"; import {fetchAllWorkspaces} from "~/stores/workspaces.js";
export default defineNuxtRouteMiddleware(async(to, from) => { export default defineNuxtRouteMiddleware(async(to, from) => {
const authStore = useAuthStore() const authStore = useAuthStore()
@ -7,5 +7,10 @@ export default defineNuxtRouteMiddleware(async(to, from) => {
if (authStore.token && !authStore.user) { if (authStore.token && !authStore.user) {
const {data, error} = await useOpnApi('user') const {data, error} = await useOpnApi('user')
authStore.setUser(data.value) authStore.setUser(data.value)
// Load workspaces
const workspaceStore = useWorkspacesStore()
const {data: workspacesData, error: workspacesError} = await fetchAllWorkspaces()
workspaceStore.save(workspacesData.value)
} }
}) })

View File

@ -23,7 +23,7 @@
<div class="flex bg-white"> <div class="flex bg-white">
<div class="w-full md:w-4/5 lg:w-3/5 md:mx-auto md:max-w-4xl px-4"> <div class="w-full md:w-4/5 lg:w-3/5 md:mx-auto md:max-w-4xl px-4">
<div class="mt-8 pb-0"> <div class="mt-8 pb-0">
<text-input v-if="forms.length > 0" class="mb-6" :form="searchForm" name="search" label="Search a form" <text-input v-if="forms.length > 0" class="mb-6" v-model="search" name="search" label="Search a form"
placeholder="Name of form to search" placeholder="Name of form to search"
/> />
<div v-if="allTags.length > 0" class="mb-4"> <div v-if="allTags.length > 0" class="mb-4">
@ -63,7 +63,7 @@
<div v-else-if="forms.length > 0" class="mb-10"> <div v-else-if="forms.length > 0" class="mb-10">
<div v-if="enrichedForms && enrichedForms.length"> <div v-if="enrichedForms && enrichedForms.length">
<div v-for="(form) in enrichedForms" :key="form.id" <div v-for="(form) in enrichedForms" :key="form.id"
class="mt-4 p-4 flex group bg-white hover:bg-gray-50 dark:bg-notion-dark items-center" class="mt-4 p-4 flex group bg-white hover:bg-gray-50 dark:bg-notion-dark items-center relative"
> >
<div class="flex-grow items-center truncate cursor-pointer" role="button" <div class="flex-grow items-center truncate cursor-pointer" role="button"
@click.prevent="viewForm(form)"> @click.prevent="viewForm(form)">
@ -111,16 +111,15 @@
</div> </div>
</template> </template>
<script> <script setup>
import {computed} from 'vue'
import {useAuthStore} from '../stores/auth'; import {useAuthStore} from '../stores/auth';
import {useFormsStore} from '../stores/forms'; import {useFormsStore} from '../stores/forms';
import {useWorkspacesStore} from '../stores/workspaces'; import {useWorkspacesStore} from '../stores/workspaces';
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
import Form from 'vform'
import TextInput from '../components/forms/TextInput.vue' import TextInput from '../components/forms/TextInput.vue'
import OpenFormFooter from '../components/pages/OpenFormFooter.vue' import OpenFormFooter from '../components/pages/OpenFormFooter.vue'
import ExtraMenu from '../components/pages/forms/show/ExtraMenu.vue' import ExtraMenu from '../components/pages/forms/show/ExtraMenu.vue'
import {refDebounced} from "@vueuse/core";
const loadForms = function () { const loadForms = function () {
const formsStore = useFormsStore() const formsStore = useFormsStore()
@ -131,105 +130,74 @@ const loadForms = function () {
}) })
} }
export default { // metaTitle: {type: String, default: 'Your Forms'},
components: {OpenFormFooter, TextInput, ExtraMenu}, // metaDescription: {
// type: String,
// default: 'All of your OpnForm are here. Create new forms, or update your existing one!'
// }
props: { const authStore = useAuthStore()
metaTitle: {type: String, default: 'Your Forms'}, const formsStore = useFormsStore()
metaDescription: { const workspacesStore = useWorkspacesStore()
type: String,
default: 'All of your OpnForm are here. Create new forms, or update your existing one!'
}
},
async setup() { definePageMeta({
const authStore = useAuthStore() middleware: "auth"
const formsStore = useFormsStore() })
const workspacesStore = useWorkspacesStore()
definePageMeta({ // State
middleware: "auth" const {content: forms, loading: formsLoading} = storeToRefs(formsStore)
}) const showEditFormModal = ref(false)
const selectedForm = ref(null)
const search = ref('')
const debounceSearch = refDebounced(search, 500)
const selectedTags = ref(new Set())
loadForms() // Methods
return { const editForm = (form) => {
formsStore, selectedForm.value = form
workspacesStore, showEditFormModal.value = true
user: computed(() => authStore.user), }
forms: computed(() => formsStore.content), const onTagClick = (tag) => {
formsLoading: computed(() => formsStore.loading) if (selectedTags.value.has(tag)) {
} selectedTags.value.remove(tag)
}, } else {
selectedTags.value.add(tag)
data() {
return {
showEditFormModal: false,
selectedForm: null,
searchForm: new Form({
search: ''
}),
selectedTags: []
}
},
mounted() {
},
methods: {
editForm(form) {
this.selectedForm = form
this.showEditFormModal = true
},
onTagClick(tag) {
const idx = this.selectedTags.indexOf(tag)
if (idx === -1) {
this.selectedTags.push(tag)
} else {
this.selectedTags.splice(idx, 1)
}
},
viewForm(form) {
this.$router.push({name: 'forms.show', params: {slug: form.slug}})
}
},
computed: {
isFilteringForms() {
return (this.searchForm.search !== '' && this.searchForm.search !== null) || this.selectedTags.length > 0
},
enrichedForms() {
let enrichedForms = this.forms.map((form) => {
form.workspace = this.workspacesStore.getById(form.workspace_id)
return form
})
// Filter by Selected Tags
if (this.selectedTags.length > 0) {
enrichedForms = enrichedForms.filter((item) => {
return (item.tags && item.tags.length > 0) ? this.selectedTags.every(r => item.tags.includes(r)) : false
})
}
if (!this.isFilteringForms || this.searchForm.search === '' || this.searchForm.search === null) {
return enrichedForms
}
// Fuze search
const fuzeOptions = {
keys: [
'title',
'slug',
'tags'
]
}
const fuse = new Fuse(enrichedForms, fuzeOptions)
return fuse.search(this.searchForm.search).map((res) => {
return res.item
})
},
allTags() {
return this.formsStore.getAllTags
}
} }
} }
const viewForm = (form) => {
useRouter.push({name: 'forms.show', params: {slug: form.slug}})
}
// Computed
const isFilteringForms = computed(() => {
return (search.value !== '' && search.value !== null) || selectedTags.value.size > 0
})
const allTags = computed(() => {
return formsStore.getAllTags
})
const enrichedForms = computed(() => {
let enrichedForms = forms.value.map((form) => {
form.workspace = workspacesStore.getByKey(form.workspace_id)
return form
}).filter((form) => {
return form.tags && form.tags.length ? [...selectedTags].every(r => form.tags.includes(r)) : false
})
if (!isFilteringForms || search.value === '' || search.value === null) {
return enrichedForms
}
// Fuze search
const fuzeOptions = {
keys: [
'title',
'slug',
'tags'
]
}
const fuse = new Fuse(enrichedForms, fuzeOptions)
return fuse.search(search.value).map((res) => {
return res.item
})
})
</script> </script>

View File

@ -126,7 +126,7 @@
<!-- <testimonials/>--> <!-- <testimonials/>-->
<!-- </div>--> <!-- </div>-->
<!-- <templates-slider class="max-w-full mb-12"/>--> <templates-slider class="max-w-full mb-12"/>
<div class="w-full bg-blue-900 p-12 md:p-24 text-center"> <div class="w-full bg-blue-900 p-12 md:p-24 text-center">
<h4 class="font-semibold text-3xl text-white"> <h4 class="font-semibold text-3xl text-white">

View File

@ -13,7 +13,7 @@
</div> </div>
</section> </section>
<templates-list :templates="templates"/> <templates-list :templates="templates" :loading="loading"/>
<open-form-footer class="mt-8 border-t"/> <open-form-footer class="mt-8 border-t"/>
</div> </div>
@ -30,5 +30,6 @@ import {loadAllTemplates} from "~/stores/templates.js";
const templatesStore = useTemplatesStore() const templatesStore = useTemplatesStore()
loadAllTemplates(templatesStore) loadAllTemplates(templatesStore)
const loading = computed(() => templatesStore.loading)
const templates = computed(() => templatesStore.getAll) const templates = computed(() => templatesStore.getAll)
</script> </script>

View File

@ -36,26 +36,29 @@ export const useTemplatesStore = defineStore('templates', () => {
...contentStore, ...contentStore,
industries, industries,
types, types,
allLoaded,
getTemplateTypes, getTemplateTypes,
getTemplateIndustries, getTemplateIndustries,
initTypesAndIndustries initTypesAndIndustries
} }
}) })
export const fetchTemplate = (slug) => { export const fetchTemplate = (slug, options = {}) => {
return useOpnApi(templatesEndpoint + '/' + slug) return useOpnApi(templatesEndpoint + '/' + slug, options)
} }
export const fetchAllTemplates = () => { export const fetchAllTemplates = (options = {}) => {
return useOpnApi(templatesEndpoint) return useOpnApi(templatesEndpoint, options)
} }
export const loadAllTemplates = async (store) => { export const loadAllTemplates = async (store, options={}) => {
console.log('in------',store, store.allLoaded)
if (!store.allLoaded) { if (!store.allLoaded) {
store.startLoading() store.startLoading()
store.initTypesAndIndustries() store.initTypesAndIndustries()
const {data} = await fetchAllTemplates() const {data} = await fetchAllTemplates(options)
store.set(data.value) store.set(data.value)
store.stopLoading()
store.allLoaded = true store.allLoaded = true
} }
} }

View File

@ -1,93 +1,50 @@
import {defineStore} from 'pinia' import {defineStore} from 'pinia'
import {useStorage} from "@vueuse/core" import {useStorage} from "@vueuse/core"
import {useContentStore} from "~/composables/stores/useContentStore.js";
export const workspaceEndpoint = 'open/workspaces/' export const workspaceEndpoint = 'open/workspaces/'
const storedWorkspaceId = useStorage('currentWorkspace', 0) export const useWorkspacesStore = defineStore('workspaces', () => {
export const useWorkspacesStore = defineStore('workspaces', { const storedWorkspaceId = useCookie('currentWorkspace')
state: () => ({
content: new Map, const contentStore = useContentStore()
currentId: null, const currentId = ref(storedWorkspaceId)
loading: false
}), const getCurrent = computed(() => {
getters: { return contentStore.getByKey(currentId.value)
getById: (state) => (id) => { })
if (state.content.length === 0) return null
return state.content.find(item => item.id === id) const setCurrentId = (id) => {
}, currentId.value = id
getCurrent (){ storedWorkspaceId.value = id
if (this.content.length === 0 || this.currentId === null) return null }
return this.content.find(item => item.id === this.currentId)
} const save = (items) => {
}, contentStore.save(items)
actions: { console.log('cookie issi', currentId.value, contentStore.length.value)
set(items) { if (currentId.value == null && contentStore.length.value) {
this.content = items setCurrentId(items[0].id)
if (this.currentId == null && this.content.length > 0) {
// If one only, set it
if (this.content.length === 1) {
this.setCurrentId(items[0].id)
} else if (storedWorkspaceId && this.content.find(item => item.id === parseInt(storedWorkspaceId.value))) {
// Check local storage for current workspace, or take first
this.setCurrentId(parseInt(storedWorkspaceId.value))
} else {
// Else, take first
this.setCurrentId(items[0].id)
}
} else {
this.setCurrentId(null)
}
},
setCurrentId(id) {
this.currentId = id
storedWorkspaceId.value = id
},
addOrUpdate(item) {
this.content = this.content.filter((val) => val.id !== item.id)
this.content.push(item)
if (this.currentId == null) {
this.currentId = item.id
storedWorkspaceId.value = this.currentId
}
},
remove(itemId) {
this.content = this.content.filter((val) => val.id !== itemId)
if (this.currentId === itemId) {
this.setCurrentId(this.content.length > 0 ? this.content[0].id : null)
}
},
startLoading() {
this.loading = true
},
stopLoading() {
this.loading = false
},
resetState() {
this.set([])
this.stopLoading()
},
load() {
this.set([])
this.startLoading()
console.log('loaindgworkspaces')
return useOpnApi(workspaceEndpoint).then(({data, error}) => {
this.set(data.value)
this.stopLoading()
})
},
loadIfEmpty() {
if (this.content.length === 0) {
return this.load()
}
return Promise.resolve()
},
delete(id) {
this.startLoading()
return useOpnApi(workspaceEndpoint + id, {method: 'DELETE'}).then(({data}) => {
this.remove(data.value.workspace_id)
this.stopLoading()
})
} }
} }
const remove = (itemId) => {
contentStore.remove(itemId)
if (currentId.value === itemId) {
setCurrentId(contentStore.length.value > 0 ? contentStore.getAll[0].id : null)
}
}
return {
...contentStore,
currentId,
getCurrent,
setCurrentId,
save,
remove
}
}) })
export const fetchAllWorkspaces = (options = {}) => {
return useOpnApi(workspaceEndpoint, options)
}

6
package-lock.json generated
View File

@ -20,7 +20,6 @@
"date-fns": "^2.28.0", "date-fns": "^2.28.0",
"debounce": "^1.2.1", "debounce": "^1.2.1",
"fuse.js": "^6.4.6", "fuse.js": "^6.4.6",
"js-cookie": "^2.2.1",
"js-sha256": "^0.9.0", "js-sha256": "^0.9.0",
"libphonenumber-js": "^1.10.44", "libphonenumber-js": "^1.10.44",
"pinia": "^2.1.7", "pinia": "^2.1.7",
@ -9283,11 +9282,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/js-cookie": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
},
"node_modules/js-sha256": { "node_modules/js-sha256": {
"version": "0.9.0", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz",

View File

@ -20,7 +20,7 @@
</button> </button>
</div> </div>
<div class="sm:flex sm:flex-col sm:items-start"> <div class="sm:flex sm:flex-col sm:items-start">
<div v-if="$scopedSlots.hasOwnProperty('icon')" class="flex w-full justify-center mb-4"> <div v-if="$slots.hasOwnProperty('icon')" class="flex w-full justify-center mb-4">
<div class="w-14 h-14 rounded-full flex justify-center items-center" <div class="w-14 h-14 rounded-full flex justify-center items-center"
:class="'bg-'+iconColor+'-100 text-'+iconColor+'-600'" :class="'bg-'+iconColor+'-100 text-'+iconColor+'-600'"
> >
@ -28,7 +28,7 @@
</div> </div>
</div> </div>
<div class="mt-3 text-center sm:mt-0 w-full"> <div class="mt-3 text-center sm:mt-0 w-full">
<h2 v-if="$scopedSlots.hasOwnProperty('title')" <h2 v-if="$slots.hasOwnProperty('title')"
class="text-2xl font-semibold text-center text-gray-900" class="text-2xl font-semibold text-center text-gray-900"
> >
<slot name="title" /> <slot name="title" />

View File

@ -71,7 +71,7 @@
My Forms My Forms
</router-link> </router-link>
<router-link v-if="userOnboarded" :to="{ name: 'my_templates' }" <router-link v-if="userOnboarded" :to="{ name: 'templates-my-templates' }"
class="block block 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" class="block block 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"
> >
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 mr-2" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 mr-2" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
@ -80,7 +80,7 @@
My Templates My Templates
</router-link> </router-link>
<router-link :to="{ name: 'settings.profile' }" <router-link :to="{ name: 'settings-profile' }"
class="block block 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" class="block block 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"
> >
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" <svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"

View File

@ -129,6 +129,12 @@ export default {
submitButtonClass: { type: String, default: '' } submitButtonClass: { type: String, default: '' }
}, },
setup () {
return {
isIframe: useIsIframe()
}
},
data () { data () {
return { return {
loading: false, loading: false,
@ -143,10 +149,8 @@ export default {
}, },
computed: { computed: {
isIframe () {
return window.location !== window.parent.location || window.frameElement
},
isEmbedPopup () { isEmbedPopup () {
if (process.server) return false
return window.location.href.includes('popup=true') return window.location.href.includes('popup=true')
}, },
theme () { theme () {

View File

@ -1,4 +1,5 @@
import { useAuthStore } from '../stores/auth'; import { useAuthStore } from '../stores/auth'
import { useWorkspacesStore } from '../stores/workspaces'
import * as Sentry from '@sentry/vue' import * as Sentry from '@sentry/vue'
export function initCrisp (user) { export function initCrisp (user) {
@ -45,6 +46,7 @@ export default async (to, from, next) => {
authStore.fetchUser().then((user) => { authStore.fetchUser().then((user) => {
initCrisp(user) initCrisp(user)
initSentry(user) initSentry(user)
useWorkspacesStore().fetchWorkspaces()
}) })
} catch (e) { } catch (e) {
console.error(e) console.error(e)

View File

@ -74,12 +74,14 @@
</li> </li>
</ul> </ul>
<div v-if="['draft','closed'].includes(form.visibility) || (form.tags && form.tags.length > 0)" class="mt-1 flex items-center flex-wrap gap-3"> <div v-if="['draft','closed'].includes(form.visibility) || (form.tags && form.tags.length > 0)" class="mt-1 flex items-center flex-wrap gap-3">
<span v-if="form.visibility=='draft'" <span v-if="form.visibility=='draft'"
class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-1 text-xs font-medium text-yellow-600 ring-1 ring-inset ring-gray-500/10 dark:text-white dark:bg-gray-700"> class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-1 text-xs font-medium text-yellow-600 ring-1 ring-inset ring-gray-500/10 dark:text-white dark:bg-gray-700"
>
Draft Draft
</span> </span>
<span v-else-if="form.visibility=='closed'" <span v-else-if="form.visibility=='closed'"
class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-1 text-xs font-medium text-yellow-600 ring-1 ring-inset ring-gray-500/10 dark:text-white dark:bg-gray-700"> class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-1 text-xs font-medium text-yellow-600 ring-1 ring-inset ring-gray-500/10 dark:text-white dark:bg-gray-700"
>
Closed Closed
</span> </span>
<span v-for="(tag,i) in form.tags" :key="tag" <span v-for="(tag,i) in form.tags" :key="tag"
@ -105,31 +107,18 @@
<script> <script>
import { computed } from 'vue' import { computed } from 'vue'
import { useAuthStore } from '../stores/auth'; import { useAuthStore } from '../stores/auth'
import { useFormsStore } from '../stores/forms'; import { useFormsStore } from '../stores/forms'
import { useWorkspacesStore } from '../stores/workspaces'; import { useWorkspacesStore } from '../stores/workspaces'
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
import Form from 'vform' import Form from 'vform'
import TextInput from '../components/forms/TextInput.vue' import TextInput from '../components/forms/TextInput.vue'
import OpenFormFooter from '../components/pages/OpenFormFooter.vue' import OpenFormFooter from '../components/pages/OpenFormFooter.vue'
import ExtraMenu from '../components/pages/forms/show/ExtraMenu.vue' import ExtraMenu from '../components/pages/forms/show/ExtraMenu.vue
const loadForms = function () {
const formsStore = useFormsStore()
const workspacesStore = useWorkspacesStore()
formsStore.startLoading()
workspacesStore.loadIfEmpty().then(() => {
formsStore.loadIfEmpty(workspacesStore.currentId)
})
}
export default { export default {
components: { OpenFormFooter, TextInput, ExtraMenu }, components: { OpenFormFooter, TextInput, ExtraMenu },
beforeRouteEnter (to, from, next) {
loadForms()
next()
},
middleware: 'auth', middleware: 'auth',
props: { props: {
@ -141,12 +130,16 @@ export default {
const authStore = useAuthStore() const authStore = useAuthStore()
const formsStore = useFormsStore() const formsStore = useFormsStore()
const workspacesStore = useWorkspacesStore() const workspacesStore = useWorkspacesStore()
formsStore.startLoading()
formsStore.loadIfEmpty(workspacesStore.currentId)
return { return {
formsStore, formsStore,
workspacesStore, workspacesStore,
user : computed(() => authStore.user), user: computed(() => authStore.user),
forms : computed(() => formsStore.content), forms: computed(() => formsStore.content),
formsLoading : computed(() => formsStore.loading) formsLoading: computed(() => formsStore.loading)
} }
}, },
@ -161,26 +154,6 @@ export default {
} }
}, },
mounted () {},
methods: {
editForm (form) {
this.selectedForm = form
this.showEditFormModal = true
},
onTagClick (tag) {
const idx = this.selectedTags.indexOf(tag)
if (idx === -1) {
this.selectedTags.push(tag)
} else {
this.selectedTags.splice(idx, 1)
}
},
viewForm (form) {
this.$router.push({ name: 'forms.show', params: { slug: form.slug } })
}
},
computed: { computed: {
isFilteringForms () { isFilteringForms () {
return (this.searchForm.search !== '' && this.searchForm.search !== null) || this.selectedTags.length > 0 return (this.searchForm.search !== '' && this.searchForm.search !== null) || this.selectedTags.length > 0
@ -218,6 +191,26 @@ export default {
allTags () { allTags () {
return this.formsStore.getAllTags return this.formsStore.getAllTags
} }
},
mounted () {},
methods: {
editForm (form) {
this.selectedForm = form
this.showEditFormModal = true
},
onTagClick (tag) {
const idx = this.selectedTags.indexOf(tag)
if (idx === -1) {
this.selectedTags.push(tag)
} else {
this.selectedTags.splice(idx, 1)
}
},
viewForm (form) {
this.$router.push({ name: 'forms.show', params: { slug: form.slug } })
}
} }
} }
</script> </script>

View File

@ -80,4 +80,4 @@ export const useFormsStore = defineStore('forms', {
return Promise.resolve() return Promise.resolve()
} }
} }
}) })