mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-19 16:13:06 +00:00
feat: apply new layout overhaul
This commit is contained in:
committed by
Rainer Killinger
parent
f16e5394cc
commit
7bbdba5c0b
264
src/app/modules/schedule/page/components/calendar.component.ts
Normal file
264
src/app/modules/schedule/page/components/calendar.component.ts
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {SCISO8601Date, SCUuid} from '@openstapps/core';
|
||||
import moment, {Moment} from 'moment';
|
||||
import {
|
||||
materialFade,
|
||||
materialManualFade,
|
||||
materialSharedAxisX,
|
||||
} from '../../../../animation/material-motion';
|
||||
import {ScheduleProvider} from '../../../calendar/schedule.provider';
|
||||
import {ScheduleEvent, ScheduleResponsiveBreakpoint} from '../schema/schema';
|
||||
import {SwiperComponent} from 'swiper/angular';
|
||||
import {InfiniteSwiperComponent} from '../grid/infinite-swiper.component';
|
||||
import {IonDatetime} from '@ionic/angular';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {CalendarService} from '../../../calendar/calendar.service';
|
||||
|
||||
/**
|
||||
* Component that displays the schedule
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-calendar-component',
|
||||
templateUrl: 'calendar-component.html',
|
||||
styleUrls: ['calendar-component.scss'],
|
||||
animations: [materialFade, materialSharedAxisX, materialManualFade],
|
||||
})
|
||||
export class CalendarComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* The day that the schedule started out on
|
||||
*/
|
||||
@Input() baselineDate: Moment;
|
||||
|
||||
/**
|
||||
* Range of date of the slides shown on screen.
|
||||
*/
|
||||
dateRange: {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
} = {
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
};
|
||||
|
||||
calendarServiceSubscription: Subscription;
|
||||
|
||||
prevHeaderIndex = 0;
|
||||
|
||||
/**
|
||||
* Hours for grid
|
||||
*/
|
||||
@Input() hours: number[];
|
||||
|
||||
/**
|
||||
* Range of hours to display
|
||||
*/
|
||||
@Input() readonly hoursRange = {
|
||||
from: 5,
|
||||
to: 22,
|
||||
};
|
||||
|
||||
todaySlideIndex: number;
|
||||
|
||||
initialSlideIndex?: Promise<number>;
|
||||
|
||||
/**
|
||||
* Layout of the schedule
|
||||
*/
|
||||
@Input() layout: ScheduleResponsiveBreakpoint;
|
||||
|
||||
/**
|
||||
* Route fragment
|
||||
*/
|
||||
routeFragment = 'schedule/calendar';
|
||||
|
||||
/**
|
||||
* Vertical scale of the schedule (distance between hour lines)
|
||||
*/
|
||||
@Input() scale = 70;
|
||||
|
||||
/**
|
||||
* unix -> (uid -> event)
|
||||
*/
|
||||
@Input() testSchedule: Record<SCISO8601Date, Record<SCUuid, ScheduleEvent>> =
|
||||
{};
|
||||
|
||||
/**
|
||||
* UUIDs
|
||||
*/
|
||||
@Input() uuids: SCUuid[];
|
||||
|
||||
/**
|
||||
* UUID subscription
|
||||
*/
|
||||
uuidSubscription: Subscription;
|
||||
|
||||
@Input() useInfiniteSwiper = true;
|
||||
|
||||
@Input() weekDates: Array<Moment>;
|
||||
|
||||
constructor(
|
||||
protected readonly activatedRoute: ActivatedRoute,
|
||||
protected readonly calendarService: CalendarService,
|
||||
protected readonly scheduleProvider: ScheduleProvider,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.onInit();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy();
|
||||
}
|
||||
|
||||
onInit() {
|
||||
this.dateRange.startDate = this.calculateDateFromIndex(0, 0, 'DD.MM.YY');
|
||||
this.dateRange.endDate = this.calculateDateFromIndex(
|
||||
0,
|
||||
this.layout.days - 1,
|
||||
'DD.MM.YY',
|
||||
);
|
||||
|
||||
let dayString: string | number | null =
|
||||
this.activatedRoute.snapshot.paramMap.get('date');
|
||||
if (dayString == undefined || dayString === 'now') {
|
||||
const fragments = window.location.href.split('/');
|
||||
const urlFragment: string = fragments[fragments.length - 1] ?? '';
|
||||
|
||||
dayString = /^\d{4}-\d{2}-\d{2}$/.test(urlFragment)
|
||||
? urlFragment
|
||||
: moment.now();
|
||||
}
|
||||
|
||||
this.baselineDate = moment(dayString).startOf('day');
|
||||
|
||||
this.initialSlideIndex = new Promise(resolve => {
|
||||
this.uuidSubscription = this.scheduleProvider.uuids$.subscribe(
|
||||
async result => {
|
||||
this.uuids = result;
|
||||
resolve(await this.loadEvents());
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
this.uuidSubscription.unsubscribe();
|
||||
if (this.calendarServiceSubscription) {
|
||||
this.calendarServiceSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date from baseline date and index of current slide.
|
||||
*
|
||||
* @param index number
|
||||
* @param delta number - is added to index
|
||||
* @param dateFormat string
|
||||
*/
|
||||
calculateDateFromIndex(index: number, delta = 0, dateFormat = 'YYYY-MM-DD') {
|
||||
return moment(this.baselineDate)
|
||||
.add(index + delta, 'days')
|
||||
.format(dateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change page
|
||||
*/
|
||||
onPageChange(index: number) {
|
||||
this.setDateRange(index);
|
||||
|
||||
window.history.replaceState(
|
||||
{},
|
||||
'',
|
||||
`${this.routeFragment}/${this.calculateDateFromIndex(index)}`,
|
||||
);
|
||||
}
|
||||
|
||||
setDateRange(index: number) {
|
||||
this.dateRange.startDate = this.calculateDateFromIndex(
|
||||
index,
|
||||
0,
|
||||
'DD.MM.YY',
|
||||
);
|
||||
this.dateRange.endDate = this.calculateDateFromIndex(
|
||||
index,
|
||||
this.layout.days - 1,
|
||||
'DD.MM.YY',
|
||||
);
|
||||
}
|
||||
|
||||
onHeaderSwipe(index: number, infiniteController: InfiniteSwiperComponent) {
|
||||
if (index < this.prevHeaderIndex) {
|
||||
infiniteController?.pageBackwards();
|
||||
}
|
||||
if (index > this.prevHeaderIndex) {
|
||||
infiniteController?.pageForward();
|
||||
}
|
||||
this.prevHeaderIndex = index;
|
||||
}
|
||||
|
||||
syncSwiper(self: SwiperComponent, other: SwiperComponent) {
|
||||
other.swiperRef.slideTo(self.swiperRef.activeIndex);
|
||||
}
|
||||
|
||||
presentDatePopover(
|
||||
mainSwiper: InfiniteSwiperComponent,
|
||||
headerSwiper: InfiniteSwiperComponent,
|
||||
index: number,
|
||||
popoverDateTime: IonDatetime,
|
||||
) {
|
||||
const nextIndex =
|
||||
moment(popoverDateTime.value).diff(this.baselineDate, 'days') -
|
||||
headerSwiper.virtualIndex -
|
||||
index;
|
||||
|
||||
mainSwiper.goToIndex(nextIndex).then(() => {
|
||||
this.setDateRange(nextIndex);
|
||||
});
|
||||
popoverDateTime.confirm(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load events
|
||||
*/
|
||||
async loadEvents(): Promise<number> {
|
||||
const dateSeries = await this.scheduleProvider.getDateSeries(this.uuids);
|
||||
|
||||
this.testSchedule = {};
|
||||
|
||||
for (const series of dateSeries.dates) {
|
||||
for (const date of series.dates) {
|
||||
const index = moment(date)
|
||||
.startOf('day')
|
||||
.diff(this.baselineDate, 'days');
|
||||
|
||||
// fall back to default
|
||||
(this.testSchedule[index] ?? (this.testSchedule[index] = {}))[
|
||||
series.uid
|
||||
] = {
|
||||
dateSeries: series,
|
||||
time: {
|
||||
start: moment(date).hours(),
|
||||
duration: series.duration,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
return this.todaySlideIndex;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user