Add gender field to users
Alters the user detail view and the list of speakers to support the gender field. Default selection of genders was set to "Female", "Male" and "Diverse". Adding genders to users is completely optional
This commit is contained in:
parent
c67aef68d9
commit
07ca50441a
@ -2,6 +2,11 @@ import { Searchable } from '../base/searchable';
|
||||
import { SearchRepresentation } from '../../../core/services/search.service';
|
||||
import { BaseModel } from '../base/base-model';
|
||||
|
||||
/**
|
||||
* Iterable pre selection of genders (sexes)
|
||||
*/
|
||||
export const genders = ['Female', 'Male', 'Diverse'];
|
||||
|
||||
/**
|
||||
* Representation of a user in contrast to the operator.
|
||||
* @ignore
|
||||
@ -14,6 +19,7 @@ export class User extends BaseModel<User> implements Searchable {
|
||||
public title: string;
|
||||
public first_name: string;
|
||||
public last_name: string;
|
||||
public gender: string;
|
||||
public structure_level: string;
|
||||
public number: string;
|
||||
public about_me: string;
|
||||
|
@ -4,9 +4,7 @@
|
||||
<h2><span translate>List of speakers</span></h2>
|
||||
</div>
|
||||
<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>
|
||||
</os-head-bar>
|
||||
|
||||
@ -68,6 +66,7 @@
|
||||
<span *ngIf="hasSpokenCount(item)" class="red-warning-text speaker-warning">
|
||||
{{ hasSpokenCount(item) + 1 }}. <span translate>contribution</span>
|
||||
</span>
|
||||
<span *ngIf="item.gender">({{ item.gender | translate }})</span>
|
||||
</span>
|
||||
<mat-button-toggle-group *osPerms="'agenda.can_manage_list_of_speakers'">
|
||||
<mat-button-toggle matTooltip="{{ 'Begin speech' | translate }}" (click)="onStartButton(item)">
|
||||
@ -117,7 +116,6 @@
|
||||
</mat-card>
|
||||
|
||||
<mat-menu #speakerMenu="matMenu">
|
||||
|
||||
<button mat-menu-item *ngIf="closedList" (click)="openSpeakerList()">
|
||||
<mat-icon>mic</mat-icon>
|
||||
<span translate>Open list of speakers</span>
|
||||
|
@ -46,6 +46,10 @@ export class ViewSpeaker extends BaseViewModel implements Selectable {
|
||||
return this.user.full_name || this.user.username;
|
||||
}
|
||||
|
||||
public get gender(): string {
|
||||
return this.user.gender || '';
|
||||
}
|
||||
|
||||
public constructor(speaker?: Speaker, user?: User) {
|
||||
super();
|
||||
this._speaker = speaker;
|
||||
|
@ -9,8 +9,7 @@
|
||||
<!-- Title -->
|
||||
<div class="title-slot">
|
||||
<h2>
|
||||
<span *ngIf="newUser" translate>New participant</span>
|
||||
<span *ngIf="!newUser">{{ user.full_name }}</span>
|
||||
<span *ngIf="newUser" translate>New participant</span> <span *ngIf="!newUser">{{ user.full_name }}</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@ -39,61 +38,74 @@
|
||||
[formGroup]="personalInfoForm"
|
||||
(ngSubmit)="saveUser()"
|
||||
*ngIf="user"
|
||||
(keydown)="onKeyDown($event)">
|
||||
(keydown)="onKeyDown($event)"
|
||||
>
|
||||
<!-- <h3 translate>Personal Data</h3> -->
|
||||
<div *ngIf="isAllowed('seeName')">
|
||||
<!-- Title -->
|
||||
<mat-form-field
|
||||
class="form16 distance force-min-with"
|
||||
*ngIf="user.title || (editUser && isAllowed('manage'))">
|
||||
*ngIf="user.title || (editUser && isAllowed('manage'))"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
osAutofocus
|
||||
placeholder="{{ 'Title' | translate }}"
|
||||
formControlName="title"
|
||||
[value]="user.title"/>
|
||||
[value]="user.title"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- First name -->
|
||||
<mat-form-field
|
||||
class="form37 distance force-min-with"
|
||||
*ngIf="user.first_name || (editUser && isAllowed('manage'))">
|
||||
*ngIf="user.first_name || (editUser && isAllowed('manage'))"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
placeholder="{{ 'Given name' | translate }}"
|
||||
formControlName="first_name"
|
||||
[value]="user.first_name"/>
|
||||
[value]="user.first_name"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Last name -->
|
||||
<mat-form-field
|
||||
class="form37 force-min-with"
|
||||
*ngIf="user.last_name || (editUser && isAllowed('manage'))">
|
||||
<mat-form-field class="form37 force-min-with" *ngIf="user.last_name || (editUser && isAllowed('manage'))">
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
placeholder="{{ 'Surname' | translate }}"
|
||||
formControlName="last_name"
|
||||
[value]="user.last_name"/>
|
||||
[value]="user.last_name"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isAllowed('seePersonal')">
|
||||
<!-- E-Mail -->
|
||||
<mat-form-field *ngIf="user.email || editUser">
|
||||
<mat-form-field class="form70 distance" *ngIf="user.email || editUser">
|
||||
<input
|
||||
type="email"
|
||||
matInput
|
||||
placeholder="{{ 'Email' | translate }}"
|
||||
name="email"
|
||||
formControlName="email"
|
||||
[value]="user.email"/>
|
||||
[value]="user.email"
|
||||
/>
|
||||
<mat-error *ngIf="personalInfoForm.get('email').hasError('email')" translate>
|
||||
Please enter a valid email address
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Gender -->
|
||||
<mat-form-field class="form25 force-min-with" *ngIf="user.gender || editUser">
|
||||
<mat-select placeholder="{{ 'Gender' | translate }}" formControlName="gender">
|
||||
<mat-option>-</mat-option>
|
||||
<mat-option *ngFor="let gender of genderList" [value]="gender">{{ gender | translate }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@ -104,19 +116,22 @@
|
||||
matInput
|
||||
placeholder="{{ 'Structure level' | translate }}"
|
||||
formControlName="structure_level"
|
||||
[value]="user.structure_level"/>
|
||||
[value]="user.structure_level"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Participant Number -->
|
||||
<mat-form-field
|
||||
class="form25 force-min-with"
|
||||
*ngIf="user.participant_number || (editUser && isAllowed('manage'))">
|
||||
*ngIf="user.participant_number || (editUser && isAllowed('manage'))"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
placeholder="{{ 'Participant number' | translate }}"
|
||||
formControlName="number"
|
||||
[value]="user.participant_number"/>
|
||||
[value]="user.participant_number"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
@ -136,7 +151,8 @@
|
||||
matInput
|
||||
placeholder="{{ 'Initial password' | translate }}"
|
||||
formControlName="default_password"
|
||||
[value]="user.default_password"/>
|
||||
[value]="user.default_password"
|
||||
/>
|
||||
<mat-hint align="end">Generate</mat-hint>
|
||||
<button
|
||||
type="button"
|
||||
@ -144,7 +160,8 @@
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
[disabled]="!newUser"
|
||||
(click)="generatePassword()">
|
||||
(click)="generatePassword()"
|
||||
>
|
||||
<mat-icon>sync_problem</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
@ -166,7 +183,8 @@
|
||||
matInput
|
||||
placeholder="{{ 'Username' | translate }}"
|
||||
formControlName="username"
|
||||
[value]="user.username"/>
|
||||
[value]="user.username"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
@ -177,7 +195,8 @@
|
||||
matInput
|
||||
placeholder="{{ 'Comment' | translate }}"
|
||||
formControlName="comment"
|
||||
[value]="user.comment"/>
|
||||
[value]="user.comment"
|
||||
/>
|
||||
<mat-hint translate>Only for internal notes.</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
@ -187,7 +206,8 @@
|
||||
<mat-checkbox
|
||||
formControlName="is_present"
|
||||
matTooltip="{{ 'Designates whether this user is in the room.' | translate }}"
|
||||
[value]="user.is_present">
|
||||
[value]="user.is_present"
|
||||
>
|
||||
<span translate>Is present</span>
|
||||
</mat-checkbox>
|
||||
|
||||
@ -199,7 +219,8 @@
|
||||
matTooltip="{{
|
||||
'Designates whether this user should be treated as active. Unselect this instead of deleting the account.'
|
||||
| translate
|
||||
}}">
|
||||
}}"
|
||||
>
|
||||
<span translate>Is active</span>
|
||||
</mat-checkbox>
|
||||
|
||||
@ -207,7 +228,8 @@
|
||||
<mat-checkbox
|
||||
formControlName="is_committee"
|
||||
[value]="user.is_committee"
|
||||
matTooltip="{{ 'Designates whether this user should be treated as a committee.' | translate }}">
|
||||
matTooltip="{{ 'Designates whether this user should be treated as a committee.' | translate }}"
|
||||
>
|
||||
<span translate>Is a committee</span>
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
@ -1,16 +1,18 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { genders } from 'app/shared/models/users/user';
|
||||
import { ViewUser } from '../../models/view-user';
|
||||
import { UserRepositoryService } from '../../services/user-repository.service';
|
||||
import { Group } from '../../../../shared/models/users/group';
|
||||
import { DataStoreService } from '../../../../core/services/data-store.service';
|
||||
import { OperatorService } from '../../../../core/services/operator.service';
|
||||
import { BaseViewComponent } from '../../../base/base-view';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { MatSnackBar } from '@angular/material';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { PromptService } from '../../../../core/services/prompt.service';
|
||||
|
||||
/**
|
||||
@ -62,6 +64,11 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
||||
*/
|
||||
public groups: Group[];
|
||||
|
||||
/**
|
||||
* Hold the list of genders (sexes) publicly to dynamically iterate in the view
|
||||
*/
|
||||
public genderList = genders;
|
||||
|
||||
/**
|
||||
* Constructor for user
|
||||
*
|
||||
@ -114,6 +121,7 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* Checks, if the given user id matches with the operator ones.
|
||||
*
|
||||
* @param userId The id to check, if it's the operator
|
||||
* @returns If the user is the operator
|
||||
*/
|
||||
@ -178,6 +186,7 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
||||
title: [''],
|
||||
first_name: [''],
|
||||
last_name: [''],
|
||||
gender: [''],
|
||||
structure_level: [''],
|
||||
number: [''],
|
||||
about_me: [''],
|
||||
@ -226,6 +235,7 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
||||
this.personalInfoForm.get('first_name'),
|
||||
this.personalInfoForm.get('last_name'),
|
||||
this.personalInfoForm.get('email'),
|
||||
this.personalInfoForm.get('gender'),
|
||||
this.personalInfoForm.get('structure_level'),
|
||||
this.personalInfoForm.get('number'),
|
||||
this.personalInfoForm.get('groups_id'),
|
||||
@ -241,6 +251,7 @@ export class UserDetailComponent extends BaseViewComponent implements OnInit {
|
||||
allowedFormFields.push(
|
||||
this.personalInfoForm.get('username'),
|
||||
this.personalInfoForm.get('email'),
|
||||
this.personalInfoForm.get('gender'),
|
||||
this.personalInfoForm.get('about_me')
|
||||
);
|
||||
}
|
||||
|
@ -47,6 +47,10 @@ export class ViewUser extends BaseProjectableModel {
|
||||
return this.user ? this.user.email : null;
|
||||
}
|
||||
|
||||
public get gender(): string {
|
||||
return this.user ? this.user.gender : null;
|
||||
}
|
||||
|
||||
public get structure_level(): string {
|
||||
return this.user ? this.user.structure_level : null;
|
||||
}
|
||||
|
@ -64,6 +64,12 @@ export class UserRepositoryService extends BaseRepository<ViewUser, User> {
|
||||
updateUser.username = viewUser.username;
|
||||
}
|
||||
|
||||
// if the update user does not have a gender-field, send gender as empty string.
|
||||
// This allow to delete a previously selected gender
|
||||
if (!updateUser.gender) {
|
||||
updateUser.gender = '';
|
||||
}
|
||||
|
||||
return await this.dataSend.updateModel(updateUser);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user