From 033b4399378e3f865ecee422e8036ff0261071e3 Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Tue, 9 Jan 2024 22:12:53 +0600 Subject: [PATCH 01/13] Added component --- package.json | 1 + src/app/app-routing.module.ts | 4 ++++ .../card-cv-files-list.component.html | 2 +- .../add-salary/add-salary.component.html | 15 ++++++++++++ .../add-salary/add-salary.component.scss | 0 .../add-salary/add-salary.component.spec.ts | 23 ++++++++++++++++++ .../add-salary/add-salary.component.ts | 9 +++++++ .../salaries-chart.component.html | 15 ++++++++++++ .../salaries-chart.component.scss | 0 .../salaries-chart.component.spec.ts | 23 ++++++++++++++++++ .../salaries-chart.component.ts | 9 +++++++ .../salaries/salaries-routing.module.ts | 15 ++++++++++++ src/app/modules/salaries/salaries.module.ts | 24 +++++++++++++++++++ src/index.html | 2 +- 14 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/app/modules/salaries/components/add-salary/add-salary.component.html create mode 100644 src/app/modules/salaries/components/add-salary/add-salary.component.scss create mode 100644 src/app/modules/salaries/components/add-salary/add-salary.component.spec.ts create mode 100644 src/app/modules/salaries/components/add-salary/add-salary.component.ts create mode 100644 src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html create mode 100644 src/app/modules/salaries/components/salaries-chart/salaries-chart.component.scss create mode 100644 src/app/modules/salaries/components/salaries-chart/salaries-chart.component.spec.ts create mode 100644 src/app/modules/salaries/components/salaries-chart/salaries-chart.component.ts create mode 100644 src/app/modules/salaries/salaries-routing.module.ts create mode 100644 src/app/modules/salaries/salaries.module.ts diff --git a/package.json b/package.json index cc77d29d..5819cb3a 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "start": "ng serve", "build": "ng build", "build-prod": "ng build --configuration=production", + "serve-prod": "ng serve --configuration=production", "watch": "ng build --watch --configuration development", "test": "ng test", "test-headless-ci-only": "ng test --browsers ChromiumNoSandbox", diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 51b7a722..f623f129 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -34,6 +34,10 @@ const routes: Routes = [ path: 'candidate-cards', loadChildren: () => import('./modules/candidate-cards/candidate-cards.module').then((m) => m.CandidateCardsModule) }, + { + path: 'salaries', + loadChildren: () => import('./modules/salaries/salaries.module').then((m) => m.SalariesModule) + }, // Fallback when no prior route is matched { path: '**', redirectTo: 'not-found', pathMatch: 'full' } diff --git a/src/app/modules/candidate-cards-shared/card-cv-files-list/card-cv-files-list.component.html b/src/app/modules/candidate-cards-shared/card-cv-files-list/card-cv-files-list.component.html index cd65624f..0035c607 100644 --- a/src/app/modules/candidate-cards-shared/card-cv-files-list/card-cv-files-list.component.html +++ b/src/app/modules/candidate-cards-shared/card-cv-files-list/card-cv-files-list.component.html @@ -21,7 +21,7 @@ - 2022-10-02 + 2024-10-02 diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.html b/src/app/modules/salaries/components/add-salary/add-salary.component.html new file mode 100644 index 00000000..72ba3cb6 --- /dev/null +++ b/src/app/modules/salaries/components/add-salary/add-salary.component.html @@ -0,0 +1,15 @@ +Add your salary + +
+
+
+ Form goes here +
+
+
+ + +
+ +
+
\ No newline at end of file diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.scss b/src/app/modules/salaries/components/add-salary/add-salary.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.spec.ts b/src/app/modules/salaries/components/add-salary/add-salary.component.spec.ts new file mode 100644 index 00000000..77d28b4f --- /dev/null +++ b/src/app/modules/salaries/components/add-salary/add-salary.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddSalaryComponent } from './add-salary.component'; + +describe('AddSalaryComponent', () => { + let component: AddSalaryComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AddSalaryComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(AddSalaryComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.ts b/src/app/modules/salaries/components/add-salary/add-salary.component.ts new file mode 100644 index 00000000..ef4ddb35 --- /dev/null +++ b/src/app/modules/salaries/components/add-salary/add-salary.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + templateUrl: './add-salary.component.html', + styleUrl: './add-salary.component.scss' +}) +export class AddSalaryComponent { + +} 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 new file mode 100644 index 00000000..c2d5e84d --- /dev/null +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.html @@ -0,0 +1,15 @@ +Salaries + +
+
+
+ Salaries chart goes here +
+
+
+ + +
+ +
+
\ No newline at end of file diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.scss b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.spec.ts b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.spec.ts new file mode 100644 index 00000000..6c060dfe --- /dev/null +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SalariesChartComponent } from './salaries-chart.component'; + +describe('SalariesChartComponent', () => { + let component: SalariesChartComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SalariesChartComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SalariesChartComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.ts b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.ts new file mode 100644 index 00000000..e82babe7 --- /dev/null +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + templateUrl: './salaries-chart.component.html', + styleUrl: './salaries-chart.component.scss' +}) +export class SalariesChartComponent { + +} diff --git a/src/app/modules/salaries/salaries-routing.module.ts b/src/app/modules/salaries/salaries-routing.module.ts new file mode 100644 index 00000000..b6282bfb --- /dev/null +++ b/src/app/modules/salaries/salaries-routing.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { SalariesChartComponent } from './components/salaries-chart/salaries-chart.component'; +import { AddSalaryComponent } from './components/add-salary/add-salary.component'; + +const routes: Routes = [ + { path: '', component: SalariesChartComponent }, + { path: 'add-salary', component: AddSalaryComponent }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class SalariesRoutingModule {} diff --git a/src/app/modules/salaries/salaries.module.ts b/src/app/modules/salaries/salaries.module.ts new file mode 100644 index 00000000..a3abcf3e --- /dev/null +++ b/src/app/modules/salaries/salaries.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SalariesRoutingModule } from './salaries-routing.module'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { SharedModule } from '@shared/shared.module'; +import { SalariesChartComponent } from './components/salaries-chart/salaries-chart.component'; +import { AddSalaryComponent } from './components/add-salary/add-salary.component'; + +@NgModule({ + declarations: [ + SalariesChartComponent, + AddSalaryComponent, + ], + imports: [ + CommonModule, + SalariesRoutingModule, + SharedModule, + FormsModule, + ReactiveFormsModule, + NgSelectModule + ] +}) +export class SalariesModule { } diff --git a/src/index.html b/src/index.html index 4352aaf0..9cc238e4 100644 --- a/src/index.html +++ b/src/index.html @@ -34,7 +34,7 @@
Tech.Interview
Kazakhstan, Almaty
-
2022, © maximgorbatyuk
+
2024, © maximgorbatyuk
From a348d09538d27b530ab9a7b343b2c3af00b00bea Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Tue, 9 Jan 2024 22:15:25 +0600 Subject: [PATCH 02/13] Tests fixed --- .../components/add-salary/add-salary.component.spec.ts | 7 ++++++- .../salaries-chart/salaries-chart.component.spec.ts | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.spec.ts b/src/app/modules/salaries/components/add-salary/add-salary.component.spec.ts index 77d28b4f..035696de 100644 --- a/src/app/modules/salaries/components/add-salary/add-salary.component.spec.ts +++ b/src/app/modules/salaries/components/add-salary/add-salary.component.spec.ts @@ -1,6 +1,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AddSalaryComponent } from './add-salary.component'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { mostUsedImports, testUtilStubs, mostUsedServices } from '@shared/test-utils'; describe('AddSalaryComponent', () => { let component: AddSalaryComponent; @@ -8,7 +10,10 @@ describe('AddSalaryComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [AddSalaryComponent] + declarations: [AddSalaryComponent], + imports: [...mostUsedImports], + providers: [...testUtilStubs, ...mostUsedServices], + schemas: [CUSTOM_ELEMENTS_SCHEMA] }) .compileComponents(); diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.spec.ts b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.spec.ts index 6c060dfe..64cb2167 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.spec.ts +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.spec.ts @@ -1,6 +1,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { SalariesChartComponent } from './salaries-chart.component'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { mostUsedImports, testUtilStubs, mostUsedServices } from '@shared/test-utils'; describe('SalariesChartComponent', () => { let component: SalariesChartComponent; @@ -8,7 +10,10 @@ describe('SalariesChartComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [SalariesChartComponent] + declarations: [SalariesChartComponent], + imports: [...mostUsedImports], + providers: [...testUtilStubs, ...mostUsedServices], + schemas: [CUSTOM_ELEMENTS_SCHEMA] }) .compileComponents(); From b2ccf97a992480eda3894b28bc05c1817ab30991 Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Tue, 9 Jan 2024 22:21:43 +0600 Subject: [PATCH 03/13] Ng lint setup --- .eslintrc.js | 33 ++++ package-lock.json | 172 +++++++++--------- package.json | 4 +- .../privacy-policy-page.component.html | 24 +-- 4 files changed, 133 insertions(+), 100 deletions(-) create mode 100644 .eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..88151e29 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,33 @@ +module.exports = { + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "overrides": [ + { + "env": { + "node": true + }, + "files": [ + ".eslintrc.{js,cjs}" + ], + "parserOptions": { + "sourceType": "script" + } + } + ], + "parser": "@angular-eslint/template-parser", + "parserOptions": { + "ecmaVersion": "latest" + }, + "plugins": [ + "@typescript-eslint", + "@angular-eslint/template" + ], + "rules": { + } +} diff --git a/package-lock.json b/package-lock.json index 43deb365..87c5fd39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,8 +47,8 @@ "@angular/compiler-cli": "~17.0.8", "@types/jasmine": "~5.1.4", "@types/node": "^20.10.5", - "@typescript-eslint/eslint-plugin": "6.16.0", - "@typescript-eslint/parser": "6.16.0", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", "eslint": "^8.56.0", "jasmine-core": "~5.1.1", "karma": "~6.4.2", @@ -3913,16 +3913,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz", - "integrity": "sha512-O5f7Kv5o4dLWQtPX4ywPPa+v9G+1q1x8mz0Kr0pXUtKsevo+gIJHLkGc8RxaZWtP8RrhwhSNIWThnW42K9/0rQ==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz", + "integrity": "sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/type-utils": "6.16.0", - "@typescript-eslint/utils": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/type-utils": "6.18.1", + "@typescript-eslint/utils": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3948,13 +3948,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.16.0.tgz", - "integrity": "sha512-ThmrEOcARmOnoyQfYkHw/DX2SEYBalVECmoldVuH6qagKROp/jMnfXpAU/pAIWub9c4YTxga+XwgAkoA0pxfmg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz", + "integrity": "sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.16.0", - "@typescript-eslint/utils": "6.16.0", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/utils": "6.18.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3975,17 +3975,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz", - "integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.1.tgz", + "integrity": "sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", "semver": "^7.5.4" }, "engines": { @@ -4000,15 +4000,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.16.0.tgz", - "integrity": "sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.1.tgz", + "integrity": "sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/typescript-estree": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4" }, "engines": { @@ -4028,13 +4028,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz", - "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz", + "integrity": "sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0" + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -4129,9 +4129,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz", - "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.1.tgz", + "integrity": "sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -4142,13 +4142,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz", - "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz", + "integrity": "sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4293,12 +4293,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz", - "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz", + "integrity": "sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/types": "6.18.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -19297,16 +19297,16 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz", - "integrity": "sha512-O5f7Kv5o4dLWQtPX4ywPPa+v9G+1q1x8mz0Kr0pXUtKsevo+gIJHLkGc8RxaZWtP8RrhwhSNIWThnW42K9/0rQ==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz", + "integrity": "sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/type-utils": "6.16.0", - "@typescript-eslint/utils": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/type-utils": "6.18.1", + "@typescript-eslint/utils": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -19316,55 +19316,55 @@ }, "dependencies": { "@typescript-eslint/type-utils": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.16.0.tgz", - "integrity": "sha512-ThmrEOcARmOnoyQfYkHw/DX2SEYBalVECmoldVuH6qagKROp/jMnfXpAU/pAIWub9c4YTxga+XwgAkoA0pxfmg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz", + "integrity": "sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "6.16.0", - "@typescript-eslint/utils": "6.16.0", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/utils": "6.18.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/utils": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz", - "integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.1.tgz", + "integrity": "sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", "semver": "^7.5.4" } } } }, "@typescript-eslint/parser": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.16.0.tgz", - "integrity": "sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.1.tgz", + "integrity": "sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/typescript-estree": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz", - "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz", + "integrity": "sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==", "dev": true, "requires": { - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0" + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1" } }, "@typescript-eslint/type-utils": { @@ -19413,19 +19413,19 @@ } }, "@typescript-eslint/types": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz", - "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.1.tgz", + "integrity": "sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz", - "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz", + "integrity": "sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA==", "dev": true, "requires": { - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -19513,12 +19513,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz", - "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz", + "integrity": "sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==", "dev": true, "requires": { - "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/types": "6.18.1", "eslint-visitor-keys": "^3.4.1" } }, diff --git a/package.json b/package.json index 5819cb3a..6b1944f0 100644 --- a/package.json +++ b/package.json @@ -54,8 +54,8 @@ "@angular/compiler-cli": "~17.0.8", "@types/jasmine": "~5.1.4", "@types/node": "^20.10.5", - "@typescript-eslint/eslint-plugin": "6.16.0", - "@typescript-eslint/parser": "6.16.0", + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", "eslint": "^8.56.0", "jasmine-core": "~5.1.1", "karma": "~6.4.2", diff --git a/src/app/modules/home/components/privacy-policy-page/privacy-policy-page.component.html b/src/app/modules/home/components/privacy-policy-page/privacy-policy-page.component.html index e0191c50..48ab8cd4 100644 --- a/src/app/modules/home/components/privacy-policy-page/privacy-policy-page.component.html +++ b/src/app/modules/home/components/privacy-policy-page/privacy-policy-page.component.html @@ -25,7 +25,7 @@ referenced, are strictly defined as:
  • - Cookie: small amount of data generated by a website and saved by your web browser. It is used to + Cookie: small amount of data generated by a website and saved by your web browser. It is used to identify your browser, provide analytics, remember information about you such as your language preference or login information.
  • @@ -38,11 +38,11 @@ Kazakhstan
  • - Customer: refers to the company, organization or person that signs up to use the Tech.Interview Service + Customer: refers to the company, organization or person that signs up to use the Tech.Interview Service to manage the relationships with your consumers or service users.
  • - Device: any internet connected device such as a phone, tablet, computer or any other device that can be + Device: any internet connected device such as a phone, tablet, computer or any other device that can be used to visit Tech.Interview and use the services.
  • @@ -51,7 +51,7 @@ to identify the location from which a device is connecting to the Internet.
  • - Personnel: refers to those individuals who are employed by Tech.Interview or are under contract to + Personnel: refers to those individuals who are employed by Tech.Interview or are under contract to perform a service on behalf of one of the parties.
  • @@ -64,7 +64,7 @@ available) and on this platform.
  • - Third-party service: refers to advertisers, contest sponsors, promotional and marketing partners, and + Third-party service: refers to advertisers, contest sponsors, promotional and marketing partners, and others who provide our content or whose products or services we think may interest you.
  • Website: Tech.Interview's site, which can be accessed via this URL: interviewer.petrelai.kz
  • @@ -157,7 +157,7 @@ shared, it may be used to estimate general location and other technographics such as connection speed, whether you have visited the website in a shared location, and type of the device used to visit the website. They may aggregate information about our advertising and what you see on the website and then provide - auditing, research and reporting for us and our advertisers. We may also disclose personal and non-personal + auditing, research and reporting for us and our advertisers. We may also disclose personal and non-personal information about you to government or law enforcement officials or private parties as we, in our sole discretion, believe necessary or appropriate in order to respond to claims, legal process (including subpoenas), to protect our rights and interests or those of a third party, the safety of the public or any @@ -252,10 +252,10 @@

    Customers have the right to request the restriction of certain uses and disclosures of personally - identifiable information as follows. You can contact us in order to (1) update or correct your personally + identifiable information as follows. You can contact us in order to (1) update or correct your personally identifiable information, (2) change your preferences with respect to communications and other information you receive from us, or (3) delete the personally identifiable information maintained about you on our - systems (subject to the following paragraph), by cancelling your account. Such updates, corrections, changes + systems (subject to the following paragraph), by cancelling your account. Such updates, corrections, changes and deletions will have no effect on other information that we maintain, or information that we have provided to third parties in accordance with this Privacy Policy prior to such update, correction, change or deletion. To protect your privacy and security, we may take reasonable steps (such as requesting a unique @@ -340,7 +340,7 @@

    Your Consent

    - We've updated our Privacy Policy to provide you with complete transparency into what is being set when you + We've updated our Privacy Policy to provide you with complete transparency into what is being set when you visit our site and how it's being used. By using our website, registering an account, or making a purchase, you hereby consent to our Privacy Policy and agree to its terms.

    @@ -454,7 +454,7 @@
    What is GDPR?

    GDPR is an EU-wide privacy and data protection law that regulates how EU residents' data is protected by - companies and enhances the control the EU residents have, over their personal data. + companies and enhances the control the EU residents have, over their personal data.

    The GDPR is relevant to any globally operating company and not just the EU-based businesses and EU @@ -504,7 +504,7 @@

    Individual Data Subject's Rights - Data Access, Portability and Deletion

    - We are committed to helping our customers meet the data subject rights requirements of GDPR. Tech.Interview + We are committed to helping our customers meet the data subject rights requirements of GDPR. Tech.Interview processes or stores all personal data in fully vetted, DPA compliant vendors. We do store all conversation and personal data for up to 6 years unless your account is deleted. In which case, we dispose of all data in accordance with our Terms of Service and Privacy Policy, but we will not hold it longer than 60 days. @@ -512,7 +512,7 @@

    We are aware that if you are working with EU customers, you need to be able to provide them with the ability to access, update, retrieve and remove personal data. We got you! We've been set up as self service from the - start and have always given you access to your data and your customers data. Our customer support team is + start and have always given you access to your data and your customers data. Our customer support team is here for you to answer any questions you might have about working with the API.

    From 81621930f673cd7da8213ca6d810eeeafc3b5cc9 Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Wed, 10 Jan 2024 22:45:31 +0600 Subject: [PATCH 04/13] Added serve configuration --- angular.json | 24 ++++++++++++++++++++++ package.json | 2 +- src/environments/environment.staging.ts | 27 +++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/environments/environment.staging.ts diff --git a/angular.json b/angular.json index 7da714c7..91b40fea 100644 --- a/angular.json +++ b/angular.json @@ -62,6 +62,27 @@ ], "outputHashing": "all" }, + "staging": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "1mb", + "maximumError": "2mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.staging.ts" + } + ], + "outputHashing": "all" + }, "development": { "buildOptimizer": false, "optimization": false, @@ -79,6 +100,9 @@ "production": { "buildTarget": "petrel.interviewer:build:production" }, + "staging": { + "buildTarget": "petrel.interviewer:build:staging" + }, "development": { "buildTarget": "petrel.interviewer:build:development" } diff --git a/package.json b/package.json index 6b1944f0..01420e14 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "start": "ng serve", "build": "ng build", "build-prod": "ng build --configuration=production", - "serve-prod": "ng serve --configuration=production", + "serve-staging": "ng serve --configuration=staging", "watch": "ng build --watch --configuration development", "test": "ng test", "test-headless-ci-only": "ng test --browsers ChromiumNoSandbox", diff --git a/src/environments/environment.staging.ts b/src/environments/environment.staging.ts new file mode 100644 index 00000000..8ee21c9e --- /dev/null +++ b/src/environments/environment.staging.ts @@ -0,0 +1,27 @@ +import { NgxGoogleAnalyticsModule, NgxGoogleAnalyticsRouterModule } from 'ngx-google-analytics'; + +export const environment = { + production: true, + staging: false, + type: 'dev', + baseUrl: 'http://techinterview.space', + resourceApiURI: 'https://api.techinterview.space', + identityApiURI: 'https://techinterview-space.eu.auth0.com', + name: '', + auth: { + domain: 'techinterview-space.eu.auth0.com', + authority: 'https://techinterview-space.eu.auth0.com', + client_id: 'juNFNVr0wy1yayFgM2KTbk8374oP8MDk', + redirect_uri: 'http://localhost:4200/auth-callback', + post_logout_redirect_uri: 'http://localhost:4200/logout-callback', + response_type: 'id_token token', + scope: 'openid profile name given_name family_name email nickname', + filterProtocolClaims: true, + loadUserInfo: true, + automaticSilentRenew: true, + silent_redirect_uri: 'http://localhost:4200/silent-refresh.html' + }, + googleAnalytics: { + imports: [] + } +}; From 6f2021a1e27e58f9b48bf2e6b511e1f4e79ee3e2 Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Thu, 11 Jan 2024 00:19:32 +0600 Subject: [PATCH 05/13] Added form but does not work --- src/app/models/salaries/company-type.ts | 5 ++ src/app/models/salaries/currency.ts | 4 ++ src/app/models/salaries/salary.model.ts | 15 +++++ src/app/models/salaries/user-profession.ts | 37 ++++++++++++ .../components/add-salary/add-salary-form.ts | 60 +++++++++++++++++++ .../add-salary/add-salary.component.html | 37 +++++++++++- .../add-salary/add-salary.component.ts | 40 ++++++++++++- .../salaries-chart.component.html | 2 +- .../salaries-chart.component.ts | 38 +++++++++++- src/app/services/index.ts | 4 +- src/app/services/organizations.service.ts | 3 +- src/app/services/user-salaries.service.ts | 47 +++++++++++++++ 12 files changed, 283 insertions(+), 9 deletions(-) create mode 100644 src/app/models/salaries/company-type.ts create mode 100644 src/app/models/salaries/currency.ts create mode 100644 src/app/models/salaries/salary.model.ts create mode 100644 src/app/models/salaries/user-profession.ts create mode 100644 src/app/modules/salaries/components/add-salary/add-salary-form.ts create mode 100644 src/app/services/user-salaries.service.ts diff --git a/src/app/models/salaries/company-type.ts b/src/app/models/salaries/company-type.ts new file mode 100644 index 00000000..dc83e336 --- /dev/null +++ b/src/app/models/salaries/company-type.ts @@ -0,0 +1,5 @@ +export enum CompanyType { + Undefined = 0, + Local = 1, + Remote = 2, +} diff --git a/src/app/models/salaries/currency.ts b/src/app/models/salaries/currency.ts new file mode 100644 index 00000000..6fe3a53c --- /dev/null +++ b/src/app/models/salaries/currency.ts @@ -0,0 +1,4 @@ +export enum Currency { + Undefined = 0, + KZT = 1, +} diff --git a/src/app/models/salaries/salary.model.ts b/src/app/models/salaries/salary.model.ts new file mode 100644 index 00000000..326dd5c6 --- /dev/null +++ b/src/app/models/salaries/salary.model.ts @@ -0,0 +1,15 @@ +import { DeveloperGrade } from "@models/enums"; +import { CompanyType } from "./company-type"; +import { Currency } from "./currency"; +import { UserProfession } from "./user-profession"; + +export interface UserSalary { + value: number; + quarter: number; + year: number; + currency: Currency; + company: CompanyType; + grade: DeveloperGrade | null; + profession: UserProfession; + createdAt: Date; +} diff --git a/src/app/models/salaries/user-profession.ts b/src/app/models/salaries/user-profession.ts new file mode 100644 index 00000000..d1be8d4e --- /dev/null +++ b/src/app/models/salaries/user-profession.ts @@ -0,0 +1,37 @@ +export enum UserProfession { + Undefined = 0, + + Developer = 1, + + QualityAssurance = 2, + + Tester = 3, + + BusinessAnalyst = 4, + + ProjectManager = 5, + + ScrumMaster = 6, + + DevOps = 7, + + SystemAdministrator = 8, + + ProductOwner = 9, + + TeamLeader = 10, + + Architect = 11, + + DataScientist = 12, + + DataAnalyst = 13, + + DataEngineer = 14, + + DataWarehouseSpecialist = 15, + + DatabaseAdministrator = 16, + + TechLeader = 17, +} diff --git a/src/app/modules/salaries/components/add-salary/add-salary-form.ts b/src/app/modules/salaries/components/add-salary/add-salary-form.ts new file mode 100644 index 00000000..77175a4b --- /dev/null +++ b/src/app/modules/salaries/components/add-salary/add-salary-form.ts @@ -0,0 +1,60 @@ +import { FormControl, FormGroup, Validators } from "@angular/forms"; +import { CompanyType } from "@models/salaries/company-type"; +import { Currency } from "@models/salaries/currency"; +import { CreateUserSalaryRequest } from "@services/user-salaries.service"; + +export class AddSalaryForm extends FormGroup { + +static readonly digitsPattern = '^[0-9]*$'; + +constructor() { + const now = new Date(Date.now()); + const currentQuarter = Math.floor((now.getMonth() + 3) / 3); + + super({ + value: new FormControl( + null, + [ + Validators.pattern(AddSalaryForm.digitsPattern), + Validators.required + ]), + quarter: new FormControl( + currentQuarter, + [ + Validators.pattern(AddSalaryForm.digitsPattern), + Validators.min(1), + Validators.max(4), + Validators.required + ]), + year: new FormControl( + now.getFullYear(), + [ + Validators.pattern(AddSalaryForm.digitsPattern), + Validators.min(2000), + Validators.max(2100), + Validators.required + ]), + currency: new FormControl(Currency.KZT, [Validators.required]), + company: new FormControl(CompanyType.Local, [Validators.required]), + grade: new FormControl(null, []), + profession: new FormControl(null, [Validators.required]), + }); + } + + createRequestOrNull(): CreateUserSalaryRequest | null { + if (this.valid) { + return { + value: this.value.value, + quarter: this.value.quarter, + year: this.value.year, + currency: this.value.currency, + company: this.value.company, + grade: this.value.grade, + profession: this.value.profession, + }; + } + + this.markAllAsTouched(); + return null; + } +} \ No newline at end of file diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.html b/src/app/modules/salaries/components/add-salary/add-salary.component.html index 72ba3cb6..066f5c08 100644 --- a/src/app/modules/salaries/components/add-salary/add-salary.component.html +++ b/src/app/modules/salaries/components/add-salary/add-salary.component.html @@ -3,7 +3,42 @@
    - Form goes here + +
    +
    + + + +
    + +
    + + + +
    + +
    +
    + + Markdown is supported +
    + + +
    + +
    + + +
    + +
    + +
    +
    +
    diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.ts b/src/app/modules/salaries/components/add-salary/add-salary.component.ts index ef4ddb35..4deff94a 100644 --- a/src/app/modules/salaries/components/add-salary/add-salary.component.ts +++ b/src/app/modules/salaries/components/add-salary/add-salary.component.ts @@ -1,9 +1,45 @@ -import { Component } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { TitleService } from '@services/title.service'; +import { UserSalariesService } from '@services/user-salaries.service'; +import { AddSalaryForm } from './add-salary-form'; +import { untilDestroyed } from '@shared/subscriptions/until-destroyed'; @Component({ templateUrl: './add-salary.component.html', styleUrl: './add-salary.component.scss' }) -export class AddSalaryComponent { +export class AddSalaryComponent implements OnInit, OnDestroy { + addSalaryForm: AddSalaryForm | null = null; + + constructor( + private readonly service: UserSalariesService, + title: TitleService, + private readonly router: Router + ) { + title.setTitle('Add salary'); + } + + ngOnInit(): void { + this.addSalaryForm = new AddSalaryForm(); + } + + addSalarySubmitAction(): void { + const data = this.addSalaryForm?.createRequestOrNull(); + if (data == null) { + return; + } + + this.service + .create(data) + .pipe(untilDestroyed(this)) + .subscribe((x) => { + this.router.navigateByUrl('/salaries'); + }); + } + + ngOnDestroy(): void { + // ignored + } } 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 c2d5e84d..31a2af81 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 @@ -1,6 +1,6 @@ Salaries -
    +
    Salaries chart goes here diff --git a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.ts b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.ts index e82babe7..72b12ee1 100644 --- a/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.ts +++ b/src/app/modules/salaries/components/salaries-chart/salaries-chart.component.ts @@ -1,9 +1,43 @@ -import { Component } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { UserSalary } from '@models/salaries/salary.model'; +import { TitleService } from '@services/title.service'; +import { SalariesChartResponse, UserSalariesService } from '@services/user-salaries.service'; +import { untilDestroyed } from '@shared/subscriptions/until-destroyed'; @Component({ templateUrl: './salaries-chart.component.html', styleUrl: './salaries-chart.component.scss' }) -export class SalariesChartComponent { +export class SalariesChartComponent implements OnInit, OnDestroy { + salariesChart: SalariesChartResponse | null = null; + + constructor( + private readonly service: UserSalariesService, + title: TitleService, + private readonly router: Router) { + title.setTitle('Salaries'); + } + + ngOnInit(): void { + this.load(); + } + + load(): void { + this.service.charts() + .pipe(untilDestroyed(this)) + .subscribe((x) => { + this.salariesChart = x; + + if (this.salariesChart.shouldAddOwnSalary) { + this.router.navigateByUrl('/salaries/add-salary'); + return; + } + }); + } + + ngOnDestroy(): void { + // ignored + } } diff --git a/src/app/services/index.ts b/src/app/services/index.ts index 900daf4e..3ef09487 100644 --- a/src/app/services/index.ts +++ b/src/app/services/index.ts @@ -19,6 +19,7 @@ import { CandidateCardsService } from './candidate-cards.service'; import { CandidatesService } from './candidates.service'; import { OrganizationLabelsService } from './organization-labels.service'; import { CandidateCvService } from './candidate-cv.service'; +import { UserSalariesService } from './user-salaries.service'; export * from './authorization.service'; export * from './api.service'; @@ -58,5 +59,6 @@ export const applicationServices = [ CandidateCardsService, CandidatesService, OrganizationLabelsService, - CandidateCvService + CandidateCvService, + UserSalariesService ]; diff --git a/src/app/services/organizations.service.ts b/src/app/services/organizations.service.ts index e173906f..7b4d6c7d 100644 --- a/src/app/services/organizations.service.ts +++ b/src/app/services/organizations.service.ts @@ -4,10 +4,9 @@ import { CandidateCard } from '@models/organizations/candidate-card.model'; import { Candidate } from '@models/organizations/candidate.model'; import { Organization } from '@models/organizations/organization.model'; import { defaultPageParams, PageParams } from '@models/page-params'; -import { PaginatedList, PaginatedModel } from '@models/paginated-list'; +import { PaginatedList } from '@models/paginated-list'; import { SelectBoxItem } from '@models/select-box-item'; import { ConvertObjectToHttpParams } from '@shared/value-objects/convert-object-to-http'; -import { createReadStream } from 'fs'; import { Observable } from 'rxjs'; import { ApiService } from './api.service'; import { CandidateCardsFilterPaginatedRequest } from './requests/candidate-cards-filters'; diff --git a/src/app/services/user-salaries.service.ts b/src/app/services/user-salaries.service.ts new file mode 100644 index 00000000..572d53c3 --- /dev/null +++ b/src/app/services/user-salaries.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { ApiService } from './api.service'; +import { DeveloperGrade } from '@models/enums'; +import { CompanyType } from '@models/salaries/company-type'; +import { Currency } from '@models/salaries/currency'; +import { UserSalary } from '@models/salaries/salary.model'; +import { UserProfession } from '@models/salaries/user-profession'; + +export interface CreateUserSalaryRequest { + value: number; + quarter: number; + year: number; + currency: Currency; + company: CompanyType; + grade: DeveloperGrade | null; + profession: UserProfession; +} + +export interface SalariesChartResponse { + salaries: UserSalary[]; + shouldAddOwnSalary: boolean; + rangeStart: Date; + rangeEnd: Date; +} + +@Injectable({ + providedIn: 'root' +}) +export class UserSalariesService { + private readonly root = '/api/salaries/'; + constructor(private readonly api: ApiService) {} + + all(): Observable> { + // for admis + return this.api.get(this.root + 'all'); + } + + charts(): Observable { + // for admis + return this.api.get(this.root + 'chart'); + } + + create(data: CreateUserSalaryRequest): Observable { + return this.api.post(this.root, data); + } +} From 2baf96e981a55b92d92e03c4036237ff894655e1 Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Thu, 11 Jan 2024 18:23:01 +0600 Subject: [PATCH 06/13] Added code for form --- .../components/add-salary/add-salary-form.ts | 62 +++++------ .../add-salary/add-salary.component.html | 105 ++++++++++-------- .../add-salary/add-salary.component.ts | 7 ++ .../select-boxes/company-type-select-item.ts | 22 ++++ .../select-boxes/currency-select-item.ts | 22 ++++ .../select-boxes/profession-select-item.ts | 22 ++++ 6 files changed, 164 insertions(+), 76 deletions(-) create mode 100644 src/app/shared/select-boxes/company-type-select-item.ts create mode 100644 src/app/shared/select-boxes/currency-select-item.ts create mode 100644 src/app/shared/select-boxes/profession-select-item.ts diff --git a/src/app/modules/salaries/components/add-salary/add-salary-form.ts b/src/app/modules/salaries/components/add-salary/add-salary-form.ts index 77175a4b..aef59000 100644 --- a/src/app/modules/salaries/components/add-salary/add-salary-form.ts +++ b/src/app/modules/salaries/components/add-salary/add-salary-form.ts @@ -7,37 +7,37 @@ export class AddSalaryForm extends FormGroup { static readonly digitsPattern = '^[0-9]*$'; -constructor() { - const now = new Date(Date.now()); - const currentQuarter = Math.floor((now.getMonth() + 3) / 3); + constructor() { + const now = new Date(Date.now()); + const currentQuarter = Math.floor((now.getMonth() + 3) / 3); - super({ - value: new FormControl( - null, - [ - Validators.pattern(AddSalaryForm.digitsPattern), - Validators.required - ]), - quarter: new FormControl( - currentQuarter, - [ - Validators.pattern(AddSalaryForm.digitsPattern), - Validators.min(1), - Validators.max(4), - Validators.required - ]), - year: new FormControl( - now.getFullYear(), - [ - Validators.pattern(AddSalaryForm.digitsPattern), - Validators.min(2000), - Validators.max(2100), - Validators.required - ]), - currency: new FormControl(Currency.KZT, [Validators.required]), - company: new FormControl(CompanyType.Local, [Validators.required]), - grade: new FormControl(null, []), - profession: new FormControl(null, [Validators.required]), + super({ + value: new FormControl( + null, + [ + Validators.pattern(AddSalaryForm.digitsPattern), + Validators.required + ]), + quarter: new FormControl( + currentQuarter, + [ + Validators.pattern(AddSalaryForm.digitsPattern), + Validators.min(1), + Validators.max(4), + Validators.required + ]), + year: new FormControl( + now.getFullYear(), + [ + Validators.pattern(AddSalaryForm.digitsPattern), + Validators.min(2000), + Validators.max(2100), + Validators.required + ]), + currency: new FormControl(Currency.KZT, [Validators.required]), + company: new FormControl(CompanyType.Local, [Validators.required]), + grade: new FormControl(null, []), + profession: new FormControl(null, [Validators.required]), }); } @@ -56,5 +56,5 @@ constructor() { this.markAllAsTouched(); return null; - } + } } \ No newline at end of file diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.html b/src/app/modules/salaries/components/add-salary/add-salary.component.html index 066f5c08..9d32f820 100644 --- a/src/app/modules/salaries/components/add-salary/add-salary.component.html +++ b/src/app/modules/salaries/components/add-salary/add-salary.component.html @@ -1,50 +1,65 @@ Add your salary
    -
    -
    - -
    -
    - - - -
    - -
    - - - -
    - -
    -
    - - Markdown is supported -
    - - -
    - -
    - - -
    - -
    - -
    -
    - -
    +
    +
    +
    +
    + + + +
    + +
    + + + +
    + +
    + + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + +
    +
    +
    - - -
    - -
    -
    \ No newline at end of file +
    + + +
    + +
    +
    \ No newline at end of file diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.ts b/src/app/modules/salaries/components/add-salary/add-salary.component.ts index 4deff94a..089f743b 100644 --- a/src/app/modules/salaries/components/add-salary/add-salary.component.ts +++ b/src/app/modules/salaries/components/add-salary/add-salary.component.ts @@ -4,6 +4,9 @@ import { TitleService } from '@services/title.service'; import { UserSalariesService } from '@services/user-salaries.service'; import { AddSalaryForm } from './add-salary-form'; import { untilDestroyed } from '@shared/subscriptions/until-destroyed'; +import { CompanyTypeSelectItem } from '@shared/select-boxes/company-type-select-item'; +import { DeveloperGradeSelectItem } from '@shared/select-boxes/developer-grade-select-item'; +import { ProfessionSelectItem } from '@shared/select-boxes/profession-select-item'; @Component({ templateUrl: './add-salary.component.html', @@ -13,6 +16,10 @@ export class AddSalaryComponent implements OnInit, OnDestroy { addSalaryForm: AddSalaryForm | null = null; + readonly companyTypes: Array = CompanyTypeSelectItem.allItems(); + readonly grades: Array = DeveloperGradeSelectItem.allGrades(); + readonly professions: Array = ProfessionSelectItem.allItems(); + constructor( private readonly service: UserSalariesService, title: TitleService, diff --git a/src/app/shared/select-boxes/company-type-select-item.ts b/src/app/shared/select-boxes/company-type-select-item.ts new file mode 100644 index 00000000..dd8d0ec1 --- /dev/null +++ b/src/app/shared/select-boxes/company-type-select-item.ts @@ -0,0 +1,22 @@ +import { EnumHelper } from '@shared/value-objects/enum-helper'; +import { SplittedByWhitespacesString } from '@shared/value-objects/splitted-by-whitespaces-string'; +import { SelectItem } from './select-item'; +import { CompanyType } from '@models/salaries/company-type'; + +export class CompanyTypeSelectItem implements SelectItem { + readonly value: string; + readonly label: string; + readonly item: CompanyType; + + constructor(item: CompanyType) { + this.value = item.toString(); + this.label = new SplittedByWhitespacesString(CompanyType[item]).value; + this.item = item; + } + + static allItems(): CompanyTypeSelectItem[] { + return EnumHelper.getValues(CompanyType) + .filter((x) => x !== CompanyType.Undefined) + .map((grade) => new CompanyTypeSelectItem(grade)); + } +} diff --git a/src/app/shared/select-boxes/currency-select-item.ts b/src/app/shared/select-boxes/currency-select-item.ts new file mode 100644 index 00000000..d75747e4 --- /dev/null +++ b/src/app/shared/select-boxes/currency-select-item.ts @@ -0,0 +1,22 @@ +import { EnumHelper } from '@shared/value-objects/enum-helper'; +import { SplittedByWhitespacesString } from '@shared/value-objects/splitted-by-whitespaces-string'; +import { SelectItem } from './select-item'; +import { Currency } from '@models/salaries/currency'; + +export class CurrencySelectItem implements SelectItem { + readonly value: string; + readonly label: string; + readonly item: Currency; + + constructor(item: Currency) { + this.value = item.toString(); + this.label = new SplittedByWhitespacesString(Currency[item]).value; + this.item = item; + } + + static allItems(): CurrencySelectItem[] { + return EnumHelper.getValues(Currency) + .filter((x) => x !== Currency.Undefined) + .map((grade) => new CurrencySelectItem(grade)); + } +} diff --git a/src/app/shared/select-boxes/profession-select-item.ts b/src/app/shared/select-boxes/profession-select-item.ts new file mode 100644 index 00000000..8cebe9c3 --- /dev/null +++ b/src/app/shared/select-boxes/profession-select-item.ts @@ -0,0 +1,22 @@ +import { EnumHelper } from '@shared/value-objects/enum-helper'; +import { SplittedByWhitespacesString } from '@shared/value-objects/splitted-by-whitespaces-string'; +import { SelectItem } from './select-item'; +import { UserProfession } from '@models/salaries/user-profession'; + +export class ProfessionSelectItem implements SelectItem { + readonly value: string; + readonly label: string; + readonly item: UserProfession; + + constructor(item: UserProfession) { + this.value = item.toString(); + this.label = new SplittedByWhitespacesString(UserProfession[item]).value; + this.item = item; + } + + static allItems(): ProfessionSelectItem[] { + return EnumHelper.getValues(UserProfession) + .filter((x) => x !== UserProfession.Undefined) + .map((grade) => new ProfessionSelectItem(grade)); + } +} From 7cd6c50ea1cd945c51c07d250d7fb663e7085235 Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Thu, 11 Jan 2024 19:04:22 +0600 Subject: [PATCH 07/13] Added routes to navbar --- src/app/components/navbar/navbar.component.ts | 16 ++++++++++++++++ .../components/add-salary/add-salary-form.ts | 16 +++++++++------- .../modules/salaries/salaries-routing.module.ts | 9 +++++++-- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/app/components/navbar/navbar.component.ts b/src/app/components/navbar/navbar.component.ts index 3785e15f..2a22de88 100644 --- a/src/app/components/navbar/navbar.component.ts +++ b/src/app/components/navbar/navbar.component.ts @@ -125,6 +125,22 @@ export class NavbarComponent implements OnInit, OnDestroy { show: true } ] + }, + { + title: 'Salaries', + show: true, + links: [ + { + title: 'Salaries chart', + url: '/salaries/', + show: hasCurrentUser && this.currentUser!.hasRole(UserRole.Interviewer) + }, + { + title: 'Add salary', + url: '/salaries/add-salary', + show: hasCurrentUser && this.currentUser!.hasRole(UserRole.Interviewer) + } + ] } ]; diff --git a/src/app/modules/salaries/components/add-salary/add-salary-form.ts b/src/app/modules/salaries/components/add-salary/add-salary-form.ts index aef59000..c7e942ef 100644 --- a/src/app/modules/salaries/components/add-salary/add-salary-form.ts +++ b/src/app/modules/salaries/components/add-salary/add-salary-form.ts @@ -1,6 +1,8 @@ import { FormControl, FormGroup, Validators } from "@angular/forms"; +import { DeveloperGrade } from "@models/enums"; import { CompanyType } from "@models/salaries/company-type"; import { Currency } from "@models/salaries/currency"; +import { UserProfession } from "@models/salaries/user-profession"; import { CreateUserSalaryRequest } from "@services/user-salaries.service"; export class AddSalaryForm extends FormGroup { @@ -44,13 +46,13 @@ static readonly digitsPattern = '^[0-9]*$'; createRequestOrNull(): CreateUserSalaryRequest | null { if (this.valid) { return { - value: this.value.value, - quarter: this.value.quarter, - year: this.value.year, - currency: this.value.currency, - company: this.value.company, - grade: this.value.grade, - profession: this.value.profession, + value: Number(this.value.value), + quarter: Number(this.value.quarter), + year: Number(this.value.year), + currency: Number(this.value.currency) as Currency, + company: Number(this.value.company) as CompanyType, + grade: Number(this.value.grade) as DeveloperGrade, + profession: Number(this.value.profession) as UserProfession, }; } diff --git a/src/app/modules/salaries/salaries-routing.module.ts b/src/app/modules/salaries/salaries-routing.module.ts index b6282bfb..7ac3f234 100644 --- a/src/app/modules/salaries/salaries-routing.module.ts +++ b/src/app/modules/salaries/salaries-routing.module.ts @@ -2,10 +2,15 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { SalariesChartComponent } from './components/salaries-chart/salaries-chart.component'; import { AddSalaryComponent } from './components/add-salary/add-salary.component'; +import { AuthGuard } from '@auth0/auth0-angular'; const routes: Routes = [ - { path: '', component: SalariesChartComponent }, - { path: 'add-salary', component: AddSalaryComponent }, + { path: '', component: SalariesChartComponent, }, + { + path: 'add-salary', + component: AddSalaryComponent, + canActivate: [AuthGuard], + }, ]; @NgModule({ From e32b8f3f115d56446f44fe71a9c971d519b31bad Mon Sep 17 00:00:00 2001 From: "maxim.gorbatyuk" Date: Thu, 11 Jan 2024 19:34:29 +0600 Subject: [PATCH 08/13] Adjusted code --- src/app/components/navbar/navbar.component.ts | 9 +- .../auth-callback/auth-callback.component.ts | 1 + .../components/add-salary/add-salary-form.ts | 2 +- .../add-salary/add-salary.component.html | 122 ++++++++++-------- .../add-salary/add-salary.component.ts | 25 ++-- .../salaries-chart.component.html | 8 +- .../salaries-chart.component.ts | 20 ++- .../salaries/salaries-routing.module.ts | 7 +- src/app/shared/guards/auth.guard.ts | 5 +- .../shared/interceptors/auth-interceptor.ts | 8 ++ 10 files changed, 119 insertions(+), 88 deletions(-) diff --git a/src/app/components/navbar/navbar.component.ts b/src/app/components/navbar/navbar.component.ts index 2a22de88..9b322f00 100644 --- a/src/app/components/navbar/navbar.component.ts +++ b/src/app/components/navbar/navbar.component.ts @@ -132,14 +132,9 @@ export class NavbarComponent implements OnInit, OnDestroy { links: [ { title: 'Salaries chart', - url: '/salaries/', - show: hasCurrentUser && this.currentUser!.hasRole(UserRole.Interviewer) + url: '/salaries', + show: hasCurrentUser }, - { - title: 'Add salary', - url: '/salaries/add-salary', - show: hasCurrentUser && this.currentUser!.hasRole(UserRole.Interviewer) - } ] } ]; diff --git a/src/app/modules/home/components/auth-callback/auth-callback.component.ts b/src/app/modules/home/components/auth-callback/auth-callback.component.ts index 2488afb7..f5222b2f 100644 --- a/src/app/modules/home/components/auth-callback/auth-callback.component.ts +++ b/src/app/modules/home/components/auth-callback/auth-callback.component.ts @@ -34,6 +34,7 @@ export class AuthCallbackComponent implements OnInit { this.cookieService.delete('url'); this.router.navigate([url]); } else { + console.log('Redirecting to /me'); this.router.navigate([this.urlToRedirectAfterLogin]); } }); diff --git a/src/app/modules/salaries/components/add-salary/add-salary-form.ts b/src/app/modules/salaries/components/add-salary/add-salary-form.ts index c7e942ef..06740061 100644 --- a/src/app/modules/salaries/components/add-salary/add-salary-form.ts +++ b/src/app/modules/salaries/components/add-salary/add-salary-form.ts @@ -37,7 +37,7 @@ static readonly digitsPattern = '^[0-9]*$'; Validators.required ]), currency: new FormControl(Currency.KZT, [Validators.required]), - company: new FormControl(CompanyType.Local, [Validators.required]), + company: new FormControl(null, [Validators.required]), grade: new FormControl(null, []), profession: new FormControl(null, [Validators.required]), }); diff --git a/src/app/modules/salaries/components/add-salary/add-salary.component.html b/src/app/modules/salaries/components/add-salary/add-salary.component.html index 9d32f820..88b7d84f 100644 --- a/src/app/modules/salaries/components/add-salary/add-salary.component.html +++ b/src/app/modules/salaries/components/add-salary/add-salary.component.html @@ -1,65 +1,73 @@ -Add your salary +