mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-06-10 08:39:28 +00:00
refactor(Calendar Tagesansicht): changes how the logic for opening a modal or showing the lvMenu next to the calendar is handled
This commit is contained in:
@@ -175,7 +175,7 @@ html {
|
||||
}
|
||||
#cis-header .btn.dropdown-toggle:after,
|
||||
#cis-nav .btn.dropdown-toggle:after {
|
||||
transition: all 0.2s ease-in-out;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
#cis-header .btn.dropdown-toggle.collapsed:after,
|
||||
#cis-nav .btn.dropdown-toggle.collapsed:after {
|
||||
|
||||
@@ -3,6 +3,7 @@ import Phrasen from "../../plugin/Phrasen.js";
|
||||
import CalendarDate from "../../composables/CalendarDate.js";
|
||||
import LvModal from "../../components/Cis/Mylv/LvModal.js";
|
||||
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'StundenplanApp',
|
||||
data() {
|
||||
@@ -17,8 +18,7 @@ const app = Vue.createApp({
|
||||
}
|
||||
},
|
||||
components: {
|
||||
FhcCalendar,
|
||||
LvModal
|
||||
FhcCalendar, LvModal
|
||||
},
|
||||
computed:{
|
||||
weekFirstDay: function () {
|
||||
@@ -36,20 +36,12 @@ const app = Vue.createApp({
|
||||
|
||||
},
|
||||
methods:{
|
||||
setWindowWidth: function () {
|
||||
this.windowWidth = window.innerWidth;
|
||||
},
|
||||
getLvID: function () {
|
||||
this.lv_id = window.location.pathname
|
||||
},
|
||||
selectDay: function(day){
|
||||
this.currentDay = day;
|
||||
},
|
||||
showDayModal: function (event) {
|
||||
// only show the modal if the window width is smaller than 1200px
|
||||
if(this.windowWidth >= 1200) return;
|
||||
this.showModal(event);
|
||||
},
|
||||
showModal: function(event){
|
||||
this.currentlySelectedEvent = event;
|
||||
Vue.nextTick(() => {
|
||||
@@ -116,13 +108,6 @@ const app = Vue.createApp({
|
||||
this.loadEvents();
|
||||
this.getLvID()
|
||||
},
|
||||
mounted(){
|
||||
this.windowWidth = window.innerWidth;
|
||||
window.addEventListener('resize', this.setWindowWidth);
|
||||
},
|
||||
beforeUnmount(){
|
||||
window.removeEventListener('resize', this.setWindowWidth);
|
||||
},
|
||||
//TODO: Stundenplan phrase
|
||||
template:/*html*/`
|
||||
<h2>Stundenplan</h2>
|
||||
@@ -142,7 +127,7 @@ const app = Vue.createApp({
|
||||
</div>
|
||||
</template>
|
||||
<template #dayPage="{event,day}">
|
||||
<div @click="showDayModal(event?.orig)" type="button" class="border border-secondary border row h-100 justify-content-center align-items-center text-center">
|
||||
<div type="button" class="fhc-entry border border-secondary border row h-100 justify-content-center align-items-center text-center">
|
||||
<div class="col ">
|
||||
<p>Lehrveranstaltung:</p>
|
||||
<p class="m-0">{{event?.orig.topic}}</p>
|
||||
|
||||
@@ -42,7 +42,7 @@ export default {
|
||||
<div class="fhc-calendar-day">
|
||||
<calendar-header :title="title" @prev="prev" @next="next" @updateMode="$emit('updateMode', $event)" @click="$emit('updateMode', 'week')"/>
|
||||
<calendar-pane ref="pane" v-slot="slot" @slid="paneChanged">
|
||||
<calendar-day-page :year="focusDate.y" :week="focusDate.w+slot.offset" @updateMode="$emit('updateMode', $event)" @page:back="prev" @page:forward="next" @input="selectEvent" >
|
||||
<calendar-day-page :active="slot.active" :year="focusDate.y" :week="focusDate.w+slot.offset" @updateMode="$emit('updateMode', $event)" @page:back="prev" @page:forward="next" @input="selectEvent" >
|
||||
<template #dayPage="{event,day}">
|
||||
<slot name="dayPage" :event="event" :day="day" ></slot>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import CalendarDate from '../../../composables/CalendarDate.js';
|
||||
import LvMenu from "../../../components/Cis/Mylv/LvMenu.js"
|
||||
import LvInfo from "../../../components/Cis/Mylv/LvInfo.js"
|
||||
import LvModal from "../../../components/Cis/Mylv/LvModal.js";
|
||||
|
||||
function ggt(m, n) { return n == 0 ? m : ggt(n, m % n); }
|
||||
function kgv(m, n) { return (m * n) / ggt(m, n); }
|
||||
@@ -9,6 +10,7 @@ export default {
|
||||
components:{
|
||||
LvMenu,
|
||||
LvInfo,
|
||||
LvModal,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -32,7 +34,8 @@ export default {
|
||||
],
|
||||
props: {
|
||||
year: Number,
|
||||
week: Number
|
||||
week: Number,
|
||||
active: Boolean,
|
||||
},
|
||||
emits: [
|
||||
'updateMode',
|
||||
@@ -41,6 +44,18 @@ export default {
|
||||
'input'
|
||||
],
|
||||
watch:{
|
||||
//TODO: on first render non of the day-page components are active and the watcher on selectedEvent does not fetch the lvMenu
|
||||
//TODO: workaround is to watch the active state and refetch in case the lvMenu is empty
|
||||
active:{
|
||||
handler(value){
|
||||
if(value){
|
||||
if(!this.lvMenu){
|
||||
this.fetchLvMenu(this.selectedEvent);
|
||||
}
|
||||
}
|
||||
},
|
||||
immediate:true,
|
||||
},
|
||||
eventsPerDayAndHour:{
|
||||
handler(newEvents) {
|
||||
// if no event is selected, select the first event of the day
|
||||
@@ -55,27 +70,20 @@ export default {
|
||||
},
|
||||
selectedEvent:{
|
||||
handler(event) {
|
||||
this.lvMenu = null;
|
||||
if (event && event.type == 'lehreinheit') {
|
||||
this.$fhcApi.factory.stundenplan.getLehreinheitStudiensemester(event.lehreinheit_id[0]).then(
|
||||
res => res.data
|
||||
).then(
|
||||
studiensemester_kurzbz => {
|
||||
this.$fhcApi.factory.addons.getLvMenu(event.lehrveranstaltung_id, studiensemester_kurzbz).then(res => {
|
||||
if (res.data) {
|
||||
this.lvMenu = res.data;
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
// return early if the day-page component is not the active carousel item
|
||||
if(!this.active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.lvMenu = null;
|
||||
this.fetchLvMenu(event);
|
||||
},
|
||||
immediate:true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
noEventsCondition(){
|
||||
return !this.isSliding && this.filteredEvents.length === 0;
|
||||
return !this.isSliding && this.filteredEvents?.length === 0;
|
||||
},
|
||||
hours() {
|
||||
// returns an array with elements starting at 7 and ending at 24
|
||||
@@ -127,6 +135,28 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
fetchLvMenu(event){
|
||||
if (event && event.type == 'lehreinheit') {
|
||||
this.$fhcApi.factory.stundenplan.getLehreinheitStudiensemester(event.lehreinheit_id[0]).then(
|
||||
res => res.data
|
||||
).then(
|
||||
studiensemester_kurzbz => {
|
||||
this.$fhcApi.factory.addons.getLvMenu(event.lehrveranstaltung_id, studiensemester_kurzbz).then(res => {
|
||||
if (res.data) {
|
||||
this.lvMenu = res.data;
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
showModal: function (evt) {
|
||||
let event = evt.orig;
|
||||
this.setSelectedEvent(event);
|
||||
Vue.nextTick(() => {
|
||||
this.$refs.lvmodal.show();
|
||||
});
|
||||
},
|
||||
eventClick(evt) {
|
||||
let event = evt.orig;
|
||||
this.setSelectedEvent(event);
|
||||
@@ -190,6 +220,8 @@ export default {
|
||||
},
|
||||
template: /*html*/`
|
||||
<div class="fhc-calendar-day-page ">
|
||||
<!-- lvModal for mobile view -->
|
||||
<lv-modal v-if="selectedEvent" :event="selectedEvent" ref="lvmodal" />
|
||||
<div class="row m-0">
|
||||
<div class="col-12 col-xl-6 p-0">
|
||||
<div class="d-flex flex-column">
|
||||
@@ -212,10 +244,20 @@ export default {
|
||||
<div v-for="hour in hours" style="min-height:100px" :key="hour" class="text-muted text-end small" :ref="'hour' + hour">{{hour}}:00</div>
|
||||
</div>
|
||||
<div v-for="day in eventsPerDayAndHour" :key="day" class=" day border-start" :style="{'grid-template-columns': '1 1fr', 'grid-template-rows': 'repeat(' + (hours.length * 60 / smallestTimeFrame) + ', 1fr)'}">
|
||||
<div :style="{'background-color':event.orig.color}" :class="{'selectedEvent':event.orig == selectedEvent}" class="mx-2 small rounded overflow-hidden " @click.prevent="eventClick(event)" :style="{'z-index':1,'grid-column-start': 1+(event.lane-1)*day.lanes/event.maxLane, 'grid-column-end': 1+event.lane*day.lanes/event.maxLane, 'grid-row-start': dateToMinutesOfDay(event.start), 'grid-row-end': dateToMinutesOfDay(event.end) ,'--test': dateToMinutesOfDay(event.end)}" v-for="event in day.events" :key="event">
|
||||
<slot name="dayPage" :event="event" :day="day">
|
||||
<p>this is a placeholder which means that no template was passed to the Calendar Page slot</p>
|
||||
</slot>
|
||||
<div :style="{'background-color':event.orig.color}" :class="{'selectedEvent':event.orig == selectedEvent}" class="mx-2 small rounded overflow-hidden " :style="{'z-index':1,'grid-column-start': 1+(event.lane-1)*day.lanes/event.maxLane, 'grid-column-end': 1+event.lane*day.lanes/event.maxLane, 'grid-row-start': dateToMinutesOfDay(event.start), 'grid-row-end': dateToMinutesOfDay(event.end) ,'--test': dateToMinutesOfDay(event.end)}" v-for="event in day.events" :key="event">
|
||||
<!-- desktop version opens the lvMenu next to the calendar -->
|
||||
<div class="d-none d-xl-block h-100 " @click.prevent="eventClick(event)">
|
||||
<slot name="dayPage" :event="event" :day="day">
|
||||
<p>this is a placeholder which means that no template was passed to the Calendar Page slot</p>
|
||||
</slot>
|
||||
</div>
|
||||
<!-- mobile version opens the lvModal in a modal -->
|
||||
<div class="d-block d-xl-none h-100" @click.prevent="showModal(event)">
|
||||
<slot name="dayPage" :event="event" :day="day">
|
||||
<p>this is a placeholder which means that no template was passed to the Calendar Page slot</p>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -225,7 +267,7 @@ export default {
|
||||
</div>
|
||||
<div class="d-none d-xl-block col-xl-6 p-0">
|
||||
<div class="p-5 sticky-top d-flex justify-content-center align-items-center flex-column">
|
||||
<div style="max-height: calc(var(--fhc-calendar-pane-height) - 100px); overflow-y:auto;">
|
||||
<div style="max-height: calc(var(--fhc-calendar-pane-height) - 100px); overflow-y:auto;" class="w-100">
|
||||
<template v-if="selectedEvent && lvMenu">
|
||||
<h3 >{{$p.t('lvinfo','lehrveranstaltungsinformationen')}}</h3>
|
||||
<div class="w-100">
|
||||
@@ -238,7 +280,7 @@ export default {
|
||||
<h3>Keine Lehrveranstaltungen</h3>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="d-flex h-100 justify-content-center align-items-center">
|
||||
<div style="height: calc(var(--fhc-calendar-pane-height) - 100px);" class="d-flex w-100 justify-content-center align-items-center">
|
||||
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -63,10 +63,6 @@ export default {
|
||||
this.$emit('updateMode', 'week');
|
||||
}
|
||||
},
|
||||
changeToDay(day) {
|
||||
this.focusDate.set(day);
|
||||
this.$emit('updateMode', 'day');
|
||||
},
|
||||
highlight(week, day){
|
||||
this.highlightedWeek = week.no;
|
||||
this.highlightedDay = day;
|
||||
@@ -77,7 +73,8 @@ export default {
|
||||
clickEvent(day,week) {
|
||||
if(!this.noWeekView)
|
||||
{
|
||||
this.changeToDay(day);
|
||||
this.focusDate.set(day);
|
||||
this.$emit('updateMode', 'day');
|
||||
}
|
||||
this.selectDay(day);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ export default {
|
||||
slideAnimation:false,
|
||||
scrollTop:null,
|
||||
clientHeight:null,
|
||||
carouselItems:null,
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
@@ -22,7 +23,19 @@ export default {
|
||||
computed: {
|
||||
offsets() {
|
||||
return [...Array(3).keys()].map(i => (3+i-this.offset)%3-1);
|
||||
},
|
||||
activeCarouselItemIndex() {
|
||||
if (Array.isArray(this.carouselItems) && this.carouselItems.length > 0) {
|
||||
for(let index=0; index < this.carouselItems.length; index++){
|
||||
if (this.carouselItems[index] == true){
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
scrollCalendar(event){
|
||||
@@ -48,6 +61,7 @@ export default {
|
||||
else
|
||||
this.carousel.prev();
|
||||
}
|
||||
this.carouselItems = this.$refs.carouselItems.map((item) => { return item.classList.contains('active') });
|
||||
this.slideAnimation = false;
|
||||
},
|
||||
slide(evt) {
|
||||
@@ -61,6 +75,7 @@ export default {
|
||||
interval: false
|
||||
});
|
||||
}
|
||||
this.carouselItems = this.$refs.carouselItems.map((item)=>{return item.classList.contains('active')});
|
||||
this.scrollTop = this.$refs.calendarContainer.scrollTop;
|
||||
this.clientHeight = this.$refs.calendarContainer.clientHeight;
|
||||
},
|
||||
@@ -68,8 +83,8 @@ export default {
|
||||
<div ref="carousel" class="calendar-pane carousel slide" @[\`slide.bs.carousel\`]="slide" @[\`slid.bs.carousel\`]="slid" :data-queue="queue">
|
||||
<!--height calc function just for user testing purpose (has to be fixed)-->
|
||||
<div @scroll="scrollCalendar" ref="calendarContainer" class="carousel-inner " style="height:var(--fhc-calendar-pane-height); overflow:scroll">
|
||||
<div v-for="i in [...Array(3).keys()]" :key="i" class="carousel-item">
|
||||
<slot :index="i" :offset="offsets[i]" />
|
||||
<div ref="carouselItems" v-for="i in [...Array(3).keys()]" :key="i" class="carousel-item">
|
||||
<slot :active="i == activeCarouselItemIndex" :index="i" :offset="offsets[i]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
@@ -141,9 +141,10 @@ export default {
|
||||
dateToMinutesOfDay(day) {
|
||||
return Math.floor(((day.getHours()-7) * 60 + day.getMinutes()) / this.smallestTimeFrame) + 1;
|
||||
},
|
||||
weekPageClick(event) {
|
||||
weekPageClick(event, day) {
|
||||
this.setSelectedEvent(event);
|
||||
$emit('input', event)
|
||||
this.focusDate.set(new CalendarDate(new Date(event.datum)));
|
||||
this.$emit('input', event)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -170,7 +171,7 @@ export default {
|
||||
<div v-for="hour in hours" style="min-height:100px" :key="hour" class="text-muted text-end small" :ref="'hour' + hour">{{hour}}:00</div>
|
||||
</div>
|
||||
<div v-for="day in eventsPerDayAndHour" :key="day" class=" day border-start" :style="{'grid-template-columns': 'repeat(' + day.lanes + ', 1fr)', 'grid-template-rows': 'repeat(' + (hours.length * 60 / smallestTimeFrame) + ', 1fr)'}">
|
||||
<div :style="{'background-color':event.orig.color}" class="mx-2 small rounded overflow-hidden " @click.prevent="weekPageClick(event.orig)" :style="{'z-index':1,'grid-column-start': 1+(event.lane-1)*day.lanes/event.maxLane, 'grid-column-end': 1+event.lane*day.lanes/event.maxLane, 'grid-row-start': dateToMinutesOfDay(event.start), 'grid-row-end': dateToMinutesOfDay(event.end) ,'--test': dateToMinutesOfDay(event.end)}" v-for="event in day.events" :key="event">
|
||||
<div :style="{'background-color':event.orig.color}" class="mx-2 small rounded overflow-hidden " @click.prevent="weekPageClick(event.orig, day)" :style="{'z-index':1,'grid-column-start': 1+(event.lane-1)*day.lanes/event.maxLane, 'grid-column-end': 1+event.lane*day.lanes/event.maxLane, 'grid-row-start': dateToMinutesOfDay(event.start), 'grid-row-end': dateToMinutesOfDay(event.end) ,'--test': dateToMinutesOfDay(event.end)}" v-for="event in day.events" :key="event">
|
||||
<slot name="weekPage" :event="event" :day="day" :isSelected="event.orig == selectedEvent" >
|
||||
<p>this is a placeholder which means that no template was passed to the Calendar Page slot</p>
|
||||
</slot>
|
||||
|
||||
Reference in New Issue
Block a user