From f1d6c63b541b870e50cc2200ec07ae35f562bdbc Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Sun, 9 Jun 2024 14:53:40 +0500 Subject: [PATCH 1/4] Currency seleciton --- .../edit-salary/edit-salary.component.ts | 6 +- .../currency-select-box.component.html | 5 +- .../currency-select-box.component.ts | 24 ++++++-- .../salaries-by-grade-block.component.ts | 6 +- .../salaries-chart.component.html | 2 +- .../salaries-chart/salaries-chart.ts | 59 ++++++++++++------- .../salary-block-remote-value.component.ts | 14 ++++- .../salary-block-value.component.ts | 18 ++++-- 8 files changed, 90 insertions(+), 44 deletions(-) diff --git a/src/app/modules/salaries/components/edit-salary/edit-salary.component.ts b/src/app/modules/salaries/components/edit-salary/edit-salary.component.ts index 5d1dfb31..cc71495f 100644 --- a/src/app/modules/salaries/components/edit-salary/edit-salary.component.ts +++ b/src/app/modules/salaries/components/edit-salary/edit-salary.component.ts @@ -18,9 +18,9 @@ import { KazakhstanCity, KazakhstanCityEnum, } from "@models/salaries/kazakhstan-city"; -import { SalariesChart } from "../salaries-chart/salaries-chart"; import { LabelEntityDto } from "@services/label-entity.model"; import { Gender, GenderEnum } from "@models/enums/gender.enum"; +import { formatNumber } from "@angular/common"; @Component({ selector: "app-edit-salary-modal", @@ -102,7 +102,7 @@ export class EditSalaryComponent implements OnInit, OnDestroy { } this.salaryValue = this.showSalaryValue - ? SalariesChart.formatNumber(this.salarytoBeEdited.value) + ? formatNumber(this.salarytoBeEdited.value, "en-US", "1.0-2") : "* * * * *"; this.form = new EditSalaryForm( this.salarytoBeEdited, @@ -139,7 +139,7 @@ export class EditSalaryComponent implements OnInit, OnDestroy { showOrHideSalary(): void { this.showSalaryValue = !this.showSalaryValue; this.salaryValue = this.showSalaryValue - ? SalariesChart.formatNumber(this.salarytoBeEdited!.value) + ? formatNumber(this.salarytoBeEdited!.value, "en-US", "1.0-2") : "* * * * *"; } diff --git a/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.html b/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.html index a6b63fde..250c26df 100644 --- a/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.html +++ b/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.html @@ -1,5 +1,5 @@ -
- +
+ diff --git a/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts b/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts index 572cb13b..975956b6 100644 --- a/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts @@ -1,6 +1,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { CurrencyData, CurrencyType } from "@services/admin-tools.service"; import { SelectItem } from "@shared/select-boxes/select-item"; +import { SalariesChart } from "../salaries-chart"; @Component({ selector: "app-currency-select-box", @@ -8,40 +9,51 @@ import { SelectItem } from "@shared/select-boxes/select-item"; styleUrl: "./currency-select-box.component.scss", }) export class CurrencySelectBoxComponent implements OnInit { + @Input() - currencies: Array | null = null; + chart: SalariesChart | null = null; @Output() readonly currencyDataSelected = new EventEmitter(); selectedCurrency: CurrencyType | null = null; currenciesAsItems: Array> = []; + currencies: Array | null = null; + currencyDate: Date | null = null; constructor() {} ngOnInit(): void { - if (!this.currencies || this.currencies.length === 0) { - this.currencies = [ + if (!this.chart) { + return; + } + + this.currencies = this.chart.currencies; + if (this.currencies.length === 0) { + this.currencies.push( { value: 1, currency: CurrencyType.KZT, currencyString: "тг", pubDate: new Date(), - }, - ]; + } + ); } this.currenciesAsItems = this.currencies .map((x) => { return { value: CurrencyType[x.currency], - label: CurrencyType[x.currency], + label: x.currency === CurrencyType.KZT + ? CurrencyType[x.currency] + : `${CurrencyType[x.currency]} (${x.value} тг.)`, item: x.currency, }; }); this.selectedCurrency = this.currenciesAsItems[0].item; + this.currencyDate = this.currencies[0].pubDate; } onSelectionChange(e: SelectItem): void { diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts index ceaa2442..5da962b0 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnInit } from "@angular/core"; import { DeveloperGrade } from "@models/enums"; import { SalariesByGrade } from "@services/user-salaries.service"; import { SalariesChart } from "../salaries-chart"; +import { formatNumber } from "@angular/common"; interface Item extends SalariesByGrade { gradeAsString: string; @@ -37,9 +38,8 @@ export class SalariesByGradeBlockComponent implements OnInit { hasData: x.hasData, averageSalary: x.averageSalary, medianSalary: x.medianSalary, - medianSalaryAsString: SalariesChart.formatNumber(x.medianSalary) ?? "", - averageSalaryAsString: - SalariesChart.formatNumber(x.averageSalary) ?? "", + medianSalaryAsString: x.medianSalary != null ? formatNumber(x.medianSalary, "en-US", "1.0-2") : "", + averageSalaryAsString: x.averageSalary != null ? formatNumber(x.averageSalary, "en-US", "1.0-2") : "", }; }); } diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html index c5ab9b5f..a12ae7a5 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html @@ -197,7 +197,7 @@ >
diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts b/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts index 03bbcb6b..eeeb1516 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts @@ -9,14 +9,15 @@ import { import { SalariesPerProfession } from "../salaries-per-profession"; import { UserSalary, UserSalaryAdminDto } from "@models/salaries/salary.model"; import { LabelEntityDto } from "@services/label-entity.model"; -import { CurrencyData } from "@services/admin-tools.service"; +import { CurrencyData, CurrencyType } from "@services/admin-tools.service"; -export class SalariesChart { - readonly averageSalary: string; - readonly medianSalary: string; +export class SalariesChart implements SalariesChartResponse { - readonly averageRemoteSalary: string | null; - readonly medianRemoteSalary: string | null; + readonly averageSalary: number; + readonly medianSalary: number; + + readonly averageRemoteSalary: number | null; + readonly medianRemoteSalary: number | null; readonly localSalariesByGrade: Array; readonly remoteSalariesByGrade: Array; @@ -31,7 +32,6 @@ export class SalariesChart { readonly salariesPerProfessionForRemote: Array | null; readonly currentUserSalary: UserSalaryAdminDto | null = null; - readonly currentUserSalaryValue: string | null = null; readonly peopleByGradesChartDataForLocal: PeopleByGradesChartData | null; readonly peopleByGradesChartDataForRemote: PeopleByGradesChartData | null; @@ -43,27 +43,32 @@ export class SalariesChart { readonly hasAuthentication: boolean; readonly hasRecentSurveyReply: boolean; - readonly currencies: CurrencyData[] + readonly currencies: CurrencyData[]; + currentCurrency: CurrencyData; + + readonly totalCountInStats: number; + readonly shouldAddOwnSalary: boolean; + readonly rangeStart: Date; + readonly rangeEnd: Date; constructor( readonly data: SalariesChartResponse, readonly allProfessions: Array ) { + this.currencies = data.currencies; + this.currentCurrency = this.getDefaultCurrency(); + this.hasRecentSurveyReply = data.hasRecentSurveyReply; - this.averageSalary = SalariesChart.formatNumber(data.averageSalary) ?? ""; - this.medianSalary = SalariesChart.formatNumber(data.medianSalary) ?? ""; + this.averageSalary = data.averageSalary; + this.medianSalary = data.averageSalary; this.localSalariesByGrade = data.localSalariesByGrade ?? []; this.remoteSalariesByGrade = data.remoteSalariesByGrade ?? []; - this.averageRemoteSalary = SalariesChart.formatNumber( - data.averageRemoteSalary - ); - this.medianRemoteSalary = SalariesChart.formatNumber( - data.medianRemoteSalary - ); + this.averageRemoteSalary = data.averageRemoteSalary; + this.medianRemoteSalary = data.medianRemoteSalary; this.countOfRecords = data.totalCountInStats; this.salaries = data.salaries; @@ -83,9 +88,6 @@ export class SalariesChart { this.hasAuthentication = data.hasAuthentication; this.currentUserSalary = data.currentUserSalary; - this.currentUserSalaryValue = data.currentUserSalary - ? SalariesChart.formatNumber(data.currentUserSalary.value) - : null; this.peopleByGradesChartDataForLocal = data.peopleByGradesChartDataForLocal; this.peopleByGradesChartDataForRemote = @@ -95,10 +97,23 @@ export class SalariesChart { this.developersByExperienceYearsChartData = data.developersByExperienceYearsChartData; - this.currencies = data.currencies; + this.totalCountInStats = data.totalCountInStats; + this.shouldAddOwnSalary = data.shouldAddOwnSalary; + this.rangeStart = data.rangeStart; + this.rangeEnd = data.rangeEnd; + } + + public setCurrentCurrency(currencyType: CurrencyType): void { + this.currentCurrency = this.currencies.find((x) => x.currency === currencyType) ?? this.getDefaultCurrency(); } - public static formatNumber(value: number | null): string | null { - return value != null ? formatNumber(value, "en-US", "1.0-2") : null; + private getDefaultCurrency(): CurrencyData { + return this.currencies.find((x) => x.currency === CurrencyType.KZT) + ?? { + value: 1, + currency: CurrencyType.KZT, + currencyString: "тг", + pubDate: new Date(), + }; } } diff --git a/src/app/modules/salaries/components/salaries-chart/salary-block-remote-value/salary-block-remote-value.component.ts b/src/app/modules/salaries/components/salaries-chart/salary-block-remote-value/salary-block-remote-value.component.ts index 90ab4d8e..d992ed33 100644 --- a/src/app/modules/salaries/components/salaries-chart/salary-block-remote-value/salary-block-remote-value.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/salary-block-remote-value/salary-block-remote-value.component.ts @@ -1,5 +1,6 @@ import { Component, Input } from "@angular/core"; import { SalariesChart } from "../salaries-chart"; +import { formatNumber } from "@angular/common"; @Component({ selector: "app-salary-block-remote-value", @@ -11,10 +12,19 @@ export class SalaryBlockRemoteValueComponent { source: SalariesChart | null = null; get median(): string { - return this.source?.medianRemoteSalary ?? ""; + return SalaryBlockRemoteValueComponent.formatNumber(this.source?.medianRemoteSalary); } get average(): string { - return this.source?.averageRemoteSalary ?? ""; + return SalaryBlockRemoteValueComponent.formatNumber(this.source?.averageRemoteSalary); + } + + private static formatNumber(value: number | null | undefined): string { + + if (value == null) { + return ""; + } + + return formatNumber(value, "en-US", "1.0-2"); } } diff --git a/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.ts b/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.ts index 8067a45a..6448c660 100644 --- a/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.ts @@ -1,5 +1,6 @@ import { Component, Input } from "@angular/core"; import { SalariesChart } from "../salaries-chart"; +import { formatNumber } from "@angular/common"; @Component({ selector: "app-salary-block-value", @@ -11,18 +12,27 @@ export class SalaryBlockValueComponent { source: SalariesChart | null = null; get median(): string { - return this.source?.medianSalary ?? ""; + return SalaryBlockValueComponent.formatNumber(this.source?.medianSalary); } get average(): string { - return this.source?.averageSalary ?? ""; + return SalaryBlockValueComponent.formatNumber(this.source?.averageSalary); } get medianRemote(): string { - return this.source?.medianRemoteSalary ?? ""; + return SalaryBlockValueComponent.formatNumber(this.source?.medianRemoteSalary); } get averageRemote(): string { - return this.source?.averageRemoteSalary ?? ""; + return SalaryBlockValueComponent.formatNumber(this.source?.averageRemoteSalary); + } + + private static formatNumber(value: number | null | undefined): string { + + if (value == null) { + return ""; + } + + return formatNumber(value, "en-US", "1.0-2"); } } From 9b10326280805b1ca886d26826ce1fb15072d393 Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Sun, 9 Jun 2024 15:17:48 +0500 Subject: [PATCH 2/4] current currency logic --- .../currency-select-box.component.ts | 1 + .../salaries-chart/salaries-chart.ts | 176 +++++++++++++----- 2 files changed, 126 insertions(+), 51 deletions(-) diff --git a/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts b/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts index 975956b6..68bb5785 100644 --- a/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts @@ -65,5 +65,6 @@ export class CurrencySelectBoxComponent implements OnInit { const selectedCurrencyData = this.currencies!.find(x => x.currency === e.item); console.log("Currency selected: ", selectedCurrencyData); + this.chart?.setCurrentCurrency(e.item); } } diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts b/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts index eeeb1516..eb37951d 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts @@ -13,25 +13,67 @@ import { CurrencyData, CurrencyType } from "@services/admin-tools.service"; export class SalariesChart implements SalariesChartResponse { - readonly averageSalary: number; - readonly medianSalary: number; + private _averageSalary = 0; + get averageSalary(): number { + return this._averageSalary; + } + + private _medianSalary = 0; + get medianSalary(): number { + return this._medianSalary; + } - readonly averageRemoteSalary: number | null; - readonly medianRemoteSalary: number | null; + private _averageRemoteSalary: number | null = null; + get averageRemoteSalary(): number | null { + return this._averageRemoteSalary; + } - readonly localSalariesByGrade: Array; - readonly remoteSalariesByGrade: Array; + private _medianRemoteSalary: number | null = null; + get medianRemoteSalary(): number | null { + return this._medianRemoteSalary; + } - readonly countOfRecords: number; - readonly salaries: Array; + private _localSalariesByGrade: Array = []; + get localSalariesByGrade(): Array { + return this._localSalariesByGrade; + } + + private _remoteSalariesByGrade: Array = []; + get remoteSalariesByGrade(): Array { + return this._remoteSalariesByGrade; + } - readonly salariesByMoneyBarChart: SalariesByMoneyBarChart | null; - readonly salariesByMoneyBarChartForRemote: SalariesByMoneyBarChart | null; + private _salaries: Array = []; + get salaries(): Array { + return this._salaries; + } - readonly salariesPerProfessionForLocal: Array | null; - readonly salariesPerProfessionForRemote: Array | null; + private _salariesByMoneyBarChart: SalariesByMoneyBarChart | null = null; + get salariesByMoneyBarChart(): SalariesByMoneyBarChart | null { + return this._salariesByMoneyBarChart; + } - readonly currentUserSalary: UserSalaryAdminDto | null = null; + private _salariesByMoneyBarChartForRemote: SalariesByMoneyBarChart | null = null; + get salariesByMoneyBarChartForRemote(): SalariesByMoneyBarChart | null { + return this._salariesByMoneyBarChartForRemote; + } + + private _salariesPerProfessionForLocal: Array | null = null; + get salariesPerProfessionForLocal(): Array | null { + return this._salariesPerProfessionForLocal; + } + + private _salariesPerProfessionForRemote: Array | null = null; + get salariesPerProfessionForRemote(): Array | null { + return this._salariesPerProfessionForRemote; + } + + private _currentUserSalary: UserSalaryAdminDto | null = null; + get currentUserSalary(): UserSalaryAdminDto | null { + return this._currentUserSalary; + } + + readonly countOfRecords: number; readonly peopleByGradesChartDataForLocal: PeopleByGradesChartData | null; readonly peopleByGradesChartDataForRemote: PeopleByGradesChartData | null; @@ -39,7 +81,10 @@ export class SalariesChart implements SalariesChartResponse { readonly developersByAgeChartData: DevelopersByCategoryChartData | null; readonly developersByExperienceYearsChartData: DevelopersByCategoryChartData | null; - readonly hasRemoteSalaries: boolean; + get hasRemoteSalaries(): boolean { + return this.salariesPerProfessionForRemote != null && this.salariesPerProfessionForRemote.length > 0 + } + readonly hasAuthentication: boolean; readonly hasRecentSurveyReply: boolean; @@ -56,55 +101,28 @@ export class SalariesChart implements SalariesChartResponse { readonly allProfessions: Array ) { + this.hasAuthentication = data.hasAuthentication; this.currencies = data.currencies; this.currentCurrency = this.getDefaultCurrency(); this.hasRecentSurveyReply = data.hasRecentSurveyReply; - - this.averageSalary = data.averageSalary; - this.medianSalary = data.averageSalary; - - this.localSalariesByGrade = data.localSalariesByGrade ?? []; - this.remoteSalariesByGrade = data.remoteSalariesByGrade ?? []; - - this.averageRemoteSalary = data.averageRemoteSalary; - this.medianRemoteSalary = data.medianRemoteSalary; - - this.countOfRecords = data.totalCountInStats; - this.salaries = data.salaries; - - this.salariesByMoneyBarChart = data.salariesByMoneyBarChart; - this.salariesByMoneyBarChartForRemote = - data.salariesByMoneyBarChartForRemote; - - const salariesPerProfession = SalariesPerProfession.from( - data.salaries, - allProfessions - ); - - this.salariesPerProfessionForLocal = salariesPerProfession.local; - this.salariesPerProfessionForRemote = salariesPerProfession.remote; - this.hasRemoteSalaries = this.salariesPerProfessionForRemote.length > 0; - this.hasAuthentication = data.hasAuthentication; - - this.currentUserSalary = data.currentUserSalary; - - this.peopleByGradesChartDataForLocal = data.peopleByGradesChartDataForLocal; - this.peopleByGradesChartDataForRemote = - data.peopleByGradesChartDataForRemote; - - this.developersByAgeChartData = data.developersByAgeChartData; - this.developersByExperienceYearsChartData = - data.developersByExperienceYearsChartData; - this.totalCountInStats = data.totalCountInStats; this.shouldAddOwnSalary = data.shouldAddOwnSalary; this.rangeStart = data.rangeStart; this.rangeEnd = data.rangeEnd; + this.countOfRecords = data.totalCountInStats; + + this.developersByAgeChartData = data.developersByAgeChartData; + this.developersByExperienceYearsChartData = data.developersByExperienceYearsChartData; + this.peopleByGradesChartDataForLocal = data.peopleByGradesChartDataForLocal; + this.peopleByGradesChartDataForRemote = data.peopleByGradesChartDataForRemote; + + this.recalculateData(data, allProfessions, this.currentCurrency); } public setCurrentCurrency(currencyType: CurrencyType): void { this.currentCurrency = this.currencies.find((x) => x.currency === currencyType) ?? this.getDefaultCurrency(); + this.recalculateData(this.data, this.allProfessions, this.currentCurrency); } private getDefaultCurrency(): CurrencyData { @@ -116,4 +134,60 @@ export class SalariesChart implements SalariesChartResponse { pubDate: new Date(), }; } + + private recalculateData( + data: SalariesChartResponse, + allProfessions: Array, + currentCurrency: CurrencyData + ): void { + + this._salaries = data.salaries.map((x) => { + x.value = x.value / currentCurrency.value; + return x; + }); + + this._currentUserSalary = data.currentUserSalary; + if (data.currentUserSalary != null) { + this._currentUserSalary!.value = data.currentUserSalary.value / currentCurrency.value; + } + + this._averageSalary = data.averageSalary / currentCurrency.value; + this._medianSalary = data.averageSalary / currentCurrency.value; + + if (data.localSalariesByGrade != null) { + this._localSalariesByGrade = data.localSalariesByGrade.map((x) => { + x.averageSalary = x.averageSalary != null ? x.averageSalary / currentCurrency.value : null; + x.medianSalary = x.medianSalary != null ? x.medianSalary / currentCurrency.value : null; + return x; + }); + } else { + this._localSalariesByGrade = []; + } + + if (data.remoteSalariesByGrade != null) { + this._remoteSalariesByGrade = data.remoteSalariesByGrade.map((x) => { + x.averageSalary = x.averageSalary != null ? x.averageSalary / currentCurrency.value : null; + x.medianSalary = x.medianSalary != null ? x.medianSalary / currentCurrency.value : null; + return x; + }); + } else { + this._remoteSalariesByGrade = []; + } + + this._averageRemoteSalary = data.averageRemoteSalary != null + ? data.averageRemoteSalary / currentCurrency.value + : null; + + this._medianRemoteSalary = data.medianRemoteSalary != null + ? data.medianRemoteSalary / currentCurrency.value + : null; + + this._salariesByMoneyBarChart = data.salariesByMoneyBarChart; + this._salariesByMoneyBarChartForRemote = data.salariesByMoneyBarChartForRemote; + + const salariesPerProfession = SalariesPerProfession.from(this.salaries, allProfessions); + + this._salariesPerProfessionForLocal = salariesPerProfession.local; + this._salariesPerProfessionForRemote = salariesPerProfession.remote; + } } From c01ee905e18e448943d35101f6e865f0b827688a Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Sun, 9 Jun 2024 15:35:47 +0500 Subject: [PATCH 3/4] Fixed changing the currency --- .../salaries-by-grade-block.component.html | 2 +- .../salaries-by-grade-block.component.ts | 35 ++++++++++++++++--- .../salaries-chart.component.html | 6 ++-- .../salaries-chart/salaries-chart.ts | 22 +++++++----- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.html b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.html index d459a89d..ecfb650c 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.html +++ b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts index 5da962b0..0e7473ab 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts @@ -1,8 +1,9 @@ -import { Component, Input, OnInit } from "@angular/core"; +import { Component, Input, OnDestroy, OnInit } from "@angular/core"; import { DeveloperGrade } from "@models/enums"; import { SalariesByGrade } from "@services/user-salaries.service"; import { SalariesChart } from "../salaries-chart"; import { formatNumber } from "@angular/common"; +import { untilDestroyed } from "@shared/subscriptions/until-destroyed"; interface Item extends SalariesByGrade { gradeAsString: string; @@ -15,21 +16,43 @@ interface Item extends SalariesByGrade { templateUrl: "./salaries-by-grade-block.component.html", styleUrl: "./salaries-by-grade-block.component.scss", }) -export class SalariesByGradeBlockComponent implements OnInit { +export class SalariesByGradeBlockComponent implements OnInit, OnDestroy { items: Array | null = null; @Input() - source: Array | null = null; + chart: SalariesChart | null = null; + + @Input() + showLocal: boolean = true; totalCount: number = 0; ngOnInit(): void { - if (this.source == null) { + + if (this.chart == null) { this.items = []; return; } - this.items = this.source.map((x) => { + this.recaulculate(); + this.chart.currentCurrencyChanged$ + .pipe(untilDestroyed(this)) + .subscribe(() => { + this.items = null; + this.totalCount = 0; + + this.recaulculate(); + }); + } + + private recaulculate(): void { + const source = this.showLocal ? this.chart!.localSalariesByGrade : this.chart!.remoteSalariesByGrade; + if (source == null) { + this.items = []; + return; + } + + this.items = source.map((x) => { this.totalCount += x.count; return { gradeAsString: DeveloperGrade[x.grade], @@ -43,4 +66,6 @@ export class SalariesByGradeBlockComponent implements OnInit { }; }); } + + ngOnDestroy(): void {} } diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html index a12ae7a5..a2d51052 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html @@ -223,13 +223,15 @@
Казахстан
Удаленка
diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts b/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts index eb37951d..2ed8b940 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts @@ -10,6 +10,7 @@ import { SalariesPerProfession } from "../salaries-per-profession"; import { UserSalary, UserSalaryAdminDto } from "@models/salaries/salary.model"; import { LabelEntityDto } from "@services/label-entity.model"; import { CurrencyData, CurrencyType } from "@services/admin-tools.service"; +import { Subject } from "rxjs"; export class SalariesChart implements SalariesChartResponse { @@ -82,7 +83,7 @@ export class SalariesChart implements SalariesChartResponse { readonly developersByExperienceYearsChartData: DevelopersByCategoryChartData | null; get hasRemoteSalaries(): boolean { - return this.salariesPerProfessionForRemote != null && this.salariesPerProfessionForRemote.length > 0 + return this._salariesPerProfessionForRemote != null && this._salariesPerProfessionForRemote.length > 0 } readonly hasAuthentication: boolean; @@ -96,6 +97,8 @@ export class SalariesChart implements SalariesChartResponse { readonly rangeStart: Date; readonly rangeEnd: Date; + public readonly currentCurrencyChanged$: Subject = new Subject(); + constructor( readonly data: SalariesChartResponse, readonly allProfessions: Array @@ -123,6 +126,7 @@ export class SalariesChart implements SalariesChartResponse { public setCurrentCurrency(currencyType: CurrencyType): void { this.currentCurrency = this.currencies.find((x) => x.currency === currencyType) ?? this.getDefaultCurrency(); this.recalculateData(this.data, this.allProfessions, this.currentCurrency); + this.currentCurrencyChanged$.next(this.currentCurrency); } private getDefaultCurrency(): CurrencyData { @@ -156,9 +160,10 @@ export class SalariesChart implements SalariesChartResponse { if (data.localSalariesByGrade != null) { this._localSalariesByGrade = data.localSalariesByGrade.map((x) => { - x.averageSalary = x.averageSalary != null ? x.averageSalary / currentCurrency.value : null; - x.medianSalary = x.medianSalary != null ? x.medianSalary / currentCurrency.value : null; - return x; + const result = { ...x }; + result.averageSalary = x.averageSalary != null ? x.averageSalary / currentCurrency.value : null; + result.medianSalary = x.medianSalary != null ? x.medianSalary / currentCurrency.value : null; + return result; }); } else { this._localSalariesByGrade = []; @@ -166,9 +171,10 @@ export class SalariesChart implements SalariesChartResponse { if (data.remoteSalariesByGrade != null) { this._remoteSalariesByGrade = data.remoteSalariesByGrade.map((x) => { - x.averageSalary = x.averageSalary != null ? x.averageSalary / currentCurrency.value : null; - x.medianSalary = x.medianSalary != null ? x.medianSalary / currentCurrency.value : null; - return x; + const result = { ...x }; + result.averageSalary = x.averageSalary != null ? x.averageSalary / currentCurrency.value : null; + result.medianSalary = x.medianSalary != null ? x.medianSalary / currentCurrency.value : null; + return result; }); } else { this._remoteSalariesByGrade = []; @@ -185,7 +191,7 @@ export class SalariesChart implements SalariesChartResponse { this._salariesByMoneyBarChart = data.salariesByMoneyBarChart; this._salariesByMoneyBarChartForRemote = data.salariesByMoneyBarChartForRemote; - const salariesPerProfession = SalariesPerProfession.from(this.salaries, allProfessions); + const salariesPerProfession = SalariesPerProfession.from(this._salaries, allProfessions); this._salariesPerProfessionForLocal = salariesPerProfession.local; this._salariesPerProfessionForRemote = salariesPerProfession.remote; From dc12bf56a6477bd458ad878408a86b3fbd29b788 Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Sun, 9 Jun 2024 15:55:44 +0500 Subject: [PATCH 4/4] Fixed currencies --- .../grades-min-max-chart.component.html | 2 +- .../grades-min-max-chart.component.ts | 7 +++- .../people-by-grades-chart.component.html | 4 +- .../people-by-grades-chart.component.ts | 3 -- .../currency-select-box.component.ts | 1 - .../salaries-by-grade-block.component.html | 4 +- .../salaries-by-grade-block.component.ts | 5 +++ .../salaries-chart.component.html | 4 -- .../salaries-chart/salaries-chart.ts | 12 ++++++ .../salary-block-value.component.html | 8 ++-- .../salary-block-value.component.ts | 41 +++++++++++++------ 11 files changed, 60 insertions(+), 31 deletions(-) diff --git a/src/app/modules/salaries/components/grades-min-max-salaries-chart/grades-min-max-chart.component.html b/src/app/modules/salaries/components/grades-min-max-salaries-chart/grades-min-max-chart.component.html index d92966c6..e3e08176 100644 --- a/src/app/modules/salaries/components/grades-min-max-salaries-chart/grades-min-max-chart.component.html +++ b/src/app/modules/salaries/components/grades-min-max-salaries-chart/grades-min-max-chart.component.html @@ -1,5 +1,5 @@
-
Зарплаты по грейдам
+
Зарплаты по грейдам в графике (тенге)
diff --git a/src/app/modules/salaries/components/grades-min-max-salaries-chart/grades-min-max-chart.component.ts b/src/app/modules/salaries/components/grades-min-max-salaries-chart/grades-min-max-chart.component.ts index 65868020..4e9e7acf 100644 --- a/src/app/modules/salaries/components/grades-min-max-salaries-chart/grades-min-max-chart.component.ts +++ b/src/app/modules/salaries/components/grades-min-max-salaries-chart/grades-min-max-chart.component.ts @@ -1,14 +1,15 @@ -import { Component, Input } from "@angular/core"; +import { Component, Input, OnDestroy } from "@angular/core"; import { UserSalary } from "@models/salaries/salary.model"; import { GradesMinMaxSalariesChartObject } from "./grades-min-max-chart-object"; import { SalariesChart } from "../salaries-chart/salaries-chart"; +import { untilDestroyed } from "@shared/subscriptions/until-destroyed"; @Component({ selector: "app-grades-min-max-chart", templateUrl: "./grades-min-max-chart.component.html", styleUrl: "./grades-min-max-chart.component.scss", }) -export class GradesMinMaxChartComponent { +export class GradesMinMaxChartComponent implements OnDestroy { @Input() source: SalariesChart | null = null; @@ -23,6 +24,8 @@ export class GradesMinMaxChartComponent { this.initChart(); } + ngOnDestroy(): void {} + private initChart(): void { if (this.source == null) { return; diff --git a/src/app/modules/salaries/components/people-by-grades-chart/people-by-grades-chart.component.html b/src/app/modules/salaries/components/people-by-grades-chart/people-by-grades-chart.component.html index b4080ede..f6a9f985 100644 --- a/src/app/modules/salaries/components/people-by-grades-chart/people-by-grades-chart.component.html +++ b/src/app/modules/salaries/components/people-by-grades-chart/people-by-grades-chart.component.html @@ -3,7 +3,7 @@
- Казахстанские компании: + Казахстанские компании (тенге) {{ totalCountLocal }} анкет
@@ -28,7 +28,7 @@
- Иностранные компании: + Иностранные компании (тенге) {{ totalCountRemote }} анкет
diff --git a/src/app/modules/salaries/components/people-by-grades-chart/people-by-grades-chart.component.ts b/src/app/modules/salaries/components/people-by-grades-chart/people-by-grades-chart.component.ts index e1ad2fe2..af948020 100644 --- a/src/app/modules/salaries/components/people-by-grades-chart/people-by-grades-chart.component.ts +++ b/src/app/modules/salaries/components/people-by-grades-chart/people-by-grades-chart.component.ts @@ -33,9 +33,6 @@ export class PeopleByGradesChartComponent implements OnInit { showPercents = true; - @Input() - title: string | null = null; - constructor() {} ngOnInit(): void { diff --git a/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts b/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts index 68bb5785..d43bc5ef 100644 --- a/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/currency-select-box/currency-select-box.component.ts @@ -64,7 +64,6 @@ export class CurrencySelectBoxComponent implements OnInit { } const selectedCurrencyData = this.currencies!.find(x => x.currency === e.item); - console.log("Currency selected: ", selectedCurrencyData); this.chart?.setCurrentCurrency(e.item); } } diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.html b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.html index ecfb650c..ee9b88b0 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.html +++ b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.html @@ -3,8 +3,8 @@
- - + + diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts index 0e7473ab..f6cc002d 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/salaries-by-grade/salaries-by-grade-block.component.ts @@ -4,6 +4,7 @@ import { SalariesByGrade } from "@services/user-salaries.service"; import { SalariesChart } from "../salaries-chart"; import { formatNumber } from "@angular/common"; import { untilDestroyed } from "@shared/subscriptions/until-destroyed"; +import { CurrencyType } from "@services/admin-tools.service"; interface Item extends SalariesByGrade { gradeAsString: string; @@ -27,6 +28,8 @@ export class SalariesByGradeBlockComponent implements OnInit, OnDestroy { totalCount: number = 0; + currentCurrencyLabel: string | null = null; + ngOnInit(): void { if (this.chart == null) { @@ -40,6 +43,7 @@ export class SalariesByGradeBlockComponent implements OnInit, OnDestroy { .subscribe(() => { this.items = null; this.totalCount = 0; + this.currentCurrencyLabel = null; this.recaulculate(); }); @@ -52,6 +56,7 @@ export class SalariesByGradeBlockComponent implements OnInit, OnDestroy { return; } + this.currentCurrencyLabel = this.chart!.getCurrentCurrencyLabel(); this.items = source.map((x) => { this.totalCount += x.count; return { diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html index a2d51052..1786f8a4 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html @@ -316,7 +316,6 @@
@@ -326,9 +325,6 @@
diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts b/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts index 2ed8b940..6948f134 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.ts @@ -129,6 +129,18 @@ export class SalariesChart implements SalariesChartResponse { this.currentCurrencyChanged$.next(this.currentCurrency); } + public getCurrentCurrencyLabel(): string { + if (this.currentCurrency.currency === CurrencyType.KZT) { + return "тг"; + } + + if (this.currentCurrency.currency === CurrencyType.USD) { + return "usd"; + } + + return this.currentCurrency.currencyString; + } + private getDefaultCurrency(): CurrencyData { return this.currencies.find((x) => x.currency === CurrencyType.KZT) ?? { diff --git a/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.html b/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.html index 150d3924..cb3496b8 100644 --- a/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.html +++ b/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.html @@ -3,7 +3,7 @@
Медианная зарплата в местных компаниях
{{ median }} - тг. + {{currentCurrencyLabel}}
@@ -11,7 +11,7 @@
Средняя зарплата
{{ average }} - тг. + {{currentCurrencyLabel}}
@@ -19,7 +19,7 @@
Медианная на удаленке
{{ medianRemote }} - тг. + {{currentCurrencyLabel}}
@@ -27,7 +27,7 @@
Средняя на удаленке
{{ averageRemote }} - тг. + {{currentCurrencyLabel}}
diff --git a/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.ts b/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.ts index 6448c660..b27af83e 100644 --- a/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/salary-block-value/salary-block-value.component.ts @@ -1,30 +1,47 @@ -import { Component, Input } from "@angular/core"; +import { Component, Input, OnInit, OnDestroy } from "@angular/core"; import { SalariesChart } from "../salaries-chart"; import { formatNumber } from "@angular/common"; +import { untilDestroyed } from "@shared/subscriptions/until-destroyed"; @Component({ selector: "app-salary-block-value", templateUrl: "./salary-block-value.component.html", styleUrl: "./salary-block-value.component.scss", }) -export class SalaryBlockValueComponent { +export class SalaryBlockValueComponent implements OnInit, OnDestroy { @Input() source: SalariesChart | null = null; - get median(): string { - return SalaryBlockValueComponent.formatNumber(this.source?.medianSalary); + median: string | null = null; + average: string | null = null; + medianRemote: string | null = null; + averageRemote: string | null = null; + currentCurrencyLabel: string = ""; + + ngOnInit(): void { + this.recalculcate(); + + if (this.source != null) { + this.source.currentCurrencyChanged$ + .pipe(untilDestroyed(this)) + .subscribe(() => { + this.recalculcate(); + }); + } } - get average(): string { - return SalaryBlockValueComponent.formatNumber(this.source?.averageSalary); - } + ngOnDestroy(): void {} - get medianRemote(): string { - return SalaryBlockValueComponent.formatNumber(this.source?.medianRemoteSalary); - } + private recalculcate(): void { + if (this.source == null) { + return; + } - get averageRemote(): string { - return SalaryBlockValueComponent.formatNumber(this.source?.averageRemoteSalary); + this.median = SalaryBlockValueComponent.formatNumber(this.source.medianSalary); + this.average = SalaryBlockValueComponent.formatNumber(this.source.averageSalary); + this.medianRemote = SalaryBlockValueComponent.formatNumber(this.source.medianRemoteSalary); + this.averageRemote = SalaryBlockValueComponent.formatNumber(this.source.averageRemoteSalary); + this.currentCurrencyLabel = this.source.getCurrentCurrencyLabel(); } private static formatNumber(value: number | null | undefined): string {
ГрейдМедианная, тг.Средняя, тг.Медианная, {{currentCurrencyLabel}}Средняя, {{currentCurrencyLabel}} Кол-во анкет