diff --git a/src/components/home/contentAuth.vue b/src/components/home/contentAuth.vue
index 3396be576..616c17dfe 100644
--- a/src/components/home/contentAuth.vue
+++ b/src/components/home/contentAuth.vue
@@ -60,65 +60,18 @@
diff --git a/src/composables/useRenewTokenOnFocus.ts b/src/composables/useRenewTokenOnFocus.ts
new file mode 100644
index 000000000..06305984e
--- /dev/null
+++ b/src/composables/useRenewTokenOnFocus.ts
@@ -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')
+ }
+ })
+}
\ No newline at end of file
diff --git a/src/composables/useRouteWithModal.ts b/src/composables/useRouteWithModal.ts
new file mode 100644
index 000000000..c7ff45985
--- /dev/null
+++ b/src/composables/useRouteWithModal.ts
@@ -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()
+ 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}
+}
\ No newline at end of file
diff --git a/src/stores/base.ts b/src/stores/base.ts
index 2e5702b6c..83be64133 100644
--- a/src/stores/base.ts
+++ b/src/stores/base.ts
@@ -12,7 +12,7 @@ import type {IList} from '@/modelTypes/IList'
export interface RootStoreState {
loading: boolean,
- currentList: IList,
+ currentList: IList | null,
background: string,
blurHash: string,
@@ -47,12 +47,13 @@ export const useBaseStore = defineStore('base', {
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
// 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.
if (
- typeof this.currentList.maxRight !== 'undefined' &&
+ typeof this.currentList?.maxRight !== 'undefined' &&
+ currentList !== null &&
(
typeof currentList.maxRight === 'undefined' ||
currentList.maxRight === null
@@ -95,7 +96,7 @@ export const useBaseStore = defineStore('base', {
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) {
this.setCurrentList({})
this.setBackground('')