ui update, init to consumer statistics and manage pos user types

This commit is contained in:
2026-04-13 13:22:40 +03:30
parent d4dff4ebfd
commit af3123e61e
85 changed files with 1054 additions and 407 deletions
@@ -43,7 +43,7 @@ export const errorInterceptor: HttpInterceptorFn = (req, next) => {
errorMessage = 'منبع مورد نظر یافت نشد';
break;
case 412:
errorMessage = error.error?.detail || 'اطلاعات ارسالی نامعتبر است';
errorMessage = error.error?.message || '';
break;
case 422:
errorMessage = error.error?.message || 'اطلاعات ارسالی نامعتبر است';
@@ -118,6 +118,7 @@ function showErrorNotification(message: string, status: number): void {
* Error types for better error handling
*/
export enum ErrorType {
PRE_CONDITION = 'PRE_CONDITION',
NETWORK = 'NETWORK',
SERVER = 'SERVER',
CLIENT = 'CLIENT',
@@ -136,9 +137,10 @@ export function getErrorType(error: HttpErrorResponse): ErrorType {
switch (error.status) {
case 400:
case 412:
case 422:
return ErrorType.VALIDATION;
case 412:
return ErrorType.PRE_CONDITION;
case 401:
return ErrorType.AUTHENTICATION;
case 403:
+10 -1
View File
@@ -5,9 +5,10 @@
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 { LOCAL_STORAGE_KEYS } from '../../../assets/constants';
import { COOKIE_KEYS, LOCAL_STORAGE_KEYS } from '../../../assets/constants';
import {
IAuthAccountResponse,
IAuthResponse,
@@ -28,6 +29,7 @@ export class AuthService {
private readonly http = inject(HttpClient);
private readonly router = inject(Router);
private readonly cookieService = inject(CookieService);
private captchaService = inject(CaptchaService);
private readonly currentAccountSubject = new BehaviorSubject<Maybe<IAuthAccountResponse>>(null);
@@ -81,6 +83,7 @@ export class AuthService {
.pipe(
tap((response) => {
this.handleAuthSuccess(response);
this.refreshCookies();
return response;
}),
catchError((error) => {
@@ -98,11 +101,17 @@ export class AuthService {
localStorage.removeItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN);
localStorage.removeItem(LOCAL_STORAGE_KEYS.USER_DATA);
localStorage.removeItem(LOCAL_STORAGE_KEYS.REFRESH_TOKEN);
this.refreshCookies();
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());
}
doRefreshToken(): Observable<IAuthResponse> {
const refreshToken = this.getRefreshToken();
if (!refreshToken) {
+34 -26
View File
@@ -26,33 +26,33 @@ export class ErrorHandlerService {
*/
private handleHttpError(error: HttpErrorResponse): void {
const errorType = getErrorType(error);
const userMessage = this.getUserMessage(error);
if (userMessage) {
this.toastService.error({
title: error.error?.title || 'خطا',
text: userMessage,
});
} else {
switch (errorType) {
case ErrorType.NETWORK:
this.showNetworkError(userMessage);
break;
case ErrorType.AUTHENTICATION:
this.showAuthError(userMessage);
break;
case ErrorType.AUTHORIZATION:
this.showAuthorizationError(userMessage);
break;
case ErrorType.VALIDATION:
this.showValidationError(userMessage, error);
break;
case ErrorType.SERVER:
this.showServerError(userMessage);
break;
default:
this.showGenericError(userMessage);
}
switch (errorType) {
case ErrorType.NETWORK:
this.showNetworkError(userMessage);
break;
case ErrorType.PRE_CONDITION:
this.showPreConditionError(userMessage);
break;
case ErrorType.AUTHENTICATION:
this.showAuthError(userMessage);
break;
case ErrorType.AUTHORIZATION:
this.showAuthorizationError(userMessage);
break;
case ErrorType.VALIDATION:
this.showValidationError(userMessage, error);
break;
case ErrorType.SERVER:
this.showServerError(userMessage);
break;
case ErrorType.SERVER:
this.showServerError(userMessage);
break;
default:
this.showGenericError(userMessage);
}
}
@@ -60,7 +60,6 @@ export class ErrorHandlerService {
* Handle generic JavaScript errors
*/
private handleGenericError(error: any): void {
console.error('Generic error:', error);
this.toastService.error({
text: 'یک خطای غیرمنتظره رخ داده است. لطفاً صفحه را تازه‌سازی کنید.',
});
@@ -76,6 +75,15 @@ export class ErrorHandlerService {
});
}
/**
* Show preCondition error notification
*/
private showPreConditionError(message: string): void {
this.toastService.warn({
text: message,
});
}
/**
* Show authentication error notification
*/
+14 -3
View File
@@ -1,3 +1,4 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Signal, WritableSignal, computed, signal } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { Maybe } from '../models';
@@ -8,7 +9,7 @@ import { IPaginatedQuery, IResponseMetadata } from '../models/service.model';
*/
export interface BaseState {
loading: boolean;
error: Maybe<string>;
error: Maybe<HttpErrorResponse>;
isRefreshing?: boolean;
initialized: boolean;
}
@@ -72,6 +73,15 @@ export interface StateChange<T = any> {
timestamp: number;
}
export const defaultBaseStateData = {
loading: false,
error: null,
errorStatus: null,
entity: null,
initialized: false,
isRefreshing: false,
};
/**
* Base store class with common functionality
*/
@@ -82,7 +92,7 @@ export abstract class BaseStore<T extends BaseState> {
// Public readonly signals
readonly state: Signal<T>;
readonly loading: Signal<boolean>;
readonly error: Signal<Maybe<string>>;
readonly error: Signal<Maybe<HttpErrorResponse>>;
readonly initialized: Signal<boolean>;
// Observable for RxJS compatibility
@@ -135,7 +145,7 @@ export abstract class BaseStore<T extends BaseState> {
/**
* Set error state
*/
protected setError(error: string): void {
protected setError(error: HttpErrorResponse): void {
this.patchState({
loading: false,
error,
@@ -180,6 +190,7 @@ export abstract class EntityStore<
setEntity(entity: Maybe<T>): void {
this.patchState({
entity,
error: null,
} as Partial<TState>);
}
override reset(): void {