feat: update app version and build details; refactor auth service and components for improved functionality
This commit is contained in:
+3
-3
@@ -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": [
|
||||
{
|
||||
|
||||
@@ -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<void> {
|
||||
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<IAuthResponse> {
|
||||
@@ -171,6 +174,22 @@ export class AuthService {
|
||||
return localStorage.getItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN);
|
||||
}
|
||||
|
||||
waitForAuthReady(maxRetries = 20): Promise<boolean> {
|
||||
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<void> {
|
||||
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<IAuthAccountResponse>): void {
|
||||
private async setCurrentUser(account: Maybe<IAuthAccountResponse>): Promise<void> {
|
||||
this.currentAccount.set(account);
|
||||
this.currentAccountSubject.next(account);
|
||||
localStorage.setItem(LOCAL_STORAGE_KEYS.USER_DATA, JSON.stringify(account));
|
||||
|
||||
@@ -25,13 +25,13 @@
|
||||
<!-- [ngStyle]="{ transform: 'scale(1.' + pullDistance() * 10 + ')' }" -->
|
||||
</div>
|
||||
}
|
||||
@if (isAuth()) {
|
||||
<!-- @if (isAuth()) {
|
||||
@defer (when isAuth()) {
|
||||
<router-outlet></router-outlet>
|
||||
}
|
||||
} @else {
|
||||
<pos-pages-layout />
|
||||
}
|
||||
} @else { -->
|
||||
<pos-pages-layout />
|
||||
<!-- } -->
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './routes/index';
|
||||
@@ -0,0 +1,19 @@
|
||||
import { NamedRoutes } from '@/core';
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
export type TPosAuthRouteNames = 'login';
|
||||
|
||||
const baseRoute = `auth`;
|
||||
|
||||
export const posAuthNamedRoutes: NamedRoutes<TPosAuthRouteNames> = {
|
||||
login: {
|
||||
path: 'auth',
|
||||
loadComponent: () => import('../../views/auth.component').then((m) => m.PosAuthComponent),
|
||||
meta: {
|
||||
title: 'ورود',
|
||||
pagePath: () => baseRoute,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const POS_AUTH_ROUTES: Routes = [posAuthNamedRoutes.login];
|
||||
@@ -0,0 +1 @@
|
||||
<app-auth (onSubmit)="onLoggedIn($event)" />
|
||||
@@ -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('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Promise<boolean>>();
|
||||
@Output() onSubmit = new EventEmitter<boolean>();
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
@@ -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<void> {
|
||||
return new Promise((resolve) => {
|
||||
let retries = 0;
|
||||
const check = () => {
|
||||
if (this.authService.getToken() || retries >= maxRetries) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
retries += 1;
|
||||
setTimeout(check, 0);
|
||||
};
|
||||
check();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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' },
|
||||
|
||||
Reference in New Issue
Block a user