feat: update consumer and partner components for improved data handling and UI enhancements
- Refactor ConsumerPosListComponent to dynamically set cookie domain based on hostname. - Modify ConsumerUserFormContentComponent to correctly handle type selection and initialization. - Enhance single.component.html to conditionally display consumer details based on type. - Update ConsumerAccountListComponent to include nested role translation and pos details. - Adjust IConsumerAccountRawResponse to use IEnumTranslate for role and add pos details. - Refine ConsumersComponent to display translated status in the list view. - Revise single.component.html for superAdmin to show translated consumer type and details. - Improve AdminPartnerChargeAccountListComponent and AdminPartnerChargeLicenseTransactionListComponent by updating header labels. - Add file upload functionality in form.component.html for partner creation. - Enhance GuildFormComponent to handle file uploads and form data submission. - Update AdminPartnerLicensesComponent to display consumer names correctly. - Modify IPartnerActivatedLicenseResponse to include consumer_name for better clarity. - Add logo_url to IPartnerRawResponse for displaying partner logos. - Refactor PartnersService to handle FormData for partner creation and updates. - Enhance list.component.html to include partner logos in the display. - Update single.component.html for partners to show total counts for licenses and users. - Implement payment result handling in AuthComponent for improved payment integration. - Refactor SharedUploadFileComponent to manage file previews and uploads more effectively. - Introduce IEnumTranslate interface for better type handling in consumer models. - Update form-data utility to allow skipping specific fields during FormData construction. - Add RTL support styles for file upload and avatar components. - Change environment configuration for API base URL.
This commit is contained in:
@@ -25,12 +25,23 @@ export class ConsumerAccountListComponent extends AbstractList<IConsumerAccountR
|
||||
type: 'nested',
|
||||
nestedOption: { path: 'account.username' },
|
||||
},
|
||||
{ field: 'role', header: 'نوع حساب' },
|
||||
{
|
||||
field: 'role',
|
||||
header: 'نوع حساب',
|
||||
type: 'nested',
|
||||
nestedOption: { path: 'role.translate' },
|
||||
},
|
||||
{
|
||||
field: 'pos',
|
||||
header: 'پایانهی مرتبط',
|
||||
customDataModel: (item) =>
|
||||
`${item.pos.name} (${item.pos.complex.name} - ${item.pos.complex.business_activity.name})`,
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
header: 'وضعیت',
|
||||
type: 'nested',
|
||||
nestedOption: { path: 'account.status' },
|
||||
nestedOption: { path: 'status.translate' },
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { TAccountType } from '@/core/constants/accountTypes.const';
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { IEnumTranslate } from '@/shared/models/enum_translate.type';
|
||||
|
||||
export interface IConsumerAccountRawResponse {
|
||||
id: string;
|
||||
role: string;
|
||||
role: IEnumTranslate;
|
||||
created_at: string;
|
||||
account: AccountInfo;
|
||||
pos: Pos;
|
||||
}
|
||||
export interface IConsumerAccountResponse extends IConsumerAccountRawResponse {}
|
||||
|
||||
@@ -22,3 +25,12 @@ interface AccountInfo {
|
||||
username: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
interface Pos extends ISummary {
|
||||
complex: {
|
||||
name: string;
|
||||
business_activity: {
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,7 +28,13 @@ export class ConsumersComponent extends AbstractList<IAdminConsumerResponse> {
|
||||
type: 'nested',
|
||||
nestedOption: { path: 'partner.name' },
|
||||
},
|
||||
{ field: 'status', header: 'وضعیت' },
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
header: 'وضعیت',
|
||||
type: 'nested',
|
||||
nestedOption: { path: 'status.translate' },
|
||||
},
|
||||
// {
|
||||
// field: 'license_expires_at',
|
||||
// header: 'تاریخ انقضای لایسنس',
|
||||
|
||||
@@ -4,8 +4,15 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="grid grid-cols-3 gap-4 items-center">
|
||||
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
||||
<app-key-value label="نوع مشتری" [value]="consumer()?.type" />
|
||||
<app-key-value label="وضعیت" [value]="consumer()?.status" />
|
||||
<app-key-value label="وضعیت" [value]="consumer()?.status?.translate" />
|
||||
<app-key-value label="نوع مشتری" [value]="consumer()?.type?.translate" />
|
||||
|
||||
@if (consumer()?.type?.value === "LEGAL") {
|
||||
<app-key-value label="شناسه ملی" [value]="consumer()?.legal?.registration_code" />
|
||||
} @else {
|
||||
<app-key-value label="شماره موبایل" [value]="consumer()?.individual?.mobile_number" />
|
||||
<app-key-value label="کد ملی" [value]="consumer()?.individual?.national_code" />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</app-card-data>
|
||||
|
||||
+1
-6
@@ -25,17 +25,12 @@ export class AdminPartnerChargeAccountListComponent extends AbstractList<IAdminP
|
||||
},
|
||||
{
|
||||
field: 'activation_expires_at',
|
||||
header: 'تاریخ انقضا',
|
||||
header: 'تاریخ انقضای فروش',
|
||||
type: 'date',
|
||||
dateOption: {
|
||||
expiredMode: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
header: 'تاریخ ایجاد',
|
||||
type: 'date',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+1
-6
@@ -26,17 +26,12 @@ export class AdminPartnerChargeLicenseTransactionListComponent extends AbstractL
|
||||
},
|
||||
{
|
||||
field: 'activation_expires_at',
|
||||
header: 'تاریخ انقضا',
|
||||
header: 'تاریخ انقضای فروش',
|
||||
type: 'date',
|
||||
dateOption: {
|
||||
expiredMode: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
header: 'تاریخ ایجاد',
|
||||
type: 'date',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
(onHide)="close()"
|
||||
>
|
||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||
<app-shared-upload-file accept="image/*" name="image" (onSelect)="changeFile($event)" />
|
||||
<app-input label="عنوان" [control]="form.controls.name" name="name" />
|
||||
<app-input label="کد" [control]="form.controls.code" name="code" />
|
||||
@if (!editMode) {
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { MustMatch } from '@/core/validators';
|
||||
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
||||
import { InputComponent, SharedPasswordInputComponent } from '@/shared/components';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { Component, computed, inject, Input } from '@angular/core';
|
||||
import { onSelectFileArgs } from '@/shared/components/uploadFile/model';
|
||||
import { SharedUploadFileComponent } from '@/shared/components/uploadFile/upload-file.component';
|
||||
import { buildFormData } from '@/utils';
|
||||
import { Component, computed, inject, Input, signal } from '@angular/core';
|
||||
import { ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Divider } from 'primeng/divider';
|
||||
import { IPartnerRequest, IPartnerResponse } from '../models';
|
||||
import { PartnersService } from '../services/main.service';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'partner-form',
|
||||
@@ -19,6 +23,7 @@ import { SharedDialogComponent } from '@/shared/components/dialog/dialog.compone
|
||||
FormFooterActionsComponent,
|
||||
Divider,
|
||||
SharedPasswordInputComponent,
|
||||
SharedUploadFileComponent,
|
||||
],
|
||||
})
|
||||
export class GuildFormComponent extends AbstractFormDialog<IPartnerRequest, IPartnerResponse> {
|
||||
@@ -70,10 +75,16 @@ export class GuildFormComponent extends AbstractFormDialog<IPartnerRequest, IPar
|
||||
return form;
|
||||
}
|
||||
|
||||
logo = signal<Maybe<File>>(null);
|
||||
|
||||
form = this.initForm();
|
||||
|
||||
preparedTitle = computed(() => `${this.editMode ? 'ویرایش' : 'ایجاد'} شریک تجاری`);
|
||||
|
||||
changeFile(payload: onSelectFileArgs) {
|
||||
this.logo.set(payload.file);
|
||||
}
|
||||
|
||||
override ngOnChanges() {
|
||||
this.form.patchValue(this.initialValues ?? {});
|
||||
if (this.editMode && !this.partnerId) {
|
||||
@@ -83,11 +94,11 @@ export class GuildFormComponent extends AbstractFormDialog<IPartnerRequest, IPar
|
||||
}
|
||||
|
||||
override submitForm(payload: IPartnerRequest) {
|
||||
const formData = buildFormData(this.form, { logo: this.logo() }, ['confirmPassword']);
|
||||
|
||||
if (this.editMode) {
|
||||
return this.service.update(this.partnerId!, payload);
|
||||
return this.service.update(this.partnerId!, formData);
|
||||
}
|
||||
// @ts-ignore
|
||||
const { confirmPassword, ...rest } = payload;
|
||||
return this.service.create(rest);
|
||||
return this.service.create(formData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export class AdminPartnerLicensesComponent extends AbstractList<IPartnerActivate
|
||||
field: 'consumer',
|
||||
header: 'مشتری',
|
||||
customDataModel(item: IPartnerActivatedLicenseResponse) {
|
||||
return `${item.business_activity.consumer.first_name} ${item.business_activity.consumer.last_name} (${item.business_activity.name})`;
|
||||
return `${item.business_activity.consumer_name} (${item.business_activity.name})`;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -31,7 +31,7 @@ export class AdminPartnerLicensesComponent extends AbstractList<IPartnerActivate
|
||||
type: 'nested',
|
||||
nestedOption: { path: 'license.accounts_limit' },
|
||||
},
|
||||
{ field: 'expires_at', header: 'تاریخ انقضا', type: 'date' },
|
||||
{ field: 'expires_at', header: 'تاریخ انقضای لایسنس', type: 'date' },
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -10,10 +10,9 @@ export interface IPartnerActivatedLicenseResponse extends IPartnerActivatedLicen
|
||||
|
||||
interface BusinessActivity extends ISummary {
|
||||
consumer: Consumer;
|
||||
consumer_name: string;
|
||||
}
|
||||
|
||||
interface Consumer {
|
||||
id: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ export interface IPartnerRawResponse {
|
||||
code: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
logo_url: string;
|
||||
licenses_status: {
|
||||
total: number;
|
||||
used: number;
|
||||
|
||||
@@ -3,7 +3,7 @@ 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 { IPartnerRawResponse, IPartnerResponse } from '../models';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PartnersService {
|
||||
@@ -18,11 +18,11 @@ export class PartnersService {
|
||||
return this.http.get<IPartnerRawResponse>(this.apiRoutes.single(partnerId));
|
||||
}
|
||||
|
||||
create(userData: IPartnerRequest): Observable<IPartnerResponse> {
|
||||
return this.http.post<IPartnerResponse>(this.apiRoutes.list(), userData);
|
||||
create(data: FormData): Observable<IPartnerResponse> {
|
||||
return this.http.post<IPartnerResponse>(this.apiRoutes.list(), data);
|
||||
}
|
||||
|
||||
update(partnerId: string, userData: IPartnerRequest): Observable<IPartnerResponse> {
|
||||
return this.http.patch<IPartnerResponse>(this.apiRoutes.single(partnerId), userData);
|
||||
update(partnerId: string, data: FormData): Observable<IPartnerResponse> {
|
||||
return this.http.patch<IPartnerResponse>(this.apiRoutes.single(partnerId), data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,18 @@
|
||||
(onEdit)="onEditClick($event)"
|
||||
(onRefresh)="refresh()"
|
||||
>
|
||||
<ng-template #name let-item>
|
||||
<div class="flex items-center gap-2">
|
||||
<p-avatar
|
||||
[image]="item.logo_url"
|
||||
[title]="item.name"
|
||||
[label]="item.logo_url ? '' : item.code.slice(0, 2)"
|
||||
shape="square"
|
||||
size="large"
|
||||
></p-avatar>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</ng-template>
|
||||
<ng-template #licensesStatus let-item>
|
||||
<span class="font-bold">
|
||||
{{ item.licenses_status.total }}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { AbstractList } from '@/shared/abstractClasses/abstract-list';
|
||||
import { PageDataListComponent } from '@/shared/components/pageDataList/page-data-list.component';
|
||||
import { Component, inject, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Avatar } from 'primeng/avatar';
|
||||
import { GuildFormComponent } from '../components/form.component';
|
||||
import { superAdminPartnersNamedRoutes } from '../constants';
|
||||
import { IPartnerResponse } from '../models';
|
||||
@@ -11,19 +12,20 @@ import { PartnersService } from '../services/main.service';
|
||||
@Component({
|
||||
selector: 'app-users',
|
||||
templateUrl: './list.component.html',
|
||||
imports: [PageDataListComponent, GuildFormComponent],
|
||||
imports: [PageDataListComponent, GuildFormComponent, Avatar],
|
||||
})
|
||||
export class PartnersComponent extends AbstractList<IPartnerResponse> {
|
||||
private readonly service = inject(PartnersService);
|
||||
private readonly router = inject(Router);
|
||||
|
||||
@ViewChild('name', { static: true }) name!: TemplateRef<any>;
|
||||
@ViewChild('licensesStatus', { static: true }) licensesStatus!: TemplateRef<any>;
|
||||
@ViewChild('accountQuotaStatus', { static: true }) accountQuotaStatus!: TemplateRef<any>;
|
||||
@ViewChild('licensesRenewStatus', { static: true }) licensesRenewStatus!: TemplateRef<any>;
|
||||
|
||||
override setColumns(): void {
|
||||
this.columns = [
|
||||
{ field: 'name', header: 'نام' },
|
||||
{ field: 'name', header: 'عنوان', customDataModel: this.name },
|
||||
{ field: 'code', header: 'کد' },
|
||||
{ field: 'licenses', header: 'تعداد لایسنسها', customDataModel: this.licensesStatus },
|
||||
{
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
<app-key-value label="عنوان شریک تجاری" [value]="partner()?.name" />
|
||||
<app-key-value label="کد شریک تجاری" [value]="partner()?.code" />
|
||||
<p-divider align="center" class="col-span-3">اطلاعات لایسنسها</p-divider>
|
||||
<app-key-value label="تعداد لایسنسهای خریداری شده" [value]="partner()?.licenses_status?.total" />
|
||||
<app-key-value label="تعداد لایسنسهای منقضی شده" [value]="partner()?.licenses_status?.expired" />
|
||||
<app-key-value label="تعداد لایسنسهای فروخته شده" [value]="partner()?.licenses_status?.used" />
|
||||
<app-key-value label="مجموع لایسنسهای خریداری شده" [value]="partner()?.licenses_status?.total" />
|
||||
<app-key-value label="مجموع لایسنسهای منقضی شده" [value]="partner()?.licenses_status?.expired" />
|
||||
<app-key-value label="مجموع لایسنسهای فروخته شده" [value]="partner()?.licenses_status?.used" />
|
||||
<app-key-value
|
||||
label="تعداد لایسنسهای باقیمانده"
|
||||
label="مجموع لایسنسهای باقیمانده"
|
||||
[value]="
|
||||
(partner()?.licenses_status?.total || 0) -
|
||||
(partner()?.licenses_status?.used || 0) -
|
||||
@@ -21,11 +21,11 @@
|
||||
"
|
||||
/>
|
||||
<p-divider align="center" class="col-span-3">اطلاعات شارژ کاربران</p-divider>
|
||||
<app-key-value label="تعداد کاربران خریداری شده" [value]="partner()?.account_quota_status?.total" />
|
||||
<app-key-value label="تعداد کاربران منقضی شده" [value]="partner()?.account_quota_status?.expired" />
|
||||
<app-key-value label="تعداد کاربران فروخته شده" [value]="partner()?.account_quota_status?.used" />
|
||||
<app-key-value label="مجموع کاربران خریداری شده" [value]="partner()?.account_quota_status?.total" />
|
||||
<app-key-value label="مجموع کاربران منقضی شده" [value]="partner()?.account_quota_status?.expired" />
|
||||
<app-key-value label="مجموع کاربران فروخته شده" [value]="partner()?.account_quota_status?.used" />
|
||||
<app-key-value
|
||||
label="تعداد کاربران باقیمانده"
|
||||
label="مجموع کاربران باقیمانده"
|
||||
[value]="
|
||||
(partner()?.account_quota_status?.total || 0) -
|
||||
(partner()?.account_quota_status?.used || 0) -
|
||||
@@ -33,11 +33,11 @@
|
||||
"
|
||||
/>
|
||||
<p-divider align="center" class="col-span-3">اطلاعات تمدید لایسنسها</p-divider>
|
||||
<app-key-value label="تعداد کاربران خریداری شده" [value]="partner()?.license_renew_status?.total" />
|
||||
<app-key-value label="تعداد کاربران منقضی شده" [value]="partner()?.license_renew_status?.expired" />
|
||||
<app-key-value label="تعداد کاربران فروخته شده" [value]="partner()?.license_renew_status?.used" />
|
||||
<app-key-value label="مجموع تمدید خریداری شده" [value]="partner()?.license_renew_status?.total" />
|
||||
<app-key-value label="مجموع تمدید منقضی شده" [value]="partner()?.license_renew_status?.expired" />
|
||||
<app-key-value label="مجموع تمدید فروخته شده" [value]="partner()?.license_renew_status?.used" />
|
||||
<app-key-value
|
||||
label="تعداد کاربران باقیمانده"
|
||||
label="مجموع تمدید باقیمانده"
|
||||
[value]="
|
||||
(partner()?.license_renew_status?.total || 0) -
|
||||
(partner()?.license_renew_status?.used || 0) -
|
||||
|
||||
Reference in New Issue
Block a user