Add current list of speakers to agenda-list

Adds a current-list-of-speakers button to the agenda list view
The user may select a projector which will return an agenda item
which will be used to determine the CLOS
This commit is contained in:
Sean Engelhardt 2019-02-01 18:11:10 +01:00
parent e281b310a7
commit 0a7f905c21
4 changed files with 121 additions and 20 deletions

View File

@ -12,6 +12,7 @@ const routes: Routes = [
{ path: 'import', component: AgendaImportListComponent }, { path: 'import', component: AgendaImportListComponent },
{ path: 'topics/new', component: TopicDetailComponent }, { path: 'topics/new', component: TopicDetailComponent },
{ path: 'sort-agenda', component: AgendaSortComponent }, { path: 'sort-agenda', component: AgendaSortComponent },
{ path: 'speakers', component: SpeakerListComponent },
{ path: 'topics/:id', component: TopicDetailComponent }, { path: 'topics/:id', component: TopicDetailComponent },
{ path: ':id/speakers', component: SpeakerListComponent } { path: ':id/speakers', component: SpeakerListComponent }
]; ];

View File

@ -110,7 +110,12 @@
<span translate>Sort</span> <span translate>Sort</span>
</button> </button>
</div> </div>
<!-- csv export --> <!-- Current list of speakers -->
<button mat-menu-item routerLink="speakers">
<mat-icon>mic</mat-icon>
<span translate>Current list of speakers</span>
</button>
<!-- CSV export -->
<button mat-menu-item (click)="csvExportItemList()"> <button mat-menu-item (click)="csvExportItemList()">
<mat-icon>archive</mat-icon> <mat-icon>archive</mat-icon>
<span translate>Export as CSV</span> <span translate>Export as CSV</span>

View File

@ -1,16 +1,33 @@
<os-head-bar [nav]="false" [goBack]="true"> <os-head-bar [nav]="false" [goBack]="true">
<!-- Title --> <!-- Title -->
<div class="title-slot"> <div class="title-slot">
<h2><span translate>List of speakers</span></h2> <h2>
<span *ngIf="!currentListOfSpeakers">List of speakers</span>
<span *ngIf="currentListOfSpeakers">Current list of speakers</span>
</h2>
</div> </div>
<div class="menu-slot" *osPerms="'agenda.can_manage_list_of_speakers'"> <div class="menu-slot" *osPerms="'agenda.can_manage_list_of_speakers'">
<button type="button" mat-icon-button [matMenuTriggerFor]="speakerMenu"><mat-icon>more_vert</mat-icon></button> <button type="button" mat-icon-button [matMenuTriggerFor]="speakerMenu"><mat-icon>more_vert</mat-icon></button>
</div> </div>
</os-head-bar> </os-head-bar>
<!-- Select projector -->
<mat-card *ngIf="currentListOfSpeakers">
<h3 translate>
Manage the list of speakers for...
</h3>
<mat-form-field *ngIf="projectors && projectors.length > 0">
<mat-select [value]="projectors[0]" (selectionChange)="onSelectProjector($event)">
<mat-option *ngFor="let projector of projectors" [value]="projector">
{{ projector.name }}
</mat-option>
</mat-select>
</mat-form-field>
</mat-card>
<h1 class="title-left on-transition-fade" *ngIf="viewItem">{{ viewItem.getTitle() }}</h1> <h1 class="title-left on-transition-fade" *ngIf="viewItem">{{ viewItem.getTitle() }}</h1>
<mat-card class="speaker-card"> <mat-card class="speaker-card" *ngIf="viewItem">
<!-- List of finished speakers --> <!-- List of finished speakers -->
<mat-expansion-panel *ngIf="finishedSpeakers && finishedSpeakers.length > 0" class="finished-list"> <mat-expansion-panel *ngIf="finishedSpeakers && finishedSpeakers.length > 0" class="finished-list">
<mat-expansion-panel-header> <mat-expansion-panel-header>

View File

@ -1,20 +1,24 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { BehaviorSubject, Subscription } from 'rxjs';
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms'; import { FormGroup, FormControl } from '@angular/forms';
import { BehaviorSubject } from 'rxjs'; import { MatSnackBar, MatSelectChange } from '@angular/material';
import { SpeakerState } from 'app/shared/models/agenda/speaker';
import { User } from 'app/shared/models/users/user';
import { ViewSpeaker } from '../../models/view-speaker';
import { DataStoreService } from 'app/core/core-services/data-store.service';
import { AgendaRepositoryService } from 'app/core/repositories/agenda/agenda-repository.service';
import { ViewItem } from '../../models/view-item';
import { OperatorService } from 'app/core/core-services/operator.service';
import { BaseViewComponent } from 'app/site/base/base-view';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { MatSnackBar } from '@angular/material';
import { AgendaRepositoryService } from 'app/core/repositories/agenda/agenda-repository.service';
import { BaseViewComponent } from 'app/site/base/base-view';
import { CurrentListOfSpeakersSlideService } from 'app/site/projector/services/current-list-of-of-speakers-slide.service';
import { DataStoreService } from 'app/core/core-services/data-store.service';
import { OperatorService } from 'app/core/core-services/operator.service';
import { ProjectorRepositoryService } from 'app/core/repositories/projector/projector-repository.service';
import { PromptService } from 'app/core/ui-services/prompt.service'; import { PromptService } from 'app/core/ui-services/prompt.service';
import { SpeakerState } from 'app/shared/models/agenda/speaker';
import { Title } from '@angular/platform-browser';
import { User } from 'app/shared/models/users/user';
import { ViewItem } from '../../models/view-item';
import { ViewSpeaker } from '../../models/view-speaker';
import { ViewProjector } from 'app/site/projector/models/view-projector';
/** /**
* The list of speakers for agenda items. * The list of speakers for agenda items.
@ -25,6 +29,11 @@ import { PromptService } from 'app/core/ui-services/prompt.service';
styleUrls: ['./speaker-list.component.scss'] styleUrls: ['./speaker-list.component.scss']
}) })
export class SpeakerListComponent extends BaseViewComponent implements OnInit { export class SpeakerListComponent extends BaseViewComponent implements OnInit {
/**
* Determine if the user is viewing the current list if speakers
*/
public currentListOfSpeakers = false;
/** /**
* Holds the view item to the given topic * Holds the view item to the given topic
*/ */
@ -35,6 +44,16 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
*/ */
public speakers: ViewSpeaker[]; public speakers: ViewSpeaker[];
/**
* Holds a list of projectors. Only in CurrentListOfSpeakers mode
*/
public projectors: ViewProjector[];
/**
* Holds the subscription to the current projector (if any)
*/
private projectorSubscription: Subscription;
/** /**
* Holds the active speaker * Holds the active speaker
*/ */
@ -76,6 +95,7 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
* @param title * @param title
* @param translate * @param translate
* @param snackBar * @param snackBar
* @param projectorRepo
* @param route Angulars ActivatedRoute * @param route Angulars ActivatedRoute
* @param DS the DataStore * @param DS the DataStore
* @param itemRepo Repository fpr agenda items * @param itemRepo Repository fpr agenda items
@ -85,15 +105,27 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
title: Title, title: Title,
translate: TranslateService, translate: TranslateService,
snackBar: MatSnackBar, snackBar: MatSnackBar,
projectorRepo: ProjectorRepositoryService,
private route: ActivatedRoute, private route: ActivatedRoute,
private DS: DataStoreService, private DS: DataStoreService,
private itemRepo: AgendaRepositoryService, private itemRepo: AgendaRepositoryService,
private op: OperatorService, private op: OperatorService,
private promptService: PromptService private promptService: PromptService,
private currentListOfSpeakersService: CurrentListOfSpeakersSlideService
) { ) {
super(title, translate, snackBar); super(title, translate, snackBar);
this.isCurrentListOfSpeakers();
this.addSpeakerForm = new FormGroup({ user_id: new FormControl([]) }); this.addSpeakerForm = new FormGroup({ user_id: new FormControl([]) });
this.getAgendaItemByUrl();
if (this.currentListOfSpeakers) {
this.projectors = projectorRepo.getViewModelList();
this.showClosOfProjector(this.projectors[0]);
projectorRepo.getViewModelListObservable().subscribe(newProjectors => {
this.projectors = newProjectors;
});
} else {
this.getItemByUrl();
}
} }
/** /**
@ -120,19 +152,64 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
}); });
} }
/**
* Check the URL to determine a current list of Speakers
*/
private isCurrentListOfSpeakers(): void {
if (this.route.snapshot.url[0]) {
this.currentListOfSpeakers = this.route.snapshot.url[0].path === 'speakers';
}
}
/**
* Executed by selecting projectors
*
* @param event Holds the selected projector
*/
public onSelectProjector(event: MatSelectChange): void {
this.showClosOfProjector(event.value);
}
/**
* Shows the current lost of speakers of a given projector.
* Triggers after mat-select-change
*
* @param event Mat select change event, holds the projector in value
*/
private showClosOfProjector(projector: ViewProjector): void {
if (this.projectorSubscription) {
this.projectorSubscription.unsubscribe();
this.viewItem = null;
}
this.projectorSubscription = this.currentListOfSpeakersService
.getAgendaItemIdObservable(projector)
.subscribe(agendaId => {
if (agendaId) {
this.setSpeakerList(agendaId);
}
});
}
/** /**
* Extract the ID from the url * Extract the ID from the url
* Determine whether the speaker list belongs to a motion or a topic * Determine whether the speaker list belongs to a motion or a topic
*/ */
public getAgendaItemByUrl(): void { private getItemByUrl(): void {
const id = +this.route.snapshot.url[0]; const id = +this.route.snapshot.url[0];
this.setSpeakerList(id);
}
/**
* Sets the current item as list of speakers
*
* @param item the item to use as List of Speakers
*/
private setSpeakerList(id: number): void {
this.itemRepo.getViewModelObservable(id).subscribe(newAgendaItem => { this.itemRepo.getViewModelObservable(id).subscribe(newAgendaItem => {
if (newAgendaItem) { if (newAgendaItem) {
this.viewItem = newAgendaItem; this.viewItem = newAgendaItem;
const allSpeakers = this.itemRepo.createViewSpeakers(newAgendaItem.item); const allSpeakers = this.itemRepo.createViewSpeakers(newAgendaItem.item);
this.speakers = allSpeakers.filter(speaker => speaker.state === SpeakerState.WAITING); this.speakers = allSpeakers.filter(speaker => speaker.state === SpeakerState.WAITING);
this.finishedSpeakers = allSpeakers.filter(speaker => speaker.state === SpeakerState.FINISHED); this.finishedSpeakers = allSpeakers.filter(speaker => speaker.state === SpeakerState.FINISHED);
this.activeSpeaker = allSpeakers.find(speaker => speaker.state === SpeakerState.CURRENT); this.activeSpeaker = allSpeakers.find(speaker => speaker.state === SpeakerState.CURRENT);
@ -142,6 +219,7 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
/** /**
* Create a speaker out of an id * Create a speaker out of an id
*
* @param userId the user id to add to the list. No parameter adds the operators user as speaker. * @param userId the user id to add to the list. No parameter adds the operators user as speaker.
*/ */
public addNewSpeaker(userId?: number): void { public addNewSpeaker(userId?: number): void {