Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
<div class="title info">
<h4
*ngIf="
(!healthIDMapping && !enablehealthIdOTPForm && !searchPopup) ||
(!healthIDMapping && !searchPopup) ||
(searchDetails !== undefined &&
searchDetails !== null &&
searchDetails.data.length > 0)
"
>
{{ currentLanguageSet?.abhaDetails }}
</h4>
<h4 *ngIf="(healthIDMapping || enablehealthIdOTPForm) && !searchPopup">
<h4 *ngIf="healthIDMapping && !searchPopup">
{{ currentLanguageSet?.aBHACareContextMapping }}
</h4>
<button
Expand Down Expand Up @@ -105,7 +105,7 @@ <h4 *ngIf="(healthIDMapping || enablehealthIdOTPForm) && !searchPopup">
</section>
<section
class="table-responsive vw100"
*ngIf="!healthIDMapping && !enablehealthIdOTPForm && !searchPopup"
*ngIf="!healthIDMapping && !searchPopup"
>
<table
mat-table
Expand Down Expand Up @@ -195,7 +195,7 @@ <h4 *ngIf="(healthIDMapping || enablehealthIdOTPForm) && !searchPopup">
<!--Map health ID to care context-->
<section
class="table-responsive vw100"
*ngIf="healthIDMapping && !enablehealthIdOTPForm && !searchPopup"
*ngIf="healthIDMapping && !searchPopup"
>
<table
mat-table
Expand Down Expand Up @@ -289,12 +289,12 @@ <h4 *ngIf="(healthIDMapping || enablehealthIdOTPForm) && !searchPopup">
mat-raised-button
class="pull-right mat_blue button-overall-disabled background-overall"
color="primary"
(click)="generateOtpForMapping()"
(click)="linkCareContextV3()"
[disabled]="
selectedHealthID === undefined || selectedHealthID === null
"
Comment on lines +292 to 295

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ—„οΈ Data Integrity & Integration | 🟠 Major | ⚑ Quick win

Disable linking while the request is already in flight.

linkCareContextV3() sets showProgressBar, but this button stays enabled, so double-clicks can generate multiple tokens and send duplicate care-context link POSTs.

Proposed fix
-          (click)="linkCareContextV3()"
+          (click)="!showProgressBar && linkCareContextV3()"
           [disabled]="
-            selectedHealthID === undefined || selectedHealthID === null
+            selectedHealthID === undefined || selectedHealthID === null || showProgressBar
           "
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(click)="linkCareContextV3()"
[disabled]="
selectedHealthID === undefined || selectedHealthID === null
"
(click)="!showProgressBar && linkCareContextV3()"
[disabled]="
selectedHealthID === undefined || selectedHealthID === null || showProgressBar
"
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/registrar/abha-components/health-id-display-modal/health-id-display-modal.component.html`
around lines 292 - 295, The link action in
health-id-display-modal.component.html remains clickable while
linkCareContextV3() is already running, which can trigger duplicate token
generation and repeated care-context link requests. Update the button’s disabled
condition to also reflect the in-flight state tracked by showProgressBar (or the
equivalent loading flag used by linkCareContextV3), so it stays disabled until
the request completes. Keep the existing selectedHealthID checks and use the
linkCareContextV3 method and showProgressBar state as the key references when
wiring the guard.

>
{{ currentLanguageSet?.generateOTP }}
{{ currentLanguageSet?.linkCareContext || 'Link Care Context' }}
</button>
</div>

Expand All @@ -308,54 +308,3 @@ <h4 *ngIf="(healthIDMapping || enablehealthIdOTPForm) && !searchPopup">
</section>
</section>
</div>
<!-- Entering OTP for Health ID Generation-->
<div
*ngIf="enablehealthIdOTPForm && !searchPopup"
class="col-xs-12 col-sm-12 container-fluid"
[formGroup]="healthIdOTPForm"
>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<mat-form-field [style.width]="'100%'">
<input
defaultNull
autocomplete="off"
required
matInput
type="text"
placeholder="{{ currentLanguageSet?.enterOTP }}"
formControlName="otp"
minlength="6"
maxlength="6"
(keypress)="numberOnly($event)"
required
/>
</mat-form-field>
</div>
<div class="col-sm-12 step-btn m-b-20" style="text-align: right">
<button
id="submitButton"
mat-raised-button
class="pull-right mat_blue"
type="accent"
color="accent"
[disabled]="!healthIdOTPForm.valid || !checkOTP()"
(click)="verifyOtp()"
>
{{ currentLanguageSet?.common?.submit }}
</button>
<button
id="cancelButton"
mat-raised-button
type="button"
style="margin-right: 3px;"
color="primary"
class="pull-right mat_blue"
(click)="resendOtp()"
>
{{ currentLanguageSet?.resendOTP }}
</button>

</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import { Component, DoCheck, Inject, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { DatePipe } from '@angular/common';
import {
MAT_DIALOG_DATA,
Expand Down Expand Up @@ -82,11 +81,8 @@
currentLanguageSet: any;
healthIDMapped: any;
benDetails: any;
enablehealthIdOTPForm = false;
healthIDMapping = false;
transactionId: any;
selectedHealthID: any;
healthIdOTPForm!: FormGroup;
showProgressBar = false;
searchPopup = false;

Expand Down Expand Up @@ -121,12 +117,11 @@
public dialogRef: MatDialogRef<HealthIdDisplayModalComponent>,
@Inject(MAT_DIALOG_DATA) public input: any,
public httpServiceService: HttpServiceService,
private formBuilder: FormBuilder,
private registrarService: RegistrarService,
private confirmationService: ConfirmationService,
private datePipe: DatePipe,
private dialogMd: MatDialog,
private sessionstorage:SessionStorageService,
private sessionstorage: SessionStorageService,
) {
dialogRef.disableClose = true;
}
Expand Down Expand Up @@ -159,7 +154,6 @@
this.benDetails = this.input.dataList.data.BenHealthDetails;
console.log("this.benDetails1",this.benDetails)
}
this.healthIdOTPForm = this.createOtpGenerationForm();
this.createList();
}
ngDoCheck() {
Expand All @@ -170,11 +164,6 @@
getLanguageJson.setLanguage();
this.currentLanguageSet = getLanguageJson.currentLanguageObject;
}
createOtpGenerationForm() {
return this.formBuilder.group({
otp: null,
});
}
createList() {
if (this.benDetails.length > 0) {
this.benDetails.forEach((healthID: any) => {
Expand All @@ -190,130 +179,124 @@
onRadioChange(data: any) {
this.selectedHealthID = data;
}
generateOtpForMapping() {
linkCareContextV3() {
this.showProgressBar = true;
const abdmFacilityId = this.sessionstorage.getItem("abdmFacilityId");
const abdmFacilityName = this.sessionstorage.getItem("abdmFacilityName");
const reqObj = {
healthID: this.selectedHealthID.healthId
? this.selectedHealthID.healthId
: null,
healthIdNumber: this.selectedHealthID.healthIdNumber
const abdmFacilityId = this.sessionstorage.getItem('abdmFacilityId');
const abdmFacilityName = this.sessionstorage.getItem('abdmFacilityName');
const tokenReqObj = {
abhaNumber: this.selectedHealthID.healthIdNumber
? this.selectedHealthID.healthIdNumber
: null,
authenticationMode: this.selectedHealthID.authenticationMode,
abdmFacilityId: (abdmFacilityId !== null && abdmFacilityId !== undefined && abdmFacilityId !== "") ? abdmFacilityId : null,
abdmFacilityName: (abdmFacilityName !== null && abdmFacilityName !== undefined && abdmFacilityName !== "") ? abdmFacilityName : null
};
this.registrarService.generateOtpForMappingCareContext(reqObj).subscribe(
(receivedOtpResponse: any) => {
if (receivedOtpResponse.statusCode === 200) {
this.showProgressBar = false;
this.confirmationService.alert(
this.currentLanguageSet.OTPSentToRegMobNo,
'success',
);
this.transactionId = receivedOtpResponse.data.txnId;
this.enablehealthIdOTPForm = true;
} else {
this.confirmationService.alert(
receivedOtpResponse.errorMessage,
'error',
);
this.enablehealthIdOTPForm = false;
this.showProgressBar = false;
}
},
(err) => {
this.showProgressBar = false;
this.confirmationService.alert(err.errorMessage, 'error');
this.enablehealthIdOTPForm = false;
},
);
}
numberOnly(event: any): boolean {
const charCode = event.which ? event.which : event.keyCode;
if (charCode > 31 && (charCode < 48 || charCode > 57)) {
return false;
}
return true;
}
checkOTP() {
const otp = this.healthIdOTPForm.controls['otp'].value;
let cflag = false;
if (otp !== '' && otp !== undefined && otp !== null) {
const hid = otp;
if (hid.length >= 4 && hid.length <= 32) {
for (let i = 0; i < hid.length; i++) {
if (!this.is_numeric(hid.charAt(i))) {
cflag = true;
break;
}
}
if (cflag) return false;
} else return false;
} else return false;
return true;
}
isLetter(str: any) {
return str.length === 1 && str.match(/[a-z]/i);
}
is_numeric(str: any) {
return /^\d+$/.test(str);
}

verifyOtp() {
this.showProgressBar = true;
const abdmFacilityId = this.sessionstorage.getItem("abdmFacilityId");
const abdmFacilityName = this.sessionstorage.getItem("abdmFacilityName");
const verifyOtpData = {
otp: this.healthIdOTPForm.controls['otp'].value,
txnId: this.transactionId,
beneficiaryID: this.selectedHealthID.beneficiaryRegID,
healthID: this.selectedHealthID.healthId
abhaAddress: this.selectedHealthID.healthId
? this.selectedHealthID.healthId
: null,
healthIdNumber: this.selectedHealthID.healthIdNumber
? this.selectedHealthID.healthIdNumber
name: this.selectedHealthID.name ? this.selectedHealthID.name : null,
gender: this.selectedHealthID.gender
? this.selectedHealthID.gender
: null,
visitCode: this.input.visitCode,
visitCategory:
this.sessionstorage.getItem('visitCategory') === 'General OPD (QC)'
? 'Emergency'
: this.sessionstorage.getItem('visitCategory'),
abdmFacilityId: (abdmFacilityId !== null && abdmFacilityId !== undefined && abdmFacilityId !== "") ? abdmFacilityId : null,
abdmFacilityName: (abdmFacilityName !== null && abdmFacilityName !== undefined && abdmFacilityName !== "") ? abdmFacilityName : null
yearOfBirth: this.selectedHealthID.yearOfBirth
? parseInt(this.selectedHealthID.yearOfBirth, 10)

Check warning on line 198 in src/registrar/abha-components/health-id-display-modal/health-id-display-modal.component.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `Number.parseInt` over `parseInt`.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Common-UI&issues=AZ74oePFePTq32QSFWnM&open=AZ74oePFePTq32QSFWnM&pullRequest=51
: null,
abdmFacilityId:
abdmFacilityId !== null &&
abdmFacilityId !== undefined &&
abdmFacilityId !== ''
? abdmFacilityId
: null,
};
this.registrarService
.verifyOtpForMappingCarecontext(verifyOtpData)
.generateLinkTokenForCareContext(tokenReqObj)
.subscribe(
(verifiedMappingData: any) => {
if (verifiedMappingData.statusCode === 200) {
this.showProgressBar = false;
this.confirmationService.alert(
verifiedMappingData.data.response,
'success',
(tokenResponse: any) => {

Check failure on line 210 in src/registrar/abha-components/health-id-display-modal/health-id-display-modal.component.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 17 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=PSMRI_Common-UI&issues=AZ74oePFePTq32QSFWnN&open=AZ74oePFePTq32QSFWnN&pullRequest=51
if (tokenResponse.statusCode === 200 && tokenResponse.data) {
const linkToken =
tokenResponse.data['X-LINK-TOKEN'] ||
tokenResponse.data['linkToken'];
if (!linkToken) {
this.showProgressBar = false;
this.confirmationService.alert(
tokenResponse.data['error'] ||
'Failed to generate link token',
'error',
);
return;
}
const visitCategory =
this.sessionstorage.getItem('visitCategory') ===
'General OPD (QC)'
? 'Emergency'
: this.sessionstorage.getItem('visitCategory');
const linkReqObj = {
beneficiaryID: this.selectedHealthID.beneficiaryRegID,
abhaAddress: this.selectedHealthID.healthId
? this.selectedHealthID.healthId
: null,
abhaNumber: this.selectedHealthID.healthIdNumber
? this.selectedHealthID.healthIdNumber
: null,
linkToken: linkToken,
requestId: tokenResponse.data['requestId'] || null,
visitCode: this.input.visitCode,
visitCategory: visitCategory,
abdmFacilityId:
abdmFacilityId !== null &&
abdmFacilityId !== undefined &&
abdmFacilityId !== ''
? abdmFacilityId
: null,
abdmFacilityName:
abdmFacilityName !== null &&
abdmFacilityName !== undefined &&
abdmFacilityName !== ''
? abdmFacilityName
: null,
};
this.registrarService.linkCareContextV3(linkReqObj).subscribe(
(linkResponse: any) => {
this.showProgressBar = false;
if (
linkResponse.statusCode === 200 &&
linkResponse.data?.message
) {
this.confirmationService.alert(
linkResponse.data.message,
'success',
);
this.closeDialog();
} else {
this.confirmationService.alert(
linkResponse.errorMessage ||
linkResponse.data?.error ||
'Failed to link care context',
'error',
);
}
},
(err: any) => {
this.showProgressBar = false;
this.confirmationService.alert(
err.errorMessage || 'Failed to link care context',
'error',
);
},
);
this.closeDialog();
} else {
this.showProgressBar = false;
this.confirmationService.alert(
verifiedMappingData.errorMessage,
tokenResponse.errorMessage || 'Failed to generate link token',
'error',
);
}
},
(err) => {
(err: any) => {
this.showProgressBar = false;
this.confirmationService.alert(err.errorMessage, 'error');
this.confirmationService.alert(
err.errorMessage || 'Failed to generate link token',
'error',
);
},
);
}
resendOtp() {
this.healthIdOTPForm.controls['otp'].reset;
this.healthIdOTPForm.controls['otp'].patchValue(null);
this.generateOtpForMapping();
}
closeDialog() {
this.dialogRef.close();
}
Expand Down
Loading
Loading