Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
#### Bug fixes
* **(guided-tour)** : correction problème de chargement des traductions du tour guidé sur certains périphériques
* **(statistics)** : suppression de l'utilisation du DeviceId pour le suivi des statistiques d'usage comme préconisé dans le RGPD. Utilisation d'une UID générée automatiquement par le client à la place.
* **(widgets)**: les widgets tiennent désormais compte de l'ionicon ou bien des icônes SVG renseignées du côté du CMS et les affichent à côté du titre de la Widget
* **(widgets)**: les widgets tiennent désormais compte de l'Ionicon ou bien des icônes SVG renseignées du côté du CMS et les affichent à côté du titre de la Widget

#### New features
* **(schedule)** : Il est désormais possible de choisir entre 2 affichages pour la widget des prochains cours à venir :
* Liste verticale (list)
* Slider horizontal (slider)

### Backend
#### Bug fixes
Expand Down
41 changes: 19 additions & 22 deletions dev/user-frontend-ionic/projects/schedule/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,33 @@

Module permettant l'affichage des emplois du temps de l'utilisateur.

## Widgets
- `next-events` : Widget qui affiche les prochains évènements de l'emploi du temps.

## Configuration

Exemple dans `app.module.ts` :
Exemple dans `environment.ts` :
```typescript
@NgModule({
declarations: [AppComponent],
imports: [
ScheduleModule.forRoot({
nextEventsWidget: {
numberOfEventsLimit: 2,
numberOfDaysLimit: 7
},
previousWeeksInCache: 1,
nextWeeksInCache: 2,
managerRoles: ['role_1', 'role_2']
})
]
})
ScheduleModule.forRoot({
nextEventsWidget: {
numberOfEventsLimit: 2,
numberOfDaysLimit: 7,
display: 'slider'
},
previousWeeksInCache: 1,
nextWeeksInCache: 2,
managerRoles: ['role_1', 'role_2']
})
```

### Configuration du widget "mes prochains cours"
- `nextEventsWidget.numberOfEventsLimit` : nombre maximum des prochains évènements à afficher.
- `nextEventsWidget.numberOfDaysLimit` : limite maximale du nombre de jours suivants le jour courant dans lesquels chercher les prochains évènements.

### Configuration du cache
- `previousWeeksInCache` : Le nombre de semaines précédentes à sauvegarder en cache.
- `nextEventsWidget.numberOfDaysLimit` : Le nombre de semaines suivant à sauvegarder en cache.

### Configuration des gestionnaires d'emploi du temps
- `managerRoles` : Liste des rôles permettant d'identifier l'utilisateur comme étant gestionnaire d'emploi du temps et lui permettant ainsi d'accéder à l'affichage d'un EDT pour une autre personne

## Widgets
- `next-events` : Widget qui affiche les prochains évènements de l'emploi du temps.

### Configuration du widget "mes prochains cours"
- `nextEventsWidget.numberOfEventsLimit` : nombre maximum des prochains évènements à afficher.
- `nextEventsWidget.numberOfDaysLimit` : limite maximale du nombre de jours suivants le jour courant dans lesquels chercher les prochains évènements.
- `nextEventsWidget.display` : ("list" | "slider") : choix de la vue, en liste ou en ligne
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { InjectionToken } from '@angular/core';
interface NextEventsWidgetConfig {
numberOfEventsLimit: number;
numberOfDaysLimit: number;
display: "list" | "slider";
}

export interface ScheduleModuleConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,65 +37,147 @@
~ termes.
-->

<ion-row *ngIf="isLoading === true">
<ion-spinner class="safe-area-lr-ionic-margin" name="dots"></ion-spinner>
</ion-row>

<ng-container *ngIf="isLoading === false">
<ion-grid class="events-container">
<ion-row *ngIf="(noNextEvents$ | async) === true" class="ion-padding-bottom">
<ion-note [ngClass]="fontColor()" class="app-text-4">
{{ "SCHEDULE.WIDGET.NEXT_EVENTS.NO_EVENTS" | translate }}
</ion-note>
<ng-container *ngTemplateOutlet="getTemplateRef()"></ng-container>

<ng-template #list>
<ion-row class="next-events-list-style">

<ion-row *ngIf="isLoading">
<ion-spinner class="safe-area-lr-ionic-margin" name="dots"></ion-spinner>
</ion-row>

<ion-col *ngFor="let event of (nextEvents$ | async) let last = last" class="ion-no-padding">
<ion-row *ngIf="displayDateForIds.includes(event.id)" class="event-day">
<ion-text [ngClass]="fontColor()" class="app-title-6 light">
{{ event.startDateTime | completeLocalDate }}
</ion-text>
</ion-row>

<ion-card [ngClass]="{'last-card': last}">
<div class="circle-top-left"></div>
<div class="dashed-line"></div>

<ion-card-header>
<ion-card-title [ngClass]="fontColor()"
class="app-title-5 light">
{{event.startDateTime | localHour}} - {{event.endDateTime | localHour}}
</ion-card-title>
</ion-card-header>

<ion-card-content>
<ion-row>
<ion-col>
<ion-text [ngClass]="fontColor()"
class="app-title-5">{{event.course.label}}</ion-text>
<ion-row>
<ion-row class="ion-align-items-center card-labels" *ngFor="let room of event.rooms">
<ion-icon [ngClass]="[fontColor(), 'card-labels-icons']" name="business-outline" aria-label=""></ion-icon>
<ion-text [ngClass]="fontColor()"
class="app-title-6 light">{{room.label}} - {{room.building}}</ion-text>
<ng-container *ngIf="!isLoading">
<ion-grid class="events-container">
<ion-row *ngIf="noNextEvents$ | async" class="ion-padding-bottom">
<ion-col>
<ion-note [ngClass]="fontColor()" class="app-text-4">
{{ "SCHEDULE.WIDGET.NEXT_EVENTS.NO_EVENTS" | translate }}
</ion-note>
</ion-col>
</ion-row>

<ion-row *ngFor="let event of (nextEvents$ | async); let last = last">
<ion-col class="ion-no-padding">
<ion-row *ngIf="displayDateForIds.includes(event.id)" class="event-day">
<ion-col>
<ion-text [ngClass]="fontColor()" class="app-title-6 light">
{{ event.startDateTime | completeLocalDate }}
</ion-text>
</ion-col>
</ion-row>

<ion-card [ngClass]="{'last-card': last}">
<div class="circle-top-left"></div>
<div class="dashed-line"></div>

<ion-card-header>
<ion-card-title [ngClass]="fontColor()" class="app-title-5 light">
{{event.startDateTime | localHour}} - {{event.endDateTime | localHour}}
</ion-card-title>
</ion-card-header>

<ion-card-content>
<ion-row>
<ion-col>
<ion-text [ngClass]="fontColor()" class="app-title-5">{{event.course.label}}</ion-text>

<ion-row class="ion-align-items-start card-labels" *ngFor="let room of event.rooms">
<ion-col size="auto" class="ion-no-padding">
<ion-icon [ngClass]="[fontColor(), 'card-labels-icons']" name="business-outline" aria-hidden="true"></ion-icon>
</ion-col>
<ion-col class="ion-no-padding">
<ion-text [ngClass]="fontColor()" class="app-title-6 light">{{room.label}} - {{room.building}}</ion-text>
</ion-col>
</ion-row>

<ion-row class="ion-align-items-start card-labels" *ngFor="let teacher of event.teachers">
<ion-col size="auto" class="ion-no-padding">
<ion-icon [ngClass]="fontColor()" class="card-labels-icons" name="man-outline" aria-hidden="true"></ion-icon>
</ion-col>
<ion-col class="ion-no-padding">
<ion-text [ngClass]="fontColor()" class="app-title-6 light">{{teacher.displayname}}</ion-text>
</ion-col>
</ion-row>

<ion-row class="ion-align-items-start card-labels" *ngIf="event.course.url">
<ion-col size="auto" class="ion-no-padding">
<ion-icon [ngClass]="fontColor()" class="card-labels-icons" name="link-outline" aria-hidden="true"></ion-icon>
</ion-col>
<ion-col class="ion-no-padding">
<ion-text [ngClass]="fontColor()" class="app-title-6 light">{{ event.course.url | truncate:35 }}</ion-text>
</ion-col>
</ion-row>
</ion-col>
</ion-row>
<ion-row class="ion-align-items-center card-labels" *ngFor="let teacher of event.teachers">
<ion-icon [ngClass]="fontColor()"
class="card-labels-icons" name="man-outline" aria-label=""></ion-icon>
<ion-text [ngClass]="fontColor()"
class="app-title-6 light">{{teacher.displayname}}</ion-text>
</ion-card-content>
</ion-card>
</ion-col>
</ion-row>
</ion-grid>
</ng-container>

</ion-row>
</ng-template>


<ng-template #slider>
<ion-row class="next-events-slider-style">

<ion-row *ngIf="isLoading === true">
<ion-spinner class="safe-area-lr-ionic-margin" name="dots"></ion-spinner>
</ion-row>

<ng-container *ngIf="isLoading === false">

<ion-grid class="empty-container" *ngIf="(noNextEvents$ | async) === true; else sliderInnerContainer">
<ion-row class="ion-padding-bottom">
<ion-note [ngClass]="fontColor()" class="app-text-4">
{{ "SCHEDULE.WIDGET.NEXT_EVENTS.NO_EVENTS" | translate }}
</ion-note>
</ion-row>
</ion-grid>
<ng-template #sliderInnerContainer>
<ion-row class="events-container">
<ion-card *ngFor="let event of (nextEvents$ | async) let last = last" class="ion-no-margin slider-theme-color">
<ion-card-content>
<ion-row [ngStyle]="{'border-left-color': event.course.color}" class="event-day-hour">
<ion-text class="hour app-title-2 slider-font-color">{{event.startDateTime | localHour}} - {{event.endDateTime | localHour}}</ion-text>
<ng-container *ngIf="(event.startDateTime | completeLocalDate) as completeLocalDate">
<ion-row class="day app-text-4">
<ion-text class="slider-font-color">{{completeLocalDate | slice: 0:completeLocalDate.indexOf(' ')}}</ion-text>
<ion-text class="slider-font-color">{{completeLocalDate | slice: completeLocalDate.indexOf(' ')}}</ion-text>
</ion-row>
</ng-container>
</ion-row>
<ion-text class="app-title-5 event-label slider-font-color">{{event.course.label}}</ion-text>
<ion-row class="event-additional">
<ion-row class="ion-align-items-center card-labels" *ngFor="let room of event.rooms">
<ion-icon class="card-labels-icons slider-font-color" name="business-outline" aria-hidden="true"></ion-icon>
<ion-text class="app-title-6 light slider-font-color">{{room.label}}<span *ngIf="room.building"> - {{room.building}}</span></ion-text>
</ion-row>
<ng-container *ngIf="event.teachers.length <= 2; else limitTeachers">
<ion-row class="ion-align-items-center card-labels" *ngFor="let teacher of event.teachers">
<ion-icon class="card-labels-icons slider-font-color" name="man-outline" aria-hidden="true"></ion-icon>
<ion-text class="app-title-6 light slider-font-color">{{teacher.displayname}}</ion-text>
</ion-row>
</ng-container>
<ng-template #limitTeachers>
<ion-row class="ion-align-items-center card-labels">
<ion-icon class="card-labels-icons slider-font-color" name="man-outline" aria-hidden="true"></ion-icon>
<ion-text class="app-title-6 light slider-font-color">{{event.teachers[0].displayname}} (+ {{event.teachers.length - 1}} {{ "SCHEDULE.WIDGET.NEXT_EVENTS.LIMIT_TEACHERS" | translate }})</ion-text>
</ion-row>
</ng-template>
<ion-row class="ion-align-items-center card-labels" *ngIf="event.course.url">
<ion-icon [ngClass]="fontColor()"
class="card-labels-icons" name="link-outline" aria-label=""></ion-icon>
<ion-text [ngClass]="fontColor()"
class="app-title-6 light">{{ event.course.url | truncate:35 }}</ion-text>
<ion-icon class="card-labels-icons slider-font-color" name="link-outline" aria-hidden="true"></ion-icon>
<ion-text class="app-title-6 light slider-font-color">{{ event.course.url | truncate:35 }}</ion-text>
</ion-row>
</ion-row>
</ion-col>
</ion-row>
</ion-card-content>

</ion-card>
</ion-col>
</ion-grid>
</ng-container>
</ion-card-content>
</ion-card>

</ion-row>
</ng-template>
</ng-container>

</ion-row>
</ng-template>
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@
* termes.
*/

import { AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core';
import { AfterViewInit, ChangeDetectorRef, Component, Inject, Input, OnDestroy, TemplateRef, ViewChild } from '@angular/core';
import { CompleteLocalDatePipe, ThemeService } from '@multi/shared';
import { Observable, Subscription } from 'rxjs';
import { finalize, map, take } from 'rxjs/operators';
import { Event } from '../../schedule.repository';
import { ScheduleService } from '../../schedule.service';
import { NextEventsService } from './next-events.service';
import { SCHEDULE_CONFIG, ScheduleModuleConfig } from '../../schedule.config';

@Component({
selector: 'app-schedule-widget-next-events',
Expand All @@ -53,6 +54,8 @@ import { NextEventsService } from './next-events.service';
export class NextEventsComponent implements OnDestroy, AfterViewInit {

@Input() widgetColor: string;
@ViewChild('list') list: TemplateRef<any>;
@ViewChild('slider') slider: TemplateRef<any>;

public isLoading = false;
public nextEvents$: Observable<Event[]>;
Expand All @@ -65,7 +68,8 @@ export class NextEventsComponent implements OnDestroy, AfterViewInit {
private scheduleService: ScheduleService,
private completeLocalDatePipe: CompleteLocalDatePipe,
private themeService: ThemeService,
private changeDetectorRef: ChangeDetectorRef
private changeDetectorRef: ChangeDetectorRef,
@Inject(SCHEDULE_CONFIG) private config: ScheduleModuleConfig
) {
this.nextEvents$ = this.nextEventsService.getNextEvents$().pipe();

Expand Down Expand Up @@ -111,5 +115,9 @@ export class NextEventsComponent implements OnDestroy, AfterViewInit {
ngOnDestroy() {
this.nextEventsSubscription.unsubscribe();
}

getTemplateRef(): TemplateRef<any> {
return this[this?.config.nextEventsWidget.display];
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
},
"WIDGET": {
"NEXT_EVENTS": {
"NO_EVENTS": "No courses soon"
"NO_EVENTS": "No courses soon",
"LIMIT_TEACHERS": "others"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
},
"WIDGET": {
"NEXT_EVENTS": {
"NO_EVENTS": "Pas de cours prochainement"
"NO_EVENTS": "Pas de cours prochainement",
"LIMIT_TEACHERS": "autres"
}
}
}
Loading