Skip to content

Commit

Permalink
CSCEXAM-000 Introduction to signals
Browse files Browse the repository at this point in the history
  • Loading branch information
Matti Lupari committed Jan 12, 2024
1 parent 8017d9b commit 8b64bbb
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 86 deletions.
24 changes: 14 additions & 10 deletions ui/src/app/calendar/booking-calendar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
Output,
SimpleChanges,
ViewChild,
signal,
} from '@angular/core';
import { FullCalendarComponent, FullCalendarModule } from '@fullcalendar/angular';
import { CalendarOptions, EventApi, EventClickArg, EventInput } from '@fullcalendar/core';
Expand All @@ -46,7 +47,7 @@ import { CalendarService } from './calendar.service';
<div class="row mart20 marb10" id="calendarBlock">
@if (visible) {
<div class="col-md-12">
<full-calendar #fc [options]="calendarOptions"></full-calendar>
<full-calendar #fc [options]="calendarOptions()"></full-calendar>
</div>
}
</div>
Expand All @@ -72,13 +73,13 @@ export class BookingCalendarComponent implements OnInit, OnChanges, AfterViewIni

@ViewChild('fc') calendar!: FullCalendarComponent;

calendarOptions: CalendarOptions;
calendarOptions = signal<CalendarOptions>({});

constructor(
private translate: TranslateService,
private Calendar: CalendarService,
) {
this.calendarOptions = {
this.calendarOptions.set({
plugins: [luxon2Plugin, timeGridPlugin],
initialView: 'timeGridWeek',
firstDay: 1,
Expand All @@ -92,17 +93,17 @@ export class BookingCalendarComponent implements OnInit, OnChanges, AfterViewIni
eventMinHeight: 45,
events: this.refetch,
eventClick: this.eventClicked.bind(this),
};
});
this.translate.onLangChange.subscribe((event) => {
this.calendarOptions = { ...this.calendarOptions, locale: event.lang };
this.calendarOptions.set({ ...this.calendarOptions(), locale: event.lang });
//this.calendar.getApi().destroy();
//this.calendar.getApi().render();
});
}

ngOnInit() {
if (this.minDate && this.maxDate) {
this.calendarOptions.validRange = {
this.calendarOptions().validRange = {
end: DateTime.fromJSDate(this.maxDate).endOf('week').plus({ hours: 1 }).toFormat('yyyy-MM-dd'),
start: DateTime.fromJSDate(this.minDate).startOf('week').toFormat('yyyy-MM-dd'),
};
Expand All @@ -127,10 +128,13 @@ export class BookingCalendarComponent implements OnInit, OnChanges, AfterViewIni
latestClosing.getHours() < 23
? DateTime.fromJSDate(latestClosing).plus({ hour: 1 }).toJSDate()
: latestClosing;
this.calendarOptions.hiddenDays = this.Calendar.getClosedWeekdays(this.room);
this.calendarOptions.slotMinTime = DateTime.fromJSDate(minTime).toFormat('HH:mm:ss');
this.calendarOptions.slotMaxTime = DateTime.fromJSDate(maxTime).toFormat('HH:mm:ss');
this.calendarOptions.timeZone = this.room.localTimezone;
this.calendarOptions.update((cos) => ({
...cos,
hiddenDays: this.Calendar.getClosedWeekdays(this.room),
slotMinTime: DateTime.fromJSDate(minTime).toFormat('HH:mm:ss'),
slotMaxTime: DateTime.fromJSDate(maxTime).toFormat('HH:mm:ss'),
timeZone: this.room.localTimezone,
}));
if (this.calendar) this.calendar.getApi().refetchEvents();
}
if (changes.accessibilities && this.calendar) {
Expand Down
36 changes: 18 additions & 18 deletions ui/src/app/calendar/helpers/exam-info.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DatePipe } from '@angular/common';
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, computed, signal } from '@angular/core';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { DateTime } from 'luxon';
import { DateTimeService } from '../../shared/date/date.service';
Expand Down Expand Up @@ -71,10 +71,10 @@ import type { ExamInfo } from '../calendar.service';
</div>
<div class="row mart10">
<div class="col-md-12">
@if (showReservationWindowInfo()) {
@if (showReservationWindowDescription()) {
<span class="infolink" role="note">
<img class="arrow_icon padr10" src="/assets/images/icon_info.png" alt="" />
{{ getReservationWindowDescription() }}
{{ reservationWindowDescription() }}
</span>
}
</div>
Expand All @@ -90,29 +90,29 @@ export class CalendarExamInfoComponent implements OnInit {
@Input() reservationWindowSize = 0;
@Input() collaborative = false;

reservationWindowEndDate = new Date();
reservationWindowEndDate = signal(new Date());
reservationWindowDescription = computed(() => {
const text = this.translate
.instant('i18n_description_reservation_window')
.replace('{}', this.reservationWindowSize.toString());
return `${text} (${DateTime.fromJSDate(this.reservationWindowEndDate()).toFormat('dd.MM.yyyy')})`;
});
showReservationWindowDescription = computed(
() =>
!!this.reservationWindowEndDate &&
DateTime.fromISO(this.examInfo.periodEnd as string).toJSDate() > this.reservationWindowEndDate(),
);

constructor(
private translate: TranslateService,
private DateTimeService: DateTimeService,
) {}

ngOnInit() {
this.reservationWindowEndDate = DateTime.fromJSDate(this.reservationWindowEndDate)
.plus({ day: this.reservationWindowSize })
.toJSDate();
this.reservationWindowEndDate.set(
DateTime.fromJSDate(this.reservationWindowEndDate()).plus({ day: this.reservationWindowSize }).toJSDate(),
);
}

printExamDuration = (exam: { duration: number }) => this.DateTimeService.printExamDuration(exam);

getReservationWindowDescription(): string {
const text = this.translate
.instant('i18n_description_reservation_window')
.replace('{}', this.reservationWindowSize.toString());
return `${text} (${DateTime.fromJSDate(this.reservationWindowEndDate).toFormat('dd.MM.yyyy')})`;
}

showReservationWindowInfo = (): boolean =>
!!this.reservationWindowEndDate &&
DateTime.fromISO(this.examInfo.periodEnd as string).toJSDate() > this.reservationWindowEndDate;
}
32 changes: 19 additions & 13 deletions ui/src/app/calendar/helpers/organisation-picker.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NgClass } from '@angular/common';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, Output, signal } from '@angular/core';
import { NgbDropdown, NgbDropdownItem, NgbDropdownMenu, NgbDropdownToggle } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import type { Organisation } from '../calendar.service';
Expand All @@ -8,7 +8,10 @@ import { CalendarService } from '../calendar.service';
@Component({
selector: 'xm-calendar-organisation-picker',
template: `
<div class="row student-enrolment-wrapper details-view row" [ngClass]="selectedOrganisation ? '' : 'notactive'">
<div
class="row student-enrolment-wrapper details-view row"
[ngClass]="selectedOrganisation() ? '' : 'notactive'"
>
<div class="col-md-12">
<div class="row">
<span class="col-md-11 col-9">
Expand All @@ -17,7 +20,7 @@ import { CalendarService } from '../calendar.service';
</h2>
</span>
<span class="col-md-1 col-3">
@if (selectedOrganisation) {
@if (selectedOrganisation()) {
<span class="calendar-phase-icon float-end">
<img class="arrow_icon" src="/assets/images/icon-phase.png" alt="" />
</span>
Expand All @@ -41,7 +44,7 @@ import { CalendarService } from '../calendar.service';
{{ 'i18n_faculty_name' | translate }}&nbsp;
</button>
<ul ngbDropdownMenu role="menu" aria-labelledby="dropDownMenu21">
@for (org of organisations; track org.code) {
@for (org of organisations(); track org.code) {
<li
ngbDropdownItem
[hidden]="org.filtered"
Expand All @@ -65,11 +68,13 @@ import { CalendarService } from '../calendar.service';
</div>
</div>
<!-- Selected organisation -->
@if (selectedOrganisation) {
@if (selectedOrganisation()) {
<div class="row">
<div class="col-md-12">
<div class="calendar-room-title">
<span>{{ selectedOrganisation?.name }}&nbsp;({{ selectedOrganisation?.code }})</span>
<span
>{{ selectedOrganisation()?.name }}&nbsp;({{ selectedOrganisation()?.code }})</span
>
</div>
</div>
</div>
Expand All @@ -86,21 +91,22 @@ export class OrganisationPickerComponent implements OnInit {
@Output() selected = new EventEmitter<Organisation>();
@Output() cancelled = new EventEmitter<void>();

organisations: Organisation[] = [];
selectedOrganisation?: Organisation;
organisations = signal<Organisation[]>([]);
selectedOrganisation = signal<Organisation | undefined>(undefined);

constructor(private Calendar: CalendarService) {}

ngOnInit() {
this.Calendar.listOrganisations$().subscribe(
(resp) => (this.organisations = resp.filter((org) => !org.homeOrg && org.facilities.length > 0)),
this.Calendar.listOrganisations$().subscribe((resp) =>
this.organisations.set(resp.filter((org) => !org.homeOrg && org.facilities.length > 0)),
);
}

setOrganisation = (organisation: Organisation) => {
this.organisations.forEach((o) => (o.filtered = false));
organisation.filtered = true;
this.selectedOrganisation = organisation;
const orgs = this.organisations().map((o) => ({ ...o, filtered: false }));
const i = this.organisations().findIndex((o) => o._id === organisation._id);
this.organisations.set(orgs.splice(i, 1, { ...orgs[i], filtered: true }));
this.selectedOrganisation.set({ ...organisation, filtered: true });
this.selected.emit(organisation);
};

Expand Down
20 changes: 9 additions & 11 deletions ui/src/app/calendar/helpers/selected-room.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DatePipe, NgClass, UpperCasePipe } from '@angular/common';
import { Component, Input, OnChanges, OnInit } from '@angular/core';
import { Component, Input, OnChanges, OnInit, signal } from '@angular/core';
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { DateTime } from 'luxon';
Expand Down Expand Up @@ -29,7 +29,7 @@ import { CalendarService } from '../calendar.service';
</div>
</div>
<div class="col-md-10 col-12">
@for (oh of openingHours; track oh.ord) {
@for (oh of openingHours(); track oh.ord) {
<div class="row">
<div class="col-md-1 col-6">{{ oh.name | uppercase }}</div>
<div class="col-md-11 col-6">{{ oh.periodText }}</div>
Expand All @@ -55,7 +55,7 @@ import { CalendarService } from '../calendar.service';
<div class="row mt-2">
<div class="col-md-2 col-12">{{ 'i18n_exception_datetimes' | translate }}:</div>
<div class="col-md-10 col-12">
@for (eh of exceptionHours; track eh.id) {
@for (eh of exceptionHours(); track eh.id) {
<div
[ngClass]="eh.outOfService ? 'text-danger' : 'text-success'"
triggers="mouseenter:mouseleave"
Expand Down Expand Up @@ -89,8 +89,8 @@ export class SelectedRoomComponent implements OnInit, OnChanges {
@Input() maintenancePeriods: MaintenancePeriod[] = [];
@Input() viewStart = DateTime.now();

openingHours: OpeningHours[] = [];
exceptionHours: (ExceptionWorkingHours & { start: string; end: string; description: string })[] = [];
openingHours = signal<OpeningHours[]>([]);
exceptionHours = signal<(ExceptionWorkingHours & { start: string; end: string; description: string })[]>([]);

constructor(
private translate: TranslateService,
Expand All @@ -99,7 +99,7 @@ export class SelectedRoomComponent implements OnInit, OnChanges {

ngOnInit() {
this.translate.onLangChange.subscribe(() => {
this.openingHours = this.Calendar.processOpeningHours(this.room);
this.openingHours.set(this.Calendar.processOpeningHours(this.room));
});
}

Expand All @@ -123,11 +123,9 @@ export class SelectedRoomComponent implements OnInit, OnChanges {
this.room.accessibilities ? this.room.accessibilities.map((a) => a.name).join(', ') : '';

private init() {
this.openingHours = this.Calendar.processOpeningHours(this.room);
this.exceptionHours = this.Calendar.getExceptionHours(
this.room,
this.viewStart,
this.viewStart.plus({ week: 1 }),
this.openingHours.set(this.Calendar.processOpeningHours(this.room));
this.exceptionHours.set(
this.Calendar.getExceptionHours(this.room, this.viewStart, this.viewStart.plus({ week: 1 })),
);
}
}
22 changes: 11 additions & 11 deletions ui/src/app/calendar/helpers/slot-picker.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ <h2 class="calendar-phase-title">{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2
@if (!disabled) {
<button
class="infolink pointer border rounded"
(click)="showAccessibilityMenu = !showAccessibilityMenu"
(keydown.enter)="showAccessibilityMenu = !showAccessibilityMenu"
[attr.aria-expanded]="showAccessibilityMenu"
(click)="showAccessibilityMenu.set(!showAccessibilityMenu())"
(keydown.enter)="showAccessibilityMenu.set(!showAccessibilityMenu())"
[attr.aria-expanded]="showAccessibilityMenu()"
>
{{ 'i18n_calendar_room_accessibility_info' | translate }}
@if (!showAccessibilityMenu) {
@if (!showAccessibilityMenu()) {
<img class="arrow_icon" aria-hidden="true" src="/assets/images/arrow_right.png" />
}
@if (showAccessibilityMenu) {
@if (showAccessibilityMenu()) {
<img class="arrow_icon" aria-hidden="true" src="/assets/images/arrow_down.png" />
}
</button>
Expand All @@ -38,7 +38,7 @@ <h2 class="calendar-phase-title">{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2
{{ 'i18n_calendar_room_accessibility_info' | translate }}
</span>
}
<div [ngbCollapse]="!showAccessibilityMenu">
<div [ngbCollapse]="!showAccessibilityMenu()">
<div class="row">
<div class="col-md-12">
<div class="calendar-accs-title">
Expand All @@ -48,7 +48,7 @@ <h2 class="calendar-phase-title">{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2
</div>
<div class="row">
<div class="col-md-12 calendar-accs-checkboxes">
@for (accessibility of accessibilities; track accessibility.id) {
@for (accessibility of accessibilities(); track accessibility.id) {
<span class="marr10 accs-list">
<label for="{{ accessibility.name }}">
<input
Expand Down Expand Up @@ -82,7 +82,7 @@ <h2 class="calendar-phase-title">{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2
<span class="caret"></span>
</button>
<div ngbDropdownMenu role="menu" aria-labelledby="dropDownMenu1" class="scrollable-menu">
@for (room of rooms; track room.id) {
@for (room of rooms(); track room.id) {
<button ngbDropdownItem role="presentation" (click)="selectRoom(room)" title="{{ room.name }}">
<div ngbDropdownItem [disabled]="room.outOfService" role="menuitem">
<a> {{ room.name }}</a>
Expand All @@ -104,8 +104,8 @@ <h2 class="calendar-phase-title">{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2
<div class="col-md-12">
<xm-calendar-selected-room
[room]="selectedRoom"
[viewStart]="currentWeek"
[maintenancePeriods]="maintenancePeriods"
[viewStart]="currentWeek()"
[maintenancePeriods]="maintenancePeriods()"
></xm-calendar-selected-room>
</div>
</div>
Expand All @@ -119,7 +119,7 @@ <h2 class="calendar-phase-title">{{ sequenceNumber }}. {{ 'i18n_calendar_phase_2
[minDate]="minDate"
[maxDate]="maxDate"
[room]="selectedRoom"
[accessibilities]="accessibilities"
[accessibilities]="accessibilities()"
[visible]="selectedRoom !== undefined"
>
</xm-booking-calendar>
Expand Down
Loading

0 comments on commit 8b64bbb

Please sign in to comment.