update error handler

This commit is contained in:
2026-04-06 18:33:17 +03:30
parent de1a046485
commit b3fb4f4baf
11 changed files with 129 additions and 24 deletions
@@ -18,6 +18,9 @@ export const errorInterceptor: HttpInterceptorFn = (req, next) => {
return next(req).pipe(
catchError((error: HttpErrorResponse) => {
console.log('error');
console.log(error);
let errorMessage = 'خطای نامشخص رخ داده است';
if (error.error instanceof ErrorEvent) {
@@ -130,9 +133,13 @@ export enum ErrorType {
* Helper function to determine error type
*/
export function getErrorType(error: HttpErrorResponse): ErrorType {
console.log('getErrorType');
console.log(error);
if (error.error instanceof ErrorEvent) {
return ErrorType.NETWORK;
}
console.log(error.status);
switch (error.status) {
case 400:
+17 -13
View File
@@ -140,19 +140,23 @@ export class ErrorHandlerService {
* Extract user-friendly message from error
*/
private getUserMessage(error: HttpErrorResponse): string {
if (error.error && typeof error.error === 'object') {
// Try different common message fields
return (
error.error.message ||
error.error.error ||
error.error.detail ||
error.statusText ||
'خطای نامشخص رخ داده است'
);
}
if (typeof error.error === 'string') {
return error.error;
if (error.error) {
if (error.error.errors && Array.isArray(error.error.errors)) {
return error.error.errors[0];
}
if (typeof error.error === 'object') {
// Try different common message fields
return (
error.error.message ||
error.error.error ||
error.error.detail ||
error.statusText ||
'خطای نامشخص رخ داده است'
);
}
if (typeof error.error === 'string') {
return error.error;
}
}
return error.statusText || 'خطای نامشخص رخ داده است';
@@ -0,0 +1,13 @@
<p-dialog
header="شارژ لایسنس"
[(visible)]="visible"
[modal]="true"
[style]="{ width: '300px' }"
[closable]="true"
(onHide)="close()"
>
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
<app-input label="تعداد شارژ" [control]="form.controls.count" type="number" />
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
</form>
</p-dialog>
@@ -0,0 +1,30 @@
import { AbstractFormDialog } from '@/shared/abstractClasses';
import { InputComponent } from '@/shared/components';
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
import { Component, inject, Input } from '@angular/core';
import { ReactiveFormsModule, Validators } from '@angular/forms';
import { Dialog } from 'primeng/dialog';
import { ILicenseChargeRequest, ILicenseChargeResponse } from '../models';
import { PartnersService } from '../services/main.service';
@Component({
selector: 'partner-charge-license-form-dialog',
templateUrl: './charge-license-form-dialog.component.html',
imports: [Dialog, ReactiveFormsModule, InputComponent, FormFooterActionsComponent],
})
export class PartnerChargeLicenseFormDialogComponent extends AbstractFormDialog<
ILicenseChargeRequest,
ILicenseChargeResponse
> {
@Input({ required: true }) partnerId!: string;
private readonly service = inject(PartnersService);
form = this.fb.group({
count: [0, [Validators.min(0)]],
});
submitForm(payload: ILicenseChargeRequest) {
return this.service.licenseCharge(this.partnerId, payload);
}
}
@@ -5,4 +5,5 @@ const baseUrl = '/api/v1/admin/partners';
export const PARTNERS_API_ROUTES = {
list: () => `${baseUrl}`,
single: (id: string) => `${baseUrl}/${id}`,
licenseCharge: (id: string) => `${baseUrl}/${id}/charge-license`,
};
@@ -12,3 +12,11 @@ export interface IPartnerRequest {
code: string;
license_quota: number;
}
//charge license
export interface ILicenseChargeRawResponse {}
export interface ILicenseChargeResponse extends ILicenseChargeRawResponse {}
export interface ILicenseChargeRequest {
count: number;
}
@@ -3,7 +3,14 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { PARTNERS_API_ROUTES } from '../constants';
import { IPartnerRawResponse, IPartnerRequest, IPartnerResponse } from '../models';
import {
ILicenseChargeRawResponse,
ILicenseChargeRequest,
ILicenseChargeResponse,
IPartnerRawResponse,
IPartnerRequest,
IPartnerResponse,
} from '../models';
@Injectable({ providedIn: 'root' })
export class PartnersService {
@@ -14,15 +21,22 @@ export class PartnersService {
getAll(): Observable<IPaginatedResponse<IPartnerResponse>> {
return this.http.get<IPaginatedResponse<IPartnerRawResponse>>(this.apiRoutes.list());
}
getSingle(userId: string): Observable<IPartnerResponse> {
return this.http.get<IPartnerRawResponse>(this.apiRoutes.single(userId));
getSingle(partnerId: string): Observable<IPartnerResponse> {
return this.http.get<IPartnerRawResponse>(this.apiRoutes.single(partnerId));
}
create(userData: IPartnerRequest): Observable<IPartnerResponse> {
return this.http.post<IPartnerResponse>(this.apiRoutes.list(), userData);
}
update(userId: string, userData: IPartnerRequest): Observable<IPartnerResponse> {
return this.http.patch<IPartnerResponse>(this.apiRoutes.single(userId), userData);
update(partnerId: string, userData: IPartnerRequest): Observable<IPartnerResponse> {
return this.http.patch<IPartnerResponse>(this.apiRoutes.single(partnerId), userData);
}
licenseCharge(
partnerId: string,
data: ILicenseChargeRequest,
): Observable<ILicenseChargeResponse> {
return this.http.post<ILicenseChargeRawResponse>(this.apiRoutes.licenseCharge(partnerId), data);
}
}
@@ -1,6 +1,9 @@
<div class="flex flex-col gap-6">
<app-card-data cardTitle="اطلاعات شریک تجاری" [editable]="true" [(editMode)]="editMode">
<ng-template #moreAction> </ng-template>
<ng-template #moreAction>
<p-button outlined size="small" (onClick)="openChargeDialog()"> شارژ لایسنس‌ </p-button>
{{ visibleChargeFormDialog() }}
</ng-template>
<div class="flex flex-col gap-4">
<div class="grid grid-cols-3 gap-4 items-center">
<app-key-value label="عنوان شریک تجاری" [value]="partner()?.name" />
@@ -20,4 +23,10 @@
[initialValues]="partner() || undefined"
(onSubmit)="getData()"
/>
<partner-charge-license-form-dialog
[(visible)]="visibleChargeFormDialog"
[partnerId]="partnerId()"
(onSubmit)="getData()"
/>
</div>
@@ -2,7 +2,9 @@ import { BreadcrumbService } from '@/core/services';
import { AppCardComponent, KeyValueComponent } from '@/shared/components';
import { Component, computed, effect, inject, signal } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Button } from 'primeng/button';
import { ConsumerAccountListComponent } from '../components/accounts/list.component';
import { PartnerChargeLicenseFormDialogComponent } from '../components/charge-license-form-dialog.component';
import { GuildFormComponent } from '../components/form.component';
import { superAdminPartnersNamedRoutes } from '../constants';
import { PartnerStore } from '../store/partner.store';
@@ -10,7 +12,14 @@ import { PartnerStore } from '../store/partner.store';
@Component({
selector: 'app-user',
templateUrl: './single.component.html',
imports: [AppCardComponent, KeyValueComponent, GuildFormComponent, ConsumerAccountListComponent],
imports: [
AppCardComponent,
KeyValueComponent,
GuildFormComponent,
ConsumerAccountListComponent,
Button,
PartnerChargeLicenseFormDialogComponent,
],
})
export class PartnerComponent {
private readonly store = inject(PartnerStore);
@@ -22,6 +31,7 @@ export class PartnerComponent {
readonly loading = computed(() => this.store.loading());
readonly partner = computed(() => this.store.entity());
visibleChargeFormDialog = signal(false);
constructor() {
effect(() => {
@@ -46,4 +56,8 @@ export class PartnerComponent {
},
]);
}
openChargeDialog() {
this.visibleChargeFormDialog.set(true);
}
}
@@ -31,8 +31,13 @@
[attr.maxlength]="preparedMaxLength || null"
[attr.type]="htmlType"
[attr.autocomplete]="autocomplete"
[class]="
`${inputClass} w-full ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`
[classList]="
[
inputClass,
'w-full',
`${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`,
suffixTemp || preparedSuffix() ? 'hasSuffix' : '',
].join(' ')
"
[required]="isRequired"
[invalid]="control.invalid && (control.touched || control.dirty)"
@@ -224,9 +224,9 @@ export class InputComponent {
// @ts-ignore
$event.target.value = newValue;
}
this.control.setValue(newValue);
}
if (!['nationalId', 'phone', 'postalCode', 'mobile'].includes(this.type))
this.control.setValue(newValue);
}
if (this.preparedMaxLength && this.preparedMaxLength < value.length) {