Release 3.6.1 to main#268
Conversation
* fix(bug): saving abdm facilityid in session storage * fix(bug): saving abdm facilityid in session storage * feat: abdm M2 V3 * feat: latest common-ui commit --------- Co-authored-by: Karyamsetty Helen Grace <ka40094929@wipro.com>
* fix(bug): saving abdm facilityid in session storage * fix(bug): saving abdm facilityid in session storage * feat: abdm M2 V3 * feat: latest common-ui commit * feat: added abha m2 APIs --------- Co-authored-by: Karyamsetty Helen Grace <ka40094929@wipro.com>
Amm 1811
* feat: amm-1811 edge cases handled * fix: amm:1307 healthId, healthIdNumber mismatch issue fix
* fix(bug): saving abdm facilityid in session storage * fix(bug): saving abdm facilityid in session storage * feat: abdm M2 V3 * feat: latest common-ui commit * feat: added abha m2 APIs * fix: closed dialog after linking --------- Co-authored-by: Karyamsetty Helen Grace <ka40094929@wipro.com>
fix: amm-1990, 1985, 1972, 1982, 1989, 1983, 1987,1986
fix: amm-1986, 1990 - common-ui reference update and version update
Elastic search implementaion.
fix: comma was missing in ci file
Elastic seach API integration.
fix: pushing the common ui code of 3.6.1 to hwc ui
fix: pushed the common ui elastic search code to HWC UI
fix: amm-2038 addind common ui changes to hwc
fix: amm-2038 updated the advancesearch api end point
Sn/es/3.6.1
fix: amm-1931 JWT error handling issue
* fix: aam-2159 changed text from advancesearch to advanced search * fix: amm-1979 validation for prescription * Correct spelling in 'advanceBeneficiarySearch' --------- Co-authored-by: 5Amogh <amoghavarsh@navadhiti.com> Co-authored-by: Amoghavarsh <93114621+5Amogh@users.noreply.github.com>
fix: amm-2192 remove mandatory for prescription
|
📝 WalkthroughWalkthroughThis PR updates build version metadata, refactors HTTP session-expiry handling with explicit state management, threads a doctor signature flag through service APIs, removes HTML template required constraints from prescription fields, adds corresponding synchronous validation logic, and extends environment configurations with Elasticsearch and ABHA care-context API endpoints alongside comprehensive UI translation updates. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/environments/environment.prod.ts (1)
71-88:⚠️ Potential issue | 🟠 MajorUse the production ABHA suffix here before enabling the new prod ABHA flows.
Line 87 still sets
abhaExtensionto@sbx. With the new production ABHA/care-context endpoints in this file, that keeps prod traffic on the sandbox namespace and will break or mismatch ABHA identifiers in production. This should be@abdmforenvironment.prod.ts.Suggested fix
- abhaExtension: `@sbx`, + abhaExtension: `@abdm`,Based on learnings, in this project
abhaExtensionis set tosbxin development/test and toabdminenvironment.prod.tsfor production.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/environments/environment.prod.ts` around lines 71 - 88, The environment.prod.ts file's environment object wrongly sets abhaExtension to '@sbx' which keeps production ABHA identifiers in the sandbox namespace; update the environment constant's abhaExtension property (abhaExtension) to '@abdm' so production ABHA/care-context endpoints use the correct production suffix and avoid mismatched identifiers when prod ABHA flows are enabled.
🧹 Nitpick comments (6)
src/app/app-modules/registrar/family-tagging/create-family-tagging/create-family-tagging.component.html (1)
117-117: Consider moving inline styles to component stylesheet.The inline styles added to
<mat-dialog-actions>would be better maintained in the component's CSS file. This improves reusability and makes it easier to maintain consistent styling across the application.Additionally, the
pull-rightclass becomes redundant whendisplay: flexis applied, as flexbox layout ignores float-based positioning.♻️ Proposed refactor
In the component's CSS/SCSS file, add:
.dialog-actions-flex { display: flex; justify-content: flex-end; gap: 12px; }Then update the template:
- <mat-dialog-actions class="padding15 margin15 pull-right" style="display: flex;justify-content: flex-end;gap:12px"> + <mat-dialog-actions class="padding15 margin15 dialog-actions-flex">Minor formatting note: The inline style could use spaces after semicolons for consistency (
flex; justify-contentinstead offlex;justify-content).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/app-modules/registrar/family-tagging/create-family-tagging/create-family-tagging.component.html` at line 117, Move the inline styles from the <mat-dialog-actions> tag into the component stylesheet: create a reusable CSS class (e.g., dialog-actions-flex) in CreateFamilyTaggingComponent's stylesheet that sets display:flex, justify-content:flex-end and gap:12px, add that class to the <mat-dialog-actions> element and remove the inline style and the redundant pull-right class; ensure spacing/formatting in the stylesheet is consistent.src/app/app-modules/core/services/http-interceptor.service.ts (2)
152-184:getErrorMessagecan be simplified; also called with a plain string at L197.Three things worth cleaning up here:
- SonarCloud flags cognitive complexity 16 (>15) on this function.
- The happy path in
handleSessionExpiryalready buildserrorMessage: stringbefore callingthis.getErrorMessage(errorMessage)— the helper only guards empty/whitespace, which is cheap to inline.- The two
returnblocks producing the fallback string are duplicated between thetrypath and thecatchpath.A small extraction of the fallback and a narrower signature (
string | Error | { message?; errorMessage?; error? }) will make the function easier to follow and drop its complexity below the Sonar threshold.🤖 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 152 - 184, Refactor getErrorMessage to reduce complexity: extract the fallback string into a single constant used everywhere, narrow the parameter type to string | Error | { message?: string; errorMessage?: string; error?: string }, and remove the outer try/catch and duplicated return paths so the function simply checks types in order (string non-empty, then Error.message, then object.message/errorMessage/error) and returns the fallback if none match; then inline the trivial string-guard logic from handleSessionExpiry (i.e. don't call getErrorMessage with an already-built non-empty string) so callers only pass payloads that need parsing.
278-286: Minor cleanups flagged by SonarCloud.
- L278: prefer
url.includes('user/userAuthenticate')overindexOf(...) >= 0.- L282:
url && url.toLowerCase().includes('/platform-feedback')→url?.toLowerCase().includes('/platform-feedback').- L286:
sessionStorage.getItem('authenticationToken') ? true : false→!!sessionStorage.getItem('authenticationToken').- L65 (same file): same optional-chain suggestion as L282.
All behavior-preserving.
🤖 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 278 - 286, Update the URL and token checks in HttpInterceptorService: replace url.indexOf('user/userAuthenticate') >= 0 with url?.includes('user/userAuthenticate'); change url && url.toLowerCase().includes('/platform-feedback') to url?.toLowerCase().includes('/platform-feedback'); replace sessionStorage.getItem('authenticationToken') ? true : false with !!sessionStorage.getItem('authenticationToken'); also apply the same optional-chaining change noted at the earlier occurrence (around L65) where url is checked. These changes preserve behavior while using modern idioms for 'user/userAuthenticate', '/platform-feedback', and 'authenticationToken' checks.src/environments/environment.dev.ts (1)
577-580: Consider renaminggetUserIdtogetUserIdUrlfor consistency.The key
getUserIdholds a URL endpoint but uses different naming from neighbouring URL keys (downloadSignUrl,checkUsersignExistUrl,elasticSearchUrl,advanceElasticSearchUrl). Renaming togetUserIdUrlwould clarify it's a URL value and match the naming convention throughout the file.Note: All new keys (
isEnableES,generateLinkTokenForCareContext,linkCareContext,getUserId,checkUsersignExistUrl,elasticSearchUrl,advanceElasticSearchUrl) are properly present across all environment files (dev, development, local, prod, test, ci).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/environments/environment.dev.ts` around lines 577 - 580, Rename the key getUserId to getUserIdUrl to match the URL naming convention used nearby (e.g., downloadSignUrl, checkUsersignExistUrl, elasticSearchUrl) and update all references to this constant across the codebase (including other environment files and any imports/usages) so they point to getUserIdUrl; ensure the value remains `${COMMON_API}user/userName/` and that tests/builds are updated to reflect the new key.src/app/app-modules/nurse-doctor/shared/services/doctor.service.ts (2)
379-384: Inconsistent shape fordoctorSignatureFlaginpostQuickConsultDetailscompared with the other save methods.All other methods place
doctorSignatureFlagdirectly inside the main payload object (e.g., alongsidetcRequest,isSpecialistinNCDScreeningDetails,ancVisitDetails, etc.). Here it is merged via a separateObject.assignfragment. The result is functionally equivalent but the divergent shape is an easy source of future confusion when grepping/diffing payloads. Consider folding it intotempfor consistency.♻️ Proposed refactor
const temp = { beneficiaryRegID: this.sessionstorage.getItem('beneficiaryRegID'), ... tcRequest: tcRequest, isSpecialist: isSpecialist, + doctorSignatureFlag: doctorSignatureFlag, }; const quickConsultation = Object.assign( {}, consultationData.quickConsultation, temp, - { doctorSignatureFlag: doctorSignatureFlag }, );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/app-modules/nurse-doctor/shared/services/doctor.service.ts` around lines 379 - 384, The construction of quickConsultation in postQuickConsultDetails uses a separate Object.assign fragment for doctorSignatureFlag which makes the payload shape diverge from other save methods; instead fold doctorSignatureFlag into the same base object (e.g., merge it into temp or include it directly when building the main payload) so quickConsultation is built consistently (same top-level placement alongside tcRequest/isSpecialist). Update the code around quickConsultation and temp in postQuickConsultDetails to include doctorSignatureFlag in temp (or the primary payload creation) rather than as a separate Object.assign entry.
3990-3992: Guard against a missing/undefineduserIDand consider encoding.
environment.checkUsersignExistUrlends with a trailing/(e.g.…/signature1/signexist/), so ifuserIDis evernull/undefinedthis will silently hit…/signexist/undefinedand return a misleading response. Also, while currentuserIDis numeric, usingencodeURIComponentfuture-proofs the concatenation if the identifier shape ever changes.🛡️ Proposed hardening
- checkUsersignatureExist(userID: any) { - return this.http.get(environment.checkUsersignExistUrl + userID); - } + checkUsersignatureExist(userID: any) { + if (userID === null || userID === undefined || userID === '') { + return throwError(() => new Error('userID is required')); + } + return this.http.get( + environment.checkUsersignExistUrl + encodeURIComponent(String(userID)), + ); + }(Requires importing
throwErrorfromrxjsif adopted.)Also worth typing the response (e.g.
Observable<{ data: { signStatus: boolean } }>) sinceworkarea.component.tsreadsres.data.signStatus— it would give the call site compile-time safety.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/app-modules/nurse-doctor/shared/services/doctor.service.ts` around lines 3990 - 3992, checkUsersignatureExist currently concatenates userID directly which allows null/undefined to request ".../undefined" and misses URL-encoding; update the method checkUsersignatureExist(userID: any) to first validate userID (return an observable error via throwError if null/undefined) and then append encodeURIComponent(String(userID)) to environment.checkUsersignExistUrl; also add a typed return Observable matching the expected shape (e.g. Observable<{ data: { signStatus: boolean } }>) so callers reading res.data.signStatus get compile-time safety (import throwError from rxjs if using it).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/app/app-modules/core/services/http-interceptor.service.ts`:
- Around line 319-323: The session-warning message is hardcoded in
confirmationService.alert; replace the English literal with the i18n lookup used
elsewhere (e.g., use currentLanguageSet?.sessionAboutToExpire with a safe
fallback to currentLanguageSet?.sessionExpired or a default string) and remove
the stray space before the question mark; update the confirmationService.alert
call in http-interceptor.service.ts and add the new i18n key
(sessionAboutToExpire) to your translations so the prompt is localized
consistently.
- Around line 43-48: The router subscription currently calls resetSessionState()
on any router event with url === '/login', which races with
handleSessionExpiry() and allows duplicate dialogs; fix by preventing reset when
navigation was initiated by the expiry flow—add a boolean flag (e.g.,
isNavigatingAfterExpiry) set in handleSessionExpiry() before calling
router.navigate(['/login']) and check that flag in the router.events handler to
skip resetSessionState() when true, or alternately set logoutMessageShown = true
before router.navigate and only clear it on explicit login/logout; update
references to isHandlingSessionExpiry, logoutMessageShown,
handleSessionExpiry(), resetSessionState(), and ConfirmationService.alert
accordingly so a second concurrent 401/403 cannot reopen the dialog.
- Around line 354-366: extendSession currently swallows errors by returning
of(null) in the catchError and then always calling resetSessionTimeoutTimer() in
subscribe; change extendSession so that resetSessionTimeoutTimer() is only
called when the backend call actually succeeds: have the catchError rethrow or
return throwError (or return of a failure sentinel and check it), and in the
subscribe success handler call resetSessionTimeoutTimer() only for a successful
response (e.g., test for non-null/ok response), while handling errors in the
error handler (or finalize) to avoid extending the client timer when the server
rejected/invalidated the session; update the logic around
this.http.post(environment.extendSessionUrl, {}) / catchError(...) /
subscribe(...) accordingly.
In
`@src/app/app-modules/nurse-doctor/case-record/general-case-record/prescription/prescription.component.ts`:
- Around line 392-446: The alert heading and all hardcoded validation labels in
submitForUpload() / validateCurrentPrescription() should be replaced with i18n
keys from current_language_set (e.g., current_language_set?.Prescription or
other existing keys); update the heading string ('Please fill the following
required fields:') to use a language key such as
current_language_set?.Prescription?.mandatoryFields (or add that key), and
replace each error label ('Medicine Form', 'Medicine Name', 'Dosage',
'Frequency', 'Duration', 'Unit', 'Quantity') with the corresponding
current_language_set?.Prescription?.* entries (use
nurseData?.chiefComplaintsDetails?.* if appropriate for any shared labels) so
the confirmationService.alert(errorMessage, 'error') shows fully localized text;
ensure validateCurrentPrescription() builds its errors array with those i18n
values and submitForUpload() composes the numbered message from them.
In
`@src/app/app-modules/nurse-doctor/doctor-worklist/doctor-worklist.component.ts`:
- Around line 119-127: In redirectToCHOReport(), guard against missing or
invalid dhistoken by safely parsing
this.sessionstorage.getItem('loginDataResponse') (catch JSON.parse errors) and
verifying the extracted dhistoken is a non-empty string before constructing the
URL and calling window.open; if the token is missing/invalid, do not call
window.open and instead handle the case (e.g., log via a logger or show a
user-facing message) so you avoid opening `${environment.dhisURL}undefined`.
In `@src/assets/Assamese.json`:
- Line 1959: The Assamese translations object contains duplicate "selfcare"
keys, causing the later value to override the earlier one; locate both
"selfcare" entries and either remove the redundant one or rename one to a
context-specific key (e.g., "selfcare_profile" or "selfcare_section") so both
translations are preserved, then update any consumers to use the new key if you
rename it.
- Around line 1800-1802: The locale object contains duplicate keys
"hypertension", "breastCancer", and "cervicalCancer" (appearing twice), causing
the earlier entries to be overwritten; remove the duplicate entries so each
concept has a single canonical key, or if the duplicated values are intended for
different screens rename one set (e.g., hypertension_screen vs
hypertension_summary) to unique keys; update only the entries for
"hypertension", "breastCancer", and "cervicalCancer" (and the other duplicates
noted around the later section) to eliminate duplication and keep the correct
translated string for each unique key.
In `@src/assets/Hindi.json`:
- Around line 1905-1907: The JSON contains a duplicate key "immunizationService"
(two entries with different Hindi/English values); remove the duplicate and keep
the intended translation or rename one key to a distinct identifier (e.g.,
"immunizationServiceLabel" vs "immunizationServiceAlt") if they represent
different UI contexts, then update any consumers that read the key (components
or i18n lookup calls) to use the chosen/renamed key so no translation is
silently overwritten at runtime.
---
Outside diff comments:
In `@src/environments/environment.prod.ts`:
- Around line 71-88: The environment.prod.ts file's environment object wrongly
sets abhaExtension to '@sbx' which keeps production ABHA identifiers in the
sandbox namespace; update the environment constant's abhaExtension property
(abhaExtension) to '@abdm' so production ABHA/care-context endpoints use the
correct production suffix and avoid mismatched identifiers when prod ABHA flows
are enabled.
---
Nitpick comments:
In `@src/app/app-modules/core/services/http-interceptor.service.ts`:
- Around line 152-184: Refactor getErrorMessage to reduce complexity: extract
the fallback string into a single constant used everywhere, narrow the parameter
type to string | Error | { message?: string; errorMessage?: string; error?:
string }, and remove the outer try/catch and duplicated return paths so the
function simply checks types in order (string non-empty, then Error.message,
then object.message/errorMessage/error) and returns the fallback if none match;
then inline the trivial string-guard logic from handleSessionExpiry (i.e. don't
call getErrorMessage with an already-built non-empty string) so callers only
pass payloads that need parsing.
- Around line 278-286: Update the URL and token checks in
HttpInterceptorService: replace url.indexOf('user/userAuthenticate') >= 0 with
url?.includes('user/userAuthenticate'); change url &&
url.toLowerCase().includes('/platform-feedback') to
url?.toLowerCase().includes('/platform-feedback'); replace
sessionStorage.getItem('authenticationToken') ? true : false with
!!sessionStorage.getItem('authenticationToken'); also apply the same
optional-chaining change noted at the earlier occurrence (around L65) where url
is checked. These changes preserve behavior while using modern idioms for
'user/userAuthenticate', '/platform-feedback', and 'authenticationToken' checks.
In `@src/app/app-modules/nurse-doctor/shared/services/doctor.service.ts`:
- Around line 379-384: The construction of quickConsultation in
postQuickConsultDetails uses a separate Object.assign fragment for
doctorSignatureFlag which makes the payload shape diverge from other save
methods; instead fold doctorSignatureFlag into the same base object (e.g., merge
it into temp or include it directly when building the main payload) so
quickConsultation is built consistently (same top-level placement alongside
tcRequest/isSpecialist). Update the code around quickConsultation and temp in
postQuickConsultDetails to include doctorSignatureFlag in temp (or the primary
payload creation) rather than as a separate Object.assign entry.
- Around line 3990-3992: checkUsersignatureExist currently concatenates userID
directly which allows null/undefined to request ".../undefined" and misses
URL-encoding; update the method checkUsersignatureExist(userID: any) to first
validate userID (return an observable error via throwError if null/undefined)
and then append encodeURIComponent(String(userID)) to
environment.checkUsersignExistUrl; also add a typed return Observable matching
the expected shape (e.g. Observable<{ data: { signStatus: boolean } }>) so
callers reading res.data.signStatus get compile-time safety (import throwError
from rxjs if using it).
In
`@src/app/app-modules/registrar/family-tagging/create-family-tagging/create-family-tagging.component.html`:
- Line 117: Move the inline styles from the <mat-dialog-actions> tag into the
component stylesheet: create a reusable CSS class (e.g., dialog-actions-flex) in
CreateFamilyTaggingComponent's stylesheet that sets display:flex,
justify-content:flex-end and gap:12px, add that class to the
<mat-dialog-actions> element and remove the inline style and the redundant
pull-right class; ensure spacing/formatting in the stylesheet is consistent.
In `@src/environments/environment.dev.ts`:
- Around line 577-580: Rename the key getUserId to getUserIdUrl to match the URL
naming convention used nearby (e.g., downloadSignUrl, checkUsersignExistUrl,
elasticSearchUrl) and update all references to this constant across the codebase
(including other environment files and any imports/usages) so they point to
getUserIdUrl; ensure the value remains `${COMMON_API}user/userName/` and that
tests/builds are updated to reflect the new key.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fa8c2136-ab25-474a-ab7d-d75c38592ff8
📒 Files selected for processing (25)
Common-UIpom.xmlsrc/app/app-modules/core/services/confirmation.service.tssrc/app/app-modules/core/services/http-interceptor.service.tssrc/app/app-modules/lab/workarea/workarea.component.tssrc/app/app-modules/nurse-doctor/case-record/general-case-record/prescription/prescription.component.htmlsrc/app/app-modules/nurse-doctor/case-record/general-case-record/prescription/prescription.component.tssrc/app/app-modules/nurse-doctor/case-sheet/general-case-sheet/doctor-diagnosis-case-sheet/doctor-diagnosis-case-sheet.component.tssrc/app/app-modules/nurse-doctor/doctor-worklist/doctor-worklist.component.tssrc/app/app-modules/nurse-doctor/nurse-worklist-wrapper/nurse-worklist/nurse-worklist.component.tssrc/app/app-modules/nurse-doctor/quick-consult/quick-consult.component.htmlsrc/app/app-modules/nurse-doctor/shared/services/doctor.service.tssrc/app/app-modules/nurse-doctor/workarea/workarea.component.tssrc/app/app-modules/registrar/family-tagging/create-family-tagging/create-family-tagging.component.htmlsrc/assets/Assamese.jsonsrc/assets/English.jsonsrc/assets/Hindi.jsonsrc/assets/Kannada.jsonsrc/assets/language.jsonsrc/environments/environment.ci.ts.templatesrc/environments/environment.dev.tssrc/environments/environment.development.tssrc/environments/environment.local.tssrc/environments/environment.prod.tssrc/environments/environment.test.ts
💤 Files with no reviewable changes (2)
- src/app/app-modules/nurse-doctor/case-record/general-case-record/prescription/prescription.component.html
- src/app/app-modules/nurse-doctor/quick-consult/quick-consult.component.html
| this.router.events.subscribe((event: any) => { | ||
| if (event.url === '/login') { | ||
| this.resetSessionState(); | ||
| } | ||
| }); | ||
| } |
There was a problem hiding this comment.
Race between /login router event and the post-navigate dialog — duplicate "session expired" dialogs possible.
resetSessionState() is invoked on every router event whose url === '/login' (NavigationStart, RoutesRecognized, NavigationEnd, etc.), flipping both isHandlingSessionExpiry and logoutMessageShown back to false. The expiry flow runs:
catchErrorsetsisHandlingSessionExpiry = trueand callshandleSessionExpiry().handleSessionExpirytriggersrouter.navigate(['/login']).- Router events fire →
resetSessionState()runs → both flags cleared. - Navigation Promise
.thenfinally setslogoutMessageShown = trueand schedules the dialog after 300 ms.
Between step 3 and step 4 there is a window where any in-flight 401/403 (typical when several parallel requests fail simultaneously) will re-enter handleSessionExpiry and open a second dialog — ConfirmationService.alert has no dedup (see confirmation.service.ts L67-86), so both dialogs will stack on top of each other.
Two ways to close the hole:
- Skip
resetSessionState()when the navigation was initiated by the expiry flow (e.g. read athis.isNavigatingAfterExpiryflag), or - Set
logoutMessageShown = truebefore callingrouter.navigate, and only clear state on a real login success / user-initiated logout rather than on every/loginURL visit.
🔒 Sketch of one fix
private handleSessionExpiry(errorMessage: string): void {
if (this.isHandlingSessionExpiry && this.logoutMessageShown) {
return;
}
this.isHandlingSessionExpiry = true;
+ this.logoutMessageShown = true; // claim dialog slot before navigating
this.clearSessionTimeoutTimer();
sessionStorage.clear();
this.sessionstorage.clear();
const displayMessage = this.getErrorMessage(errorMessage);
try {
this.router
.navigate(['/login'])
.then((navigated: boolean) => {
if (!navigated) {
console.error('Navigation to login failed');
}
- if (!this.logoutMessageShown) {
- this.logoutMessageShown = true;
- setTimeout(() => {
+ setTimeout(() => {
try {
this.confirmationService
.alert(displayMessage, 'error')
.afterClosed()
.subscribe(
() => {
console.log('Session expiry dialog closed');
},
(dialogError: any) => {
console.error('Error in dialog:', dialogError);
},
);
} catch (dialogErr) {
console.error(
'Failed to show session expiry dialog:',
dialogErr,
);
}
- }, 300);
- }
+ }, 300);
})And narrow the router subscription so it only resets on a real login, not every visit:
- this.router.events.subscribe((event: any) => {
- if (event.url === '/login') {
- this.resetSessionState();
- }
- });
+ // Reset is driven by successful login response in `onSuccess`
+ // (already handled via `isLoginRequest && event.status === 200`).Also applies to: 186-237
🤖 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
43 - 48, The router subscription currently calls resetSessionState() on any
router event with url === '/login', which races with handleSessionExpiry() and
allows duplicate dialogs; fix by preventing reset when navigation was initiated
by the expiry flow—add a boolean flag (e.g., isNavigatingAfterExpiry) set in
handleSessionExpiry() before calling router.navigate(['/login']) and check that
flag in the router.events handler to skip resetSessionState() when true, or
alternately set logoutMessageShown = true before router.navigate and only clear
it on explicit login/logout; update references to isHandlingSessionExpiry,
logoutMessageShown, handleSessionExpiry(), resetSessionState(), and
ConfirmationService.alert accordingly so a second concurrent 401/403 cannot
reopen the dialog.
| this.confirmationService | ||
| .alert( | ||
| 'Your session is about to Expire. Do you need more time ? ', | ||
| 'sessionTimeOut', | ||
| ) |
There was a problem hiding this comment.
Hardcoded English in the session-about-to-expire prompt.
The "timeout"/"error" branches below use currentLanguageSet?.sessionExpired fallbacks, but the primary prompt on line 321 is an English-only literal (and also has a stray space before ?). Align with the rest of the service and add an i18n key with a safe fallback.
🌐 Suggested fix
this.confirmationService
.alert(
- 'Your session is about to Expire. Do you need more time ? ',
- 'sessionTimeOut',
+ this.currentLanguageSet?.sessionAboutToExpire ||
+ 'Your session is about to expire. Do you need more time?',
+ 'sessionTimeOut',
)📝 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.
| this.confirmationService | |
| .alert( | |
| 'Your session is about to Expire. Do you need more time ? ', | |
| 'sessionTimeOut', | |
| ) | |
| this.confirmationService | |
| .alert( | |
| this.currentLanguageSet?.sessionAboutToExpire || | |
| 'Your session is about to expire. Do you need more time?', | |
| 'sessionTimeOut', | |
| ) |
🤖 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
319 - 323, The session-warning message is hardcoded in
confirmationService.alert; replace the English literal with the i18n lookup used
elsewhere (e.g., use currentLanguageSet?.sessionAboutToExpire with a safe
fallback to currentLanguageSet?.sessionExpired or a default string) and remove
the stray space before the question mark; update the confirmationService.alert
call in http-interceptor.service.ts and add the new i18n key
(sessionAboutToExpire) to your translations so the prompt is localized
consistently.
| private extendSession(): void { | ||
| this.http | ||
| .post(environment.extendSessionUrl, {}) | ||
| .pipe( | ||
| catchError((error: any) => { | ||
| console.error('Failed to extend session:', error); | ||
| return of(null); | ||
| }), | ||
| ) | ||
| .subscribe(() => { | ||
| this.resetSessionTimeoutTimer(); | ||
| }); | ||
| } |
There was a problem hiding this comment.
extendSession silently extends the timer even when the backend call fails.
catchError returns of(null) and the subscribe unconditionally runs resetSessionTimeoutTimer(). If the extend endpoint returns 4xx/5xx (or the token has already been invalidated server-side), the client will keep scheduling another 27‑minute window as if the session was renewed — the user keeps working until the next authenticated call 401s, at which point all their in-progress input is lost.
🛡️ Suggested fix
private extendSession(): void {
- this.http
- .post(environment.extendSessionUrl, {})
- .pipe(
- catchError((error: any) => {
- console.error('Failed to extend session:', error);
- return of(null);
- }),
- )
- .subscribe(() => {
- this.resetSessionTimeoutTimer();
- });
+ this.http.post(environment.extendSessionUrl, {}).subscribe({
+ next: () => this.resetSessionTimeoutTimer(),
+ error: (err: any) => {
+ console.error('Failed to extend session:', err);
+ // Treat as expiry; let the standard flow surface the message.
+ this.handleSessionExpiry(
+ this.currentLanguageSet?.sessionExpiredPleaseLogin ||
+ 'Session has expired, please login 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
354 - 366, extendSession currently swallows errors by returning of(null) in the
catchError and then always calling resetSessionTimeoutTimer() in subscribe;
change extendSession so that resetSessionTimeoutTimer() is only called when the
backend call actually succeeds: have the catchError rethrow or return throwError
(or return of a failure sentinel and check it), and in the subscribe success
handler call resetSessionTimeoutTimer() only for a successful response (e.g.,
test for non-null/ok response), while handling errors in the error handler (or
finalize) to avoid extending the client timer when the server
rejected/invalidated the session; update the logic around
this.http.post(environment.extendSessionUrl, {}) / catchError(...) /
subscribe(...) accordingly.
| submitForUpload() { | ||
| const validationErrors = this.validateCurrentPrescription(); | ||
|
|
||
| if (validationErrors.length > 0) { | ||
| const errorMessage = | ||
| 'Please fill the following required fields:\n' + | ||
| validationErrors.map((e, i) => `${i + 1}. ${e}`).join('\n'); | ||
| this.confirmationService.alert(errorMessage, 'error'); | ||
| return; | ||
| } | ||
|
|
||
| this.addMedicine(); | ||
| this.clearCurrentaddDetails(); | ||
| } | ||
|
|
||
| validateCurrentPrescription(): string[] { | ||
| const errors: string[] = []; | ||
|
|
||
| if (!this.currentPrescription.formName) { | ||
| errors.push('Medicine Form'); | ||
| } | ||
| if (!this.currentPrescription.drugName || !this.tempDrugName) { | ||
| errors.push('Medicine Name'); | ||
| } | ||
| if (!this.currentPrescription.dose) { | ||
| errors.push('Dosage'); | ||
| } | ||
| if (!this.currentPrescription.frequency) { | ||
| errors.push('Frequency'); | ||
| } | ||
|
|
||
| // Conditional validations | ||
| if ( | ||
| this.currentPrescription.frequency && | ||
| this.currentPrescription.frequency !== 'SOS' | ||
| ) { | ||
| if (!this.currentPrescription.duration) { | ||
| errors.push('Duration'); | ||
| } | ||
| if (!this.currentPrescription.unit) { | ||
| errors.push('Unit'); | ||
| } | ||
| } | ||
|
|
||
| // Quantity required for non-liquid forms | ||
| if ( | ||
| this.currentPrescription.formID && | ||
| this.currentPrescription.formID > 2 && | ||
| !this.currentPrescription.qtyPrescribed | ||
| ) { | ||
| errors.push('Quantity'); | ||
| } | ||
|
|
||
| return errors; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find which language keys the prescription form labels already use
rg -nP --type=html -C1 'current_language_set\?\.Prescription\?\.' src/app/app-modules/nurse-doctor/case-record/general-case-record/prescription/
rg -nP --type=html -C1 'nurseData\?\.chiefComplaintsDetails\?\.duration' src/app/app-modules/nurse-doctor/
# Confirm no existing "fillRequiredFields" key before introducing a new one
fd -t f -e json . src/assets | head -20
rg -nP '"fillRequiredFields"|"alerts"\s*:' -g '*.json' | headRepository: PSMRI/HWC-UI
Length of output: 10209
🏁 Script executed:
# Check the structure of alerts in the main language JSON file
head -100 src/assets/English.json | tail -50
# Find the alerts section
rg -A20 '"alerts"' src/assets/English.json | head -40
# Check if medicineName or medicine is used in JSON
rg -i '"medicine' src/assets/English.json | head -10
# Check Prescription section in JSON
rg -A30 '"Prescription"' src/assets/English.json | head -50Repository: PSMRI/HWC-UI
Length of output: 6135
i18n gap: validation error strings are hardcoded in English.
The rest of this component renders field labels from current_language_set?.Prescription?.* / nurseData?.chiefComplaintsDetails?.*, but the heading "Please fill the following required fields:" and the error labels (Medicine Form, Medicine Name, Dosage, Frequency, Duration, Unit, Quantity) are plain English. Non-English users will see a mixed-language alert. Source each label and the heading from current_language_set.
🌐 Example fix using existing language keys
validateCurrentPrescription(): string[] {
const errors: string[] = [];
+ const lang = this.current_language_set;
if (!this.currentPrescription.formName) {
- errors.push('Medicine Form');
+ errors.push(lang?.Prescription?.form || 'Medicine Form');
}
if (!this.currentPrescription.drugName || !this.tempDrugName) {
- errors.push('Medicine Name');
+ errors.push(lang?.Prescription?.medicine || 'Medicine Name');
}
if (!this.currentPrescription.dose) {
- errors.push('Dosage');
+ errors.push(lang?.Prescription?.dosage || 'Dosage');
}
if (!this.currentPrescription.frequency) {
- errors.push('Frequency');
+ errors.push(lang?.Prescription?.frequency || 'Frequency');
}
if (
this.currentPrescription.frequency &&
this.currentPrescription.frequency !== 'SOS'
) {
if (!this.currentPrescription.duration) {
- errors.push('Duration');
+ errors.push(lang?.nurseData?.chiefComplaintsDetails?.duration || 'Duration');
}
if (!this.currentPrescription.unit) {
- errors.push('Unit');
+ errors.push(lang?.Prescription?.unit || 'Unit');
}
}
if (
this.currentPrescription.formID &&
this.currentPrescription.formID > 2 &&
!this.currentPrescription.qtyPrescribed
) {
- errors.push('Quantity');
+ errors.push(lang?.Prescription?.quantity || 'Quantity');
}
return errors;
}For the heading, use an existing language key such as mandatoryFields or add one consistent with your i18n schema.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/app/app-modules/nurse-doctor/case-record/general-case-record/prescription/prescription.component.ts`
around lines 392 - 446, The alert heading and all hardcoded validation labels in
submitForUpload() / validateCurrentPrescription() should be replaced with i18n
keys from current_language_set (e.g., current_language_set?.Prescription or
other existing keys); update the heading string ('Please fill the following
required fields:') to use a language key such as
current_language_set?.Prescription?.mandatoryFields (or add that key), and
replace each error label ('Medicine Form', 'Medicine Name', 'Dosage',
'Frequency', 'Duration', 'Unit', 'Quantity') with the corresponding
current_language_set?.Prescription?.* entries (use
nurseData?.chiefComplaintsDetails?.* if appropriate for any shared labels) so
the confirmationService.alert(errorMessage, 'error') shows fully localized text;
ensure validateCurrentPrescription() builds its errors array with those i18n
values and submitForUpload() composes the numbered message from them.
| redirectToCHOReport() { | ||
| window.location.href = `${environment.dhisURL}${JSON.parse(this.sessionstorage.getItem('loginDataResponse'))?.dhistoken}`; | ||
| const token = JSON.parse( | ||
| this.sessionstorage.getItem('loginDataResponse'), | ||
| )?.dhistoken; | ||
|
|
||
| const url = `${environment.dhisURL}${token}`; | ||
|
|
||
| window.open(url, '_blank', 'noopener,noreferrer'); | ||
| } |
There was a problem hiding this comment.
Guard against a missing dhistoken before opening the URL.
If loginDataResponse is absent or the parsed payload has no dhistoken, token will be undefined and the method will still open ${environment.dhisURL}undefined in a new tab, leading to a confusing broken page. A simple guard avoids this edge case. Opening _blank with noopener,noreferrer looks good otherwise.
🛡️ Proposed fix
redirectToCHOReport() {
- const token = JSON.parse(
- this.sessionstorage.getItem('loginDataResponse'),
- )?.dhistoken;
-
- const url = `${environment.dhisURL}${token}`;
-
- window.open(url, '_blank', 'noopener,noreferrer');
+ const loginData = this.sessionstorage.getItem('loginDataResponse');
+ const token = loginData ? JSON.parse(loginData)?.dhistoken : undefined;
+
+ if (!token) {
+ this.confirmationService.alert(
+ this.currentLanguageSet?.alerts?.info?.somethingWentWrong ||
+ 'Unable to open CHO report: missing session token.',
+ 'error',
+ );
+ return;
+ }
+
+ const url = `${environment.dhisURL}${token}`;
+ window.open(url, '_blank', 'noopener,noreferrer');
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@src/app/app-modules/nurse-doctor/doctor-worklist/doctor-worklist.component.ts`
around lines 119 - 127, In redirectToCHOReport(), guard against missing or
invalid dhistoken by safely parsing
this.sessionstorage.getItem('loginDataResponse') (catch JSON.parse errors) and
verifying the extracted dhistoken is a non-empty string before constructing the
URL and calling window.open; if the token is missing/invalid, do not call
window.open and instead handle the case (e.g., log via a logger or show a
user-facing message) so you avoid opening `${environment.dhisURL}undefined`.
| "hypertension": "উচ্চ ৰক্তচাপ স্ক্ৰীণিং", | ||
| "breastCancer": "স্তনৰ কেঞ্চাৰ স্ক্ৰীণিং", | ||
| "cervicalCancer": "গৰ্ভাশয়ৰ মুখৰ কেঞ্চাৰ স্ক্ৰীণিং", |
There was a problem hiding this comment.
Remove the duplicated disease keys from this locale object.
These hypertension, breastCancer, and cervicalCancer entries are declared twice in the same JSON object, so one set is overwritten at parse time and becomes unreachable. Please keep one canonical key per concept, or rename them if these labels are meant for different screens.
Also applies to: 2033-2036
🧰 Tools
🪛 Biome (2.4.12)
[error] 1800-1800: The key hypertension was already declared.
(lint/suspicious/noDuplicateObjectKeys)
[error] 1801-1801: The key breastCancer was already declared.
(lint/suspicious/noDuplicateObjectKeys)
[error] 1802-1802: The key cervicalCancer was already declared.
(lint/suspicious/noDuplicateObjectKeys)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/assets/Assamese.json` around lines 1800 - 1802, The locale object
contains duplicate keys "hypertension", "breastCancer", and "cervicalCancer"
(appearing twice), causing the earlier entries to be overwritten; remove the
duplicate entries so each concept has a single canonical key, or if the
duplicated values are intended for different screens rename one set (e.g.,
hypertension_screen vs hypertension_summary) to unique keys; update only the
entries for "hypertension", "breastCancer", and "cervicalCancer" (and the other
duplicates noted around the later section) to eliminate duplication and keep the
correct translated string for each unique key.
| "count": "গণনা", | ||
| "information": "তথ্য", | ||
| "dosDont": "কৰিবলগীয়া আৰু নকৰিবলগীয়া", | ||
| "selfcare": "নিজে যত্ন লোৱা", |
There was a problem hiding this comment.
selfcare is declared twice in the same object.
The later declaration overrides the earlier one, so one translation is effectively dead. Keep a single selfcare key or split the contexts into distinct names.
Also applies to: 2091-2091
🧰 Tools
🪛 Biome (2.4.12)
[error] 1959-1959: The key selfcare was already declared.
(lint/suspicious/noDuplicateObjectKeys)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/assets/Assamese.json` at line 1959, The Assamese translations object
contains duplicate "selfcare" keys, causing the later value to override the
earlier one; locate both "selfcare" entries and either remove the redundant one
or rename one to a context-specific key (e.g., "selfcare_profile" or
"selfcare_section") so both translations are preserved, then update any
consumers to use the new key if you rename it.
| "immunizationService": "Immunization Services", | ||
| "birthImmunizationHistory" :"Birth & Immunization History", | ||
| "birthImmunizationHistory": "जन्म एवं टीकाकरण का इतिहास", | ||
| "immunizationService": "टीकाकरण सेवाएँ", |
There was a problem hiding this comment.
immunizationService is duplicated here.
Lines 1905 and 1907 define the same key in the same object, so only the last value survives at runtime. Please keep one key or rename them if they are intended for different UI contexts.
🧰 Tools
🪛 Biome (2.4.12)
[error] 1905-1905: The key immunizationService was already declared.
(lint/suspicious/noDuplicateObjectKeys)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/assets/Hindi.json` around lines 1905 - 1907, The JSON contains a
duplicate key "immunizationService" (two entries with different Hindi/English
values); remove the duplicate and keep the intended translation or rename one
key to a distinct identifier (e.g., "immunizationServiceLabel" vs
"immunizationServiceAlt") if they represent different UI contexts, then update
any consumers that read the key (components or i18n lookup calls) to use the
chosen/renamed key so no translation is silently overwritten at runtime.


📋 Description
JIRA ID:
Amm-2279
✅ Type of Change
Summary by CodeRabbit
Release Notes - Version 3.6.1
New Features
Improvements
Chores