diff --git a/src/app/app-provider-admin/provider-admin/configurations/change-username/change-username.component.css b/src/app/app-provider-admin/provider-admin/configurations/change-username/change-username.component.css new file mode 100644 index 00000000..6c6c1510 --- /dev/null +++ b/src/app/app-provider-admin/provider-admin/configurations/change-username/change-username.component.css @@ -0,0 +1,15 @@ +.screen-note { + font-size: 12px; + color: rgba(0, 0, 0, 0.6); + margin: 4px 0 0 0; +} + +.validation-note { + font-size: 12px; + color: #d32f2f; + margin: 4px 0 0 0; +} + +.m-l-10 { + margin-left: 10px; +} diff --git a/src/app/app-provider-admin/provider-admin/configurations/change-username/change-username.component.html b/src/app/app-provider-admin/provider-admin/configurations/change-username/change-username.component.html new file mode 100644 index 00000000..1a5ffc55 --- /dev/null +++ b/src/app/app-provider-admin/provider-admin/configurations/change-username/change-username.component.html @@ -0,0 +1,125 @@ +
+
+
+

Change Username

+

+ Renaming a user also repoints the Created By and Modified By records + they own. Fill in only what you want to change — leave a field blank to + keep its current value. This cannot be undone. +

+
+ +
+ + Select User + + + {{ item.userName }} + + + +
+ +
+ + Current Username + + +
+ +
+ + New Username + + Maximum {{ effectiveMaxLength }} characters + +
+
+ +
+
+ + Current Employee ID + + +
+ +
+ + New Employee ID + + Maximum {{ maxEmployeeIdLength }} characters + +
+
+ +
+
+ + Also update contact numbers + +

+ Only tick this where the username is the user's mobile number. It + overwrites Contact No and Emergency Contact No, which limits the new + username to {{ maxContactLength }} characters. +

+
+
+ +
+
+

{{ validationMessage }}

+
+
+ +
+
+ +
+
+ +
+
+
Update complete
+

+ Username: {{ renameResult.oldUserName }} → + {{ renameResult.newUserName }} +

+

+ Employee ID: {{ renameResult.oldEmployeeId || "not set" }} → + {{ renameResult.newEmployeeId }} +

+

+ Employee ID unchanged ({{ renameResult.oldEmployeeId || "not set" }}) +

+
+
+
diff --git a/src/app/app-provider-admin/provider-admin/configurations/change-username/change-username.component.ts b/src/app/app-provider-admin/provider-admin/configurations/change-username/change-username.component.ts new file mode 100644 index 00000000..de3802ec --- /dev/null +++ b/src/app/app-provider-admin/provider-admin/configurations/change-username/change-username.component.ts @@ -0,0 +1,236 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +import { Component, OnInit } from '@angular/core'; +import { ChangeUsernameService } from 'src/app/core/services/ProviderAdminServices/change-username.service'; +import { ConfirmationDialogsService } from 'src/app/core/services/dialog/confirmation.service'; +import { SessionStorageService } from 'Common-UI/src/registrar/services/session-storage.service'; + +@Component({ + selector: 'app-change-username', + templateUrl: './change-username.component.html', + styleUrls: ['./change-username.component.css'], +}) +export class ChangeUsernameComponent implements OnInit { + serviceProviderID: any; + user: any; + newUserName = ''; + + currentEmployeeId = ''; + newEmployeeId = ''; + + userNamesList: any = []; + + updateContactFields = true; + + renameResult: any = null; + submitting = false; + + userNameTaken = false; + employeeIdTaken = false; + + readonly maxUserNameLength = 20; + readonly maxContactLength = 12; + readonly maxEmployeeIdLength = 20; + + constructor( + private changeUsernameService: ChangeUsernameService, + private alertService: ConfirmationDialogsService, + readonly sessionstorage: SessionStorageService, + ) {} + + ngOnInit() { + this.serviceProviderID = this.sessionstorage.getItem('service_providerID'); + this.getUserList(); + } + + getUserList() { + this.changeUsernameService.getUserList(this.serviceProviderID).subscribe( + (response: any) => { + this.userNamesList = response.data; + }, + (err: any) => this.alertService.alert(err.errorMessage, 'error'), + ); + } + + onSelectionChange() { + this.renameResult = null; + } + + onUserChange() { + this.onSelectionChange(); + this.currentEmployeeId = ''; + this.newUserName = ''; + this.newEmployeeId = ''; + this.userNameTaken = false; + this.employeeIdTaken = false; + if (!this.user) { + return; + } + this.changeUsernameService.getUserDetail(this.user.userName).subscribe( + (response: any) => { + this.currentEmployeeId = response.data?.employeeID || ''; + }, + (err: any) => this.alertService.alert(err.errorMessage, 'error'), + ); + } + + checkUserNameAvailability() { + this.onSelectionChange(); + this.userNameTaken = false; + const newUserName = (this.newUserName || '').trim(); + if (!this.user || !newUserName || newUserName === this.user.userName) { + return; + } + this.changeUsernameService.checkUserAvailability(newUserName).subscribe( + (response: any) => { + this.userNameTaken = response.data?.response === 'userexist'; + }, + (err: any) => console.log('error', err), + ); + } + + checkEmployeeIdAvailability() { + this.onSelectionChange(); + this.employeeIdTaken = false; + const newEmployeeId = (this.newEmployeeId || '').trim(); + if (!newEmployeeId || newEmployeeId === this.currentEmployeeId) { + return; + } + this.changeUsernameService.checkEmpIdAvailability(newEmployeeId).subscribe( + (response: any) => { + this.employeeIdTaken = response.data?.response === 'true'; + }, + (err: any) => console.log('error', err), + ); + } + + get effectiveMaxLength(): number { + return this.updateContactFields + ? this.maxContactLength + : this.maxUserNameLength; + } + + get validationMessage(): string | null { + if (!this.user) { + return 'Select a user'; + } + const newUserName = (this.newUserName || '').trim(); + const newEmployeeId = (this.newEmployeeId || '').trim(); + + const userNameChanged = !!newUserName && newUserName !== this.user.userName; + const employeeIdChanged = + !!newEmployeeId && newEmployeeId !== this.currentEmployeeId; + + if (!userNameChanged && !employeeIdChanged) { + return 'Enter a new username or a new employee ID'; + } + if (userNameChanged) { + if (newUserName.length > this.effectiveMaxLength) { + return this.updateContactFields + ? `Maximum ${this.maxContactLength} characters while contact numbers are being updated` + : `Maximum ${this.maxUserNameLength} characters`; + } + if (this.userNameTaken) { + return `Username ${newUserName} is already in use`; + } + } + if (employeeIdChanged) { + if (newEmployeeId.length > this.maxEmployeeIdLength) { + return `Employee ID: maximum ${this.maxEmployeeIdLength} characters`; + } + if (this.employeeIdTaken) { + return `Employee ID ${newEmployeeId} is already in use`; + } + } + return null; + } + + get canSubmit(): boolean { + return this.validationMessage === null && !this.submitting; + } + + private buildRequest() { + const newUserName = (this.newUserName || '').trim(); + const newEmployeeId = (this.newEmployeeId || '').trim(); + return { + userID: this.user.userID, + oldUserName: this.user.userName, + newUserName: newUserName || null, + newEmployeeId: newEmployeeId || null, + updateContactFields: this.updateContactFields, + }; + } + + confirmAndRename() { + if (!this.canSubmit) { + return; + } + const request = this.buildRequest(); + this.alertService + .confirm('Confirm', this.confirmMessage(request)) + .subscribe((accept: any) => { + if (accept) { + this.rename(request); + } + }); + } + + private confirmMessage(request: any): string { + const changes: string[] = []; + if (request.newUserName) { + changes.push( + `username from ${request.oldUserName} to ${request.newUserName}`, + ); + } + if (request.newEmployeeId) { + changes.push( + `employee ID from ${this.currentEmployeeId || 'not set'} to ${request.newEmployeeId}`, + ); + } + const audit = request.newUserName + ? ' This also repoints the Created By and Modified By records they own.' + : ''; + return `Change ${changes.join(' and ')}?${audit} This cannot be undone.`; + } + + private rename(request: any) { + this.submitting = true; + this.changeUsernameService.renameUsername(request).subscribe( + (response: any) => { + this.submitting = false; + this.renameResult = response.data; + this.alertService.alert('Username updated successfully', 'success'); + this.newUserName = ''; + this.newEmployeeId = ''; + this.currentEmployeeId = ''; + this.userNameTaken = false; + this.employeeIdTaken = false; + this.user = null; + this.getUserList(); + }, + (err: any) => { + this.submitting = false; + this.alertService.alert(err.errorMessage, 'error'); + }, + ); + } +} diff --git a/src/app/app-provider-admin/provider-admin/configurations/configurations.module.ts b/src/app/app-provider-admin/provider-admin/configurations/configurations.module.ts index 78b36204..1a051bac 100644 --- a/src/app/app-provider-admin/provider-admin/configurations/configurations.module.ts +++ b/src/app/app-provider-admin/provider-admin/configurations/configurations.module.ts @@ -24,8 +24,10 @@ import { UserRoleAgentID_MappingService } from './services/user-role-agentID-map import { HospitalInstituteDirectorySubdirectoryMappingComponent } from './hospital-institute-directory-subdirectory-mapping/hospital-institute-directory-subdirectory-mapping.component'; import { HospitalInstituteMappingService } from '../activities/services/hospital-institute-mapping-service.service'; import { ResetUserPasswordService } from 'src/app/core/services/ProviderAdminServices/reset-user-password.service'; +import { ChangeUsernameService } from 'src/app/core/services/ProviderAdminServices/change-username.service'; import { UtcDatePipe } from './utc-date.pipe'; import { ResetUserPasswordComponent } from './reset-user-password/reset-user-password.component'; +import { ChangeUsernameComponent } from './change-username/change-username.component'; import { SwymedUserMappingComponent } from './swymed-user-mapping/swymed-user-mapping.component'; import { SwymedUserConfigurationService } from './services/swymed-user-service'; import { ServicePointVillageMapComponent } from './service-point-village-mapping/service-point-village-mapping.component'; @@ -63,6 +65,7 @@ import { MatInputModule } from '@angular/material/input'; AgentIDMappingModalComponent, HospitalInstituteDirectorySubdirectoryMappingComponent, ResetUserPasswordComponent, + ChangeUsernameComponent, SwymedUserMappingComponent, UtcDatePipe, ServicePointVillageMapComponent, @@ -98,6 +101,7 @@ import { MatInputModule } from '@angular/material/input'; UserRoleAgentID_MappingService, HospitalInstituteMappingService, ResetUserPasswordService, + ChangeUsernameService, SwymedUserConfigurationService, ServicePointVillageMapService, VanServicePointMappingService, @@ -120,6 +124,7 @@ import { MatInputModule } from '@angular/material/input'; AgentIDMappingModalComponent, HospitalInstituteDirectorySubdirectoryMappingComponent, ResetUserPasswordComponent, + ChangeUsernameComponent, SwymedUserMappingComponent, UtcDatePipe, ServicePointVillageMapComponent, diff --git a/src/app/app-provider-admin/provider-admin/provider-admin.component.html b/src/app/app-provider-admin/provider-admin/provider-admin.component.html index bc38e96d..bdd779c6 100644 --- a/src/app/app-provider-admin/provider-admin/provider-admin.component.html +++ b/src/app/app-provider-admin/provider-admin/provider-admin.component.html @@ -125,6 +125,7 @@ Email and Contact Number Configuration +