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",
|
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
|
||||||
"appData": {
|
"appData": {
|
||||||
"appVersion": "0.0.12",
|
"appVersion": "0.0.13",
|
||||||
"buildDate": "2026-05-16T08:49:47.932Z",
|
"buildDate": "2026-05-16T11:46:52.423Z",
|
||||||
"buildNumber": 12
|
"buildNumber": 13
|
||||||
},
|
},
|
||||||
"assetGroups": [
|
"assetGroups": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
import { computed, inject, Injectable, signal } from '@angular/core';
|
import { computed, inject, Injectable, signal } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { CookieService } from 'ngx-cookie-service';
|
import { CookieService } from 'ngx-cookie-service';
|
||||||
import { BehaviorSubject, Observable, throwError } from 'rxjs';
|
import { BehaviorSubject, from, Observable, throwError } from 'rxjs';
|
||||||
import { catchError, finalize, tap } from 'rxjs/operators';
|
import { catchError, finalize, switchMap, tap } from 'rxjs/operators';
|
||||||
import config from 'src/config';
|
import config from 'src/config';
|
||||||
import { COOKIE_KEYS, LOCAL_STORAGE_KEYS } from '../../../assets/constants';
|
import { COOKIE_KEYS, LOCAL_STORAGE_KEYS } from '../../../assets/constants';
|
||||||
import {
|
import {
|
||||||
@@ -82,11 +82,14 @@ export class AuthService {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((response) => {
|
switchMap((response) =>
|
||||||
this.handleAuthSuccess(response);
|
from(
|
||||||
|
this.handleAuthSuccess(response).then(() => {
|
||||||
this.refreshCookies();
|
this.refreshCookies();
|
||||||
return response;
|
return response;
|
||||||
}),
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
catchError((error) => {
|
catchError((error) => {
|
||||||
console.error('Login error:', error);
|
console.error('Login error:', error);
|
||||||
this.isLoadingSubject.next(false);
|
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.AUTH_TOKEN);
|
||||||
localStorage.removeItem(LOCAL_STORAGE_KEYS.USER_DATA);
|
localStorage.removeItem(LOCAL_STORAGE_KEYS.USER_DATA);
|
||||||
localStorage.removeItem(LOCAL_STORAGE_KEYS.REFRESH_TOKEN);
|
localStorage.removeItem(LOCAL_STORAGE_KEYS.REFRESH_TOKEN);
|
||||||
this.refreshCookies();
|
await this.refreshCookies();
|
||||||
|
|
||||||
this.setCurrentUser(null);
|
await this.setCurrentUser(null);
|
||||||
this.router.navigate(['/auth']);
|
this.router.navigate(['/auth']);
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshCookies() {
|
async refreshCookies() {
|
||||||
this.cookieService.set(COOKIE_KEYS.POS_ID, '', new Date());
|
await this.cookieService.set(COOKIE_KEYS.POS_ID, '', new Date());
|
||||||
this.cookieService.set(COOKIE_KEYS.ACCESS_TOKEN, '', new Date());
|
await this.cookieService.set(COOKIE_KEYS.ACCESS_TOKEN, '', new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
doRefreshToken(): Observable<IAuthResponse> {
|
doRefreshToken(): Observable<IAuthResponse> {
|
||||||
@@ -171,6 +174,22 @@ export class AuthService {
|
|||||||
return localStorage.getItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN);
|
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
|
* Get current refresh token
|
||||||
*/
|
*/
|
||||||
@@ -247,7 +266,7 @@ export class AuthService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleAuthSuccess(response: IAuthResponse): void {
|
private async handleAuthSuccess(response: IAuthResponse): Promise<void> {
|
||||||
localStorage.setItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN, response.accessToken);
|
localStorage.setItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN, response.accessToken);
|
||||||
this.token.set(response.accessToken);
|
this.token.set(response.accessToken);
|
||||||
this.refreshToken.set(response.refreshToken);
|
this.refreshToken.set(response.refreshToken);
|
||||||
@@ -260,7 +279,7 @@ export class AuthService {
|
|||||||
// this.navigateByRole(response.user.role);
|
// this.navigateByRole(response.user.role);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setCurrentUser(account: Maybe<IAuthAccountResponse>): void {
|
private async setCurrentUser(account: Maybe<IAuthAccountResponse>): Promise<void> {
|
||||||
this.currentAccount.set(account);
|
this.currentAccount.set(account);
|
||||||
this.currentAccountSubject.next(account);
|
this.currentAccountSubject.next(account);
|
||||||
localStorage.setItem(LOCAL_STORAGE_KEYS.USER_DATA, JSON.stringify(account));
|
localStorage.setItem(LOCAL_STORAGE_KEYS.USER_DATA, JSON.stringify(account));
|
||||||
|
|||||||
@@ -25,13 +25,13 @@
|
|||||||
<!-- [ngStyle]="{ transform: 'scale(1.' + pullDistance() * 10 + ')' }" -->
|
<!-- [ngStyle]="{ transform: 'scale(1.' + pullDistance() * 10 + ')' }" -->
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (isAuth()) {
|
<!-- @if (isAuth()) {
|
||||||
@defer (when isAuth()) {
|
@defer (when isAuth()) {
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
}
|
}
|
||||||
} @else {
|
} @else { -->
|
||||||
<pos-pages-layout />
|
<pos-pages-layout />
|
||||||
}
|
<!-- } -->
|
||||||
</div>
|
</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 { IAuthResponse, TRoles } from '@/core';
|
||||||
|
import { AuthService } from '@/core/services/auth.service';
|
||||||
import { ToastService } from '@/core/services/toast.service';
|
import { ToastService } from '@/core/services/toast.service';
|
||||||
import { Component, EventEmitter, inject, Input, Output, signal } from '@angular/core';
|
import { Component, EventEmitter, inject, Input, Output, signal } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
@@ -19,10 +20,11 @@ export class AuthComponent {
|
|||||||
@Input() role?: TRoles;
|
@Input() role?: TRoles;
|
||||||
@Input() defaultStep: TSteps = 'login';
|
@Input() defaultStep: TSteps = 'login';
|
||||||
|
|
||||||
@Output() submit = new EventEmitter<Promise<boolean>>();
|
@Output() onSubmit = new EventEmitter<boolean>();
|
||||||
|
|
||||||
private readonly toastService = inject(ToastService);
|
private readonly toastService = inject(ToastService);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
|
private readonly authService = inject(AuthService);
|
||||||
|
|
||||||
readonly logo = images.logo;
|
readonly logo = images.logo;
|
||||||
readonly authVector = images.login;
|
readonly authVector = images.login;
|
||||||
@@ -36,7 +38,7 @@ export class AuthComponent {
|
|||||||
this.activeStep.set('signup');
|
this.activeStep.set('signup');
|
||||||
};
|
};
|
||||||
|
|
||||||
onLoggedIn = (data: IAuthResponse) => {
|
onLoggedIn = async (data: IAuthResponse) => {
|
||||||
this.toastService.success({ text: 'شما با موفقیت وارد شدید.' });
|
this.toastService.success({ text: 'شما با موفقیت وارد شدید.' });
|
||||||
|
|
||||||
this.selectedRole.set(data.account.type.toUpperCase() as TRoles);
|
this.selectedRole.set(data.account.type.toUpperCase() as TRoles);
|
||||||
@@ -46,15 +48,18 @@ export class AuthComponent {
|
|||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (this.submit.observed) {
|
if (this.onSubmit.observed) {
|
||||||
return this.submit.emit(Promise.resolve(true));
|
const isReady = await this.authService.waitForAuthReady();
|
||||||
}
|
return this.onSubmit.emit(isReady);
|
||||||
|
} else {
|
||||||
this.redirectToDashboard();
|
this.redirectToDashboard();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onModifyLoginInfo = () => {
|
onModifyLoginInfo = async () => {
|
||||||
if (this.submit.observed) {
|
if (this.onSubmit.observed) {
|
||||||
return this.submit.emit(Promise.resolve(true));
|
const isReady = await this.authService.waitForAuthReady();
|
||||||
|
return this.onSubmit.emit(isReady);
|
||||||
}
|
}
|
||||||
this.redirectToDashboard();
|
this.redirectToDashboard();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -101,9 +101,11 @@ export class LoginComponent {
|
|||||||
next: (data) => {
|
next: (data) => {
|
||||||
this.errorMessage.set('');
|
this.errorMessage.set('');
|
||||||
if (this.redirectUrl) {
|
if (this.redirectUrl) {
|
||||||
this.router.navigateByUrl(this.redirectUrl.replace(/\/[^/]*$/, ''));
|
this.navigateAfterAuth(this.redirectUrl.replace(/\/[^/]*$/, ''));
|
||||||
} else {
|
} else {
|
||||||
|
this.waitForAuthState().then(() => {
|
||||||
this.onSuccessfullySubmit.emit(data);
|
this.onSuccessfullySubmit.emit(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: (error) => {
|
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 { POS_ROUTES } from '@/domains/pos/routes';
|
||||||
import { Notfound } from '@/pages/notfound/notfound.component';
|
import { Notfound } from '@/pages/notfound/notfound.component';
|
||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
@@ -7,14 +8,11 @@ export const appRoutes: Routes = [
|
|||||||
path: '',
|
path: '',
|
||||||
loadComponent: () =>
|
loadComponent: () =>
|
||||||
import('@/domains/pos/layouts/layout.component').then((m) => m.PosLayoutComponent),
|
import('@/domains/pos/layouts/layout.component').then((m) => m.PosLayoutComponent),
|
||||||
children: [
|
children: [POS_ROUTES],
|
||||||
POS_ROUTES,
|
|
||||||
{
|
|
||||||
path: 'auth',
|
|
||||||
loadComponent: () =>
|
|
||||||
import('@/modules/auth/pages/auth.component').then((m) => m.AuthComponent),
|
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
|
...posAuthNamedRoutes.login,
|
||||||
|
path: 'auth',
|
||||||
},
|
},
|
||||||
{ path: 'notfound', component: Notfound },
|
{ path: 'notfound', component: Notfound },
|
||||||
{ path: '**', redirectTo: '/notfound' },
|
{ path: '**', redirectTo: '/notfound' },
|
||||||
|
|||||||
Reference in New Issue
Block a user