Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edit scheduleEntry on activity view without redirection problem #4975

Open
wants to merge 18 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 78 additions & 9 deletions frontend/src/components/activity/ScheduleEntry.vue
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,15 @@ Displays a single scheduleEntry
<template v-else>
<!-- Header -->
<v-row dense class="activity-header">
<v-col class="col col-sm-6 col-12 px-0 pt-0">
<v-col class="col col-sm-6 col-12 px-0 pt-0 d-flex flex-wrap gap-x-4">
<table>
<thead>
<tr>
<th scope="col" class="text-right pb-2 pr-4">
<th
v-if="category.numberingStyle !== '-'"
scope="col"
class="text-right pb-2 pr-4"
>
{{ $tc('entity.scheduleEntry.fields.nr') }}
</th>
<th scope="col" class="text-left pb-2 pr-4">
Expand All @@ -184,8 +188,20 @@ Displays a single scheduleEntry
v-for="scheduleEntryItem in scheduleEntries"
:key="scheduleEntryItem._meta.self"
>
<th class="text-right tabular-nums pb-2 pr-4">
{{ scheduleEntryItem.number }}
<th
v-if="category.numberingStyle !== '-'"
class="text-right tabular-nums pb-2 pr-4"
>
<RouterLink
v-if="scheduleEntryItem._meta.self !== scheduleEntry._meta.self"
:to="scheduleEntryRoute(scheduleEntryItem)"
class="e-title-link"
>
{{ scheduleEntryItem.number }}
</RouterLink>
<template v-else>
{{ scheduleEntryItem.number }}
</template>
</th>
<td class="text-left tabular-nums pb-2 pr-4">
{{
Expand All @@ -196,11 +212,33 @@ Displays a single scheduleEntry
{{ dateShort(scheduleEntryItem.start) }}
</td>
<td class="text-left tabular-nums pb-2 pr-0">
{{ rangeLongEnd(scheduleEntryItem.start, scheduleEntryItem.end) }}
<RouterLink
v-if="
category.numberingStyle === '-' &&
scheduleEntryItem._meta.self !== scheduleEntry._meta.self
"
:to="scheduleEntryRoute(scheduleEntryItem)"
class="e-title-link"
>
{{ rangeLongEnd(scheduleEntryItem.start, scheduleEntryItem.end) }}
</RouterLink>
<template v-else>
{{ rangeLongEnd(scheduleEntryItem.start, scheduleEntryItem.end) }}
</template>
</td>
</tr>
</tbody>
</table>
<DialogActivityEdit
v-if="scheduleEntry && isContributor"
:schedule-entry="scheduleEntry"
hide-header-fields
@activity-updated="activity.$reload()"
>
<template #activator="{ on }">
<ButtonEdit text small class="v-btn--has-bg" v-on="on" />
</template>
</DialogActivityEdit>
</v-col>
<v-col class="col col-sm-6 col-12 px-0">
<api-form :entity="activity" name="activity">
Expand Down Expand Up @@ -254,7 +292,11 @@ import RootNode from '@/components/activity/RootNode.vue'
import ActivityResponsibles from '@/components/activity/ActivityResponsibles.vue'
import { dateHelperUTCFormatted } from '@/mixins/dateHelperUTCFormatted.js'
import { campRoleMixin } from '@/mixins/campRoleMixin'
import router, { periodRoute, scheduleEntryRoute } from '@/router.js'
import router, {
firstActivityScheduleEntry,
periodRoute,
scheduleEntryRoute,
} from '@/router.js'
import DownloadNuxtPdf from '@/components/print/print-nuxt/DownloadNuxtPdfListItem.vue'
import DownloadClientPdf from '@/components/print/print-client/DownloadClientPdfListItem.vue'
import { errorToMultiLineToast } from '@/components/toast/toasts'
Expand All @@ -264,10 +306,15 @@ import DialogEntityDelete from '@/components/dialog/DialogEntityDelete.vue'
import TogglePaperSize from '@/components/activity/TogglePaperSize.vue'
import ApiForm from '@/components/form/api/ApiForm.vue'
import ApiSelect from '@/components/form/api/ApiSelect.vue'
import ButtonEdit from '@/components/buttons/ButtonEdit.vue'
import DialogActivityEdit from '@/components/activity/dialog/DialogActivityEdit.vue'
import scheduleEntryRouteChange from '@/helpers/scheduleEntryRouteChange.js'

export default {
name: 'ScheduleEntry',
components: {
DialogActivityEdit,
ButtonEdit,
ApiForm,
ApiSelect,
TogglePaperSize,
Expand All @@ -290,23 +337,31 @@ export default {
isPaperDisplaySize: () => this.isPaperDisplaySize,
}
},
async beforeRouteUpdate(to, from, next) {
return scheduleEntryRouteChange(this.activityId, to, from, next)
},
props: {
scheduleEntry: {
type: Object,
activityId: {
type: String,
required: true,
},
scheduleEntryId: {
type: String,
default: null,
},
},
data() {
return {
layoutMode: false,
editActivityTitle: false,
categoryChangeState: null,
scheduleEntry: null,
loading: true,
}
},
computed: {
activity() {
return this.scheduleEntry.activity()
return this.api.get().activities({ id: this.activityId })
},
camp() {
return this.activity.camp()
Expand Down Expand Up @@ -366,6 +421,19 @@ export default {
},
},

watch: {
scheduleEntryId: {
async handler(id) {
try {
this.scheduleEntry = this.api.get().scheduleEntries({ id })
} catch {
this.scheduleEntry = await firstActivityScheduleEntry(this.activityId)
}
},
immediate: true,
},
},

// reload data every time user navigates to Activity view
async mounted() {
this.loading = true
Expand All @@ -390,6 +458,7 @@ export default {
this.$toast.error(errorToMultiLineToast(e))
})
},
scheduleEntryRoute,
countContentNodes(contentType) {
return this.contentNodes.items.filter((cn) => {
return cn.contentType().id === contentType.id
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<dialog-form
v-model="showDialog"
:title="$tc('components.program.dialogActivityEdit.title')"
:title="$tc('components.activity.dialog.dialogActivityEdit.title')"
:loading="loading"
:error="error"
icon="mdi-calendar-plus"
Expand All @@ -15,30 +15,33 @@
<slot name="activator" v-bind="scope" />
</template>
<template #moreActions>
<v-btn
v-if="!scheduleEntry.tmpEvent"
color="primary"
:to="scheduleEntryRoute(scheduleEntry)"
>
{{ $tc('global.button.open') }}
</v-btn>
<slot name="moreActions" />
</template>
<dialog-activity-form :activity="entityData" :period="scheduleEntry.period()" />
<DialogActivityForm
:activity="entityData"
:current-schedule-entry="scheduleEntry"
:period="period"
:hide-location="hideHeaderFields"
/>
</dialog-form>
</template>

<script>
import DialogForm from '@/components/dialog/DialogForm.vue'
import DialogBase from '@/components/dialog/DialogBase.vue'
import DialogActivityForm from './DialogActivityForm.vue'
import { scheduleEntryRoute } from '@/router.js'
import { firstActivityScheduleEntryRoute } from '@/router.js'

export default {
name: 'DialogActivityEdit',
components: { DialogForm, DialogActivityForm },
extends: DialogBase,
props: {
scheduleEntry: { type: Object, required: true },
hideHeaderFields: {
type: Boolean,
default: false,
},
},
data() {
return {
Expand All @@ -47,12 +50,15 @@ export default {
}
},
computed: {
scheduleEntries() {
return this.activity.scheduleEntries()
},
activity() {
return this.scheduleEntry.activity()
},
period() {
return this.scheduleEntry.period()
},
scheduleEntries() {
return this.activity.scheduleEntries()
},
},
watch: {
showDialog: async function (showDialog) {
Expand Down Expand Up @@ -95,24 +101,49 @@ export default {

// update existing
if (entry.self) {
return this.api.patch(entry.self, {
return this.api
.patch(entry.self, {
period: entry.period()._meta.self,
start: entry.start,
end: entry.end,
})
.then((serverEntry) => {
entry.start = serverEntry.start
entry.end = serverEntry.end
entry.period = serverEntry.period
})
.catch(async (e) => {
// entry was deleted in the meantime
if (e.response.status === 404) {
if (entry.self === this.scheduleEntry._meta.self) {
// redirect to first entry to not break UI
this.$router.push(await firstActivityScheduleEntryRoute(this.activity))
}
entry.deleted = true
return Promise.resolve()
}
return Promise.reject(e)
})
}

// else: create new entry
return this.scheduleEntries
.$post({
period: entry.period()._meta.self,
start: entry.start,
end: entry.end,
activity: this.activity._meta.self,
})
.then((data) => {
entry.self = data._meta.self
})
}

// else: create new entry
return this.scheduleEntries.$post({
period: entry.period()._meta.self,
start: entry.start,
end: entry.end,
activity: this.activity._meta.self,
})
})

// patch activity entity
const activityPayload = { ...this.entityData }
if (this.hideHeaderFields) {
delete activityPayload.location
}
delete activityPayload.scheduleEntries
promises.push(this.api.patch(this.entityUri, activityPayload))

Expand All @@ -126,9 +157,10 @@ export default {
},
updatedSuccessful(data) {
this.close()
this.api.reload(this.activity)
this.api.reload(this.scheduleEntry.period().scheduleEntries())
this.$emit('activity-updated', data)
},
scheduleEntryRoute,
},
}
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@
</template>
</e-select>

<e-text-field v-model="localActivity.location" path="location" />
<e-text-field v-if="!hideLocation" v-model="localActivity.location" path="location" />

<FormScheduleEntryList
v-if="activity.scheduleEntries"
:schedule-entries="activity.scheduleEntries"
:current-schedule-entry="currentScheduleEntry"
:period="period"
:periods="camp.periods().items"
/>
Expand Down Expand Up @@ -69,10 +70,18 @@ export default {
type: Object,
required: true,
},
currentScheduleEntry: {
type: Object,
default: null,
},
autoselectTitle: {
type: Boolean,
default: false,
},
hideLocation: {
type: Boolean,
default: false,
},
},
data() {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
</v-col>

<v-col cols="1" class="pt-3 text-center">
<button-delete v-if="!isLastItem" icon-only @click="$emit('delete')" />
<button-delete v-if="deletable" icon-only @click="$emit('delete')" />
</v-col>
</v-row>
</v-container>
Expand Down Expand Up @@ -82,9 +82,9 @@ export default {
},

// true if current item is the last scheduleEntry
isLastItem: {
deletable: {
type: Boolean,
required: true,
required: false,
},
},
data() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<v-row no-gutters>
<v-col class="header mb-3">
<legend class="pa-2 float-left">
{{ $tc('components.program.formScheduleEntryList.name') }}
{{ $tc('components.activity.dialog.formScheduleEntryList.name') }}
</legend>

<button-add
Expand All @@ -22,7 +22,11 @@
class="transition-list-item pa-0 mb-4"
:schedule-entry="scheduleEntry"
:periods="periods"
:is-last-item="scheduleEntriesWithoutDeleted.length === 1"
:deletable="
scheduleEntriesWithoutDeleted.length > 1 &&
($route.name !== 'camp/activity' ||
scheduleEntry.self !== currentScheduleEntry?._meta.self)
"
@delete="deleteEntry(scheduleEntry)"
/>
</transition-group>
Expand All @@ -47,6 +51,11 @@ export default {
required: true,
},

currentScheduleEntry: {
type: Object,
default: null,
},

// all available periods
periods: {
type: Array,
Expand Down
Loading
Loading