Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
15 changes: 9 additions & 6 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ export class AppComponent {
iconRegistry.addSvgIcon(
'usersettings',
sanitizer.bypassSecurityTrustResourceUrl('assets/icons/settings.svg'));
iconRegistry.addSvgIcon(
'male',
sanitizer.bypassSecurityTrustResourceUrl('assets/icons/male.svg'));
iconRegistry.addSvgIcon(
'female',
sanitizer.bypassSecurityTrustResourceUrl('assets/icons/female.svg'));
iconRegistry.addSvgIcon(
'male',
sanitizer.bypassSecurityTrustResourceUrl('assets/icons/male.svg'));
iconRegistry.addSvgIcon(
'female',
sanitizer.bypassSecurityTrustResourceUrl('assets/icons/female.svg'));
iconRegistry.addSvgIcon(
'other',
sanitizer.bypassSecurityTrustResourceUrl('assets/icons/other.svg'));
iconRegistry.addSvgIcon(
'home',
sanitizer.bypassSecurityTrustResourceUrl('assets/icons/home.svg'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ <h1 class="mat-title" i18n>Members</h1>
<span i18n>Female</span>
</mat-grid-tile>
<mat-grid-tile>{{reports?.usersByGender?.female || 0}}</mat-grid-tile>
<mat-grid-tile class="label">
<mat-icon>subdirectory_arrow_right</mat-icon>
<span i18n>Other</span>
</mat-grid-tile>
<mat-grid-tile>{{reports?.usersByGender?.other || 0}}</mat-grid-tile>
<mat-grid-tile class="label">
<mat-icon>subdirectory_arrow_right</mat-icon>
<span i18n>Did not specify</span>
Expand Down
11 changes: 6 additions & 5 deletions src/app/manager-dashboard/reports/reports-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,8 @@ export class ReportsDetailComponent implements OnInit, OnDestroy {
});
const labels = months.map(month => monthDataLabels(month));

const genderFilter = (gender: string) =>
months.map((month) => data.find((datum: any) => datum.gender === gender && datum.date === month) || { date: month, unique: [] });
const genderFilter = (gender: string | undefined) =>
months.map((month) => data.find((datum: any) => datum.gender === gender && datum.date === month) || { date: month, unique: [] });
const monthlyObj = (month) => {
const monthlyData = data.filter((datum: any) => datum.date === month);
return ({
Expand All @@ -454,9 +454,10 @@ export class ReportsDetailComponent implements OnInit, OnDestroy {
return ({
data: {
datasets: [
datasetObject($localize`Male`, xyChartData(genderFilter('male'), unique), styleVariables.primaryLighter),
datasetObject($localize`Female`, xyChartData(genderFilter('female'), unique), styleVariables.accentLighter),
datasetObject($localize`Did not specify`, xyChartData(genderFilter(undefined), unique), styleVariables.grey),
datasetObject($localize`Male`, xyChartData(genderFilter('male'), unique), styleVariables.primaryLighter),
datasetObject($localize`Female`, xyChartData(genderFilter('female'), unique), styleVariables.accentLighter),
datasetObject($localize`Other`, xyChartData(genderFilter('other'), unique), styleVariables.warnLighter),
datasetObject($localize`Did not specify`, xyChartData(genderFilter(undefined), unique), styleVariables.grey),
datasetObject($localize`Total`, xyChartData(totals(), unique), styleVariables.primary)
]
},
Expand Down
18 changes: 15 additions & 3 deletions src/app/manager-dashboard/reports/reports.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,16 @@ export class ReportsService {
return ({
count: users.length,
byGender: users.reduce((usersByGender: any, user: any) => {
usersByGender[(user.doc || user).gender || 'didNotSpecify'] += 1;
const userRecord = user.doc || user;
const rawGender = userRecord?.gender;
const normalizedGender = typeof rawGender === 'string' ? rawGender.toLowerCase() : '';
const hasGender = rawGender !== undefined && rawGender !== null && rawGender !== '';
const gender = normalizedGender === 'male' || normalizedGender === 'female' || normalizedGender === 'other'
? normalizedGender
: hasGender ? 'other' : 'didNotSpecify';
usersByGender[gender] += 1;
return usersByGender;
}, { 'male': 0, 'female': 0, 'didNotSpecify': 0 }),
}, { 'male': 0, 'female': 0, 'other': 0, 'didNotSpecify': 0 }),
byMonth: this.groupByMonth(users, 'joinDate')
});
}
Expand Down Expand Up @@ -199,9 +206,14 @@ export class ReportsService {
appendGender(array) {
return array.map((item: any) => {
const user = this.users.find((u: any) => u.name === item.user) || {};
const rawGender = user.gender;
const normalizedGender = typeof rawGender === 'string' ? rawGender.toLowerCase() : '';
const gender = normalizedGender === 'male' || normalizedGender === 'female' || normalizedGender === 'other'
? normalizedGender
: rawGender ? 'other' : undefined;
return ({
...item,
gender: user.gender
gender
});
});
}
Expand Down
70 changes: 37 additions & 33 deletions src/app/shared/csv.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,39 +103,43 @@ export class CsvService {
private processSection(
formattedData: any[], title: string, groupedData: any[], countUnique: boolean, sortedMonths: string[], monthLabels: string[]
): void {
const pushRow = (section, month, all, male, female, unspecified) => {
formattedData.push({
[$localize`Section`]: section,
[$localize`Month`]: month,
[$localize`All`]: all,
[$localize`Male`]: male,
[$localize`Female`]: female,
[$localize`Unspecified`]: unspecified
});
};

pushRow(title, '', '', '', '', '');
let totalAll = 0;
let totalMale = 0;
let totalFemale = 0;
let totalUnspecified = 0;

sortedMonths.forEach((month, i) => {
const monthLabel = monthLabels[i];
const all = this.getMonthlyData(month, groupedData, countUnique);
const male = this.getMonthlyData(month, groupedData.filter(item => item.gender === 'male'), countUnique);
const female = this.getMonthlyData(month, groupedData.filter(item => item.gender === 'female'), countUnique);
const unspecified = this.getMonthlyData(month, groupedData.filter(item => item.gender === undefined), countUnique);

totalAll += all;
totalMale += male;
totalFemale += female;
totalUnspecified += unspecified;
pushRow('', monthLabel, all, male, female, unspecified);
});

pushRow('', $localize`Total`, totalAll, totalMale, totalFemale, totalUnspecified);
}
const pushRow = (section, month, all, male, female, other, unspecified) => {
formattedData.push({
[$localize`Section`]: section,
[$localize`Month`]: month,
[$localize`All`]: all,
[$localize`Male`]: male,
[$localize`Female`]: female,
[$localize`Other`]: other,
[$localize`Unspecified`]: unspecified
});
};

pushRow(title, '', '', '', '', '', '');
let totalAll = 0;
let totalMale = 0;
let totalFemale = 0;
let totalOther = 0;
let totalUnspecified = 0;

sortedMonths.forEach((month, i) => {
const monthLabel = monthLabels[i];
const all = this.getMonthlyData(month, groupedData, countUnique);
const male = this.getMonthlyData(month, groupedData.filter(item => item.gender === 'male'), countUnique);
const female = this.getMonthlyData(month, groupedData.filter(item => item.gender === 'female'), countUnique);
const other = this.getMonthlyData(month, groupedData.filter(item => item.gender === 'other'), countUnique);
const unspecified = this.getMonthlyData(month, groupedData.filter(item => item.gender === undefined), countUnique);

totalAll += all;
totalMale += male;
totalFemale += female;
totalOther += other;
totalUnspecified += unspecified;
pushRow('', monthLabel, all, male, female, other, unspecified);
});

pushRow('', $localize`Total`, totalAll, totalMale, totalFemale, totalOther, totalUnspecified);
}

formatValue(key: string, value: any) {
const dateString = (date: number | undefined) => date ? new Date(date).toString() : '';
Expand Down
1 change: 1 addition & 0 deletions src/app/shared/forms/planet-rating.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<div class="list-item-rating">
<div class="stats-ratio" [ngClass]="{'invisible':rating.totalRating===0}">
<mat-icon svgIcon="male" class="male-icon primary-text-color"></mat-icon>
<mat-icon svgIcon="other" class="other-icon warn-text-color"></mat-icon>
<mat-icon svgIcon="female" class="female-icon accent-text-color"></mat-icon>
<planet-stacked-bar [data]="stackedBarData"></planet-stacked-bar>
</div>
Expand Down
19 changes: 13 additions & 6 deletions src/app/shared/forms/planet-rating.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,21 @@ export class PlanetRatingComponent implements OnChanges {

ngOnChanges() {
// After any changes to ratings ensures all properties are set
this.rating = Object.assign({ rateSum: 0, totalRating: 0, maleRating: 0, femaleRating: 0, userRating: {} }, this.rating);
this.rating = Object.assign({
rateSum: 0,
totalRating: 0,
maleRating: 0,
femaleRating: 0,
otherRating: 0,
userRating: {}
}, this.rating);
const unspecifiedAmount = this.rating.totalRating === 0
? 1
: Math.max(this.rating.totalRating - this.rating.maleRating - this.rating.femaleRating - this.rating.otherRating, 0);
this.stackedBarData = [
{ class: 'primary-color', amount: this.rating.maleRating },
{ class: 'primary-light-color',
amount: this.rating.totalRating === 0 ? 1
: this.rating.totalRating - this.rating.maleRating - this.rating.femaleRating,
noLabel: true
},
{ class: 'warn-color', amount: this.rating.otherRating },
{ class: 'primary-light-color', amount: unspecifiedAmount, noLabel: true },
{ class: 'accent-color', amount: this.rating.femaleRating, align: 'right' }
];
this.rateForm.setValue(this.rateFormField);
Expand Down
36 changes: 27 additions & 9 deletions src/app/shared/forms/rating.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ import { of, Subject } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { StateService } from '../state.service';

const startingRating = { rateSum: 0, totalRating: 0, maleRating: 0, femaleRating: 0, userRating: {}, allRatings: [] };
const startingRating = {
rateSum: 0,
totalRating: 0,
maleRating: 0,
femaleRating: 0,
otherRating: 0,
userRating: {},
allRatings: []
};

@Injectable({
providedIn: 'root'
Expand Down Expand Up @@ -67,14 +75,24 @@ export class RatingService {
// If totalRating is undefined, will start count at 1
ratingInfo.totalRating = ratingInfo.totalRating + 1;
ratingInfo.rateSum = ratingInfo.rateSum + rating.rate;
switch (rating.user.gender) {
case 'male':
ratingInfo.maleRating = ratingInfo.maleRating + 1;
break;
case 'female':
ratingInfo.femaleRating = ratingInfo.femaleRating + 1;
break;
}
const gender = typeof rating.user.gender === 'string'
? rating.user.gender.toLowerCase()
: rating.user.gender;
switch (gender) {
case 'male':
ratingInfo.maleRating = ratingInfo.maleRating + 1;
break;
case 'female':
ratingInfo.femaleRating = ratingInfo.femaleRating + 1;
break;
case 'other':
ratingInfo.otherRating = ratingInfo.otherRating + 1;
break;
default:
if (gender) {
ratingInfo.otherRating = ratingInfo.otherRating + 1;
}
}
ratingInfo.userRating = rating.user.name === this.userService.get().name ? rating : ratingInfo.userRating;
ratingInfo.allRatings = [ ...ratingInfo.allRatings, rating ];
if (ratings.length > index + 1 && ratings[index + 1].item === id) {
Expand Down
2 changes: 2 additions & 0 deletions src/app/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export const styleVariables: any = {
accent: '#ffc107',
accentLighter: '#ffecb3',
accentText: 'rgba(0, 0, 0, 0.87)',
warn: '#ed9121',
warnLighter: '#ffe1c6',
grey: '#bdbdbd',
greyText: 'rgba(0, 0, 0, 0.54)',
lightGrey: 'whitesmoke'
Expand Down
6 changes: 4 additions & 2 deletions src/app/submissions/submissions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ export class SubmissionsService {
const data = updatedSubmissions.map(submission => {
const answerIndexes = this.answerIndexes(questionTexts, submission);
return {
[$localize`Gender`]: submission.user.gender || 'N/A',
[$localize`Gender`]: submission.user.gender ? toProperCase(submission.user.gender.toString().toLowerCase()) : 'N/A',
[$localize`Age (years)`]: submission.user.birthDate ?
ageFromBirthDate(time, submission.user.birthDate) :
submission.user.age || 'N/A',
Expand Down Expand Up @@ -522,7 +522,9 @@ export class SubmissionsService {
const userAge = submission.user.birthDate ?
ageFromBirthDate(submission.lastUpdateTime, submission.user.birthDate) :
submission.user.age;
const userGender = submission.user.gender;
const userGender = submission.user.gender
? toProperCase(submission.user.gender.toString().toLowerCase())
: '';
const communityOrNation = submission.planetName;
const teamType = submission.teamInfo?.type ? toProperCase(submission.teamInfo.type) : '';
const teamName = submission.teamInfo?.name || '';
Expand Down
7 changes: 6 additions & 1 deletion src/app/users/users-profile/users-profile.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
<div class="space-container">
<mat-toolbar class="primary-color font-size-1">
<span>{{userDetail.name}}</span>
<mat-icon class="margin-lr-5" *ngIf="userDetail.gender" svgIcon="{{userDetail.gender.toLowerCase()}}"></mat-icon>
<ng-container *ngIf="genderIcon(userDetail.gender) as genderIconName">
<mat-icon
class="margin-lr-5"
[svgIcon]="genderIconName"
[ngClass]="['gender-icon', genderColorClass(genderIconName)]"></mat-icon>
</ng-container>
<span class="toolbar-fill"></span>
<button mat-icon-button [matMenuTriggerFor]="menu" *ngIf="isMobile; else actionButtons">
<mat-icon>more_vert</mat-icon>
Expand Down
24 changes: 24 additions & 0 deletions src/app/users/users-profile/users-profile.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,28 @@ export class UsersProfileComponent implements OnInit, OnDestroy {
this.enterprises = teams.filter((team: any) => team.doc.type === 'enterprise');
});
}

genderIcon(gender: any): 'male' | 'female' | 'other' | null {
if (!gender) {
return null;
}
const normalizedGender = gender.toString().toLowerCase();
if (normalizedGender === 'male' || normalizedGender === 'female') {
return normalizedGender;
}
return 'other';
}

genderColorClass(icon: string | null): string {
switch (icon) {
case 'male':
return 'gender-icon-male';
case 'female':
return 'gender-icon-female';
case 'other':
return 'gender-icon-other';
default:
return 'gender-icon-other';
}
}
}
17 changes: 17 additions & 0 deletions src/app/users/users-profile/users-profile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@
}
}

.gender-icon {
width: 24px;
height: 24px;
}

.gender-icon-male {
color: $primary;
}

.gender-icon-female {
color: $accent;
}

.gender-icon-other {
color: $warn;
}

@media (max-width: $screen-sm) {
.profile-image-section {
grid-area: icon;
Expand Down
7 changes: 6 additions & 1 deletion src/app/users/users-update/users-update.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
</mat-form-field>
</div>
</ng-container>
<mat-radio-group class="radio-group" formControlName="gender" [required]="!submissionMode" class="full-width">
<mat-radio-group class="radio-group full-width" formControlName="gender" [required]="!submissionMode">
<label i18n>Gender</label>
<mat-radio-button class="planet-radio-button" value="male">
<div class="radio-icon-label">
Expand All @@ -95,6 +95,11 @@
i18n>Female</span>
</div>
</mat-radio-button>
<mat-radio-button class="planet-radio-button" value="other">
<div class="radio-icon-label">
<mat-icon svgIcon="other" class="margin-lr-3 warn-text-color"></mat-icon><span i18n>Other</span>
</div>
</mat-radio-button>
<mat-error i18n *ngIf="editForm.controls.gender.invalid && editForm.controls.gender.touched">
This field is required
</mat-error>
Expand Down
3 changes: 3 additions & 0 deletions src/assets/icons/other.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading