Skip to content

Commit f1a84b6

Browse files
committed
Fix redirect problem for scheduleEntry delete
1 parent 88380a4 commit f1a84b6

File tree

12 files changed

+148
-67
lines changed

12 files changed

+148
-67
lines changed

frontend/src/components/activity/ScheduleEntry.vue

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ Displays a single scheduleEntry
193193
class="text-right tabular-nums pb-2 pr-4"
194194
>
195195
<RouterLink
196-
v-if="scheduleEntryItem._meta.self !== scheduleEntry()._meta.self"
196+
v-if="scheduleEntryItem._meta.self !== scheduleEntry._meta.self"
197197
:to="scheduleEntryRoute(scheduleEntryItem)"
198198
class="e-title-link"
199199
>
@@ -215,7 +215,7 @@ Displays a single scheduleEntry
215215
<RouterLink
216216
v-if="
217217
category.numberingStyle === '-' &&
218-
scheduleEntryItem._meta.self !== scheduleEntry()._meta.self
218+
scheduleEntryItem._meta.self !== scheduleEntry._meta.self
219219
"
220220
:to="scheduleEntryRoute(scheduleEntryItem)"
221221
class="e-title-link"
@@ -231,9 +231,9 @@ Displays a single scheduleEntry
231231
</table>
232232
<DialogActivityEdit
233233
v-if="activity && isContributor"
234-
:schedule-entry="scheduleEntry()"
234+
:schedule-entry="scheduleEntry"
235235
hide-header-fields
236-
@activityUpdated="activity.$reload()"
236+
@activity-updated="activity.$reload()"
237237
>
238238
<template #activator="{ on }">
239239
<ButtonEdit text small class="v-btn--has-bg" v-on="on" />
@@ -292,7 +292,11 @@ import RootNode from '@/components/activity/RootNode.vue'
292292
import ActivityResponsibles from '@/components/activity/ActivityResponsibles.vue'
293293
import { dateHelperUTCFormatted } from '@/mixins/dateHelperUTCFormatted.js'
294294
import { campRoleMixin } from '@/mixins/campRoleMixin'
295-
import router, { periodRoute, scheduleEntryRoute } from '@/router.js'
295+
import router, {
296+
firstActivityScheduleEntry,
297+
periodRoute,
298+
scheduleEntryRoute,
299+
} from '@/router.js'
296300
import DownloadNuxtPdf from '@/components/print/print-nuxt/DownloadNuxtPdfListItem.vue'
297301
import DownloadClientPdf from '@/components/print/print-client/DownloadClientPdfListItem.vue'
298302
import { errorToMultiLineToast } from '@/components/toast/toasts'
@@ -332,11 +336,34 @@ export default {
332336
isPaperDisplaySize: () => this.isPaperDisplaySize,
333337
}
334338
},
339+
async beforeRouteUpdate(to, from, next) {
340+
if (to.params.scheduleEntryId !== from.params.scheduleEntryId) {
341+
return await this.api
342+
.get()
343+
.scheduleEntries({ id: to.params.scheduleEntryId })
344+
._meta.load.then(() => next())
345+
.catch(() =>
346+
next({
347+
name: 'camp/activity',
348+
params: {
349+
...to.params,
350+
scheduleEntryId: firstActivityScheduleEntry(this.activity).id,
351+
},
352+
})
353+
)
354+
} else {
355+
return next()
356+
}
357+
},
335358
props: {
336-
scheduleEntry: {
337-
type: Object,
359+
activityId: {
360+
type: String,
338361
required: true,
339362
},
363+
scheduleEntryId: {
364+
type: String,
365+
default: null,
366+
},
340367
},
341368
data() {
342369
return {
@@ -348,7 +375,18 @@ export default {
348375
},
349376
computed: {
350377
activity() {
351-
return this.scheduleEntry.activity()
378+
return this.api.get().activities({ id: this.activityId })
379+
},
380+
scheduleEntry() {
381+
try {
382+
if (this.scheduleEntryId) {
383+
return this.api.get().scheduleEntries({ id: this.scheduleEntryId })
384+
} else {
385+
return firstActivityScheduleEntry(this.activity)
386+
}
387+
} catch {
388+
return firstActivityScheduleEntry(this.activity)
389+
}
352390
},
353391
camp() {
354392
return this.activity.camp()

frontend/src/components/activity/dialog/DialogActivityEdit.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<DialogActivityForm
2121
:activity="entityData"
2222
:current-schedule-entry="scheduleEntry"
23-
:period="scheduleEntry.period"
23+
:period="scheduleEntry.period()"
2424
:hide-location="hideHeaderFields"
2525
/>
2626
</dialog-form>
@@ -131,6 +131,7 @@ export default {
131131
},
132132
updatedSuccessful(data) {
133133
this.close()
134+
this.api.reload(this.activity)
134135
this.$emit('activity-updated', data)
135136
},
136137
},

frontend/src/components/activity/dialog/DialogActivityForm.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export default {
7272
},
7373
currentScheduleEntry: {
7474
type: Object,
75-
required: true,
75+
default: null,
7676
},
7777
autoselectTitle: {
7878
type: Boolean,

frontend/src/components/activity/dialog/FormScheduleEntryList.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
:periods="periods"
2525
:deletable="
2626
scheduleEntriesWithoutDeleted.length > 1 &&
27-
($route.name !== 'activity' ||
28-
scheduleEntry.self !== currentScheduleEntry._meta.self)
27+
($route.name !== 'camp/activity' ||
28+
scheduleEntry.self !== currentScheduleEntry?._meta.self)
2929
"
3030
@delete="deleteEntry(scheduleEntry)"
3131
/>
@@ -53,7 +53,7 @@ export default {
5353
5454
currentScheduleEntry: {
5555
type: Object,
56-
required: true,
56+
default: null,
5757
},
5858
5959
// all available periods

frontend/src/components/campAdmin/DialogCategoryCreate.vue

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,7 @@ export default {
264264
const match = router.matcher.match(url)
265265
266266
if (match.name === 'camp/activity') {
267-
const scheduleEntry = await this.api
268-
.get()
269-
.scheduleEntries({ id: match.params['scheduleEntryId'] })
270-
return await scheduleEntry.activity()
267+
return await this.api.get().activities({ id: match.params['activityId'] })
271268
} else if (match.name === 'camp/admin/activity/category') {
272269
return await this.api.get().categories({ id: match.params['categoryId'] })
273270
}

frontend/src/components/campAdmin/ErrorExistingActivitiesList.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
name: 'camp/activity',
1717
params: {
1818
campId: camp.id,
19+
activityId: activity.id,
1920
scheduleEntryId: scheduleEntry.id,
2021
},
2122
}"

frontend/src/components/dashboard/ActivityRow.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ export default {
139139
name: 'camp/activity',
140140
params: {
141141
campId: this.scheduleEntry.period().camp().id,
142+
activityId: this.scheduleEntry.activity().id,
142143
scheduleEntryId: this.scheduleEntry.id,
143144
},
144145
}

frontend/src/components/program/DialogActivityCreate.vue

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export default {
143143
return this.period.camp()
144144
},
145145
period() {
146-
return this.scheduleEntry.period
146+
return this.scheduleEntry.period()
147147
},
148148
clipboardAccessDenied() {
149149
return (
@@ -282,11 +282,7 @@ export default {
282282
const match = router.matcher.match(url)
283283
284284
if (match.name === 'camp/activity') {
285-
const scheduleEntry = await this.api
286-
.get()
287-
.scheduleEntries({ id: match.params['scheduleEntryId'] })
288-
289-
return await scheduleEntry.activity()
285+
return await this.api.get().activities({ id: match.params['activityId'] })
290286
}
291287
}
292288
return null

frontend/src/components/story/StoryDay.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
name: 'camp/activity',
2525
params: {
2626
campId: day.period().camp().id,
27+
activityId: scheduleEntry.activity().id,
2728
scheduleEntryId: scheduleEntry.id,
2829
},
2930
}"

frontend/src/router.js

Lines changed: 73 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -502,23 +502,32 @@ export default new Router({
502502
],
503503
},
504504
{
505-
path: '/camps/:campId/:campShortTitle/program/activities/:scheduleEntryId/:activityName?',
505+
path: '/camps/:campId/:campShortTitle/program/activity/:activityId/:scheduleEntryId?/:activityName?',
506506
name: 'camp/activity',
507507
components: {
508508
navigation: NavigationCamp,
509509
default: () => import('./views/camp/activity/Activity.vue'),
510510
aside: () => import('./views/camp/activity/SideBarProgram.vue'),
511511
},
512-
beforeEnter: all([requireAuth, requireCamp, requireScheduleEntry]),
512+
beforeEnter: all([requireAuth, requireCamp, requireActivityScheduleEntry]),
513513
props: {
514514
navigation: (route) => ({ camp: campFromRoute(route) }),
515-
default: (route) => ({ scheduleEntry: scheduleEntryFromRoute(route) }),
515+
default: (route) => ({
516+
activityId: route.params.activityId,
517+
scheduleEntryId: route.params.scheduleEntryId,
518+
}),
516519
aside: (route) => ({
517520
camp: campFromRoute(route),
518-
day: dayFromScheduleEntryInRoute(route),
521+
activityId: route.params.activityId,
522+
scheduleEntryId: route.params.scheduleEntryId,
519523
}),
520524
},
521525
},
526+
{
527+
path: '/camps/:campId/:campShortTitle/program/activities/:scheduleEntryId/:activityName?',
528+
redirect:
529+
'/camps/:campId/:campShortTitle/program/activity/0/:scheduleEntryId?/:activityName?',
530+
},
522531
{
523532
path: '/',
524533
name: 'home',
@@ -600,27 +609,48 @@ async function requireCamp(to, from, next) {
600609
}
601610
}
602611

603-
async function requireScheduleEntry(to, from, next) {
604-
const scheduleEntry = await scheduleEntryFromRoute(to)
605-
if (scheduleEntry === undefined) {
606-
next({
607-
name: 'PageNotFound',
608-
params: [to.fullPath, ''],
609-
replace: true,
612+
async function requireActivityScheduleEntry(to, from, next) {
613+
await apiStore
614+
.get()
615+
.activities({ id: to.params.activityId })
616+
._meta.load.then((activity) => {
617+
// activity exists
618+
if (to.params.scheduleEntryId) {
619+
apiStore
620+
.get()
621+
.scheduleEntries({ id: to.params.scheduleEntryId })
622+
._meta.load.then(() => {
623+
// activity and scheduleEntry exist
624+
next()
625+
})
626+
.catch(async () => {
627+
// scheduleEntry is not found, use first activity scheduleEntry
628+
to.params.scheduleEntryId = firstActivityScheduleEntry(activity).id
629+
next(to)
630+
})
631+
}
632+
next()
633+
})
634+
.catch(() => {
635+
// activityId does not exist, check if scheduleEntryId exists
636+
if (to.params.scheduleEntryId) {
637+
apiStore
638+
.get()
639+
.scheduleEntries({ id: to.params.scheduleEntryId })
640+
._meta.load.then(async (scheduleEntry) => {
641+
const activity = await scheduleEntry.activity()._meta.load
642+
to.params.activityId = activity.id
643+
next(to)
644+
})
645+
.catch(async () => {
646+
// scheduleEntry and activity are not found, fallback to camp program
647+
next({
648+
...to,
649+
name: 'camp/program',
650+
})
651+
})
652+
}
610653
})
611-
} else {
612-
await scheduleEntry._meta.load
613-
.then(() => {
614-
next()
615-
})
616-
.catch(() => {
617-
next({
618-
name: 'PageNotFound',
619-
params: [to.fullPath, ''],
620-
replace: true,
621-
})
622-
})
623-
}
624654
}
625655

626656
async function requirePeriod(to, from, next) {
@@ -721,13 +751,6 @@ export function periodFromRoute(route) {
721751
return apiStore.get().periods({ id: route.params.periodId })
722752
}
723753

724-
function scheduleEntryFromRoute(route) {
725-
if (!route.params.scheduleEntryId) {
726-
return undefined
727-
}
728-
return apiStore.get().scheduleEntries({ id: route.params.scheduleEntryId })
729-
}
730-
731754
function categoryFromRoute(route) {
732755
if (!route.params.categoryId) {
733756
return undefined
@@ -772,13 +795,6 @@ function getContentLayout(route) {
772795
}
773796
}
774797

775-
function dayFromScheduleEntryInRoute(route) {
776-
if (!route.params.scheduleEntryId) {
777-
return undefined
778-
}
779-
return apiStore.get().scheduleEntries({ id: route.params.scheduleEntryId }).day()
780-
}
781-
782798
/**
783799
* @param camp
784800
* @param subroute {'admin' | 'dashboard' | 'program' | 'material' | 'story' | 'home' | 'collaborators' | 'print' }
@@ -856,7 +872,8 @@ export function periodRoute(period, routeName = 'camp/period/program', query = {
856872
export function scheduleEntryRoute(scheduleEntry, query = {}) {
857873
if (scheduleEntry._meta.loading || scheduleEntry.activity()._meta.loading) return {}
858874

859-
const camp = scheduleEntry.activity().camp()
875+
const activity = scheduleEntry.activity()
876+
const camp = activity.camp()
860877

861878
// if (camp._meta.loading) return {}
862879

@@ -866,7 +883,8 @@ export function scheduleEntryRoute(scheduleEntry, query = {}) {
866883
campId: camp.id,
867884
campShortTitle: slugify(campShortTitle(camp)),
868885
scheduleEntryId: scheduleEntry.id,
869-
activityName: slugify(scheduleEntry.activity().title),
886+
activityId: activity.id,
887+
activityName: slugify(activity.title),
870888
},
871889
query,
872890
}
@@ -967,6 +985,21 @@ async function firstFuturePeriod(route) {
967985
)
968986
}
969987

988+
export async function firstActivityScheduleEntry(activity) {
989+
if (typeof activity === 'string') {
990+
activity = apiStore.get().activities({ id: activity })
991+
}
992+
return activity
993+
.scheduleEntries()
994+
.items.reduce(
995+
(result, current) =>
996+
result === null || new Date(result.start) > new Date(current.start)
997+
? current
998+
: result,
999+
null
1000+
)
1001+
}
1002+
9701003
async function redirectToPeriod(to, from, next, routeName) {
9711004
const period = await firstFuturePeriod(to)
9721005
if (period) {

0 commit comments

Comments
 (0)