Skip to content
Open
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
314 changes: 178 additions & 136 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"@angular/core": "^16.2.0",
"@angular/forms": "^16.2.0",
"@angular/material": "^16.2.12",
"@angular/material-moment-adapter": "^18.2.3",
"@angular/material-moment-adapter": "^16.2.12",
"@angular/platform-browser": "^16.2.0",
"@angular/platform-browser-dynamic": "^16.2.0",
"@angular/router": "^16.2.0",
Expand All @@ -54,7 +54,7 @@
"ng-cryptostore": "^16.0.0",
"ng2-charts": "^5.0.4",
"ng2-completer": "^9.0.1",
"ngx-bootstrap": "^12.0.0",
"ngx-bootstrap": "^11.0.0",
"ngx-cookie-service": "^16.1.0",
"ngx-pagination": "^6.0.3",
"ngx-webcam": "^0.4.1",
Expand Down
10 changes: 9 additions & 1 deletion src/app/app-modules/core/services/http-interceptor.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@
catchError((error: HttpErrorResponse) => {
console.error(error);

if (isLoginRequest) {
return throwError(() => error.error || error);
}
Comment on lines +112 to +114
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find error handlers that access errorMessage directly on the error object
rg -n --type=ts -C2 '\.subscribe\s*\(' | rg -A5 'error.*errorMessage'

Repository: PSMRI/HWC-UI

Length of output: 38


🏁 Script executed:

# First, let's check if set-password.component.ts exists and examine lines 138-141
fd -t f 'set-password.component.ts'

Repository: PSMRI/HWC-UI

Length of output: 175


🏁 Script executed:

# Search for errorMessage references across the codebase
rg -n 'errorMessage' --type=ts -B2 -A2

Repository: PSMRI/HWC-UI

Length of output: 50368


🏁 Script executed:

# Look at the http-interceptor.service.ts file to understand the error handling context
fd -t f 'http-interceptor.service.ts'

Repository: PSMRI/HWC-UI

Length of output: 117


🏁 Script executed:

# Read set-password.component.ts, focusing on lines 138-141
wc -l src/app/user-login/set-password/set-password.component.ts

Repository: PSMRI/HWC-UI

Length of output: 117


🏁 Script executed:

# Read http-interceptor.service.ts around lines 112-114
wc -l src/app/app-modules/core/services/http-interceptor.service.ts

Repository: PSMRI/HWC-UI

Length of output: 121


🏁 Script executed:

# Check set-password.component.ts around lines 138-141
sed -n '130,150p' src/app/user-login/set-password/set-password.component.ts

Repository: PSMRI/HWC-UI

Length of output: 742


🏁 Script executed:

# Check http-interceptor.service.ts around lines 112-114 for context
sed -n '100,125p' src/app/app-modules/core/services/http-interceptor.service.ts

Repository: PSMRI/HWC-UI

Length of output: 822


🏁 Script executed:

# Look at broader context in http-interceptor.service.ts to see how errors are handled
sed -n '1,50p' src/app/app-modules/core/services/http-interceptor.service.ts

Repository: PSMRI/HWC-UI

Length of output: 1764


🏁 Script executed:

# Check the full error handling and what the API actually returns
sed -n '100,150p' src/app/app-modules/core/services/http-interceptor.service.ts

Repository: PSMRI/HWC-UI

Length of output: 1476


🏁 Script executed:

# Let's see the full context of set-password.component.ts to understand the flow
cat -n src/app/user-login/set-password/set-password.component.ts

Repository: PSMRI/HWC-UI

Length of output: 6105


🏁 Script executed:

# Search for any response/error object structure definitions or types
rg -n 'interface.*Error|interface.*Response' --type=ts | head -20

Repository: PSMRI/HWC-UI

Length of output: 38


🏁 Script executed:

# Check if there's any error transformation or mapping happening elsewhere
rg -n 'error\.error.*errorMessage|errorMessage.*error\.error' --type=ts

Repository: PSMRI/HWC-UI

Length of output: 504


🏁 Script executed:

# Look at actual error scenarios in the interceptor to see if error.error structure is defined anywhere
rg -n 'error\.error' src/app/app-modules/core/services/http-interceptor.service.ts -B2 -A2

Repository: PSMRI/HWC-UI

Length of output: 588


🏁 Script executed:

# Let's look at the onSuccess/onError method more carefully to understand the error handling pattern
sed -n '160,200p' src/app/app-modules/core/services/http-interceptor.service.ts

Repository: PSMRI/HWC-UI

Length of output: 1342


🏁 Script executed:

# Check the login.component.ts error handling to see how it deals with the error shape
sed -n '290,315p' src/app/user-login/login/login.component.ts

Repository: PSMRI/HWC-UI

Length of output: 719


🏁 Script executed:

# Check how other components handle errors from setNewPassword or similar auth service calls
rg -n 'setNewPassword|authService' src/app/user-login/set-password/set-password.component.ts -B2 -A2

Repository: PSMRI/HWC-UI

Length of output: 1049


🏁 Script executed:

# Look for any error response body structure in auth service
fd -t f 'auth.service.ts' | head -5

Repository: PSMRI/HWC-UI

Length of output: 105


🏁 Script executed:

# Check if there are any HTTP error interceptor tests or docs that show expected error structure
fd -t f -i '*spec.ts' | xargs grep -l 'HttpInterceptor\|error\.error' 2>/dev/null | head -3

Repository: PSMRI/HWC-UI

Length of output: 343


🏁 Script executed:

# Let's examine the auth.service.ts to see how setNewPassword is implemented
cat -n src/app/app-modules/core/services/auth.service.ts | grep -A 15 'setNewPassword'

Repository: PSMRI/HWC-UI

Length of output: 654


🏁 Script executed:

# Check what the backend typically returns for errors by looking at successful responses structure
rg -n 'statusCode.*200\|errorMessage' src/app/app-modules/nurse-doctor/shared/mocks/mock-data.ts | head -10

Repository: PSMRI/HWC-UI

Length of output: 38


🏁 Script executed:

# Let's verify what setNewPassword actually returns by checking if there are any test fixtures or API documentation
rg -n 'setNewPassword' --type=ts -B5 -A10 | head -40

Repository: PSMRI/HWC-UI

Length of output: 3728


🏁 Script executed:

# Check how the error interceptor is being used in login component to see if there's a pattern difference
sed -n '280,320p' src/app/user-login/login/login.component.ts

Repository: PSMRI/HWC-UI

Length of output: 1106


🏁 Script executed:

# Check if setNewPassword endpoint is marked as a login request in the interceptor
rg -n 'isLoginRequest\|setForgetPassword\|setNewPassword' src/app/app-modules/core/services/http-interceptor.service.ts -B3 -A3

Repository: PSMRI/HWC-UI

Length of output: 38


🏁 Script executed:

# Look at what endpoints are considered login requests
sed -n '50,100p' src/app/app-modules/core/services/http-interceptor.service.ts

Repository: PSMRI/HWC-UI

Length of output: 1664


🏁 Script executed:

# Let's check the full error handling in http-interceptor to see all error paths
sed -n '105,145p' src/app/app-modules/core/services/http-interceptor.service.ts

Repository: PSMRI/HWC-UI

Length of output: 1242


🏁 Script executed:

# Let me verify if setNewPassword is marked as a login request
rg -n 'user/userAuthenticate\|setForgetPassword' src/app/app-modules/core/services/http-interceptor.service.ts

Repository: PSMRI/HWC-UI

Length of output: 38


🏁 Script executed:

# Check the full intercept logic to understand both error paths
sed -n '59,75p' src/app/app-modules/core/services/http-interceptor.service.ts

Repository: PSMRI/HWC-UI

Length of output: 553


Add defensive error extraction in set-password.component's error handler.

The error handler at line 140 directly accesses error.errorMessage, but the interceptor returns error.error || error without guaranteeing errorMessage exists. If error.error is falsy, the raw HttpErrorResponse is thrown (which lacks errorMessage). Use defensive extraction like login.component.ts (lines 295-315) to safely handle missing or nested error messages:

Example pattern:
private getErrorMessage(error: any): string {
  if (error?.errorMessage && typeof error.errorMessage === 'string') {
    return error.errorMessage;
  }
  if (error?.error?.errorMessage && typeof error.error.errorMessage === 'string') {
    return error.error.errorMessage;
  }
  return 'Password update failed. Please try again.';
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/app-modules/core/services/http-interceptor.service.ts` around lines
112 - 114, The set-password component's error handler assumes error.errorMessage
exists but the interceptor (HttpInterceptorService) can emit either error.error
or the raw HttpErrorResponse, so add a defensive extractor (e.g., a private
getErrorMessage(error: any): string in SetPasswordComponent) that checks
error?.errorMessage, then error?.error?.errorMessage, and falls back to a
default message; replace direct access to error.errorMessage in the component's
subscription/error handler with a call to this helper to safely derive the
displayed message.


let sessionExpired = false;

if (!this.isHandlingSessionExpiry) {
Expand All @@ -133,7 +137,7 @@
return EMPTY;
}

return throwError(error);
return throwError(() => error.error || error);
}),

finalize(() => {
Expand All @@ -149,6 +153,10 @@
return this.isHandlingSessionExpiry;
}

private isLoginRequest(url: string): boolean {
return url.indexOf('user/userAuthenticate') >= 0;

Check warning on line 157 in src/app/app-modules/core/services/http-interceptor.service.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use `.includes()`, rather than `.indexOf()`, when checking for existence.

See more on https://sonarcloud.io/project/issues?id=PSMRI_HWC-UI-NEXT&issues=AZ0Jo6Aont4r1UpcBlQ-&open=AZ0Jo6Aont4r1UpcBlQ-&pullRequest=263
}

private getErrorMessage(error: any): string {
try {
if (typeof error === 'string') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ export class DoctorWorklistComponent implements OnInit, DoCheck, OnDestroy {
}

redirectToCHOReport() {
const token = JSON.parse(
this.sessionstorage.getItem('loginDataResponse'),
)?.dhistoken;
const loginDataResponse =
this.sessionstorage.getItem('loginDataResponse') ?? 'null';
const token = JSON.parse(loginDataResponse)?.dhistoken;

const url = `${environment.dhisURL}${token}`;

Expand Down
11 changes: 11 additions & 0 deletions src/app/app-modules/registrar/shared/services/registrar.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,17 @@ export class RegistrarService {
getHealthIdDetails(reqObj: any) {
return this.http.post(environment.gethealthIdDetailsUrl, reqObj);
}

getMappedFacility(workLocationId: any) {
return this.http.get(
`${environment.getAbdmMappedFacility}${workLocationId}`,
);
}

saveAbdmFacilityForVisit(reqObj: any) {
return this.http.post(environment.saveAbdmFacilityIdForVisit, reqObj);
}

generateOtpForMappingCareContext(reqObjForMapping: any) {
return this.http.post(
environment.careContextGenerateOtpUrl,
Expand Down
149 changes: 91 additions & 58 deletions src/app/user-login/login/login.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,80 +207,113 @@
.userLogoutPreviousSession(
this.loginForm.controls.userName.value,
)
.subscribe((userlogoutPreviousSession: any) => {
if (userlogoutPreviousSession.statusCode === 200) {
this.authService
.login(
this.loginForm.controls.userName.value,
encryptPassword,
true,
this.enableCaptcha
? this.captchaToken
: undefined,
)
.subscribe((userLoggedIn: any) => {
if (userLoggedIn.statusCode === 200) {
if (userLoggedIn?.data?.previlegeObj[0]) {
this.sessionstorage.setItem(
'loginDataResponse',
JSON.stringify(userLoggedIn.data),
);
this.trackingService.setUserId(
userLoggedIn.data.userID,
);
this.authService.sessionExpiredHandled =
false;
this.sessionstorage.setItem(
'loginDataResponse',
JSON.stringify(userLoggedIn.data),
);
this.getServicesAuthdetails(
userLoggedIn.data,
);
} else {
this.resetCaptcha();
this.confirmationService.alert(
'Seems you are logged in from somewhere else, Logout from there & try back in.',
'error',
);
}
} else {
this.resetCaptcha();
this.confirmationService.alert(
userLoggedIn.errorMessage,
'error',
);
}
});
} else {
this.resetCaptcha();
this.confirmationService.alert(
userlogoutPreviousSession.errorMessage,
'error',
);
}
});
.subscribe(
(userlogoutPreviousSession: any) => {
if (userlogoutPreviousSession.statusCode === 200) {
this.authService
.login(
this.loginForm.controls.userName.value,
encryptPassword,
true,
this.enableCaptcha
? this.captchaToken
: undefined,
)
.subscribe(
(userLoggedIn: any) => {

Check failure on line 223 in src/app/user-login/login/login.component.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest functions more than 4 levels deep.

See more on https://sonarcloud.io/project/issues?id=PSMRI_HWC-UI-NEXT&issues=AZ0Jo6EAnt4r1UpcBlQ_&open=AZ0Jo6EAnt4r1UpcBlQ_&pullRequest=263
if (userLoggedIn.statusCode === 200) {
if (userLoggedIn?.data?.previlegeObj[0]) {
this.sessionstorage.setItem(
'loginDataResponse',
JSON.stringify(userLoggedIn.data),
);
this.trackingService.setUserId(
userLoggedIn.data.userID,
);
this.authService.sessionExpiredHandled =
false;
this.sessionstorage.setItem(
'loginDataResponse',
JSON.stringify(userLoggedIn.data),
);
Comment on lines +226 to +238
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.

⚠️ Potential issue | 🟡 Minor

Duplicate session storage write.

loginDataResponse is stored twice (lines 226-228 and 235-238). Remove one of the duplicates.

🧹 Proposed fix
                                      if (userLoggedIn?.data?.previlegeObj[0]) {
-                                        this.sessionstorage.setItem(
-                                          'loginDataResponse',
-                                          JSON.stringify(userLoggedIn.data),
-                                        );
                                        this.trackingService.setUserId(
                                          userLoggedIn.data.userID,
                                        );
                                        this.authService.sessionExpiredHandled =
                                          false;
                                        this.sessionstorage.setItem(
                                          'loginDataResponse',
                                          JSON.stringify(userLoggedIn.data),
                                        );
📝 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
this.sessionstorage.setItem(
'loginDataResponse',
JSON.stringify(userLoggedIn.data),
);
this.trackingService.setUserId(
userLoggedIn.data.userID,
);
this.authService.sessionExpiredHandled =
false;
this.sessionstorage.setItem(
'loginDataResponse',
JSON.stringify(userLoggedIn.data),
);
this.trackingService.setUserId(
userLoggedIn.data.userID,
);
this.authService.sessionExpiredHandled =
false;
this.sessionstorage.setItem(
'loginDataResponse',
JSON.stringify(userLoggedIn.data),
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/user-login/login/login.component.ts` around lines 226 - 238, Remove
the duplicate sessionStorage write for 'loginDataResponse' by deleting the
redundant call to this.sessionstorage.setItem('loginDataResponse',
JSON.stringify(userLoggedIn.data)); so that only one storage write remains (keep
the single call that logically fits alongside
trackingService.setUserId(userLoggedIn.data.userID) and
this.authService.sessionExpiredHandled = false). Ensure the remaining call uses
JSON.stringify(userLoggedIn.data) and keep the surrounding statements unchanged.

this.getServicesAuthdetails(
userLoggedIn.data,
);
} else {
this.resetCaptcha();
this.confirmationService.alert(
'Seems you are logged in from somewhere else, Logout from there & try back in.',
'error',
);
}
} else {
this.resetCaptcha();
this.showLoginError(userLoggedIn);
}
},
(error) => {

Check failure on line 254 in src/app/user-login/login/login.component.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest functions more than 4 levels deep.

See more on https://sonarcloud.io/project/issues?id=PSMRI_HWC-UI-NEXT&issues=AZ0Jo6EAnt4r1UpcBlRA&open=AZ0Jo6EAnt4r1UpcBlRA&pullRequest=263
this.showLoginError(error);
},
);
} else {
this.showLoginError(userlogoutPreviousSession);
}
},
(error) => {
this.showLoginError(error);
},
);
} else {
this.resetCaptcha();
sessionStorage.clear();
this.router.navigate(['/login']);
this.confirmationService.alert(res.errorMessage, 'error');
this.showLoginError(res);
}
});
} else {
this.resetCaptcha();
this.confirmationService.alert(res.errorMessage, 'error');
this.showLoginError(res);
}
}
},
(err) => {
this.resetCaptcha();
this.confirmationService.alert(err, 'error');
this.showLoginError(err);
},
);
}
}

private showLoginError(error: any) {
this.resetCaptcha();
this.confirmationService.alert(this.getLoginErrorMessage(error), 'error');
}

private getLoginErrorMessage(error: any): string {
if (typeof error === 'string' && error.trim()) {
return error;
}

if (error?.errorMessage && typeof error.errorMessage === 'string') {
return error.errorMessage;
}

if (error?.message && typeof error.message === 'string') {
return error.message;
}

if (
error?.error?.errorMessage &&
typeof error.error.errorMessage === 'string'
) {
return error.error.errorMessage;
}

if (error?.error?.message && typeof error.error.message === 'string') {
return error.error.message;
}

return 'Unable to login. Please try again.';
}

getServicesAuthdetails(loginDataResponse: any) {
const userName: any = this.loginForm.controls.userName.value;
sessionStorage.setItem('key', loginDataResponse.key);
Expand Down
3 changes: 2 additions & 1 deletion src/app/user-login/service/service.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ export class ServiceComponent implements OnInit, DoCheck {
const serviceProviderId: any =
this.sessionstorage.getItem('providerServiceID');
const userId: any = this.sessionstorage.getItem('userID');
const loginData = this.sessionstorage.getItem('loginDataResponse');
const loginData =
this.sessionstorage.getItem('loginDataResponse') ?? '{}';
const parsedLoginData = JSON.parse(loginData);
const designation = parsedLoginData.designation?.designationName;
this.servicePointService
Expand Down
1 change: 0 additions & 1 deletion src/environments/environment.local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,6 @@ export const environment = {
siteKey: siteKey,
captchaChallengeURL: captchaChallengeURL,
enableCaptcha: enableCaptcha,
getUserId: `${COMMON_API}user/userName/`,
enableCHOReportBtn: enableCHOReportBtn,
dhisURL: dhisURL,
elasticSearchUrl: `${HWC_API}registrar/quickSearchES`,
Expand Down
8 changes: 8 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"paths": {
"Common-UI/*": [
"Common-UI/*"
],
"Common-UI/src/*": [
"Common-UI/src/*"
]
},
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
Expand Down