@@ -123,16 +123,79 @@ const router = createRouter({
123123 path : 'event/:eventId/:repetitionId?' ,
124124 name : 'event' ,
125125 component : ( ) => import ( /* webpackChunkName: 'event-overview' */ './components/event/Layout.vue' ) ,
126- redirect : ( to ) => {
127- const projectId = to . params . projectId as string ;
128- const eventId = to . params . eventId as string ;
129- const repetitionId = to . params . repetitionId as string | undefined ;
126+ // eslint-disable-next-line jsdoc/require-param
127+ /**
128+ * Support old-style event urls:
129+ * - without repetitionId
130+ * - without tab
131+ */
132+ beforeEnter : ( to , from , next ) => {
133+ /**
134+ * Normalize path by removing trailing slashes
135+ */
136+ const normalizedPath = to . path . replace ( / \/ + $ / , '' ) ;
130137
131- if ( repetitionId !== undefined && repetitionId !== '' ) {
132- return `/project/${ projectId } /event/${ eventId } /${ repetitionId } /overview` ;
138+ /**
139+ * Match the event route path pattern:
140+ * /project/:projectId/event/:eventId[/:repetitionId][/:tab]
141+ */
142+ const pathMatch = normalizedPath . match (
143+ / ^ \/ p r o j e c t \/ ( [ ^ / ] + ) \/ e v e n t \/ ( [ ^ / ] + ) (?: \/ ( [ ^ / ] + ) ) ? (?: \/ ( [ ^ / ] + ) ) ? $ /
144+ ) ;
145+
146+ if ( ! pathMatch ) {
147+ next ( ) ;
148+
149+ return ;
150+ }
151+
152+ const projectId = pathMatch [ 1 ] ;
153+ const eventId = pathMatch [ 2 ] ;
154+ const segment3 = pathMatch [ 3 ] ;
155+ const segment4 = pathMatch [ 4 ] ;
156+ const knownTabs = new Set ( [ 'overview' , 'repetitions' , 'daily' , 'affected' ] ) ;
157+
158+ /**
159+ * Determine if segment3 is a tab name or a repetitionId
160+ */
161+ const isSegment3Tab = segment3 !== undefined && knownTabs . has ( segment3 ) ;
162+
163+ /**
164+ * Legacy format: /project/:projectId/event/:eventId/:tab
165+ * segment3 is a tab, segment4 is undefined
166+ */
167+ if ( isSegment3Tab && segment4 === undefined ) {
168+ next ( `/project/${ projectId } /event/${ eventId } /${ eventId } /${ segment3 } ` ) ;
169+
170+ return ;
171+ }
172+
173+ /**
174+ * Normal format: /project/:projectId/event/:eventId/:repetitionId/:tab
175+ * segment3 is repetitionId, segment4 is tab
176+ */
177+ if ( segment3 !== undefined && ! isSegment3Tab && segment4 !== undefined ) {
178+ /**
179+ * Already in correct format, continue
180+ */
181+ next ( ) ;
182+
183+ return ;
184+ }
185+
186+ /**
187+ * Missing tab: /project/:projectId/event/:eventId[/:repetitionId]
188+ * Redirect to overview
189+ */
190+ if ( segment4 === undefined ) {
191+ const repetitionId = segment3 && ! isSegment3Tab ? segment3 : eventId ;
192+
193+ next ( `/project/${ projectId } /event/${ eventId } /${ repetitionId } /overview` ) ;
194+
195+ return ;
133196 }
134197
135- return `/project/ ${ projectId } /event/ ${ eventId } / ${ eventId } /overview` ;
198+ next ( ) ;
136199 } ,
137200 children : [
138201 {
0 commit comments