Merge pull request #5330 from tsiegleauq/mark-first-time-speaker

Show first contribution hint in list of speaker
This commit is contained in:
Emanuel Schütze 2020-04-30 15:03:55 +02:00 committed by GitHub
commit 3842f66877
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 3 deletions

View File

@ -224,6 +224,10 @@ export class ListOfSpeakersRepositoryService extends BaseHasContentObjectReposit
await this.httpService.post('/rest/agenda/list-of-speakers/delete_all_speakers/'); await this.httpService.post('/rest/agenda/list-of-speakers/delete_all_speakers/');
} }
public isFirstContribution(speaker: ViewSpeaker): boolean {
return !this.getViewModelList().some(list => list.hasSpeakerSpoken(speaker));
}
/** /**
* Helper function get the url to the speaker rest address * Helper function get the url to the speaker rest address
* *

View File

@ -95,9 +95,18 @@
<!-- implicit speaker references into the component using ng-template slot --> <!-- implicit speaker references into the component using ng-template slot -->
<ng-template let-speaker> <ng-template let-speaker>
<span *osPerms="'agenda.can_manage_list_of_speakers'"> <span *osPerms="'agenda.can_manage_list_of_speakers'">
<!-- Speaker count -->
<span *ngIf="hasSpokenCount(speaker)" class="red-warning-text speaker-warning"> <span *ngIf="hasSpokenCount(speaker)" class="red-warning-text speaker-warning">
{{ hasSpokenCount(speaker) + 1 }}. <span>{{ 'contribution' | translate }}</span> {{ hasSpokenCount(speaker) + 1 }}. <span>{{ 'contribution' | translate }}</span>
</span> </span>
<!-- First contribution -->
<span *ngIf="showFistContributionHint && isFirstContribution(speaker)" class="speaker-warning">
{{ 'First contribution' | translate }}
</span>
<!-- Speaker gender -->
<span *ngIf="speaker.gender">({{ speaker.gender | translate }})</span> <span *ngIf="speaker.gender">({{ speaker.gender | translate }})</span>
</span> </span>

View File

@ -1,4 +1,4 @@
import { Component, OnInit, ViewChild } from '@angular/core'; import { ChangeDetectionStrategy, Component, OnInit, ViewChild } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms'; import { FormControl, FormGroup } from '@angular/forms';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
@ -31,7 +31,8 @@ import { SpeakerState, ViewSpeaker } from '../../models/view-speaker';
@Component({ @Component({
selector: 'os-list-of-speakers', selector: 'os-list-of-speakers',
templateUrl: './list-of-speakers.component.html', templateUrl: './list-of-speakers.component.html',
styleUrls: ['./list-of-speakers.component.scss'] styleUrls: ['./list-of-speakers.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit { export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit {
@ViewChild(SortingListComponent) @ViewChild(SortingListComponent)
@ -122,6 +123,8 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
private closSubscription: Subscription | null; private closSubscription: Subscription | null;
public showFistContributionHint: boolean;
/** /**
* Constructor for speaker list component. Generates the forms. * Constructor for speaker list component. Generates the forms.
* *
@ -205,6 +208,9 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
this.subscriptions.push( this.subscriptions.push(
this.config.get('agenda_present_speakers_only').subscribe(() => { this.config.get('agenda_present_speakers_only').subscribe(() => {
this.filterUsers(); this.filterUsers();
}),
this.config.get<boolean>('agenda_show_first_contribution').subscribe(show => {
this.showFistContributionHint = show;
}) })
); );
} }
@ -416,6 +422,15 @@ export class ListOfSpeakersComponent extends BaseViewComponent implements OnInit
}).length; }).length;
} }
/**
* Returns true if the speaker did never appear on any list of speakers
*
* @param speaker
*/
public isFirstContribution(speaker: ViewSpeaker): boolean {
return this.listOfSpeakersRepo.isFirstContribution(speaker);
}
/** /**
* Closes the current list of speakers * Closes the current list of speakers
*/ */

View File

@ -24,11 +24,19 @@ export class ViewListOfSpeakers extends BaseViewModelWithContentObject<ListOfSpe
return this._model; return this._model;
} }
public get finishedSpeakers(): ViewSpeaker[] {
return this.speakers.filter(speaker => speaker.state === SpeakerState.FINISHED);
}
/** /**
* Gets the amount of waiting speakers * Gets the amount of waiting speakers
*/ */
public get waitingSpeakerAmount(): number { public get waitingSpeakerAmount(): number {
return this.speakers.filter(speaker => speaker.state === SpeakerState.WAITING).length; return this.waitingSpeakers.length;
}
public get waitingSpeakers(): ViewSpeaker[] {
return this.speakers.filter(speaker => speaker.state === SpeakerState.WAITING);
} }
public get listOfSpeakersUrl(): string { public get listOfSpeakersUrl(): string {
@ -51,6 +59,10 @@ export class ViewListOfSpeakers extends BaseViewModelWithContentObject<ListOfSpe
getDialogTitle: () => this.getTitle() getDialogTitle: () => this.getTitle()
}; };
} }
public hasSpeakerSpoken(checkSpeaker: ViewSpeaker): boolean {
return this.finishedSpeakers.findIndex(speaker => speaker.user_id === checkSpeaker.user_id) !== -1;
}
} }
interface IListOfSpeakersRelations { interface IListOfSpeakersRelations {
speakers: ViewSpeaker[]; speakers: ViewSpeaker[];

View File

@ -188,3 +188,13 @@ def get_config_variables():
group="Agenda", group="Agenda",
subgroup="List of speakers", subgroup="List of speakers",
) )
yield ConfigVariable(
name="agenda_show_first_contribution",
default_value=False,
input_type="boolean",
label="Show a note when a speaker appears for the first time",
weight=234,
group="Agenda",
subgroup="List of speakers",
)