Add option to select landing page

This commit is contained in:
surfingbytes 2026-03-20 12:59:40 +00:00
parent de1d5d1241
commit d9c4988229
9 changed files with 131 additions and 3 deletions

View File

@ -1,5 +1,7 @@
import {useRouter} from 'vue-router'
import {getLastVisited, clearLastVisited} from '@/helpers/saveLastVisited'
import {getLastVisited, clearLastVisited, getLastVisitedPage} from '@/helpers/saveLastVisited'
import {useAuthStore} from '@/stores/auth'
import {DEFAULT_PAGE} from '@/constants/defaultPage'
export function useRedirectToLastVisited() {
@ -19,10 +21,36 @@ export function useRedirectToLastVisited() {
}
}
function getDefaultPageRoute() {
const authStore = useAuthStore()
const defaultPage = authStore.settings?.frontendSettings?.defaultPage
switch (defaultPage) {
case DEFAULT_PAGE.UPCOMING:
return {name: 'tasks.range'}
case DEFAULT_PAGE.DEFAULT_PROJECT: {
const projectId = authStore.settings?.defaultProjectId
if (projectId) {
return {name: 'project.index', params: {projectId}}
}
return {name: 'home'}
}
case DEFAULT_PAGE.LAST_VISITED: {
const last = getLastVisitedPage()
if (last) {
return {name: last.name, params: last.params, query: last.query}
}
return {name: 'home'}
}
default:
return {name: 'home'}
}
}
function redirectIfSaved() {
const lastRoute = getLastVisitedRoute()
if (!lastRoute) {
return router.push({name: 'home'})
return router.push(getDefaultPageRoute())
}
return router.push(lastRoute)

View File

@ -0,0 +1,8 @@
export const DEFAULT_PAGE = {
OVERVIEW: 'overview',
UPCOMING: 'upcoming',
DEFAULT_PROJECT: 'defaultProject',
LAST_VISITED: 'lastVisited',
} as const
export type DefaultPage = typeof DEFAULT_PAGE[keyof typeof DEFAULT_PAGE]

View File

@ -1,4 +1,5 @@
const LAST_VISITED_KEY = 'lastVisited'
const LAST_VISITED_PAGE_KEY = 'lastVisitedPage'
export const saveLastVisited = (name: string | undefined, params: object, query: object) => {
if (typeof name === 'undefined') {
@ -20,3 +21,20 @@ export const getLastVisited = () => {
export const clearLastVisited = () => {
return localStorage.removeItem(LAST_VISITED_KEY)
}
export const saveLastVisitedPage = (name: string | undefined, params: object, query: object) => {
if (typeof name === 'undefined') {
return
}
localStorage.setItem(LAST_VISITED_PAGE_KEY, JSON.stringify({name, params, query}))
}
export const getLastVisitedPage = () => {
const lastVisited = localStorage.getItem(LAST_VISITED_PAGE_KEY)
if (lastVisited === null) {
return null
}
return JSON.parse(lastVisited)
}

View File

@ -121,6 +121,13 @@
"12h": "12-hour (AM/PM)",
"24h": "24-hour (HH:mm)"
},
"defaultPage": "Default page",
"defaultPageOptions": {
"overview": "Overview",
"upcoming": "Upcoming",
"defaultProject": "Default project",
"lastVisited": "Last visited"
},
"externalUserNameChange": "Your name is managed by your login provider ({provider}). To change it, please update it there instead."
},
"sections": {

View File

@ -8,6 +8,7 @@ import type {Priority} from '@/constants/priorities'
import type {DateDisplay} from '@/constants/dateDisplay'
import type {TimeFormat} from '@/constants/timeFormat'
import type {IRelationKind} from '@/types/IRelationKind'
import type {DefaultPage} from '@/constants/defaultPage'
export interface IFrontendSettings {
playSoundWhenDone: boolean
@ -24,6 +25,7 @@ export interface IFrontendSettings {
alwaysShowBucketTaskCount: boolean
sidebarWidth: number | null
commentSortOrder: 'asc' | 'desc'
defaultPage: DefaultPage
}
export interface IExtraSettingsLink {

View File

@ -8,6 +8,7 @@ import {PRIORITIES} from '@/constants/priorities'
import {DATE_DISPLAY} from '@/constants/dateDisplay'
import {TIME_FORMAT} from '@/constants/timeFormat'
import {RELATION_KIND} from '@/types/IRelationKind'
import {DEFAULT_PAGE} from '@/constants/defaultPage'
export default class UserSettingsModel extends AbstractModel<IUserSettings> implements IUserSettings {
name = ''
@ -35,6 +36,7 @@ export default class UserSettingsModel extends AbstractModel<IUserSettings> impl
alwaysShowBucketTaskCount: false,
sidebarWidth: null,
commentSortOrder: 'asc',
defaultPage: DEFAULT_PAGE.LAST_VISITED,
}
extraSettingsLinks = {}

View File

@ -1,12 +1,13 @@
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteLocation } from 'vue-router'
import {saveLastVisited} from '@/helpers/saveLastVisited'
import {saveLastVisited, saveLastVisitedPage, getLastVisitedPage} from '@/helpers/saveLastVisited'
import {getProjectViewId} from '@/helpers/projectView'
import {parseDateOrString} from '@/helpers/time/parseDateOrString'
import {getNextWeekDate} from '@/helpers/time/getNextWeekDate'
import {LINK_SHARE_HASH_PREFIX} from '@/constants/linkShareHash'
import {AUTH_ROUTE_NAMES} from '@/constants/authRouteNames'
import {DEFAULT_PAGE} from '@/constants/defaultPage'
import {useAuthStore} from '@/stores/auth'
@ -42,6 +43,33 @@ const router = createRouter({
path: '/',
name: 'home',
component: () => import('@/views/Home.vue'),
beforeEnter(_to, from) {
if (from.name !== undefined) {
return
}
const authStore = useAuthStore()
const defaultPage = authStore.settings?.frontendSettings?.defaultPage
switch (defaultPage) {
case DEFAULT_PAGE.UPCOMING:
return {name: 'tasks.range'}
case DEFAULT_PAGE.DEFAULT_PROJECT: {
const projectId = authStore.settings?.defaultProjectId
if (projectId) {
return {name: 'project.index', params: {projectId}}
}
break
}
case DEFAULT_PAGE.LAST_VISITED: {
const last = getLastVisitedPage()
if (last) {
return {name: last.name, params: last.params, query: last.query}
}
break
}
}
},
},
{
path: '/:pathMatch(.*)*',
@ -480,4 +508,10 @@ router.beforeEach(async (to, from) => {
}
})
router.afterEach((to) => {
if (!AUTH_ROUTE_NAMES.has(to.name as string) && to.name !== 'home') {
saveLastVisitedPage(to.name as string, to.params, to.query)
}
})
export default router

View File

@ -25,6 +25,7 @@ import {PrefixMode} from '@/modules/parseTaskText'
import {DATE_DISPLAY} from '@/constants/dateDisplay'
import {TIME_FORMAT} from '@/constants/timeFormat'
import {RELATION_KIND} from '@/types/IRelationKind'
import {DEFAULT_PAGE} from '@/constants/defaultPage'
import type {IProvider} from '@/types/IProvider'
function redirectToSpecifiedProvider() {
@ -141,6 +142,7 @@ export const useAuthStore = defineStore('auth', () => {
backgroundBrightness: 100,
sidebarWidth: null,
commentSortOrder: 'asc',
defaultPage: DEFAULT_PAGE.LAST_VISITED,
...newSettings.frontendSettings,
},
})

View File

@ -47,6 +47,24 @@
:loading="loading"
>
<div class="field-group">
<div class="field">
<label class="two-col">
<span>
{{ $t('user.settings.general.defaultPage') }}
</span>
<div class="select">
<select v-model="settings.frontendSettings.defaultPage">
<option
v-for="(label, value) in defaultPageSettings"
:key="value"
:value="value"
>
{{ label }}
</option>
</select>
</div>
</label>
</div>
<div class="field">
<label class="two-col">
<span>
@ -412,6 +430,7 @@ import {PRIORITIES} from '@/constants/priorities'
import {DATE_DISPLAY} from '@/constants/dateDisplay'
import {TIME_FORMAT} from '@/constants/timeFormat'
import {RELATION_KINDS} from '@/types/IRelationKind'
import {DEFAULT_PAGE} from '@/constants/defaultPage'
defineOptions({name: 'UserSettingsGeneral'})
@ -420,6 +439,13 @@ useTitle(() => `${t('user.settings.general.title')} - ${t('user.settings.title')
const DEFAULT_PROJECT_ID = 0
const defaultPageSettings = computed(() => ({
[DEFAULT_PAGE.OVERVIEW]: t('user.settings.general.defaultPageOptions.overview'),
[DEFAULT_PAGE.UPCOMING]: t('user.settings.general.defaultPageOptions.upcoming'),
[DEFAULT_PAGE.DEFAULT_PROJECT]: t('user.settings.general.defaultPageOptions.defaultProject'),
[DEFAULT_PAGE.LAST_VISITED]: t('user.settings.general.defaultPageOptions.lastVisited'),
}))
const colorSchemeSettings = computed(() => ({
light: t('user.settings.appearance.colorScheme.light'),
auto: t('user.settings.appearance.colorScheme.system'),
@ -462,6 +488,7 @@ const settings = ref<IUserSettings>({
timeFormat: authStore.settings.frontendSettings.timeFormat ?? TIME_FORMAT.HOURS_12,
// Add fallback for old settings that don't have the default task relation type set
defaultTaskRelationType: authStore.settings.frontendSettings.defaultTaskRelationType ?? 'related',
defaultPage: authStore.settings.frontendSettings.defaultPage ?? DEFAULT_PAGE.LAST_VISITED,
},
})