Reworked workspaces store
This commit is contained in:
parent
aac4d1da04
commit
5640f43b9d
|
@ -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)
|
||||||
},
|
},
|
||||||
|
|
|
@ -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()
|
||||||
},
|
},
|
||||||
|
|
|
@ -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']
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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,18 +130,12 @@ 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: {
|
|
||||||
metaTitle: {type: String, default: 'Your Forms'},
|
|
||||||
metaDescription: {
|
|
||||||
type: String,
|
|
||||||
default: 'All of your OpnForm are here. Create new forms, or update your existing one!'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async setup() {
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const formsStore = useFormsStore()
|
const formsStore = useFormsStore()
|
||||||
const workspacesStore = useWorkspacesStore()
|
const workspacesStore = useWorkspacesStore()
|
||||||
|
@ -151,66 +144,46 @@ export default {
|
||||||
middleware: "auth"
|
middleware: "auth"
|
||||||
})
|
})
|
||||||
|
|
||||||
loadForms()
|
// State
|
||||||
return {
|
const {content: forms, loading: formsLoading} = storeToRefs(formsStore)
|
||||||
formsStore,
|
const showEditFormModal = ref(false)
|
||||||
workspacesStore,
|
const selectedForm = ref(null)
|
||||||
user: computed(() => authStore.user),
|
const search = ref('')
|
||||||
forms: computed(() => formsStore.content),
|
const debounceSearch = refDebounced(search, 500)
|
||||||
formsLoading: computed(() => formsStore.loading)
|
const selectedTags = ref(new Set())
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
const editForm = (form) => {
|
||||||
|
selectedForm.value = form
|
||||||
|
showEditFormModal.value = true
|
||||||
}
|
}
|
||||||
},
|
const onTagClick = (tag) => {
|
||||||
|
if (selectedTags.value.has(tag)) {
|
||||||
data() {
|
selectedTags.value.remove(tag)
|
||||||
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 {
|
} else {
|
||||||
this.selectedTags.splice(idx, 1)
|
selectedTags.value.add(tag)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
viewForm(form) {
|
|
||||||
this.$router.push({name: 'forms.show', params: {slug: form.slug}})
|
|
||||||
}
|
}
|
||||||
},
|
const viewForm = (form) => {
|
||||||
|
useRouter.push({name: 'forms.show', params: {slug: form.slug}})
|
||||||
|
}
|
||||||
|
|
||||||
computed: {
|
// Computed
|
||||||
isFilteringForms() {
|
const isFilteringForms = computed(() => {
|
||||||
return (this.searchForm.search !== '' && this.searchForm.search !== null) || this.selectedTags.length > 0
|
return (search.value !== '' && search.value !== null) || selectedTags.value.size > 0
|
||||||
},
|
})
|
||||||
enrichedForms() {
|
const allTags = computed(() => {
|
||||||
let enrichedForms = this.forms.map((form) => {
|
return formsStore.getAllTags
|
||||||
form.workspace = this.workspacesStore.getById(form.workspace_id)
|
})
|
||||||
|
const enrichedForms = computed(() => {
|
||||||
|
let enrichedForms = forms.value.map((form) => {
|
||||||
|
form.workspace = workspacesStore.getByKey(form.workspace_id)
|
||||||
return form
|
return form
|
||||||
|
}).filter((form) => {
|
||||||
|
return form.tags && form.tags.length ? [...selectedTags].every(r => form.tags.includes(r)) : false
|
||||||
})
|
})
|
||||||
|
|
||||||
// Filter by Selected Tags
|
if (!isFilteringForms || search.value === '' || search.value === null) {
|
||||||
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
|
return enrichedForms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,13 +196,8 @@ export default {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
const fuse = new Fuse(enrichedForms, fuzeOptions)
|
const fuse = new Fuse(enrichedForms, fuzeOptions)
|
||||||
return fuse.search(this.searchForm.search).map((res) => {
|
return fuse.search(search.value).map((res) => {
|
||||||
return res.item
|
return res.item
|
||||||
})
|
})
|
||||||
},
|
})
|
||||||
allTags() {
|
|
||||||
return this.formsStore.getAllTags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 (){
|
|
||||||
if (this.content.length === 0 || this.currentId === null) return null
|
|
||||||
return this.content.find(item => item.id === this.currentId)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
set(items) {
|
|
||||||
this.content = items
|
|
||||||
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
|
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) {
|
const save = (items) => {
|
||||||
this.content = this.content.filter((val) => val.id !== itemId)
|
contentStore.save(items)
|
||||||
if (this.currentId === itemId) {
|
console.log('cookie issi', currentId.value, contentStore.length.value)
|
||||||
this.setCurrentId(this.content.length > 0 ? this.content[0].id : null)
|
if (currentId.value == null && contentStore.length.value) {
|
||||||
|
setCurrentId(items[0].id)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
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()
|
|
||||||
},
|
const remove = (itemId) => {
|
||||||
delete(id) {
|
contentStore.remove(itemId)
|
||||||
this.startLoading()
|
if (currentId.value === itemId) {
|
||||||
return useOpnApi(workspaceEndpoint + id, {method: 'DELETE'}).then(({data}) => {
|
setCurrentId(contentStore.length.value > 0 ? contentStore.getAll[0].id : null)
|
||||||
this.remove(data.value.workspace_id)
|
|
||||||
this.stopLoading()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...contentStore,
|
||||||
|
currentId,
|
||||||
|
getCurrent,
|
||||||
|
setCurrentId,
|
||||||
|
save,
|
||||||
|
remove
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const fetchAllWorkspaces = (options = {}) => {
|
||||||
|
return useOpnApi(workspaceEndpoint, options)
|
||||||
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 () {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -75,11 +75,13 @@
|
||||||
</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,6 +130,10 @@ 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,
|
||||||
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue