From 82a0a9e1b26babbc1a49b434181dafa23252dcee Mon Sep 17 00:00:00 2001 From: Yuriy Yakymiv Date: Thu, 30 Jan 2025 14:35:18 +0200 Subject: [PATCH 1/6] fetched data from endpoint and tabs removed --- .../users-list/users-list.component.html | 8 +++ src/app/shared/models/employee.model.ts | 1 + src/app/shared/models/official.model.ts | 18 ++++++ src/app/shared/models/users-table.ts | 7 +++ .../services/employee/employee.service.ts | 5 +- src/app/shared/store/provider.actions.ts | 2 +- src/app/shared/store/provider.state.ts | 23 +++---- src/app/shared/utils/utils.ts | 25 ++++---- .../employees/employees.component.html | 21 ++----- .../employees/employees.component.scss | 6 +- .../provider/employees/employees.component.ts | 60 ++++++++----------- src/assets/i18n/en.json | 1 + src/assets/i18n/uk.json | 1 + 13 files changed, 97 insertions(+), 81 deletions(-) create mode 100644 src/app/shared/models/official.model.ts diff --git a/src/app/shared/components/users-list/users-list.component.html b/src/app/shared/components/users-list/users-list.component.html index 6d311191c6..4316e56765 100644 --- a/src/app/shared/components/users-list/users-list.component.html +++ b/src/app/shared/components/users-list/users-list.component.html @@ -24,6 +24,14 @@ + + + + {{ 'FORMS.LABELS.RNOKPP' | translate }} + + {{ element.rnokpp }} + + diff --git a/src/app/shared/models/employee.model.ts b/src/app/shared/models/employee.model.ts index 96ca80d9a8..91d3fb67d7 100644 --- a/src/app/shared/models/employee.model.ts +++ b/src/app/shared/models/employee.model.ts @@ -4,6 +4,7 @@ import { Person } from './user.model'; export interface EmployeeParameters extends PaginationParameters { searchString?: string; + providerId?: string; } export class Employee implements Person { diff --git a/src/app/shared/models/official.model.ts b/src/app/shared/models/official.model.ts new file mode 100644 index 0000000000..4cc057838e --- /dev/null +++ b/src/app/shared/models/official.model.ts @@ -0,0 +1,18 @@ +import { Person } from './user.model'; + +export class Official implements Person { + id?: string; + userId?: string; + position: string; + positionId: string; + firstName: string; + middleName?: string; + lastName: string; + rnokpp: string; + dismissalOrder: string; + recruitmentOrder: string; + dismissalReason: string; + employmentType: string; + activeFrom: string; + activeTo: string; +} diff --git a/src/app/shared/models/users-table.ts b/src/app/shared/models/users-table.ts index 49bf32c595..7633b20b3b 100644 --- a/src/app/shared/models/users-table.ts +++ b/src/app/shared/models/users-table.ts @@ -48,3 +48,10 @@ export interface InvitationData { user: AdminsTableData; adminType: AdminRoles; } + +export interface OfficialTableData { + id: string; + pib: string; + role: string; + rnokpp: string; +} diff --git a/src/app/shared/services/employee/employee.service.ts b/src/app/shared/services/employee/employee.service.ts index 256d9d8113..ec353873ee 100644 --- a/src/app/shared/services/employee/employee.service.ts +++ b/src/app/shared/services/employee/employee.service.ts @@ -4,6 +4,7 @@ import { Observable } from 'rxjs'; import { EmployeeBlockData } from 'shared/models/block.model'; import { Employee, EmployeeParameters } from 'shared/models/employee.model'; +import { Official } from 'shared/models/official.model'; import { SearchResponse } from 'shared/models/search.model'; @Injectable({ @@ -23,13 +24,13 @@ export class EmployeeService { /** * This method get provider admisn with filter parameters */ - public getFilteredEmployees(filterParams: EmployeeParameters): Observable> { + public getFilteredOfficials(filterParams: EmployeeParameters): Observable> { const params = new HttpParams() .set('searchString', `${filterParams.searchString}`) .set('from', `${filterParams.from}`) .set('size', `${filterParams.size}`); - return this.http.get>('/api/v1/Employees/GetFilteredEmployees', { + return this.http.get>(`/api/v1/providers/${filterParams.providerId}/officials/Get`, { params }); } diff --git a/src/app/shared/store/provider.actions.ts b/src/app/shared/store/provider.actions.ts index 4796f9e60e..b83a7520ef 100644 --- a/src/app/shared/store/provider.actions.ts +++ b/src/app/shared/store/provider.actions.ts @@ -79,7 +79,7 @@ export class GetProviderViewWorkshops { constructor(public workshopCardParameters: WorkshopCardParameters) {} } -export class GetFilteredEmployees { +export class GetFilteredOfficials { static readonly type = '[provider] get filtered Employee users'; constructor(public payload: EmployeeParameters) {} } diff --git a/src/app/shared/store/provider.state.ts b/src/app/shared/store/provider.state.ts index c5eae5d499..197cd69baa 100644 --- a/src/app/shared/store/provider.state.ts +++ b/src/app/shared/store/provider.state.ts @@ -14,6 +14,7 @@ import { BlockedParent } from 'shared/models/block.model'; import { Child } from 'shared/models/child.model'; import { TruncatedItem } from 'shared/models/item.model'; import { Employee } from 'shared/models/employee.model'; +import { Official } from 'shared/models/official.model'; import { Provider, ProviderWithLicenseStatus, ProviderWithStatus } from 'shared/models/provider.model'; import { SearchResponse } from 'shared/models/search.model'; import { Workshop, WorkshopProviderViewCard, WorkshopStatus } from 'shared/models/workshop.model'; @@ -37,7 +38,7 @@ export interface ProviderStateModel { selectedAchievement: Achievement; approvedChildren: SearchResponse; providerWorkshops: SearchResponse; - employees: SearchResponse; + officials: SearchResponse; selectedEmployee: Employee; blockedParent: BlockedParent; truncatedItems: TruncatedItem[]; @@ -54,7 +55,7 @@ export interface ProviderStateModel { achievements: null, selectedAchievement: null, providerWorkshops: null, - employees: null, + officials: null, selectedEmployee: null, blockedParent: null, truncatedItems: null, @@ -102,8 +103,8 @@ export class ProviderState { } @Selector() - static employees(state: ProviderStateModel): SearchResponse { - return state.employees; + static officials(state: ProviderStateModel): SearchResponse { + return state.officials; } @Selector() @@ -322,15 +323,15 @@ export class ProviderState { ); } - @Action(providerActions.GetFilteredEmployees) + @Action(providerActions.GetFilteredOfficials) getFilteredEmployees( { patchState }: StateContext, - { payload }: providerActions.GetFilteredEmployees - ): Observable> { + { payload }: providerActions.GetFilteredOfficials + ): Observable> { patchState({ isLoading: true }); return this.employeeService - .getFilteredEmployees(payload) - .pipe(tap((employees: SearchResponse) => patchState({ employees: employees ?? EMPTY_RESULT, isLoading: false }))); + .getFilteredOfficials(payload) + .pipe(tap((officials: SearchResponse) => patchState({ officials: officials ?? EMPTY_RESULT, isLoading: false }))); } @Action(providerActions.CreateWorkshop) @@ -595,7 +596,7 @@ export class ProviderState { { payload, filterParams }: providerActions.OnBlockEmployeeSuccess ): void { dispatch([ - new providerActions.GetFilteredEmployees(filterParams), + new providerActions.GetFilteredOfficials(filterParams), new ShowMessageBar({ message: payload.isBlocked ? SnackbarText.blockPerson : SnackbarText.unblockPerson, type: 'success' @@ -622,7 +623,7 @@ export class ProviderState { @Action(providerActions.OnDeleteEmployeeSuccess) onDeleteEmployeeSuccess({ dispatch }: StateContext, { filterParams }: providerActions.OnDeleteEmployeeSuccess): void { dispatch([ - new providerActions.GetFilteredEmployees(filterParams), + new providerActions.GetFilteredOfficials(filterParams), new ShowMessageBar({ message: SnackbarText.deleteEmployee, type: 'success' diff --git a/src/app/shared/utils/utils.ts b/src/app/shared/utils/utils.ts index c54358966b..ac32227a37 100644 --- a/src/app/shared/utils/utils.ts +++ b/src/app/shared/utils/utils.ts @@ -2,7 +2,6 @@ import { KeyValue } from '@angular/common'; import { CodeMessageErrors } from 'shared/enum/enumUA/errors'; import { Localization } from 'shared/enum/enumUA/localization'; -import { EmployeeTitles } from 'shared/enum/enumUA/employee'; import { UserTabsTitles } from 'shared/enum/enumUA/user'; import { NotificationDescriptionType, NotificationType } from 'shared/enum/notifications'; import { EmailConfirmationStatuses, UserStatuses } from 'shared/enum/statuses'; @@ -15,13 +14,13 @@ import { MessageBarData } from 'shared/models/message-bar.model'; import { MinistryAdmin } from 'shared/models/ministry-admin.model'; import { Notification } from 'shared/models/notification.model'; import { PaginationElement } from 'shared/models/pagination-element.model'; -import { Employee } from 'shared/models/employee.model'; import { PaginationParameters } from 'shared/models/query-parameters.model'; import { Person } from 'shared/models/user.model'; -import { AdminsTableData, EmployeesTableData, UsersTableData } from 'shared/models/users-table'; +import { AdminsTableData, OfficialTableData, UsersTableData } from 'shared/models/users-table'; import { Workshop } from 'shared/models/workshop.model'; import { ValidationConstants } from 'shared/constants/validation'; import { TIME_REGEX_REPLACE } from 'shared/constants/regex-constants'; +import { Official } from 'shared/models/official.model'; /** * Utility class that providers methods for shared data manipulations @@ -138,23 +137,21 @@ export class Util { } /** - * This method returns updated array structure for the Employee table - * @param admins Employee[] + * This method returns updated array structure for the Officials table + * @param admins Official[] * @returns array of objects */ - public static updateStructureForTheTableEmployees(admins: Employee[]): EmployeesTableData[] { - const updatedEmployees = []; - admins.forEach((admin: Employee) => { - updatedEmployees.push({ + public static updateStructureForTheTableOfficials(admins: Official[]): OfficialTableData[] { + const updatedOfficials: OfficialTableData[] = []; + admins.forEach((admin: Official) => { + updatedOfficials.push({ id: admin.id, pib: `${admin.lastName} ${admin.firstName} ${admin.middleName}`, - email: admin.email, - phoneNumber: `${admin.phoneNumber}`, - role: EmployeeTitles.Admin, - status: admin.accountStatus + role: admin.position, + rnokpp: admin.rnokpp }); }); - return updatedEmployees; + return updatedOfficials; } /** diff --git a/src/app/shell/personal-cabinet/provider/employees/employees.component.html b/src/app/shell/personal-cabinet/provider/employees/employees.component.html index 094ab9d7ac..527a01ed9a 100644 --- a/src/app/shell/personal-cabinet/provider/employees/employees.component.html +++ b/src/app/shell/personal-cabinet/provider/employees/employees.component.html @@ -1,5 +1,5 @@
-
+
- +
@@ -57,10 +57,6 @@ - - - - diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index a669c18ff5..ea4f84945d 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -494,6 +494,7 @@ "SEARCH_NAME_PHONE_EMAIL": "Search by name, e-mail, phone", "SEARCH_PROVIDER_CHILD_WORKSHOP": "Search by provider title, child name or workshop title", "SEARCH_NAME_EMAIL_PHONE_CITY_STATUS": "Search by provider email, phone, city, status", + "SEARCH_NAME_RNOKPP_POSITION": "Search by provider name, RNOKPP or position", "SEARCH_PROVIDER_EDRPO_MAIL_PHONE": "Search by provider title, provider registration code, email, phone", "SEARCH_NAME_EMAIL_CITY_TYPE_CHANGE": "Search by name, phone, email, type of change", "SEARCH_BY_DIRECTIONS": "Search by directions", diff --git a/src/assets/i18n/uk.json b/src/assets/i18n/uk.json index 190a62775b..d675b17910 100644 --- a/src/assets/i18n/uk.json +++ b/src/assets/i18n/uk.json @@ -494,6 +494,7 @@ "SEARCH_NAME_PHONE_EMAIL": "Пошук за ПІБ, електронною поштою, телефоном", "SEARCH_PROVIDER_CHILD_WORKSHOP": "Пошук за закладом, дитиною чи назвою гуртка", "SEARCH_NAME_EMAIL_PHONE_CITY_STATUS": "Пошук за ПІБ, імейлом, телефоном, містом чи статусом", + "SEARCH_NAME_RNOKPP_POSITION": "Пошук за ПІБ, РНОКПП чи посадою", "SEARCH_PROVIDER_EDRPO_MAIL_PHONE": "Пошук за закладом, ЄДРПОУ, імейлом, телефоном", "SEARCH_NAME_EMAIL_CITY_TYPE_CHANGE": "Пошук за ПІБ, імейлом, містом, типом чи зміною", "SEARCH_BY_DIRECTIONS": "Пошук за напрямками", From 0979aec83600f99a5aff60943cfc5070919e8f9d Mon Sep 17 00:00:00 2001 From: Yuriy Yakymiv Date: Sun, 2 Feb 2025 12:47:43 +0200 Subject: [PATCH 3/6] employees tests adjusted --- .../provider/employees/employees.component.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts b/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts index 94e826420c..5138d517df 100644 --- a/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts +++ b/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts @@ -98,6 +98,7 @@ describe('EmployeesComponent', () => { isBlocking: false } as EmployeesBlockData; mockFilterParams = { + providerId: '', from: 0, searchString: '', size: 12 From 13bbd0262f03e6fb2590164697d9e7aa4589730d Mon Sep 17 00:00:00 2001 From: Yuriy Yakymiv Date: Mon, 3 Feb 2025 14:52:37 +0200 Subject: [PATCH 4/6] unit tests for employee service and component --- .../employee/employee.service.spec.ts | 145 +++++++++++++++++- src/app/shared/store/provider.actions.ts | 2 +- src/app/shared/store/provider.state.ts | 2 +- .../employees/employees.component.spec.ts | 47 ++++-- .../provider/employees/employees.component.ts | 1 - 5 files changed, 179 insertions(+), 18 deletions(-) diff --git a/src/app/shared/services/employee/employee.service.spec.ts b/src/app/shared/services/employee/employee.service.spec.ts index df728a49ab..8f180a4e09 100644 --- a/src/app/shared/services/employee/employee.service.spec.ts +++ b/src/app/shared/services/employee/employee.service.spec.ts @@ -1,20 +1,159 @@ -import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; import { NgxsModule } from '@ngxs/store'; - +import { Employee, EmployeeParameters } from 'shared/models/employee.model'; +import { SearchResponse } from 'shared/models/search.model'; +import { Official } from 'shared/models/official.model'; +import { EmployeeBlockData } from 'shared/models/block.model'; import { EmployeeService } from './employee.service'; describe('EmployeeService', () => { let service: EmployeeService; + let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, NgxsModule.forRoot([])] + imports: [HttpClientTestingModule, NgxsModule.forRoot([])], + providers: [EmployeeService] }); service = TestBed.inject(EmployeeService); + httpMock = TestBed.inject(HttpTestingController); + }); + + afterEach(() => { + httpMock.verify(); }); it('should be created', () => { expect(service).toBeTruthy(); }); + + it('should GET employee by id', () => { + const mockEmployee: Employee = { id: '1', firstName: 'John', lastName: 'Smith', email: 'email', phoneNumber: 'number' }; + const employeeId = '1'; + + service.getEmployeeById(employeeId).subscribe((employee) => { + expect(employee).toEqual(mockEmployee); + }); + + const req = httpMock.expectOne(`/api/v1/Employees/GetEmployeeById/${employeeId}`); + expect(req.request.method).toBe('GET'); + + req.flush(mockEmployee); + }); + + it('should GET filtered officials', () => { + const filterParams: EmployeeParameters = { + searchString: 'John', + from: 0, + size: 10, + providerId: '1' + }; + + const mockResponse: SearchResponse = { + entities: [ + { + id: '1', + firstName: 'John', + lastName: 'Doe', + position: 'employee', + positionId: '1', + rnokpp: '111', + dismissalOrder: '', + recruitmentOrder: '', + dismissalReason: '', + employmentType: '', + activeFrom: '', + activeTo: '' + } + ], + totalAmount: 1 + }; + + service.getFilteredOfficials(filterParams).subscribe((response) => { + expect(response).toEqual(mockResponse); + }); + + const req = httpMock.expectOne(`/api/v1/providers/${filterParams.providerId}/officials/Get?searchString=John&from=0&size=10`); + expect(req.request.method).toBe('GET'); + + req.flush(mockResponse); + }); + + it('should create a new employee', () => { + const newEmployee: Employee = { id: '1', firstName: 'John', lastName: 'Smith', email: 'email', phoneNumber: '+000' }; + + service.createEmployee(newEmployee).subscribe((response) => { + expect(response).toEqual(newEmployee); + }); + + const req = httpMock.expectOne('/api/v1/Employees/Create'); + expect(req.request.method).toBe('POST'); + expect(req.request.body).toEqual(newEmployee); + + req.flush(newEmployee); + }); + + it('should DELETE an employee', () => { + const employeeId = '1'; + const providerId = '1'; + + service.deleteEmployee(employeeId, providerId).subscribe((response) => { + expect(response).toBeUndefined(); + }); + + const req = httpMock.expectOne(`/api/v1/Employees/Delete?employeeId=${employeeId}&providerId=${providerId}`); + expect(req.request.method).toBe('DELETE'); + + req.flush(null); + }); + + it('should block an employee successfully', () => { + const employeeBlockParams: EmployeeBlockData = { + userId: '1', + providerId: '1', + isBlocked: true + }; + + service.blockEmployee(employeeBlockParams).subscribe((response) => { + expect(response).toBeUndefined(); + }); + + const req = httpMock.expectOne( + `/api/v1/Employees/Block?employeeId=${employeeBlockParams.userId}&providerId=${employeeBlockParams.providerId}&isBlocked=true` + ); + expect(req.request.method).toBe('PUT'); + expect(req.request.body).toEqual({}); + + req.flush(null); + }); + + it('should update an employee successfully', () => { + const providerId = '1'; + const updatedEmployee: Employee = { id: '1', firstName: 'John', lastName: 'Smith', email: 'email', phoneNumber: 'number' }; + + service.updateEmployee(providerId, updatedEmployee).subscribe((response) => { + expect(response).toEqual(updatedEmployee); + }); + + const req = httpMock.expectOne(`/api/v1/Employees/Update?providerId=${providerId}`); + expect(req.request.method).toBe('PUT'); + expect(req.request.body).toEqual(updatedEmployee); + + req.flush(updatedEmployee); + }); + + it('should reinvite an employee successfully', () => { + const employee: Employee = { id: '1', firstName: 'John', lastName: 'Smith', email: 'email', phoneNumber: 'number' }; + + service.reinvateEmployee(employee).subscribe((response) => { + expect(response).toBeUndefined(); + }); + + const req = httpMock.expectOne(`/api/v1/Employees/Reinvite/${employee.id}`); + expect(req.request.method).toBe('PUT'); + expect(req.request.body).toEqual(employee); + + req.flush(null); + }); }); diff --git a/src/app/shared/store/provider.actions.ts b/src/app/shared/store/provider.actions.ts index b83a7520ef..fb7827eb1f 100644 --- a/src/app/shared/store/provider.actions.ts +++ b/src/app/shared/store/provider.actions.ts @@ -80,7 +80,7 @@ export class GetProviderViewWorkshops { } export class GetFilteredOfficials { - static readonly type = '[provider] get filtered Employee users'; + static readonly type = '[provider] get filtered Official users'; constructor(public payload: EmployeeParameters) {} } diff --git a/src/app/shared/store/provider.state.ts b/src/app/shared/store/provider.state.ts index 197cd69baa..01a2d57e0f 100644 --- a/src/app/shared/store/provider.state.ts +++ b/src/app/shared/store/provider.state.ts @@ -324,7 +324,7 @@ export class ProviderState { } @Action(providerActions.GetFilteredOfficials) - getFilteredEmployees( + getFilteredOfficials( { patchState }: StateContext, { payload }: providerActions.GetFilteredOfficials ): Observable> { diff --git a/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts b/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts index 5138d517df..c0b18e6914 100644 --- a/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts +++ b/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts @@ -1,3 +1,4 @@ +import { GetFilteredOfficials } from 'shared/store/provider.actions'; import { Component, Input } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; @@ -12,10 +13,12 @@ import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; import { NgxsModule, Store } from '@ngxs/store'; import { of } from 'rxjs'; +import { PaginationElement } from 'shared/models/pagination-element.model'; +import { Util } from 'shared/utils/utils'; import { ConfirmationModalWindowComponent } from 'shared/components/confirmation-modal-window/confirmation-modal-window.component'; import { NoResultCardComponent } from 'shared/components/no-result-card/no-result-card.component'; -import { Constants } from 'shared/constants/constants'; +import { Constants, PaginationConstants } from 'shared/constants/constants'; import { ModalConfirmationType } from 'shared/enum/modal-confirmation'; import { Role } from 'shared/enum/role'; import { EmployeeParameters } from 'shared/models/employee.model'; @@ -80,6 +83,26 @@ describe('EmployeesComponent', () => { expect(component.isSmallMobileView).toBeFalsy(); }); + it('should update currentPage and call getFilteredOfficials on page change', () => { + const mockPage: PaginationElement = { element: 1, isActive: true }; + jest.spyOn(component as any, 'getFilteredOfficials'); + + component.onPageChange(mockPage); + + expect(component.currentPage).toEqual(mockPage); + expect((component as any).getFilteredOfficials).toHaveBeenCalled(); + }); + + it('should update items per page and trigger first page load', () => { + const testItemsPerPage = 20; + jest.spyOn(component, 'onPageChange'); + + component.onItemsPerPageChange(testItemsPerPage); + + expect(component.filterParams.size).toBe(testItemsPerPage); + expect(component.onPageChange).toHaveBeenCalledWith(PaginationConstants.firstPage); + }); + describe('onBlockUnblock method', () => { let expectingMatDialogData: object; let matDialogSpy: jest.SpyInstance; @@ -181,15 +204,15 @@ describe('EmployeesComponent', () => { expect(dispatchSpy).toHaveBeenCalledWith(expectingUnblockingData); }); }); -}); -@Component({ - selector: 'app-users-list', - template: '' -}) -class MockUsersListComponent { - @Input() employees: EmployeesTableData[]; - @Input() users: EmployeesTableData[]; - @Input() userType: string; - @Input() isEdit: boolean; -} + @Component({ + selector: 'app-users-list', + template: '' + }) + class MockUsersListComponent { + @Input() employees: EmployeesTableData[]; + @Input() users: EmployeesTableData[]; + @Input() userType: string; + @Input() isEdit: boolean; + } +}); diff --git a/src/app/shell/personal-cabinet/provider/employees/employees.component.ts b/src/app/shell/personal-cabinet/provider/employees/employees.component.ts index 035b3a33df..5193268b49 100644 --- a/src/app/shell/personal-cabinet/provider/employees/employees.component.ts +++ b/src/app/shell/personal-cabinet/provider/employees/employees.component.ts @@ -1,7 +1,6 @@ import { Component, OnDestroy, OnInit, HostListener } from '@angular/core'; import { FormControl } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; -import { MatTabChangeEvent } from '@angular/material/tabs'; import { ActivatedRoute, Router } from '@angular/router'; import { Select, Store } from '@ngxs/store'; import { Observable } from 'rxjs'; From cac50c6597ce4b81ce0fffb838d86393e03ac0d9 Mon Sep 17 00:00:00 2001 From: Yuriy Yakymiv Date: Tue, 4 Feb 2025 18:58:33 +0200 Subject: [PATCH 5/6] naming updated to officialEmployee --- ...al.model.ts => official-employee.model.ts} | 2 +- src/app/shared/models/users-table.ts | 2 +- .../employee/employee.service.spec.ts | 8 ++--- .../services/employee/employee.service.ts | 6 ++-- src/app/shared/store/provider.actions.ts | 4 +-- src/app/shared/store/provider.state.ts | 30 +++++++++------- src/app/shared/utils/utils.ts | 18 +++++----- .../employees/employees.component.html | 8 ++--- .../employees/employees.component.spec.ts | 9 +++-- .../provider/employees/employees.component.ts | 35 +++++++++---------- 10 files changed, 62 insertions(+), 60 deletions(-) rename src/app/shared/models/{official.model.ts => official-employee.model.ts} (87%) diff --git a/src/app/shared/models/official.model.ts b/src/app/shared/models/official-employee.model.ts similarity index 87% rename from src/app/shared/models/official.model.ts rename to src/app/shared/models/official-employee.model.ts index 4cc057838e..edda3d0d78 100644 --- a/src/app/shared/models/official.model.ts +++ b/src/app/shared/models/official-employee.model.ts @@ -1,6 +1,6 @@ import { Person } from './user.model'; -export class Official implements Person { +export class OfficialEmployee implements Person { id?: string; userId?: string; position: string; diff --git a/src/app/shared/models/users-table.ts b/src/app/shared/models/users-table.ts index 7633b20b3b..0f4e628b4f 100644 --- a/src/app/shared/models/users-table.ts +++ b/src/app/shared/models/users-table.ts @@ -49,7 +49,7 @@ export interface InvitationData { adminType: AdminRoles; } -export interface OfficialTableData { +export interface OfficialEmployeeTableData { id: string; pib: string; role: string; diff --git a/src/app/shared/services/employee/employee.service.spec.ts b/src/app/shared/services/employee/employee.service.spec.ts index 8f180a4e09..e48fe9bb2b 100644 --- a/src/app/shared/services/employee/employee.service.spec.ts +++ b/src/app/shared/services/employee/employee.service.spec.ts @@ -3,7 +3,7 @@ import { TestBed } from '@angular/core/testing'; import { NgxsModule } from '@ngxs/store'; import { Employee, EmployeeParameters } from 'shared/models/employee.model'; import { SearchResponse } from 'shared/models/search.model'; -import { Official } from 'shared/models/official.model'; +import { OfficialEmployee } from 'shared/models/official-employee.model'; import { EmployeeBlockData } from 'shared/models/block.model'; import { EmployeeService } from './employee.service'; @@ -42,7 +42,7 @@ describe('EmployeeService', () => { req.flush(mockEmployee); }); - it('should GET filtered officials', () => { + it('should GET filtered official employees', () => { const filterParams: EmployeeParameters = { searchString: 'John', from: 0, @@ -50,7 +50,7 @@ describe('EmployeeService', () => { providerId: '1' }; - const mockResponse: SearchResponse = { + const mockResponse: SearchResponse = { entities: [ { id: '1', @@ -70,7 +70,7 @@ describe('EmployeeService', () => { totalAmount: 1 }; - service.getFilteredOfficials(filterParams).subscribe((response) => { + service.getFilteredOfficialEmployees(filterParams).subscribe((response) => { expect(response).toEqual(mockResponse); }); diff --git a/src/app/shared/services/employee/employee.service.ts b/src/app/shared/services/employee/employee.service.ts index ec353873ee..ebb92b8c21 100644 --- a/src/app/shared/services/employee/employee.service.ts +++ b/src/app/shared/services/employee/employee.service.ts @@ -4,7 +4,7 @@ import { Observable } from 'rxjs'; import { EmployeeBlockData } from 'shared/models/block.model'; import { Employee, EmployeeParameters } from 'shared/models/employee.model'; -import { Official } from 'shared/models/official.model'; +import { OfficialEmployee } from 'shared/models/official-employee.model'; import { SearchResponse } from 'shared/models/search.model'; @Injectable({ @@ -24,13 +24,13 @@ export class EmployeeService { /** * This method get provider admisn with filter parameters */ - public getFilteredOfficials(filterParams: EmployeeParameters): Observable> { + public getFilteredOfficialEmployees(filterParams: EmployeeParameters): Observable> { const params = new HttpParams() .set('searchString', `${filterParams.searchString}`) .set('from', `${filterParams.from}`) .set('size', `${filterParams.size}`); - return this.http.get>(`/api/v1/providers/${filterParams.providerId}/officials/Get`, { + return this.http.get>(`/api/v1/providers/${filterParams.providerId}/officials/Get`, { params }); } diff --git a/src/app/shared/store/provider.actions.ts b/src/app/shared/store/provider.actions.ts index fb7827eb1f..bab3a347f4 100644 --- a/src/app/shared/store/provider.actions.ts +++ b/src/app/shared/store/provider.actions.ts @@ -79,8 +79,8 @@ export class GetProviderViewWorkshops { constructor(public workshopCardParameters: WorkshopCardParameters) {} } -export class GetFilteredOfficials { - static readonly type = '[provider] get filtered Official users'; +export class GetFilteredOfficialEmployees { + static readonly type = '[provider] get filtered Official Employee users'; constructor(public payload: EmployeeParameters) {} } diff --git a/src/app/shared/store/provider.state.ts b/src/app/shared/store/provider.state.ts index 01a2d57e0f..cebadcc757 100644 --- a/src/app/shared/store/provider.state.ts +++ b/src/app/shared/store/provider.state.ts @@ -14,7 +14,7 @@ import { BlockedParent } from 'shared/models/block.model'; import { Child } from 'shared/models/child.model'; import { TruncatedItem } from 'shared/models/item.model'; import { Employee } from 'shared/models/employee.model'; -import { Official } from 'shared/models/official.model'; +import { OfficialEmployee } from 'shared/models/official-employee.model'; import { Provider, ProviderWithLicenseStatus, ProviderWithStatus } from 'shared/models/provider.model'; import { SearchResponse } from 'shared/models/search.model'; import { Workshop, WorkshopProviderViewCard, WorkshopStatus } from 'shared/models/workshop.model'; @@ -38,7 +38,7 @@ export interface ProviderStateModel { selectedAchievement: Achievement; approvedChildren: SearchResponse; providerWorkshops: SearchResponse; - officials: SearchResponse; + officialEmployees: SearchResponse; selectedEmployee: Employee; blockedParent: BlockedParent; truncatedItems: TruncatedItem[]; @@ -55,7 +55,7 @@ export interface ProviderStateModel { achievements: null, selectedAchievement: null, providerWorkshops: null, - officials: null, + officialEmployees: null, selectedEmployee: null, blockedParent: null, truncatedItems: null, @@ -103,8 +103,8 @@ export class ProviderState { } @Selector() - static officials(state: ProviderStateModel): SearchResponse { - return state.officials; + static officialEmployees(state: ProviderStateModel): SearchResponse { + return state.officialEmployees; } @Selector() @@ -323,15 +323,19 @@ export class ProviderState { ); } - @Action(providerActions.GetFilteredOfficials) - getFilteredOfficials( + @Action(providerActions.GetFilteredOfficialEmployees) + getFilteredOfficialEmployees( { patchState }: StateContext, - { payload }: providerActions.GetFilteredOfficials - ): Observable> { + { payload }: providerActions.GetFilteredOfficialEmployees + ): Observable> { patchState({ isLoading: true }); return this.employeeService - .getFilteredOfficials(payload) - .pipe(tap((officials: SearchResponse) => patchState({ officials: officials ?? EMPTY_RESULT, isLoading: false }))); + .getFilteredOfficialEmployees(payload) + .pipe( + tap((officials: SearchResponse) => + patchState({ officialEmployees: officials ?? EMPTY_RESULT, isLoading: false }) + ) + ); } @Action(providerActions.CreateWorkshop) @@ -596,7 +600,7 @@ export class ProviderState { { payload, filterParams }: providerActions.OnBlockEmployeeSuccess ): void { dispatch([ - new providerActions.GetFilteredOfficials(filterParams), + new providerActions.GetFilteredOfficialEmployees(filterParams), new ShowMessageBar({ message: payload.isBlocked ? SnackbarText.blockPerson : SnackbarText.unblockPerson, type: 'success' @@ -623,7 +627,7 @@ export class ProviderState { @Action(providerActions.OnDeleteEmployeeSuccess) onDeleteEmployeeSuccess({ dispatch }: StateContext, { filterParams }: providerActions.OnDeleteEmployeeSuccess): void { dispatch([ - new providerActions.GetFilteredOfficials(filterParams), + new providerActions.GetFilteredOfficialEmployees(filterParams), new ShowMessageBar({ message: SnackbarText.deleteEmployee, type: 'success' diff --git a/src/app/shared/utils/utils.ts b/src/app/shared/utils/utils.ts index ac32227a37..9d43693192 100644 --- a/src/app/shared/utils/utils.ts +++ b/src/app/shared/utils/utils.ts @@ -16,11 +16,11 @@ import { Notification } from 'shared/models/notification.model'; import { PaginationElement } from 'shared/models/pagination-element.model'; import { PaginationParameters } from 'shared/models/query-parameters.model'; import { Person } from 'shared/models/user.model'; -import { AdminsTableData, OfficialTableData, UsersTableData } from 'shared/models/users-table'; +import { AdminsTableData, OfficialEmployeeTableData, UsersTableData } from 'shared/models/users-table'; import { Workshop } from 'shared/models/workshop.model'; import { ValidationConstants } from 'shared/constants/validation'; import { TIME_REGEX_REPLACE } from 'shared/constants/regex-constants'; -import { Official } from 'shared/models/official.model'; +import { OfficialEmployee } from 'shared/models/official-employee.model'; /** * Utility class that providers methods for shared data manipulations @@ -137,21 +137,21 @@ export class Util { } /** - * This method returns updated array structure for the Officials table - * @param admins Official[] + * This method returns updated array structure for the Official Employees table + * @param admins OfficialEmployee[] * @returns array of objects */ - public static updateStructureForTheTableOfficials(admins: Official[]): OfficialTableData[] { - const updatedOfficials: OfficialTableData[] = []; - admins.forEach((admin: Official) => { - updatedOfficials.push({ + public static updateStructureForTheTableOfficialEmployees(admins: OfficialEmployee[]): OfficialEmployeeTableData[] { + const updatedOfficialEmployees: OfficialEmployeeTableData[] = []; + admins.forEach((admin: OfficialEmployee) => { + updatedOfficialEmployees.push({ id: admin.id, pib: `${admin.lastName} ${admin.firstName} ${admin.middleName}`, role: admin.position, rnokpp: admin.rnokpp }); }); - return updatedOfficials; + return updatedOfficialEmployees; } /** diff --git a/src/app/shell/personal-cabinet/provider/employees/employees.component.html b/src/app/shell/personal-cabinet/provider/employees/employees.component.html index 9902e33358..1dd5046f93 100644 --- a/src/app/shell/personal-cabinet/provider/employees/employees.component.html +++ b/src/app/shell/personal-cabinet/provider/employees/employees.component.html @@ -16,12 +16,12 @@
- +
- +
- +
diff --git a/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts b/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts index c0b18e6914..83ef2f1dad 100644 --- a/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts +++ b/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts @@ -1,4 +1,4 @@ -import { GetFilteredOfficials } from 'shared/store/provider.actions'; +import { GetFilteredOfficialEmployees } from 'shared/store/provider.actions'; import { Component, Input } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; @@ -14,7 +14,6 @@ import { TranslateModule } from '@ngx-translate/core'; import { NgxsModule, Store } from '@ngxs/store'; import { of } from 'rxjs'; import { PaginationElement } from 'shared/models/pagination-element.model'; -import { Util } from 'shared/utils/utils'; import { ConfirmationModalWindowComponent } from 'shared/components/confirmation-modal-window/confirmation-modal-window.component'; import { NoResultCardComponent } from 'shared/components/no-result-card/no-result-card.component'; @@ -83,14 +82,14 @@ describe('EmployeesComponent', () => { expect(component.isSmallMobileView).toBeFalsy(); }); - it('should update currentPage and call getFilteredOfficials on page change', () => { + it('should update currentPage and call getFilteredOfficialEmployees on page change', () => { const mockPage: PaginationElement = { element: 1, isActive: true }; - jest.spyOn(component as any, 'getFilteredOfficials'); + jest.spyOn(component as any, 'getFilteredOfficialEmployees'); component.onPageChange(mockPage); expect(component.currentPage).toEqual(mockPage); - expect((component as any).getFilteredOfficials).toHaveBeenCalled(); + expect((component as any).getFilteredOfficialEmployees).toHaveBeenCalled(); }); it('should update items per page and trigger first page load', () => { diff --git a/src/app/shell/personal-cabinet/provider/employees/employees.component.ts b/src/app/shell/personal-cabinet/provider/employees/employees.component.ts index 5193268b49..1aed870d2f 100644 --- a/src/app/shell/personal-cabinet/provider/employees/employees.component.ts +++ b/src/app/shell/personal-cabinet/provider/employees/employees.component.ts @@ -16,12 +16,12 @@ import { ModalConfirmationType } from 'shared/enum/modal-confirmation'; import { EmployeeRole } from 'shared/enum/employee'; import { PaginationElement } from 'shared/models/pagination-element.model'; import { Employee, EmployeeParameters } from 'shared/models/employee.model'; -import { Official } from 'shared/models/official.model'; +import { OfficialEmployee } from 'shared/models/official-employee.model'; import { Provider } from 'shared/models/provider.model'; import { SearchResponse } from 'shared/models/search.model'; -import { EmployeesBlockData, EmployeesTableData, OfficialTableData } from 'shared/models/users-table'; +import { EmployeesBlockData, EmployeesTableData, OfficialEmployeeTableData } from 'shared/models/users-table'; import { PushNavPath } from 'shared/store/navigation.actions'; -import { BlockEmployeeById, DeleteEmployeeById, GetFilteredOfficials, ReinviteEmployee } from 'shared/store/provider.actions'; +import { BlockEmployeeById, DeleteEmployeeById, GetFilteredOfficialEmployees, ReinviteEmployee } from 'shared/store/provider.actions'; import { ProviderState } from 'shared/store/provider.state'; import { Util } from 'shared/utils/utils'; import { ProviderComponent } from '../provider.component'; @@ -34,8 +34,8 @@ import { ProviderComponent } from '../provider.component'; export class EmployeesComponent extends ProviderComponent implements OnInit, OnDestroy { @Select(ProviderState.isLoading) public isLoadingCabinet$: Observable; - @Select(ProviderState.officials) - private officials$: Observable>; + @Select(ProviderState.officialEmployees) + private officialEmployees$: Observable>; public readonly EmployeeTitles = EmployeeTitles; public readonly employeeRole = EmployeeRole; @@ -43,9 +43,8 @@ export class EmployeesComponent extends ProviderComponent implements OnInit, OnD public readonly constants = Constants; public readonly statusesTitles = UserStatusesTitles; - public officials: SearchResponse; - public officialsData: OfficialTableData[] = []; - public filteredOfficials: OfficialTableData[] = this.officialsData; + public officialEmployees: SearchResponse; + public officialEmployeesData: OfficialEmployeeTableData[] = []; public filterFormControl: FormControl = new FormControl(''); public currentPage: PaginationElement = PaginationConstants.firstPage; public tabIndex: number; @@ -73,19 +72,19 @@ export class EmployeesComponent extends ProviderComponent implements OnInit, OnD public ngOnInit(): void { super.ngOnInit(); - Util.setFromPaginationParam(this.filterParams, this.currentPage, this.officials?.totalAmount); + Util.setFromPaginationParam(this.filterParams, this.currentPage, this.officialEmployees?.totalAmount); this.provider$.pipe(filter(Boolean), takeUntil(this.destroy$)).subscribe((provider: Provider) => { this.filterParams.providerId = provider.id; this.setTabOptions(); - this.getFilteredOfficials(); + this.getFilteredOfficialEmployees(); }); this.onResize(window); } public onPageChange(page: PaginationElement): void { this.currentPage = page; - this.getFilteredOfficials(); + this.getFilteredOfficialEmployees(); } public onItemsPerPageChange(itemsPerPage: number): void { @@ -183,9 +182,9 @@ export class EmployeesComponent extends ProviderComponent implements OnInit, OnD this.currentPage = PaginationConstants.firstPage; } - private getFilteredOfficials(): void { - Util.setFromPaginationParam(this.filterParams, this.currentPage, this.officials?.totalAmount); - this.store.dispatch(new GetFilteredOfficials(this.filterParams)); + private getFilteredOfficialEmployees(): void { + Util.setFromPaginationParam(this.filterParams, this.currentPage, this.officialEmployees?.totalAmount); + this.store.dispatch(new GetFilteredOfficialEmployees(this.filterParams)); } /** @@ -197,12 +196,12 @@ export class EmployeesComponent extends ProviderComponent implements OnInit, OnD .subscribe((val: string) => { this.filterParams.searchString = val; this.currentPage = PaginationConstants.firstPage; - this.getFilteredOfficials(); + this.getFilteredOfficialEmployees(); }); - this.officials$.pipe(filter(Boolean), takeUntil(this.destroy$)).subscribe((officials: SearchResponse) => { - this.officials = officials; - this.officialsData = Util.updateStructureForTheTableOfficials(officials.entities); + this.officialEmployees$.pipe(filter(Boolean), takeUntil(this.destroy$)).subscribe((officials: SearchResponse) => { + this.officialEmployees = officials; + this.officialEmployeesData = Util.updateStructureForTheTableOfficialEmployees(officials.entities); }); } } From c42143702c149a21f672badb7c9a90e1e628bb5f Mon Sep 17 00:00:00 2001 From: Yuriy Yakymiv Date: Wed, 5 Feb 2025 13:35:04 +0200 Subject: [PATCH 6/6] imports sorted and comment in the model --- src/app/shared/models/official-employee.model.ts | 2 ++ .../provider/employees/employees.component.spec.ts | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/shared/models/official-employee.model.ts b/src/app/shared/models/official-employee.model.ts index edda3d0d78..28b02a05b0 100644 --- a/src/app/shared/models/official-employee.model.ts +++ b/src/app/shared/models/official-employee.model.ts @@ -9,10 +9,12 @@ export class OfficialEmployee implements Person { middleName?: string; lastName: string; rnokpp: string; + // TODO: add this functionality when avaliable on backend dismissalOrder: string; recruitmentOrder: string; dismissalReason: string; employmentType: string; + // activeFrom: string; activeTo: string; } diff --git a/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts b/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts index 83ef2f1dad..3b9e1c0aad 100644 --- a/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts +++ b/src/app/shell/personal-cabinet/provider/employees/employees.component.spec.ts @@ -1,4 +1,3 @@ -import { GetFilteredOfficialEmployees } from 'shared/store/provider.actions'; import { Component, Input } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; @@ -13,7 +12,6 @@ import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; import { NgxsModule, Store } from '@ngxs/store'; import { of } from 'rxjs'; -import { PaginationElement } from 'shared/models/pagination-element.model'; import { ConfirmationModalWindowComponent } from 'shared/components/confirmation-modal-window/confirmation-modal-window.component'; import { NoResultCardComponent } from 'shared/components/no-result-card/no-result-card.component'; @@ -23,6 +21,7 @@ import { Role } from 'shared/enum/role'; import { EmployeeParameters } from 'shared/models/employee.model'; import { Provider } from 'shared/models/provider.model'; import { EmployeesBlockData, EmployeesTableData } from 'shared/models/users-table'; +import { PaginationElement } from 'shared/models/pagination-element.model'; import { EmployeesComponent } from './employees.component'; describe('EmployeesComponent', () => {