feat: move composables in separate files (#2485)
Co-authored-by: Dominik Pschenitschni <mail@celement.de> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/2485 Reviewed-by: konrad <k@knt.li> Co-authored-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de> Co-committed-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
This commit is contained in:
parent
6f2dedcb48
commit
c206fc6f34
4 changed files with 106 additions and 93 deletions
|
@ -60,65 +60,18 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {watch, computed, shallowRef, watchEffect, type VNode, h} from 'vue'
|
import {watch, computed} from 'vue'
|
||||||
import {useBaseStore} from '@/stores/base'
|
import {useRoute} from 'vue-router'
|
||||||
import {useRoute, useRouter} from 'vue-router'
|
|
||||||
import {useEventListener} from '@vueuse/core'
|
|
||||||
|
|
||||||
import {useLabelStore} from '@/stores/labels'
|
|
||||||
import Navigation from '@/components/home/navigation.vue'
|
import Navigation from '@/components/home/navigation.vue'
|
||||||
import QuickActions from '@/components/quick-actions/quick-actions.vue'
|
import QuickActions from '@/components/quick-actions/quick-actions.vue'
|
||||||
import BaseButton from '@/components/base/BaseButton.vue'
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
import {useAuthStore} from '@/stores/auth'
|
|
||||||
|
|
||||||
function useRouteWithModal() {
|
import {useBaseStore} from '@/stores/base'
|
||||||
const router = useRouter()
|
import {useLabelStore} from '@/stores/labels'
|
||||||
const route = useRoute()
|
|
||||||
const backdropView = computed(() => route.fullPath && window.history.state.backdropView)
|
|
||||||
|
|
||||||
const routeWithModal = computed(() => {
|
import {useRouteWithModal} from '@/composables/useRouteWithModal'
|
||||||
return backdropView.value
|
import {useRenewTokenOnFocus} from '@/composables/useRenewTokenOnFocus'
|
||||||
? router.resolve(backdropView.value)
|
|
||||||
: route
|
|
||||||
})
|
|
||||||
|
|
||||||
const currentModal = shallowRef<VNode>()
|
|
||||||
watchEffect(() => {
|
|
||||||
if (!backdropView.value) {
|
|
||||||
currentModal.value = undefined
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// logic from vue-router
|
|
||||||
// https://github.com/vuejs/vue-router-next/blob/798cab0d1e21f9b4d45a2bd12b840d2c7415f38a/src/RouterView.ts#L125
|
|
||||||
const routePropsOption = route.matched[0]?.props.default
|
|
||||||
const routeProps = routePropsOption
|
|
||||||
? routePropsOption === true
|
|
||||||
? route.params
|
|
||||||
: typeof routePropsOption === 'function'
|
|
||||||
? routePropsOption(route)
|
|
||||||
: routePropsOption
|
|
||||||
: null
|
|
||||||
|
|
||||||
currentModal.value = h(
|
|
||||||
route.matched[0]?.components.default,
|
|
||||||
routeProps,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
function closeModal() {
|
|
||||||
const historyState = computed(() => route.fullPath && window.history.state)
|
|
||||||
|
|
||||||
if (historyState.value) {
|
|
||||||
router.back()
|
|
||||||
} else {
|
|
||||||
const backdropRoute = historyState.value?.backdropView && router.resolve(historyState.value.backdropView)
|
|
||||||
router.push(backdropRoute)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {routeWithModal, currentModal, closeModal}
|
|
||||||
}
|
|
||||||
|
|
||||||
const {routeWithModal, currentModal, closeModal} = useRouteWithModal()
|
const {routeWithModal, currentModal, closeModal} = useRouteWithModal()
|
||||||
|
|
||||||
|
@ -162,43 +115,8 @@ watch(() => route.name as string, (routeName) => {
|
||||||
|
|
||||||
// TODO: Reset the title if the page component does not set one itself
|
// TODO: Reset the title if the page component does not set one itself
|
||||||
|
|
||||||
function useRenewTokenOnFocus() {
|
|
||||||
const router = useRouter()
|
|
||||||
const authStore = useAuthStore()
|
|
||||||
|
|
||||||
|
|
||||||
const userInfo = computed(() => authStore.info)
|
|
||||||
const authenticated = computed(() => authStore.authenticated)
|
|
||||||
|
|
||||||
// Try renewing the token every time vikunja is loaded initially
|
|
||||||
// (When opening the browser the focus event is not fired)
|
|
||||||
authStore.renewToken()
|
|
||||||
|
|
||||||
// Check if the token is still valid if the window gets focus again to maybe renew it
|
|
||||||
useEventListener('focus', () => {
|
|
||||||
if (!authenticated.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const expiresIn = (userInfo.value !== null ? userInfo.value.exp : 0) - +new Date() / 1000
|
|
||||||
|
|
||||||
// If the token expiry is negative, it is already expired and we have no choice but to redirect
|
|
||||||
// the user to the login page
|
|
||||||
if (expiresIn < 0) {
|
|
||||||
authStore.checkAuth()
|
|
||||||
router.push({name: 'user.login'})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the token is valid for less than 60 hours and renew if thats the case
|
|
||||||
if (expiresIn < 60 * 3600) {
|
|
||||||
authStore.renewToken()
|
|
||||||
console.debug('renewed token')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useRenewTokenOnFocus()
|
useRenewTokenOnFocus()
|
||||||
|
|
||||||
const labelStore = useLabelStore()
|
const labelStore = useLabelStore()
|
||||||
labelStore.loadAllLabels()
|
labelStore.loadAllLabels()
|
||||||
</script>
|
</script>
|
||||||
|
|
40
src/composables/useRenewTokenOnFocus.ts
Normal file
40
src/composables/useRenewTokenOnFocus.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import {computed} from 'vue'
|
||||||
|
import {useRouter} from 'vue-router'
|
||||||
|
import {useEventListener} from '@vueuse/core'
|
||||||
|
|
||||||
|
import {useAuthStore} from '@/stores/auth'
|
||||||
|
|
||||||
|
export function useRenewTokenOnFocus() {
|
||||||
|
const router = useRouter()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
|
const userInfo = computed(() => authStore.info)
|
||||||
|
const authenticated = computed(() => authStore.authenticated)
|
||||||
|
|
||||||
|
// Try renewing the token every time vikunja is loaded initially
|
||||||
|
// (When opening the browser the focus event is not fired)
|
||||||
|
authStore.renewToken()
|
||||||
|
|
||||||
|
// Check if the token is still valid if the window gets focus again to maybe renew it
|
||||||
|
useEventListener('focus', () => {
|
||||||
|
if (!authenticated.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const expiresIn = (userInfo.value !== null ? userInfo.value.exp : 0) - +new Date() / 1000
|
||||||
|
|
||||||
|
// If the token expiry is negative, it is already expired and we have no choice but to redirect
|
||||||
|
// the user to the login page
|
||||||
|
if (expiresIn < 0) {
|
||||||
|
authStore.checkAuth()
|
||||||
|
router.push({name: 'user.login'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the token is valid for less than 60 hours and renew if thats the case
|
||||||
|
if (expiresIn < 60 * 3600) {
|
||||||
|
authStore.renewToken()
|
||||||
|
console.debug('renewed token')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
54
src/composables/useRouteWithModal.ts
Normal file
54
src/composables/useRouteWithModal.ts
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import { computed, shallowRef, watchEffect, h, type VNode } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
export function useRouteWithModal() {
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const backdropView = computed(() => route.fullPath && window.history.state.backdropView)
|
||||||
|
|
||||||
|
const routeWithModal = computed(() => {
|
||||||
|
return backdropView.value
|
||||||
|
? router.resolve(backdropView.value)
|
||||||
|
: route
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentModal = shallowRef<VNode>()
|
||||||
|
watchEffect(() => {
|
||||||
|
if (!backdropView.value) {
|
||||||
|
currentModal.value = undefined
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// logic from vue-router
|
||||||
|
// https://github.com/vuejs/vue-router-next/blob/798cab0d1e21f9b4d45a2bd12b840d2c7415f38a/src/RouterView.ts#L125
|
||||||
|
const routePropsOption = route.matched[0]?.props.default
|
||||||
|
const routeProps = routePropsOption
|
||||||
|
? routePropsOption === true
|
||||||
|
? route.params
|
||||||
|
: typeof routePropsOption === 'function'
|
||||||
|
? routePropsOption(route)
|
||||||
|
: routePropsOption
|
||||||
|
: null
|
||||||
|
|
||||||
|
const component = route.matched[0]?.components?.default
|
||||||
|
|
||||||
|
if (!component) {
|
||||||
|
currentModal.value = undefined
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentModal.value = h(component, routeProps)
|
||||||
|
})
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
const historyState = computed(() => route.fullPath && window.history.state)
|
||||||
|
|
||||||
|
if (historyState.value) {
|
||||||
|
router.back()
|
||||||
|
} else {
|
||||||
|
const backdropRoute = historyState.value?.backdropView && router.resolve(historyState.value.backdropView)
|
||||||
|
router.push(backdropRoute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {routeWithModal, currentModal, closeModal}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ import type {IList} from '@/modelTypes/IList'
|
||||||
export interface RootStoreState {
|
export interface RootStoreState {
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
|
|
||||||
currentList: IList,
|
currentList: IList | null,
|
||||||
background: string,
|
background: string,
|
||||||
blurHash: string,
|
blurHash: string,
|
||||||
|
|
||||||
|
@ -47,12 +47,13 @@ export const useBaseStore = defineStore('base', {
|
||||||
this.loading = loading
|
this.loading = loading
|
||||||
},
|
},
|
||||||
|
|
||||||
setCurrentList(currentList: IList) {
|
setCurrentList(currentList: IList | null) {
|
||||||
// Server updates don't return the right. Therefore, the right is reset after updating the list which is
|
// Server updates don't return the right. Therefore, the right is reset after updating the list which is
|
||||||
// confusing because all the buttons will disappear in that case. To prevent this, we're keeping the right
|
// confusing because all the buttons will disappear in that case. To prevent this, we're keeping the right
|
||||||
// when updating the list in global state.
|
// when updating the list in global state.
|
||||||
if (
|
if (
|
||||||
typeof this.currentList.maxRight !== 'undefined' &&
|
typeof this.currentList?.maxRight !== 'undefined' &&
|
||||||
|
currentList !== null &&
|
||||||
(
|
(
|
||||||
typeof currentList.maxRight === 'undefined' ||
|
typeof currentList.maxRight === 'undefined' ||
|
||||||
currentList.maxRight === null
|
currentList.maxRight === null
|
||||||
|
@ -95,7 +96,7 @@ export const useBaseStore = defineStore('base', {
|
||||||
this.logoVisible = visible
|
this.logoVisible = visible
|
||||||
},
|
},
|
||||||
|
|
||||||
async handleSetCurrentList({list, forceUpdate = false} : {list: IList, forceUpdate: boolean}) {
|
async handleSetCurrentList({list, forceUpdate = false} : {list: IList | null, forceUpdate: boolean}) {
|
||||||
if (list === null) {
|
if (list === null) {
|
||||||
this.setCurrentList({})
|
this.setCurrentList({})
|
||||||
this.setBackground('')
|
this.setBackground('')
|
||||||
|
|
Loading…
Reference in a new issue