From adadfc20db245105e860628d00347bc9b271bb6a Mon Sep 17 00:00:00 2001 From: Gagan7900 <54118395+Gagan7900@users.noreply.github.com> Date: Mon, 17 Aug 2026 14:06:54 +0700 Subject: [PATCH] changes related to session expire warning, session time out issue, exchange rate search label and modal resize-able --- .../services/auth/session-timeout.service.ts | 44 ++++++-------- .../exchange-rate-list.html | 4 +- .../states/pages/state-list/state-list.html | 60 ------------------- .../states/pages/state-list/state-list.ts | 7 +-- .../components/data-table/data-table.scss | 2 +- .../form/form-field/form-field.scss | 2 +- .../form/form-input/form-input.scss | 5 +- src/app/shared/components/modal/modal.html | 2 +- src/app/shared/components/modal/modal.scss | 14 ++++- src/app/shared/components/modal/modal.ts | 19 +++--- src/environments/environment.model.ts | 6 -- src/environments/environment.prod.ts | 4 -- src/environments/environment.ts | 4 -- src/index.html | 2 + src/styles.scss | 4 +- 15 files changed, 53 insertions(+), 126 deletions(-) diff --git a/src/app/core/services/auth/session-timeout.service.ts b/src/app/core/services/auth/session-timeout.service.ts index 5fa78c0b..99e6d491 100644 --- a/src/app/core/services/auth/session-timeout.service.ts +++ b/src/app/core/services/auth/session-timeout.service.ts @@ -4,7 +4,6 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { Router } from '@angular/router'; import { merge, fromEvent, Subscription } from 'rxjs'; import { throttleTime } from 'rxjs/operators'; -import { environment } from '../../../../environments/environment'; import { AuthService } from '../../../features/authentication/data-access/auth.service'; import { TokenStorageService } from './token-storage.service'; @@ -19,9 +18,6 @@ export class SessionTimeoutService implements OnDestroy { readonly showWarning = signal(false); readonly remainingSeconds = signal(0); - private readonly configWarningAfterMs = environment.sessionTimeout?.warningAfterMs ?? 25 * 60 * 1000; - private readonly configLogoutAfterMs = environment.sessionTimeout?.logoutAfterMs ?? 30 * 60 * 1000; - private activitySubscription: Subscription | null = null; private warningTimer: ReturnType | null = null; private logoutTimer: ReturnType | null = null; @@ -109,8 +105,15 @@ export class SessionTimeoutService implements OnDestroy { this.showWarning.set(false); this.remainingSeconds.set(0); - // Calculate effective delays based on token expiry if available - const { warningDelay, logoutDelay } = this.calculateEffectiveDelays(); + // Delays are derived solely from the access token expiry issued by the backend. + const delays = this.calculateEffectiveDelays(); + + if (!delays) { + // No token expiry info available - nothing to schedule client-side. + return; + } + + const { warningDelay, logoutDelay } = delays; const safeWarningDelay = Math.max(Math.min(warningDelay, logoutDelay), 0); const safeLogoutDelay = Math.max(logoutDelay, 0); @@ -130,39 +133,30 @@ export class SessionTimeoutService implements OnDestroy { } /** - * Calculate effective warning/logout delays based on the sooner of: - * - Configured timeout values - * - Actual token expiry from backend + * Derive warning/logout delays purely from the access token's expiry + * timestamp issued by the backend - no client-side hard-coded durations. */ - private calculateEffectiveDelays(): { warningDelay: number; logoutDelay: number } { + private calculateEffectiveDelays(): { warningDelay: number; logoutDelay: number } | null { const accessTokenExpiresOn = this.tokenStorage.getAccessTokenExpiresOn(); - + if (!accessTokenExpiresOn) { - // No token expiry info - use configured values - return { - warningDelay: this.configWarningAfterMs, - logoutDelay: this.configLogoutAfterMs - }; + return null; } const tokenExpiryMs = Date.parse(accessTokenExpiresOn); const now = Date.now(); - + if (Number.isNaN(tokenExpiryMs) || tokenExpiryMs <= now) { // Token already expired or invalid - logout immediately return { warningDelay: 0, logoutDelay: 0 }; } const tokenTimeRemaining = tokenExpiryMs - now; - - // Use the sooner of configured timeout or token expiry - // Warning at 80% of token lifetime or configured warning, whichever is sooner - const tokenBasedWarning = Math.floor(tokenTimeRemaining * 0.8); - const tokenBasedLogout = tokenTimeRemaining; - + + // Warn at 80% of the remaining token lifetime. return { - warningDelay: Math.min(this.configWarningAfterMs, tokenBasedWarning), - logoutDelay: Math.min(this.configLogoutAfterMs, tokenBasedLogout) + warningDelay: Math.floor(tokenTimeRemaining * 0.8), + logoutDelay: tokenTimeRemaining }; } diff --git a/src/app/features/global-masters/exchange-rates/pages/exchange-rate-list/exchange-rate-list.html b/src/app/features/global-masters/exchange-rates/pages/exchange-rate-list/exchange-rate-list.html index 67d26099..268c0dd0 100644 --- a/src/app/features/global-masters/exchange-rates/pages/exchange-rate-list/exchange-rate-list.html +++ b/src/app/features/global-masters/exchange-rates/pages/exchange-rate-list/exchange-rate-list.html @@ -2,9 +2,9 @@ [totalRecords]="tableStore.filteredRecords()" [pageIndex]="tableStore.queryState.pageIndex()" [pageSize]="tableStore.queryState.pageSize()" [initialSortColumn]="tableStore.queryState.sortColumn()" [initialSortDirection]="tableStore.queryState.sortDirection()" - tableTitle="Exchange Rates (ROE)" buttonTitle="Add" + tableTitle="Exchange Rates" buttonTitle="Add" [showSearch]="true" [showAddButton]="true" [showFilterButton]="true" [filterActive]="showFilters()" - searchPlaceholder="Search pair..." [searchDebounceTime]="300" toolTip="Add New Rate" (addClicked)="onAddRate()" + searchPlaceholder="Search rates..." [searchDebounceTime]="300" toolTip="Add New Rate" (addClicked)="onAddRate()" (searchChanged)="tableStore.onSearch($event)" (pageChanged)="tableStore.onPageChange($event)" (sortChanged)="tableStore.onSortChange($event)" (actionClicked)="onActionClick($event)" (filterClicked)="onToggleFilters()"> diff --git a/src/app/features/global-masters/states/pages/state-list/state-list.html b/src/app/features/global-masters/states/pages/state-list/state-list.html index ebeb6caa..3a465b43 100644 --- a/src/app/features/global-masters/states/pages/state-list/state-list.html +++ b/src/app/features/global-masters/states/pages/state-list/state-list.html @@ -1,62 +1,3 @@ -<<<<<<< HEAD - - -
-
- -
-
-
- - - - -
-======= ->>>>>>> dev !value); } - onFilterCountrySelected(country: CountryLookupDto | null): void { - this.selectedCountryLookup.set(country); - this.countryFilterForm.controls.countryId.setValue(country ? country.id : ''); onCountrySearchChanged(term: string): void { this.countrySearch$.next(term); } diff --git a/src/app/shared/components/data-table/data-table.scss b/src/app/shared/components/data-table/data-table.scss index 1588c84e..4ac024d4 100644 --- a/src/app/shared/components/data-table/data-table.scss +++ b/src/app/shared/components/data-table/data-table.scss @@ -434,7 +434,7 @@ cursor: default; } -:host-context(.dark) .data-table-modern .ti-pagination li .page-link { +:host-context(.dark) .data-table-modern .ti-pagination li .page-link, :host-context(.dark) .data-table-modern ::ng-deep .p-paginator .p-paginator-page, :host-context(.dark) .data-table-modern ::ng-deep .p-paginator .p-paginator-prev, :host-context(.dark) .data-table-modern ::ng-deep .p-paginator .p-paginator-next { diff --git a/src/app/shared/components/form/form-field/form-field.scss b/src/app/shared/components/form/form-field/form-field.scss index c04a0d6d..b3c2a5bb 100644 --- a/src/app/shared/components/form/form-field/form-field.scss +++ b/src/app/shared/components/form/form-field/form-field.scss @@ -18,7 +18,7 @@ } ::ng-deep .form-control:focus { - border-color: var(--color-primary); + border-color: var(--color-primary) !important; box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--color-primary) 20%, transparent); } diff --git a/src/app/shared/components/form/form-input/form-input.scss b/src/app/shared/components/form/form-input/form-input.scss index 67455565..9382b3c6 100644 --- a/src/app/shared/components/form/form-input/form-input.scss +++ b/src/app/shared/components/form/form-input/form-input.scss @@ -308,8 +308,9 @@ .shared-form-input::placeholder { color: transparent; } .shared-form-control.is-focused .shared-form-input, -.shared-form-control.has-value .shared-form-input { - border-color: var(--color-primary); +.shared-form-control.has-value .shared-form-input, +.shared-form-input:focus { + border-color: var(--color-primary) !important; } .shared-floating-label { diff --git a/src/app/shared/components/modal/modal.html b/src/app/shared/components/modal/modal.html index f5c113f2..27d53e39 100644 --- a/src/app/shared/components/modal/modal.html +++ b/src/app/shared/components/modal/modal.html @@ -74,7 +74,7 @@ tabindex="-1" (mousedown)="$event.stopPropagation()"> -
+
@if (showHeader()) {
diff --git a/src/app/shared/components/modal/modal.scss b/src/app/shared/components/modal/modal.scss index 1af35a83..ee3db6ac 100644 --- a/src/app/shared/components/modal/modal.scss +++ b/src/app/shared/components/modal/modal.scss @@ -91,7 +91,7 @@ position: relative; - width: 100%; + max-width: 100%; display: flex; justify-content: center; @@ -113,10 +113,18 @@ display: flex; flex-direction: column; - width: 100%; + min-width: 320px; + min-height: 220px; + max-width: 96vw; max-height: 90vh; + box-sizing: border-box; overflow: hidden; + resize: both; + + &::-webkit-resizer { + background: transparent; + } border-radius: 20px; @@ -920,6 +928,8 @@ border-radius: 18px; max-height: 95vh; + width: 100% !important; + resize: none; } .modal-header-content { diff --git a/src/app/shared/components/modal/modal.ts b/src/app/shared/components/modal/modal.ts index faf5b0f4..d1d72f0e 100644 --- a/src/app/shared/components/modal/modal.ts +++ b/src/app/shared/components/modal/modal.ts @@ -40,16 +40,16 @@ export class Modal implements OnDestroy { readonly closed = output(); readonly submitted = output(); - readonly modalSizeClass = computed(() => { - const sizes: Record = { - sm: 'max-w-md', - md: 'max-w-2xl', - lg: 'max-w-4xl', - xl: 'max-w-6xl', - full: 'max-w-[96vw]' + readonly modalInitialWidth = computed(() => { + const widths: Record = { + sm: '28rem', + md: '42rem', + lg: '56rem', + xl: '72rem', + full: '96vw' }; - return sizes[this.size()]; + return widths[this.size()]; }); readonly modalBoxClass = computed(() => { @@ -60,8 +60,7 @@ export class Modal implements OnDestroy { 'ease-out', 'relative', 'z-[1]', - 'pointer-events-auto', - this.modalSizeClass() + 'pointer-events-auto' ].join(' '); }); diff --git a/src/environments/environment.model.ts b/src/environments/environment.model.ts index fb64671b..1822cbfb 100644 --- a/src/environments/environment.model.ts +++ b/src/environments/environment.model.ts @@ -1,13 +1,7 @@ -export interface AppSessionTimeoutConfig { - warningAfterMs: number; - logoutAfterMs: number; -} - export interface AppEnvironment { production: boolean; api: { identity: string; masterAdmin: string; }; - sessionTimeout: AppSessionTimeoutConfig; } diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index b0b2a45f..d84c7fbe 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -6,8 +6,4 @@ export const environment: AppEnvironment = { identity: '/api', masterAdmin: '/api', }, - sessionTimeout: { - warningAfterMs: 25 * 60 * 1000, - logoutAfterMs: 30 * 60 * 1000, - }, }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 278da4e0..e22e1ab1 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -12,10 +12,6 @@ export const environment: AppEnvironment = { // identity: 'https://identity.yourdomain.com/api', // masterAdmin: 'https://master-admin.yourdomain.com/api', }, - sessionTimeout: { - warningAfterMs: 25 * 60 * 1000, - logoutAfterMs: 30 * 60 * 1000, - }, }; /* diff --git a/src/index.html b/src/index.html index 62361cf5..ff084e1b 100644 --- a/src/index.html +++ b/src/index.html @@ -11,6 +11,8 @@ + + diff --git a/src/styles.scss b/src/styles.scss index bcc3b06e..9fc373b4 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -2,9 +2,7 @@ @forward "../public/assets/css/style.css"; @forward "../node_modules/ngx-toastr/toastr.css"; -@import "flatpickr/dist/flatpickr.css"; -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@500;600&display=swap'); +@use "flatpickr/dist/flatpickr.css"; /* Etihad Altis Text (local font) */ @font-face {