From fe09aa4931db13058764ca74c72ccecf4f733ae9 Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Sat, 16 May 2026 16:11:58 +0330 Subject: [PATCH] feat: update app version and build details; refactor auth service and components for improved functionality --- ngsw-config.json | 6 +-- src/app/core/services/auth.service.ts | 49 +++++++++++++------ .../domains/pos/layouts/layout.component.html | 8 +-- .../pos/modules/auth/constants/index.ts | 1 + .../modules/auth/constants/routes/index.ts | 19 +++++++ .../modules/auth/views/auth.component.html | 1 + .../pos/modules/auth/views/auth.component.ts | 18 +++++++ src/app/modules/auth/pages/auth.component.ts | 21 +++++--- .../auth/pages/login/login.component.ts | 27 +++++++++- src/tenants/tis/app.routes.ts | 14 +++--- 10 files changed, 124 insertions(+), 40 deletions(-) create mode 100644 src/app/domains/pos/modules/auth/constants/index.ts create mode 100644 src/app/domains/pos/modules/auth/constants/routes/index.ts create mode 100644 src/app/domains/pos/modules/auth/views/auth.component.html create mode 100644 src/app/domains/pos/modules/auth/views/auth.component.ts diff --git a/ngsw-config.json b/ngsw-config.json index 5362cee..0ce673f 100644 --- a/ngsw-config.json +++ b/ngsw-config.json @@ -1,9 +1,9 @@ { "$schema": "./node_modules/@angular/service-worker/config/schema.json", "appData": { - "appVersion": "0.0.12", - "buildDate": "2026-05-16T08:49:47.932Z", - "buildNumber": 12 + "appVersion": "0.0.13", + "buildDate": "2026-05-16T11:46:52.423Z", + "buildNumber": 13 }, "assetGroups": [ { diff --git a/src/app/core/services/auth.service.ts b/src/app/core/services/auth.service.ts index d0384c8..34efff7 100644 --- a/src/app/core/services/auth.service.ts +++ b/src/app/core/services/auth.service.ts @@ -6,8 +6,8 @@ import { HttpClient } from '@angular/common/http'; import { computed, inject, Injectable, signal } from '@angular/core'; import { Router } from '@angular/router'; import { CookieService } from 'ngx-cookie-service'; -import { BehaviorSubject, Observable, throwError } from 'rxjs'; -import { catchError, finalize, tap } from 'rxjs/operators'; +import { BehaviorSubject, from, Observable, throwError } from 'rxjs'; +import { catchError, finalize, switchMap, tap } from 'rxjs/operators'; import config from 'src/config'; import { COOKIE_KEYS, LOCAL_STORAGE_KEYS } from '../../../assets/constants'; import { @@ -82,11 +82,14 @@ export class AuthService { }, ) .pipe( - tap((response) => { - this.handleAuthSuccess(response); - this.refreshCookies(); - return response; - }), + switchMap((response) => + from( + this.handleAuthSuccess(response).then(() => { + this.refreshCookies(); + return response; + }), + ), + ), catchError((error) => { console.error('Login error:', error); this.isLoadingSubject.next(false); @@ -98,19 +101,19 @@ export class AuthService { ); } - logout(): void { + async logout(): Promise { localStorage.removeItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN); localStorage.removeItem(LOCAL_STORAGE_KEYS.USER_DATA); localStorage.removeItem(LOCAL_STORAGE_KEYS.REFRESH_TOKEN); - this.refreshCookies(); + await this.refreshCookies(); - this.setCurrentUser(null); + await this.setCurrentUser(null); this.router.navigate(['/auth']); } - refreshCookies() { - this.cookieService.set(COOKIE_KEYS.POS_ID, '', new Date()); - this.cookieService.set(COOKIE_KEYS.ACCESS_TOKEN, '', new Date()); + async refreshCookies() { + await this.cookieService.set(COOKIE_KEYS.POS_ID, '', new Date()); + await this.cookieService.set(COOKIE_KEYS.ACCESS_TOKEN, '', new Date()); } doRefreshToken(): Observable { @@ -171,6 +174,22 @@ export class AuthService { return localStorage.getItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN); } + waitForAuthReady(maxRetries = 20): Promise { + return new Promise((resolve) => { + let retries = 0; + const check = () => { + const isReady = Boolean(this.getToken()) && Boolean(this.currentAccount()); + if (isReady || retries >= maxRetries) { + resolve(isReady); + return; + } + retries += 1; + setTimeout(check, 0); + }; + check(); + }); + } + /** * Get current refresh token */ @@ -247,7 +266,7 @@ export class AuthService { return true; } - private handleAuthSuccess(response: IAuthResponse): void { + private async handleAuthSuccess(response: IAuthResponse): Promise { localStorage.setItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN, response.accessToken); this.token.set(response.accessToken); this.refreshToken.set(response.refreshToken); @@ -260,7 +279,7 @@ export class AuthService { // this.navigateByRole(response.user.role); } - private setCurrentUser(account: Maybe): void { + private async setCurrentUser(account: Maybe): Promise { this.currentAccount.set(account); this.currentAccountSubject.next(account); localStorage.setItem(LOCAL_STORAGE_KEYS.USER_DATA, JSON.stringify(account)); diff --git a/src/app/domains/pos/layouts/layout.component.html b/src/app/domains/pos/layouts/layout.component.html index 15e8236..a872b4d 100644 --- a/src/app/domains/pos/layouts/layout.component.html +++ b/src/app/domains/pos/layouts/layout.component.html @@ -25,13 +25,13 @@ } - @if (isAuth()) { + + + } } diff --git a/src/app/domains/pos/modules/auth/constants/index.ts b/src/app/domains/pos/modules/auth/constants/index.ts new file mode 100644 index 0000000..442ce07 --- /dev/null +++ b/src/app/domains/pos/modules/auth/constants/index.ts @@ -0,0 +1 @@ +export * from './routes/index'; diff --git a/src/app/domains/pos/modules/auth/constants/routes/index.ts b/src/app/domains/pos/modules/auth/constants/routes/index.ts new file mode 100644 index 0000000..0068e2e --- /dev/null +++ b/src/app/domains/pos/modules/auth/constants/routes/index.ts @@ -0,0 +1,19 @@ +import { NamedRoutes } from '@/core'; +import { Routes } from '@angular/router'; + +export type TPosAuthRouteNames = 'login'; + +const baseRoute = `auth`; + +export const posAuthNamedRoutes: NamedRoutes = { + login: { + path: 'auth', + loadComponent: () => import('../../views/auth.component').then((m) => m.PosAuthComponent), + meta: { + title: 'ورود', + pagePath: () => baseRoute, + }, + }, +}; + +export const POS_AUTH_ROUTES: Routes = [posAuthNamedRoutes.login]; diff --git a/src/app/domains/pos/modules/auth/views/auth.component.html b/src/app/domains/pos/modules/auth/views/auth.component.html new file mode 100644 index 0000000..855d0fa --- /dev/null +++ b/src/app/domains/pos/modules/auth/views/auth.component.html @@ -0,0 +1 @@ + diff --git a/src/app/domains/pos/modules/auth/views/auth.component.ts b/src/app/domains/pos/modules/auth/views/auth.component.ts new file mode 100644 index 0000000..a8b652f --- /dev/null +++ b/src/app/domains/pos/modules/auth/views/auth.component.ts @@ -0,0 +1,18 @@ +import { AuthComponent } from '@/modules/auth/pages/auth.component'; +import { Component, inject } from '@angular/core'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'pos-auth', + templateUrl: 'auth.component.html', + imports: [AuthComponent], +}) +export class PosAuthComponent { + private readonly router = inject(Router); + + onLoggedIn(isReady: boolean) { + if (isReady) { + this.router.navigateByUrl('/'); + } + } +} diff --git a/src/app/modules/auth/pages/auth.component.ts b/src/app/modules/auth/pages/auth.component.ts index 47403ee..52e83d4 100644 --- a/src/app/modules/auth/pages/auth.component.ts +++ b/src/app/modules/auth/pages/auth.component.ts @@ -1,4 +1,5 @@ import { IAuthResponse, TRoles } from '@/core'; +import { AuthService } from '@/core/services/auth.service'; import { ToastService } from '@/core/services/toast.service'; import { Component, EventEmitter, inject, Input, Output, signal } from '@angular/core'; import { Router } from '@angular/router'; @@ -19,10 +20,11 @@ export class AuthComponent { @Input() role?: TRoles; @Input() defaultStep: TSteps = 'login'; - @Output() submit = new EventEmitter>(); + @Output() onSubmit = new EventEmitter(); private readonly toastService = inject(ToastService); private readonly router = inject(Router); + private readonly authService = inject(AuthService); readonly logo = images.logo; readonly authVector = images.login; @@ -36,7 +38,7 @@ export class AuthComponent { this.activeStep.set('signup'); }; - onLoggedIn = (data: IAuthResponse) => { + onLoggedIn = async (data: IAuthResponse) => { this.toastService.success({ text: 'شما با موفقیت وارد شدید.' }); this.selectedRole.set(data.account.type.toUpperCase() as TRoles); @@ -46,15 +48,18 @@ export class AuthComponent { // return; // } - if (this.submit.observed) { - return this.submit.emit(Promise.resolve(true)); + if (this.onSubmit.observed) { + const isReady = await this.authService.waitForAuthReady(); + return this.onSubmit.emit(isReady); + } else { + this.redirectToDashboard(); } - this.redirectToDashboard(); }; - onModifyLoginInfo = () => { - if (this.submit.observed) { - return this.submit.emit(Promise.resolve(true)); + onModifyLoginInfo = async () => { + if (this.onSubmit.observed) { + const isReady = await this.authService.waitForAuthReady(); + return this.onSubmit.emit(isReady); } this.redirectToDashboard(); }; diff --git a/src/app/modules/auth/pages/login/login.component.ts b/src/app/modules/auth/pages/login/login.component.ts index 7e61bbc..8686d70 100644 --- a/src/app/modules/auth/pages/login/login.component.ts +++ b/src/app/modules/auth/pages/login/login.component.ts @@ -101,9 +101,11 @@ export class LoginComponent { next: (data) => { this.errorMessage.set(''); if (this.redirectUrl) { - this.router.navigateByUrl(this.redirectUrl.replace(/\/[^/]*$/, '')); + this.navigateAfterAuth(this.redirectUrl.replace(/\/[^/]*$/, '')); } else { - this.onSuccessfullySubmit.emit(data); + this.waitForAuthState().then(() => { + this.onSuccessfullySubmit.emit(data); + }); } }, error: (error) => { @@ -113,4 +115,25 @@ export class LoginComponent { }, }); } + + private navigateAfterAuth(url: string) { + this.waitForAuthState().then(() => { + this.router.navigateByUrl(url); + }); + } + + private waitForAuthState(maxRetries = 10): Promise { + return new Promise((resolve) => { + let retries = 0; + const check = () => { + if (this.authService.getToken() || retries >= maxRetries) { + resolve(); + return; + } + retries += 1; + setTimeout(check, 0); + }; + check(); + }); + } } diff --git a/src/tenants/tis/app.routes.ts b/src/tenants/tis/app.routes.ts index 7b408f2..d537af9 100644 --- a/src/tenants/tis/app.routes.ts +++ b/src/tenants/tis/app.routes.ts @@ -1,3 +1,4 @@ +import { posAuthNamedRoutes } from '@/domains/pos/modules/auth/constants'; import { POS_ROUTES } from '@/domains/pos/routes'; import { Notfound } from '@/pages/notfound/notfound.component'; import { Routes } from '@angular/router'; @@ -7,14 +8,11 @@ export const appRoutes: Routes = [ path: '', loadComponent: () => import('@/domains/pos/layouts/layout.component').then((m) => m.PosLayoutComponent), - children: [ - POS_ROUTES, - { - path: 'auth', - loadComponent: () => - import('@/modules/auth/pages/auth.component').then((m) => m.AuthComponent), - }, - ], + children: [POS_ROUTES], + }, + { + ...posAuthNamedRoutes.login, + path: 'auth', }, { path: 'notfound', component: Notfound }, { path: '**', redirectTo: '/notfound' },