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:
@@ -71,7 +71,7 @@ export class ConsumerPosListComponent extends AbstractList<IPosResponse> {
|
|||||||
sameSite: 'Lax', // or 'Strict' for same-site requests only
|
sameSite: 'Lax', // or 'Strict' for same-site requests only
|
||||||
secure: false,
|
secure: false,
|
||||||
path: '/',
|
path: '/',
|
||||||
domain: 'localhost',
|
domain: window.location.hostname,
|
||||||
});
|
});
|
||||||
window.open('/pos', '_blank');
|
window.open('/pos', '_blank');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { MustMatch } from '@/core/validators';
|
import { MustMatch } from '@/core/validators';
|
||||||
import { AbstractForm } from '@/shared/abstractClasses';
|
import { AbstractForm } from '@/shared/abstractClasses';
|
||||||
import { fieldControl } from '@/shared/constants/fields';
|
|
||||||
import {
|
import {
|
||||||
FirstNameComponent,
|
FirstNameComponent,
|
||||||
LastNameComponent,
|
LastNameComponent,
|
||||||
@@ -12,6 +11,7 @@ import {
|
|||||||
UsernameComponent,
|
UsernameComponent,
|
||||||
} from '@/shared/components';
|
} from '@/shared/components';
|
||||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||||
|
import { fieldControl } from '@/shared/constants/fields';
|
||||||
import { Component, inject, Input, signal } from '@angular/core';
|
import { Component, inject, Input, signal } from '@angular/core';
|
||||||
import { FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
import { Divider } from 'primeng/divider';
|
import { Divider } from 'primeng/divider';
|
||||||
@@ -56,10 +56,10 @@ export class ConsumerUserFormContentComponent extends AbstractForm<
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
selectedType = signal<string>(this.initialValues?.type || this.consumerTypes[0].value);
|
selectedType = signal<string>(this.initialValues?.type?.value || this.consumerTypes[0].value);
|
||||||
|
|
||||||
initForm = () => {
|
initForm = () => {
|
||||||
this.selectedType.set(this.initialValues?.type || this.consumerTypes[0].value);
|
this.selectedType.set(this.initialValues?.type?.value || this.consumerTypes[0].value);
|
||||||
const legal = this.fb.group({
|
const legal = this.fb.group({
|
||||||
name: fieldControl.legal_name(this.initialValues?.legal?.name || ''),
|
name: fieldControl.legal_name(this.initialValues?.legal?.name || ''),
|
||||||
registration_code: fieldControl.registration_code(
|
registration_code: fieldControl.registration_code(
|
||||||
|
|||||||
@@ -4,8 +4,15 @@
|
|||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="grid grid-cols-3 gap-4 items-center">
|
<div class="grid grid-cols-3 gap-4 items-center">
|
||||||
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
||||||
<app-key-value label="نوع مشتری" [value]="consumer()?.type" />
|
<app-key-value label="وضعیت" [value]="consumer()?.status?.translate" />
|
||||||
<app-key-value label="وضعیت" [value]="consumer()?.status" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</app-card-data>
|
</app-card-data>
|
||||||
|
|||||||
@@ -25,12 +25,23 @@ export class ConsumerAccountListComponent extends AbstractList<IConsumerAccountR
|
|||||||
type: 'nested',
|
type: 'nested',
|
||||||
nestedOption: { path: 'account.username' },
|
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',
|
field: 'status',
|
||||||
header: 'وضعیت',
|
header: 'وضعیت',
|
||||||
type: 'nested',
|
type: 'nested',
|
||||||
nestedOption: { path: 'account.status' },
|
nestedOption: { path: 'status.translate' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'created_at',
|
field: 'created_at',
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { TAccountType } from '@/core/constants/accountTypes.const';
|
import { TAccountType } from '@/core/constants/accountTypes.const';
|
||||||
|
import ISummary from '@/core/models/summary';
|
||||||
|
import { IEnumTranslate } from '@/shared/models/enum_translate.type';
|
||||||
|
|
||||||
export interface IConsumerAccountRawResponse {
|
export interface IConsumerAccountRawResponse {
|
||||||
id: string;
|
id: string;
|
||||||
role: string;
|
role: IEnumTranslate;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
account: AccountInfo;
|
account: AccountInfo;
|
||||||
|
pos: Pos;
|
||||||
}
|
}
|
||||||
export interface IConsumerAccountResponse extends IConsumerAccountRawResponse {}
|
export interface IConsumerAccountResponse extends IConsumerAccountRawResponse {}
|
||||||
|
|
||||||
@@ -22,3 +25,12 @@ interface AccountInfo {
|
|||||||
username: string;
|
username: string;
|
||||||
status: 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',
|
type: 'nested',
|
||||||
nestedOption: { path: 'partner.name' },
|
nestedOption: { path: 'partner.name' },
|
||||||
},
|
},
|
||||||
{ field: 'status', header: 'وضعیت' },
|
|
||||||
|
{
|
||||||
|
field: 'status',
|
||||||
|
header: 'وضعیت',
|
||||||
|
type: 'nested',
|
||||||
|
nestedOption: { path: 'status.translate' },
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// field: 'license_expires_at',
|
// field: 'license_expires_at',
|
||||||
// header: 'تاریخ انقضای لایسنس',
|
// header: 'تاریخ انقضای لایسنس',
|
||||||
|
|||||||
@@ -4,8 +4,15 @@
|
|||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="grid grid-cols-3 gap-4 items-center">
|
<div class="grid grid-cols-3 gap-4 items-center">
|
||||||
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
||||||
<app-key-value label="نوع مشتری" [value]="consumer()?.type" />
|
<app-key-value label="وضعیت" [value]="consumer()?.status?.translate" />
|
||||||
<app-key-value label="وضعیت" [value]="consumer()?.status" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</app-card-data>
|
</app-card-data>
|
||||||
|
|||||||
+1
-6
@@ -25,17 +25,12 @@ export class AdminPartnerChargeAccountListComponent extends AbstractList<IAdminP
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'activation_expires_at',
|
field: 'activation_expires_at',
|
||||||
header: 'تاریخ انقضا',
|
header: 'تاریخ انقضای فروش',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
dateOption: {
|
dateOption: {
|
||||||
expiredMode: true,
|
expiredMode: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: 'created_at',
|
|
||||||
header: 'تاریخ ایجاد',
|
|
||||||
type: 'date',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-6
@@ -26,17 +26,12 @@ export class AdminPartnerChargeLicenseTransactionListComponent extends AbstractL
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'activation_expires_at',
|
field: 'activation_expires_at',
|
||||||
header: 'تاریخ انقضا',
|
header: 'تاریخ انقضای فروش',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
dateOption: {
|
dateOption: {
|
||||||
expiredMode: true,
|
expiredMode: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
field: 'created_at',
|
|
||||||
header: 'تاریخ ایجاد',
|
|
||||||
type: 'date',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
(onHide)="close()"
|
(onHide)="close()"
|
||||||
>
|
>
|
||||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
<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.name" name="name" />
|
||||||
<app-input label="کد" [control]="form.controls.code" name="code" />
|
<app-input label="کد" [control]="form.controls.code" name="code" />
|
||||||
@if (!editMode) {
|
@if (!editMode) {
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
|
import { Maybe } from '@/core';
|
||||||
import { MustMatch } from '@/core/validators';
|
import { MustMatch } from '@/core/validators';
|
||||||
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
||||||
import { InputComponent, SharedPasswordInputComponent } from '@/shared/components';
|
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 { 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 { ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
import { Divider } from 'primeng/divider';
|
import { Divider } from 'primeng/divider';
|
||||||
import { IPartnerRequest, IPartnerResponse } from '../models';
|
import { IPartnerRequest, IPartnerResponse } from '../models';
|
||||||
import { PartnersService } from '../services/main.service';
|
import { PartnersService } from '../services/main.service';
|
||||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'partner-form',
|
selector: 'partner-form',
|
||||||
@@ -19,6 +23,7 @@ import { SharedDialogComponent } from '@/shared/components/dialog/dialog.compone
|
|||||||
FormFooterActionsComponent,
|
FormFooterActionsComponent,
|
||||||
Divider,
|
Divider,
|
||||||
SharedPasswordInputComponent,
|
SharedPasswordInputComponent,
|
||||||
|
SharedUploadFileComponent,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class GuildFormComponent extends AbstractFormDialog<IPartnerRequest, IPartnerResponse> {
|
export class GuildFormComponent extends AbstractFormDialog<IPartnerRequest, IPartnerResponse> {
|
||||||
@@ -70,10 +75,16 @@ export class GuildFormComponent extends AbstractFormDialog<IPartnerRequest, IPar
|
|||||||
return form;
|
return form;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logo = signal<Maybe<File>>(null);
|
||||||
|
|
||||||
form = this.initForm();
|
form = this.initForm();
|
||||||
|
|
||||||
preparedTitle = computed(() => `${this.editMode ? 'ویرایش' : 'ایجاد'} شریک تجاری`);
|
preparedTitle = computed(() => `${this.editMode ? 'ویرایش' : 'ایجاد'} شریک تجاری`);
|
||||||
|
|
||||||
|
changeFile(payload: onSelectFileArgs) {
|
||||||
|
this.logo.set(payload.file);
|
||||||
|
}
|
||||||
|
|
||||||
override ngOnChanges() {
|
override ngOnChanges() {
|
||||||
this.form.patchValue(this.initialValues ?? {});
|
this.form.patchValue(this.initialValues ?? {});
|
||||||
if (this.editMode && !this.partnerId) {
|
if (this.editMode && !this.partnerId) {
|
||||||
@@ -83,11 +94,11 @@ export class GuildFormComponent extends AbstractFormDialog<IPartnerRequest, IPar
|
|||||||
}
|
}
|
||||||
|
|
||||||
override submitForm(payload: IPartnerRequest) {
|
override submitForm(payload: IPartnerRequest) {
|
||||||
|
const formData = buildFormData(this.form, { logo: this.logo() }, ['confirmPassword']);
|
||||||
|
|
||||||
if (this.editMode) {
|
if (this.editMode) {
|
||||||
return this.service.update(this.partnerId!, payload);
|
return this.service.update(this.partnerId!, formData);
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
return this.service.create(formData);
|
||||||
const { confirmPassword, ...rest } = payload;
|
|
||||||
return this.service.create(rest);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class AdminPartnerLicensesComponent extends AbstractList<IPartnerActivate
|
|||||||
field: 'consumer',
|
field: 'consumer',
|
||||||
header: 'مشتری',
|
header: 'مشتری',
|
||||||
customDataModel(item: IPartnerActivatedLicenseResponse) {
|
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',
|
type: 'nested',
|
||||||
nestedOption: { path: 'license.accounts_limit' },
|
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 {
|
interface BusinessActivity extends ISummary {
|
||||||
consumer: Consumer;
|
consumer: Consumer;
|
||||||
|
consumer_name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Consumer {
|
interface Consumer {
|
||||||
id: string;
|
id: string;
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export interface IPartnerRawResponse {
|
|||||||
code: string;
|
code: string;
|
||||||
status: string;
|
status: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
logo_url: string;
|
||||||
licenses_status: {
|
licenses_status: {
|
||||||
total: number;
|
total: number;
|
||||||
used: number;
|
used: number;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { PARTNERS_API_ROUTES } from '../constants';
|
import { PARTNERS_API_ROUTES } from '../constants';
|
||||||
import { IPartnerRawResponse, IPartnerRequest, IPartnerResponse } from '../models';
|
import { IPartnerRawResponse, IPartnerResponse } from '../models';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class PartnersService {
|
export class PartnersService {
|
||||||
@@ -18,11 +18,11 @@ export class PartnersService {
|
|||||||
return this.http.get<IPartnerRawResponse>(this.apiRoutes.single(partnerId));
|
return this.http.get<IPartnerRawResponse>(this.apiRoutes.single(partnerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
create(userData: IPartnerRequest): Observable<IPartnerResponse> {
|
create(data: FormData): Observable<IPartnerResponse> {
|
||||||
return this.http.post<IPartnerResponse>(this.apiRoutes.list(), userData);
|
return this.http.post<IPartnerResponse>(this.apiRoutes.list(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(partnerId: string, userData: IPartnerRequest): Observable<IPartnerResponse> {
|
update(partnerId: string, data: FormData): Observable<IPartnerResponse> {
|
||||||
return this.http.patch<IPartnerResponse>(this.apiRoutes.single(partnerId), userData);
|
return this.http.patch<IPartnerResponse>(this.apiRoutes.single(partnerId), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,18 @@
|
|||||||
(onEdit)="onEditClick($event)"
|
(onEdit)="onEditClick($event)"
|
||||||
(onRefresh)="refresh()"
|
(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>
|
<ng-template #licensesStatus let-item>
|
||||||
<span class="font-bold">
|
<span class="font-bold">
|
||||||
{{ item.licenses_status.total }}
|
{{ 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 { PageDataListComponent } from '@/shared/components/pageDataList/page-data-list.component';
|
||||||
import { Component, inject, TemplateRef, ViewChild } from '@angular/core';
|
import { Component, inject, TemplateRef, ViewChild } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
import { Avatar } from 'primeng/avatar';
|
||||||
import { GuildFormComponent } from '../components/form.component';
|
import { GuildFormComponent } from '../components/form.component';
|
||||||
import { superAdminPartnersNamedRoutes } from '../constants';
|
import { superAdminPartnersNamedRoutes } from '../constants';
|
||||||
import { IPartnerResponse } from '../models';
|
import { IPartnerResponse } from '../models';
|
||||||
@@ -11,19 +12,20 @@ import { PartnersService } from '../services/main.service';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-users',
|
selector: 'app-users',
|
||||||
templateUrl: './list.component.html',
|
templateUrl: './list.component.html',
|
||||||
imports: [PageDataListComponent, GuildFormComponent],
|
imports: [PageDataListComponent, GuildFormComponent, Avatar],
|
||||||
})
|
})
|
||||||
export class PartnersComponent extends AbstractList<IPartnerResponse> {
|
export class PartnersComponent extends AbstractList<IPartnerResponse> {
|
||||||
private readonly service = inject(PartnersService);
|
private readonly service = inject(PartnersService);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
|
|
||||||
|
@ViewChild('name', { static: true }) name!: TemplateRef<any>;
|
||||||
@ViewChild('licensesStatus', { static: true }) licensesStatus!: TemplateRef<any>;
|
@ViewChild('licensesStatus', { static: true }) licensesStatus!: TemplateRef<any>;
|
||||||
@ViewChild('accountQuotaStatus', { static: true }) accountQuotaStatus!: TemplateRef<any>;
|
@ViewChild('accountQuotaStatus', { static: true }) accountQuotaStatus!: TemplateRef<any>;
|
||||||
@ViewChild('licensesRenewStatus', { static: true }) licensesRenewStatus!: TemplateRef<any>;
|
@ViewChild('licensesRenewStatus', { static: true }) licensesRenewStatus!: TemplateRef<any>;
|
||||||
|
|
||||||
override setColumns(): void {
|
override setColumns(): void {
|
||||||
this.columns = [
|
this.columns = [
|
||||||
{ field: 'name', header: 'نام' },
|
{ field: 'name', header: 'عنوان', customDataModel: this.name },
|
||||||
{ field: 'code', header: 'کد' },
|
{ field: 'code', header: 'کد' },
|
||||||
{ field: 'licenses', header: 'تعداد لایسنسها', customDataModel: this.licensesStatus },
|
{ field: 'licenses', header: 'تعداد لایسنسها', customDataModel: this.licensesStatus },
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
<app-key-value label="عنوان شریک تجاری" [value]="partner()?.name" />
|
<app-key-value label="عنوان شریک تجاری" [value]="partner()?.name" />
|
||||||
<app-key-value label="کد شریک تجاری" [value]="partner()?.code" />
|
<app-key-value label="کد شریک تجاری" [value]="partner()?.code" />
|
||||||
<p-divider align="center" class="col-span-3">اطلاعات لایسنسها</p-divider>
|
<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?.total" />
|
||||||
<app-key-value label="تعداد لایسنسهای منقضی شده" [value]="partner()?.licenses_status?.expired" />
|
<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?.used" />
|
||||||
<app-key-value
|
<app-key-value
|
||||||
label="تعداد لایسنسهای باقیمانده"
|
label="مجموع لایسنسهای باقیمانده"
|
||||||
[value]="
|
[value]="
|
||||||
(partner()?.licenses_status?.total || 0) -
|
(partner()?.licenses_status?.total || 0) -
|
||||||
(partner()?.licenses_status?.used || 0) -
|
(partner()?.licenses_status?.used || 0) -
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<p-divider align="center" class="col-span-3">اطلاعات شارژ کاربران</p-divider>
|
<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?.total" />
|
||||||
<app-key-value label="تعداد کاربران منقضی شده" [value]="partner()?.account_quota_status?.expired" />
|
<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?.used" />
|
||||||
<app-key-value
|
<app-key-value
|
||||||
label="تعداد کاربران باقیمانده"
|
label="مجموع کاربران باقیمانده"
|
||||||
[value]="
|
[value]="
|
||||||
(partner()?.account_quota_status?.total || 0) -
|
(partner()?.account_quota_status?.total || 0) -
|
||||||
(partner()?.account_quota_status?.used || 0) -
|
(partner()?.account_quota_status?.used || 0) -
|
||||||
@@ -33,11 +33,11 @@
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<p-divider align="center" class="col-span-3">اطلاعات تمدید لایسنسها</p-divider>
|
<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?.total" />
|
||||||
<app-key-value label="تعداد کاربران منقضی شده" [value]="partner()?.license_renew_status?.expired" />
|
<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?.used" />
|
||||||
<app-key-value
|
<app-key-value
|
||||||
label="تعداد کاربران باقیمانده"
|
label="مجموع تمدید باقیمانده"
|
||||||
[value]="
|
[value]="
|
||||||
(partner()?.license_renew_status?.total || 0) -
|
(partner()?.license_renew_status?.total || 0) -
|
||||||
(partner()?.license_renew_status?.used || 0) -
|
(partner()?.license_renew_status?.used || 0) -
|
||||||
|
|||||||
@@ -35,3 +35,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="w-screen h-screen flex items-center justify-center bg-red-400">
|
||||||
|
<div class="bg-white p-8 rounded-lg shadow-md w-[520px]">
|
||||||
|
<h1 class="text-2xl font-bold mb-4">Auth Page</h1>
|
||||||
|
<p class="mb-4">WebView payment listener test</p>
|
||||||
|
<div class="flex gap-3 mb-4">
|
||||||
|
<button pButton outlined class="mx-auto" (click)="pay()">pay</button>
|
||||||
|
<button pButton outlined class="mx-auto" (click)="mockPaymentResult()">mock paymentResult</button>
|
||||||
|
</div>
|
||||||
|
<pre class="bg-gray-100 p-3 rounded text-xs overflow-auto max-h-52">{{ text() }}</pre>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { IAuthResponse, TRoles } from '@/core';
|
import { IAuthResponse, Maybe, TRoles } from '@/core';
|
||||||
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, OnDestroy, OnInit, inject, Input, Output, signal } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
import { ButtonDirective } from 'primeng/button';
|
||||||
import images from 'src/assets/images';
|
import images from 'src/assets/images';
|
||||||
import { LoginComponent } from './login/login.component';
|
import { LoginComponent } from './login/login.component';
|
||||||
|
|
||||||
@@ -10,9 +11,9 @@ type TSteps = 'login' | 'otp' | 'modifyLoginInfo' | 'signup';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-auth',
|
selector: 'app-auth',
|
||||||
templateUrl: './auth.component.html',
|
templateUrl: './auth.component.html',
|
||||||
imports: [LoginComponent],
|
imports: [LoginComponent, ButtonDirective],
|
||||||
})
|
})
|
||||||
export class AuthComponent {
|
export class AuthComponent implements OnInit, OnDestroy {
|
||||||
@Input() redirectUrl!: string;
|
@Input() redirectUrl!: string;
|
||||||
@Input() loginApiUrl!: string;
|
@Input() loginApiUrl!: string;
|
||||||
@Input() role?: TRoles;
|
@Input() role?: TRoles;
|
||||||
@@ -83,4 +84,67 @@ export class AuthComponent {
|
|||||||
}
|
}
|
||||||
this.router.navigateByUrl(redirectUrl);
|
this.router.navigateByUrl(redirectUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
text = signal<string>('waiting for paymentResult...');
|
||||||
|
private restorePaymentCallback: Maybe<() => void> = null;
|
||||||
|
private readonly injectedPaymentResultHandler = (payload: unknown) => {
|
||||||
|
this.handlePaymentResult(payload);
|
||||||
|
};
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.listenAndroidPaymentResultCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.restorePaymentCallback?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
private listenAndroidPaymentResultCallback() {
|
||||||
|
const w = window as any;
|
||||||
|
const previousGlobal = w.onPaymentResult;
|
||||||
|
// Android app can call this function directly via evaluateJavascript.
|
||||||
|
w.onPaymentResult = this.injectedPaymentResultHandler;
|
||||||
|
|
||||||
|
const bridge = w.AndroidPSP;
|
||||||
|
const previousBridge = bridge?.onPaymentResult;
|
||||||
|
if (bridge) {
|
||||||
|
bridge.onPaymentResult = this.injectedPaymentResultHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.restorePaymentCallback = () => {
|
||||||
|
w.onPaymentResult = previousGlobal;
|
||||||
|
if (bridge) {
|
||||||
|
bridge.onPaymentResult = previousBridge;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private handlePaymentResult(result: unknown) {
|
||||||
|
const value = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
|
||||||
|
this.text.set(value);
|
||||||
|
this.toastService.success({ text: 'Result received from Android.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
async pay() {
|
||||||
|
//@ts-ignore
|
||||||
|
this.toastService.success({ text: window.AndroidPSP.pay(100000) });
|
||||||
|
//@ts-ignore
|
||||||
|
await window.AndroidPSP?.pay(100000)
|
||||||
|
.then((response: any) => {
|
||||||
|
// alert('payment')
|
||||||
|
// console.log('Payment response:', response);
|
||||||
|
this.toastService.success({ text: 'پرداخت با موفقیت انجام شد.' });
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
// console.error('Payment error:', error);
|
||||||
|
this.toastService.error({ text: 'خطا در انجام پرداخت.' });
|
||||||
|
});
|
||||||
|
this.toastService.success({ text: 'پرداخت با موفقیت انجام شد.' });
|
||||||
|
// //@ts-ignore
|
||||||
|
// alert(window.AndroidPSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
mockPaymentResult() {
|
||||||
|
this.injectedPaymentResultHandler(`test-result-${Date.now()}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class CatalogGuildSelectComponent extends AbstractSelectComponent<
|
|||||||
@Input() label: string = '';
|
@Input() label: string = '';
|
||||||
private readonly service = inject(CatalogsService);
|
private readonly service = inject(CatalogsService);
|
||||||
|
|
||||||
ngOnInit() {
|
ngAfterViewInit() {
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,88 @@
|
|||||||
<p-fileupload [name]="name" [accept]="accept" [maxFileSize]="maxSize" (onSelect)="onSelectedFile($event)">
|
<p-fileupload
|
||||||
<ng-template #header let-chooseCallback="chooseCallback">
|
[name]="name"
|
||||||
<div class="flex items-center justify-center flex-col cursor-pointer py-5 w-full" (click)="chooseCallback()">
|
[accept]="accept"
|
||||||
<i class="pi pi-cloud-upload border-2! rounded-full! p-8! text-4xl! text-muted-color!"></i>
|
[maxFileSize]="maxSize"
|
||||||
<p class="mt-6 mb-0">فایل مورد نظر خود را در اینجا رها کنید</p>
|
mode="advanced"
|
||||||
|
(onSelect)="onSelectedFile($event)"
|
||||||
|
>
|
||||||
|
<ng-template
|
||||||
|
#header
|
||||||
|
let-files
|
||||||
|
let-chooseCallback="chooseCallback"
|
||||||
|
let-clearCallback="clearCallback"
|
||||||
|
let-uploadCallback="uploadCallback"
|
||||||
|
class="hidden"
|
||||||
|
[style]="{ display: 'none' }"
|
||||||
|
>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template
|
||||||
|
#content
|
||||||
|
let-files
|
||||||
|
let-chooseCallback="chooseCallback"
|
||||||
|
let-uploadedFiles="uploadedFiles"
|
||||||
|
let-removeFileCallback="removeFileCallback"
|
||||||
|
let-removeUploadedFileCallback="removeUploadedFileCallback"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-8 pt-4">
|
||||||
|
@if (filePreview) {
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<div class="inline-block relative">
|
||||||
|
<img [src]="filePreview" alt="Preview" class="max-h-52 rounded-lg object-contain" />
|
||||||
|
<div class="absolute left-2 top-2 flex gap-2">
|
||||||
|
<button
|
||||||
|
pButton
|
||||||
|
type="button"
|
||||||
|
icon="pi pi-pencil"
|
||||||
|
severity="warn"
|
||||||
|
size="small"
|
||||||
|
(click)="chooseCallback()"
|
||||||
|
></button>
|
||||||
|
<button
|
||||||
|
pButton
|
||||||
|
type="button"
|
||||||
|
icon="pi pi-trash"
|
||||||
|
severity="danger"
|
||||||
|
size="small"
|
||||||
|
(click)="onDeleteFilePreview()"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
|
<div class="flex items-center justify-center flex-col cursor-pointer py-5 w-full" (click)="chooseCallback()">
|
||||||
|
<i class="pi pi-cloud-upload border-2! rounded-full! p-8! text-4xl! text-muted-color!"></i>
|
||||||
|
<p class="mt-6 mb-0">فایل مورد نظر خود را در اینجا رها کنید</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<!-- <div *ngIf="files?.length > 0">
|
||||||
|
<h5>Pending</h5>
|
||||||
|
<div class="flex flex-wrap gap-4">
|
||||||
|
<div *ngFor="let file of files; let i = index" class="p-8 rounded-border flex flex-col border border-surface items-center gap-4">
|
||||||
|
<div>
|
||||||
|
<img role="presentation" [alt]="file.name" [src]="file.objectURL" width="100" height="50" />
|
||||||
|
</div>
|
||||||
|
<span class="font-semibold text-ellipsis max-w-60 whitespace-nowrap overflow-hidden">{{ file.name }}</span>
|
||||||
|
<div>{{ formatSize(file.size) }}</div>
|
||||||
|
<p-badge value="Pending" severity="warn" />
|
||||||
|
<p-button icon="pi pi-times" (click)="onRemoveTemplatingFile($event, file, removeFileCallback, index)" [outlined]="true" [rounded]="true" severity="danger" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="uploadedFiles?.length > 0">
|
||||||
|
<h5>Completed</h5>
|
||||||
|
<div class="flex flex-wrap gap-4">
|
||||||
|
<div *ngFor="let file of uploadedFiles; let i = index" class="card m-0 px-12 flex flex-col border border-surface items-center gap-4">
|
||||||
|
<div>
|
||||||
|
<img role="presentation" [alt]="file.name" [src]="file.objectURL" width="100" height="50" />
|
||||||
|
</div>
|
||||||
|
<span class="font-semibold text-ellipsis max-w-60 whitespace-nowrap overflow-hidden">{{ file.name }}</span>
|
||||||
|
<div>{{ formatSize(file.size) }}</div>
|
||||||
|
<p-badge value="Completed" class="mt-4" severity="success" />
|
||||||
|
<p-button icon="pi pi-times" (onClick)="removeUploadedFileCallback(index)" [outlined]="true" [rounded]="true" severity="danger" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
<ng-template #file></ng-template>
|
||||||
</p-fileupload>
|
</p-fileupload>
|
||||||
|
|||||||
@@ -1,31 +1,90 @@
|
|||||||
import { Maybe } from '@/core';
|
import { Maybe } from '@/core';
|
||||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
EventEmitter,
|
||||||
|
Input,
|
||||||
|
OnChanges,
|
||||||
|
OnDestroy,
|
||||||
|
Output,
|
||||||
|
SimpleChanges,
|
||||||
|
ViewChild,
|
||||||
|
} from '@angular/core';
|
||||||
|
import { ButtonDirective } from 'primeng/button';
|
||||||
import { FileSelectEvent, FileUpload } from 'primeng/fileupload';
|
import { FileSelectEvent, FileUpload } from 'primeng/fileupload';
|
||||||
import { onSelectFileArgs } from './model';
|
import { onSelectFileArgs } from './model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-shared-upload-file',
|
selector: 'app-shared-upload-file',
|
||||||
templateUrl: './upload-file.component.html',
|
templateUrl: './upload-file.component.html',
|
||||||
imports: [FileUpload],
|
imports: [FileUpload, ButtonDirective],
|
||||||
})
|
})
|
||||||
export class SharedUploadFileComponent {
|
export class SharedUploadFileComponent implements OnChanges, OnDestroy {
|
||||||
@Input() currentImage: Maybe<string> = null;
|
|
||||||
@Input() loading: boolean = false;
|
@Input() loading: boolean = false;
|
||||||
@Input() name: string = 'file';
|
@Input() name: string = 'file';
|
||||||
@Input() accept: string = 'image/*';
|
@Input() accept: string = 'image/*';
|
||||||
@Input() maxSize: Maybe<number> = 5 * 1024 * 1024;
|
@Input() maxSize: Maybe<number> = 5 * 1024 * 1024;
|
||||||
@Input() error: Maybe<string> = null;
|
@Input() error: Maybe<string> = null;
|
||||||
@Input() hint: Maybe<string> = null;
|
@Input() hint: Maybe<string> = null;
|
||||||
|
@Input() initial_file_url: Maybe<string> = null;
|
||||||
|
|
||||||
@Output() onSelect = new EventEmitter<onSelectFileArgs>();
|
@Output() onSelect = new EventEmitter<onSelectFileArgs>();
|
||||||
|
|
||||||
|
@ViewChild(FileUpload) uploader?: FileUpload;
|
||||||
|
|
||||||
|
filePreview: Maybe<string> = null;
|
||||||
|
private objectUrl: Maybe<string> = null;
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
if ('initial_file_url' in changes && !this.objectUrl) {
|
||||||
|
this.filePreview = this.initial_file_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.revokeObjectUrl();
|
||||||
|
console.log('first');
|
||||||
|
|
||||||
|
if (this.initial_file_url && !this.objectUrl) {
|
||||||
|
this.filePreview = this.initial_file_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.revokeObjectUrl();
|
||||||
|
}
|
||||||
|
|
||||||
onSelectedFile($event: FileSelectEvent) {
|
onSelectedFile($event: FileSelectEvent) {
|
||||||
const file = $event.files?.[0];
|
const file = $event.files?.[0];
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.setPreviewFromFile(file);
|
||||||
const payload = new FormData();
|
const payload = new FormData();
|
||||||
payload.append(this.name, file, file.name);
|
payload.append(this.name, file, file.name);
|
||||||
this.onSelect.emit({ data: payload, file });
|
this.onSelect.emit({ data: payload, file });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onEditFile() {
|
||||||
|
this.uploader?.choose();
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteFilePreview() {
|
||||||
|
this.revokeObjectUrl();
|
||||||
|
this.filePreview = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setPreviewFromFile(file: File) {
|
||||||
|
this.revokeObjectUrl();
|
||||||
|
this.objectUrl = URL.createObjectURL(file);
|
||||||
|
this.filePreview = this.objectUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private revokeObjectUrl() {
|
||||||
|
if (!this.objectUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.filePreview = null;
|
||||||
|
URL.revokeObjectURL(this.objectUrl);
|
||||||
|
this.objectUrl = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Maybe } from '@/core';
|
import { Maybe } from '@/core';
|
||||||
|
import { IEnumTranslate } from './enum_translate.type';
|
||||||
|
|
||||||
export interface IConsumerRawResponse {
|
export interface IConsumerRawResponse {
|
||||||
id: string;
|
id: string;
|
||||||
status: string;
|
|
||||||
created_at: string;
|
created_at: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: 'INDIVIDUAL' | 'LEGAL';
|
type: IEnumTranslate;
|
||||||
|
status: IEnumTranslate;
|
||||||
partner: {
|
partner: {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface IEnumTranslate<T = string> {
|
||||||
|
value: T;
|
||||||
|
translate: string;
|
||||||
|
}
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
export function buildFormData(
|
export function buildFormData(
|
||||||
formGroup: any,
|
formGroup: any,
|
||||||
fileProperties: { [key: string]: File | null } = {},
|
fileProperties: { [key: string]: File | null } = {},
|
||||||
|
skipFieldKeys: string[] = [],
|
||||||
): FormData {
|
): FormData {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
Object.keys(formGroup.controls).forEach((key) => {
|
Object.keys(formGroup.controls).forEach((key) => {
|
||||||
|
if (skipFieldKeys.includes(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const control = formGroup.get(key);
|
const control = formGroup.get(key);
|
||||||
if (control && control.value !== null && control.value !== undefined) {
|
if (control && control.value !== null && control.value !== undefined) {
|
||||||
formData.append(key, control.value);
|
formData.append(key, control.value);
|
||||||
|
|||||||
@@ -58,3 +58,11 @@ input.p-inputtext {
|
|||||||
.p-tablist {
|
.p-tablist {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-fileupload-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-avatar-image {
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
// apiBaseUrl: 'http://194.59.214.243:5002',
|
// apiBaseUrl: 'http://194.59.214.243:5002',
|
||||||
apiBaseUrl: 'http://localhost:5002',
|
apiBaseUrl: 'http://192.168.128.73:5002',
|
||||||
|
// apiBaseUrl: 'http://localhost:5002',
|
||||||
// host: 'http://194.59.214.243',
|
// host: 'http://194.59.214.243',
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 5000,
|
port: 5000,
|
||||||
|
|||||||
Reference in New Issue
Block a user