defined new CI routes to differentiate between 5 cases CI doesnt handle anymore but vue router does; define Stundenplan/:lv_id? route for old links to redirect to new route Stundenplan/:mode/:focus_date/lv_id; new route with props route param handling to put them into viewData to always check for the same object; define day as allowed init mode; WIP same thing for raum calendar page;

This commit is contained in:
Johann Hoffmann
2025-02-18 10:18:39 +01:00
parent f6f06c4d5e
commit d45a41b949
6 changed files with 143 additions and 22 deletions
+11 -1
View File
@@ -61,7 +61,17 @@ $route['api/v1/organisation/[O|o]rganisationseinheit/(:any)'] = 'api/v1/organisa
$route['api/v1/ressource/[B|b]etriebsmittelperson/(:any)'] = 'api/v1/ressource/betriebsmittelperson2/$1';
$route['api/v1/system/[S|s]prache/(:any)'] = 'api/v1/system/sprache2/$1';
$route['Cis/Stundenplan/(:any)?'] = 'Cis/Stundenplan/index/$1';
$route['Cis/Stundenplan'] = 'Cis/Stundenplan/index/null/null/null';
$route['Cis/Stundenplan/(:num)'] = 'Cis/Stundenplan/index/null/null/$1';
$route['Cis/Stundenplan/(:num)/(:any)'] = 'Cis/Stundenplan/index/null/$2/$1';
// Specific route (for mode: month|week|day, focusdate, lv_id optional)
$route['Cis/Stundenplan/([M|m]onth|[W|w]eek|[D|d]ay)'] = 'Cis/Stundenplan/index/$1';
$route['Cis/Stundenplan/([M|m]onth|[W|w]eek|[D|d]ay)(/(:any))?'] = 'Cis/Stundenplan/index/$1/$3';
$route['Cis/Stundenplan/([M|m]onth|[W|w]eek|[D|d]ay)(/(:any))?(/(:num))?'] = 'Cis/Stundenplan/index/$1/$3/$5';
// load routes from extensions
$subdir = 'application/config/extensions';
+10 -1
View File
@@ -23,9 +23,18 @@ class Stundenplan extends Auth_Controller
/**
* @return void
*/
public function index($lv_id = null)
public function index($mode = 'Week', $focus_date = null, $lv_id = null)
{
// Convert string "null" to actual null values -> ci3 reroute fix
$mode = ($mode === 'null') ? 'Week' : ucfirst(strtolower($mode));
$focus_date = ($focus_date === 'null') ? date('Y-m-d') : $focus_date;
$lv_id = ($lv_id === 'null') ? null : $lv_id;
if($mode) $mode = ucfirst(strtolower($mode));
$viewData = array(
'mode' => $mode,
'focus_date' => $focus_date,
'lv_id' => $lv_id,
'uid'=>getAuthUID(),
);
+63 -2
View File
@@ -58,10 +58,71 @@ const router = VueRouter.createRouter({
component: Info,
props: true
},
// Redirect old links to new format
{
path: `/Cis/Stundenplan/:lv_id?`,
path: "/Cis/Stundenplan/:lv_id(\\d+)", // define lv_id as numeric so this matches
name: "StundenplanNumeric",
component: Stundenplan,
redirect: (to) => {
debugger
return { // redirect to longer Stundenplan url and map params
name: "Stundenplan",
params: {
mode: "Week",
focus_date: new Date().toISOString().split("T")[0],
lv_id: to.params.lv_id || null
},
};
},
},
{
// actual routes after Stundenplan -> config/routes.php
// actual param handling -> controllers/Cis/Stundenplan.php
path: `/Cis/Stundenplan/:mode?/:focus_date?/:lv_id?`,
name: 'Stundenplan',
component: Stundenplan
component: Stundenplan,
props: (route) => { // validate and set mode/focus date if for some reason missing
const validModes = ["Month", "Week", "Day"];
// default to mode week if not provided
let mode = route.params.mode &&
validModes.includes(route.params.mode.charAt(0).toUpperCase() + route.params.mode.slice(1).toLowerCase())
? route.params.mode.charAt(0).toUpperCase() + route.params.mode.slice(1).toLowerCase()
: "Week";
// default focus_date: today date if not provided
let focusDate = route.params.focus_date || new Date().toISOString().split("T")[0];
// for consistency reasons format the props into the viewData object so we have consistency in the form
// we access route specific data whether it is codigniter served or just another vue component that has been
// mounted
return {
viewData: {
mode,
focusDate,
lv_id: route.params.lv_id || null
}
};
},
beforeEnter: (to, from, next) => {
console.log('beforeEnter')
// If missing mode or focus_date, redirect with defaults
if (!to.params.mode || !to.params.focus_date) {
next({
name: "Stundenplan",
params: {
mode: to.params.mode || "Week",
focus_date: to.params.focus_date || new Date().toISOString().split("T")[0],
lv_id: to.params.lv_id || null
},
});
} else {
next();
}
}
},
{
path: `/`,
+3 -3
View File
@@ -192,12 +192,13 @@ export default {
},
},
created() {
const allowedInitialModes = ['years'];
const initMode = this.initialMode.toLowerCase()
const allowedInitialModes = ['years', 'day'];
if (!this.noWeekView)
allowedInitialModes.push('week');
if (!this.noMonthView)
allowedInitialModes.push('month');
this.mode = allowedInitialModes[allowedInitialModes.indexOf(this.initialMode)] || allowedInitialModes.pop();
this.mode = allowedInitialModes[allowedInitialModes.indexOf(initMode)] || allowedInitialModes.pop();
this.date.set(new Date(this.initialDate));
this.focusDate.set(this.date);
},
@@ -227,7 +228,6 @@ export default {
}
}).observe(this.$refs.container);
}
},
unmounted(){
CalendarDates.cleanup();
@@ -273,6 +273,7 @@ export default {
}
},
dateToMinutesOfDay(day) {
// subtract 7 from the total hours because the hours range from 7 to 24
return Math.floor(((day.getHours()-7) * 60 + day.getMinutes()) / this.smallestTimeFrame) + 1;
},
weekPageClick(event, day) {
@@ -4,24 +4,26 @@ import LvModal from "../Mylv/LvModal.js";
import LvInfo from "../Mylv/LvInfo.js"
import LvMenu from "../Mylv/LvMenu.js"
// TODO: define in one place that week is the default mode, it is hardcoded in 27 places currently
export const Stundenplan = {
name: 'Stundenplan',
data() {
return {
events: null,
calendarMode: "Week",
calendarDate: new CalendarDate(new Date()),
eventCalendarDate: new CalendarDate(new Date()),
currentlySelectedEvent: null,
currentDay: new Date(),
currentDay: this.viewData?.focus_date ? new Date(this.viewData.focus_date) : new Date(),
minimized: false,
studiensemester_kurzbz:null,
studiensemester_start:null,
studiensemester_ende:null,
uid:null,
studiensemester_kurzbz: null,
studiensemester_start: null,
studiensemester_ende: null,
uid: null,
}
},
props: [
"viewData",
"viewData"
],
watch: {
weekFirstDay: {
@@ -33,6 +35,12 @@ export const Stundenplan = {
this.studiensemester_ende = ende;
},
immediate: true,
},
'viewData.lv_id'(newVal) {
// console.log('viewData.lv_id', newVal)
},
'viewData.focus_date'(newVal) {
// console.log('viewData.focus_date', newVal)
}
},
components: {
@@ -49,11 +57,6 @@ export const Stundenplan = {
let download_link = (format, version = "", target = "") => `${FHC_JS_DATA_STORAGE_OBJECT.app_root}cis/private/lvplan/stpl_kalender.php?type=student&pers_uid=${this.uid}&begin=${start}&ende=${ende}&format=${format}${version ? '&version=' + version : ''}${target ? '&target=' + target : ''}`;
return [{ title: "excel", icon: 'fa-solid fa-file-excel', link: download_link('excel') }, { title: "csv", icon: 'fa-solid fa-file-csv', link: download_link('csv') }, { title: "ical1", icon: 'fa-regular fa-calendar', link: download_link('ical', '1', 'ical') }, { title: "ical2", icon: 'fa-regular fa-calendar', link: download_link('ical', '2', 'ical') }];
},
lv_id() { // computed so we can theoretically change path/lva selection and reload without page refresh
const pathParts = window.location.pathname.split('/').filter(Boolean);
const id = pathParts[pathParts.length - 1];
return id && !isNaN(Number(id)) ? id : null; // only return id if it is a number string since the path might contain invalid elements
},
weekFirstDay: function () {
return this.calendarDateToString(this.calendarDate.cdFirstDayOfWeek);
},
@@ -66,7 +69,6 @@ export const Stundenplan = {
monthLastDay: function () {
return this.calendarDateToString(this.eventCalendarDate.cdLastDayOfCalendarMonth);
},
},
methods:{
fetchStudiensemesterDetails: async function (date) {
@@ -84,8 +86,37 @@ export const Stundenplan = {
this.currentlySelectedEvent = event;
},
selectDay: function(day){
const date = day.getFullYear() + "-" +
String(day.getMonth() + 1).padStart(2, "0") + "-" +
String(day.getDate()).padStart(2, "0");
this.$router.replace({
name: "Stundenplan",
params: {
mode: this.calendarMode,
focus_date: date,
lv_id: this.viewData?.lv_id || null
}
})
this.currentDay = day;
},
handleChangeMode(mode) {
console.log('handleChangeMode', mode)
const modeCapitalized = mode.charAt(0).toUpperCase() + mode.slice(1)
// TODO: clashes with initial mode and needs to be differentiated
// this.$router.replace({
// name: "Stundenplan",
// params: {
// mode: modeCapitalized,
// focus_date: this.currentDay.toISOString().split("T")[0],
// lv_id: this.viewData?.lv_id || null
// }
// })
this.calendarMode = mode
},
showModal: function(event){
this.currentlySelectedEvent = event;
Vue.nextTick(() => {
@@ -163,7 +194,17 @@ export const Stundenplan = {
<h2>{{$p.t('lehre/stundenplan')}}</h2>
<hr>
<lv-modal v-if="currentlySelectedEvent" :event="currentlySelectedEvent" ref="lvmodal" />
<fhc-calendar @selectedEvent="setSelectedEvent" :initial-date="currentDay" @change:range="updateRange" :events="events" initial-mode="week" show-weeks @select:day="selectDay" v-model:minimized="minimized">
<fhc-calendar
@selectedEvent="setSelectedEvent"
:initial-date="currentDay"
@change:range="updateRange"
:events="events"
:initial-mode="viewData.mode"
show-weeks
@select:day="selectDay"
@change:mode="handleChangeMode"
v-model:minimized="minimized"
>
<template #calendarDownloads>
<div v-for="{title,icon,link} in downloadLinks">
<a :href="link" :title="title" class="py-1 px-2 m-1 btn btn-outline-secondary">
@@ -230,8 +271,7 @@ export const Stundenplan = {
<template #pageMobilContentEmpty >
<h3>{{ $p.t('lehre/noLvFound') }}</h3>
</template>
</fhc-calendar>
`
</fhc-calendar>`
}
export default Stundenplan