diff --git a/src/app/domains/consumer/modules/businessActivities/components/complexes/form.component.html b/src/app/domains/consumer/modules/businessActivities/components/complexes/form.component.html index 394ad56..248f2ba 100644 --- a/src/app/domains/consumer/modules/businessActivities/components/complexes/form.component.html +++ b/src/app/domains/consumer/modules/businessActivities/components/complexes/form.component.html @@ -8,7 +8,7 @@ >
- + diff --git a/src/app/domains/consumer/modules/businessActivities/components/complexes/form.component.ts b/src/app/domains/consumer/modules/businessActivities/components/complexes/form.component.ts index b71a8c7..fb7778a 100644 --- a/src/app/domains/consumer/modules/businessActivities/components/complexes/form.component.ts +++ b/src/app/domains/consumer/modules/businessActivities/components/complexes/form.component.ts @@ -25,7 +25,7 @@ export class ConsumerComplexFormComponent extends AbstractFormDialog< initForm = () => { return this.fb.group({ name: [this.initialValues?.name || '', [Validators.required]], - tax_id: [this.initialValues?.tax_id || '', [Validators.required]], + branch_code: [this.initialValues?.branch_code || ''], address: [this.initialValues?.address || '', [Validators.required]], }); }; @@ -33,7 +33,7 @@ export class ConsumerComplexFormComponent extends AbstractFormDialog< form = this.initForm(); get preparedTitle() { - return `ویرایش فروشگاه ${this.initialValues?.name}`; + return `ویرایش شعبه ${this.initialValues?.name}`; } override ngOnChanges(): void { diff --git a/src/app/domains/consumer/modules/businessActivities/components/complexes/list.component.html b/src/app/domains/consumer/modules/businessActivities/components/complexes/list.component.html index 3198c56..1b1cee9 100644 --- a/src/app/domains/consumer/modules/businessActivities/components/complexes/list.component.html +++ b/src/app/domains/consumer/modules/businessActivities/components/complexes/list.component.html @@ -1,7 +1,7 @@ = { loadComponent: () => import('../../views/complexes/list.component').then((m) => m.ConsumerComplexesComponent), meta: { - title: 'فروشگاه‌ها', + title: 'شعب', pagePath: (businessId: string) => baseUrl(businessId), }, }, @@ -21,7 +21,7 @@ export const consumerComplexesNamedRoutes: NamedRoutes = { loadComponent: () => import('../../views/complexes/single.component').then((m) => m.ConsumerComplexComponent), meta: { - title: 'فروشگاه', + title: 'شعبه', pagePath: (businessId: string, complexId: string) => `${baseUrl(businessId)}/${complexId}`, }, }, diff --git a/src/app/domains/consumer/modules/businessActivities/models/complexes_io.d.ts b/src/app/domains/consumer/modules/businessActivities/models/complexes_io.d.ts index ba9ebe0..8ea2421 100644 --- a/src/app/domains/consumer/modules/businessActivities/models/complexes_io.d.ts +++ b/src/app/domains/consumer/modules/businessActivities/models/complexes_io.d.ts @@ -1,7 +1,7 @@ export interface IComplexRawResponse { name: string; address: string; - tax_id: string; + branch_code: string; id: string; } export interface IComplexResponse extends IComplexRawResponse {} @@ -9,5 +9,5 @@ export interface IComplexResponse extends IComplexRawResponse {} export interface IComplexRequest { name: string; address: string; - tax_id: string; + branch_code: string; } diff --git a/src/app/domains/consumer/modules/businessActivities/models/io.d.ts b/src/app/domains/consumer/modules/businessActivities/models/io.d.ts index b04691b..9a9f1ca 100644 --- a/src/app/domains/consumer/modules/businessActivities/models/io.d.ts +++ b/src/app/domains/consumer/modules/businessActivities/models/io.d.ts @@ -3,10 +3,12 @@ import ISummary from '@/core/models/summary'; export interface IBusinessActivityRawResponse { id: string; name: string; + economic_code: string; guild: ISummary; } export interface IBusinessActivityResponse extends IBusinessActivityRawResponse {} export interface IBusinessActivityRequest { + economic_code: string; name: string; } diff --git a/src/app/domains/consumer/modules/businessActivities/views/complexes/single.component.html b/src/app/domains/consumer/modules/businessActivities/views/complexes/single.component.html index 2a8f962..6ce51b1 100644 --- a/src/app/domains/consumer/modules/businessActivities/views/complexes/single.component.html +++ b/src/app/domains/consumer/modules/businessActivities/views/complexes/single.component.html @@ -1,9 +1,8 @@
- +
-
diff --git a/src/app/domains/consumer/modules/businessActivities/views/single.component.html b/src/app/domains/consumer/modules/businessActivities/views/single.component.html index ddf9078..acc7272 100644 --- a/src/app/domains/consumer/modules/businessActivities/views/single.component.html +++ b/src/app/domains/consumer/modules/businessActivities/views/single.component.html @@ -4,6 +4,7 @@
+
diff --git a/src/app/domains/consumer/modules/customers/components/saleInvoices/list.component.ts b/src/app/domains/consumer/modules/customers/components/saleInvoices/list.component.ts index 1e459d5..23c60fb 100644 --- a/src/app/domains/consumer/modules/customers/components/saleInvoices/list.component.ts +++ b/src/app/domains/consumer/modules/customers/components/saleInvoices/list.component.ts @@ -27,9 +27,9 @@ export class ConsumerCustomerSaleInvoiceListComponent extends AbstractList { }, { field: 'complex', - header: 'عنوان فروشگاه', + header: 'عنوان شعبه', type: 'nested', nestedPath: 'complex.name', }, diff --git a/src/app/domains/consumer/modules/saleInvoices/components/list.component.ts b/src/app/domains/consumer/modules/saleInvoices/components/list.component.ts index 49f205e..105b6d9 100644 --- a/src/app/domains/consumer/modules/saleInvoices/components/list.component.ts +++ b/src/app/domains/consumer/modules/saleInvoices/components/list.component.ts @@ -26,9 +26,9 @@ export class ConsumerSaleInvoiceListComponent extends AbstractList +
+ + + + + + رمز باید حداقل ۸ کاراکتر بوده و شامل حداقل یک حرف بزرگ، یک حرف کوچک، یک عدد و یک کاراکتر ویژه باشد. + + + + + + + + + diff --git a/src/app/domains/partner/modules/consumers/components/accounts/form.component.ts b/src/app/domains/partner/modules/consumers/components/accounts/form.component.ts new file mode 100644 index 0000000..2c4a26f --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/accounts/form.component.ts @@ -0,0 +1,78 @@ +import { MustMatch, password } from '@/core/validators'; +// import { CatalogRolesComponent } from '@/shared/catalog/roles'; +import { AbstractFormDialog } from '@/shared/abstractClasses'; +import { EnumSelectComponent } from '@/shared/apiEnum/select.component'; +import { InputComponent } from '@/shared/components'; +import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; +import { UikitFieldComponent } from '@/uikit'; +import { Component, inject, Input } from '@angular/core'; +import { ReactiveFormsModule, Validators } from '@angular/forms'; +import { Dialog } from 'primeng/dialog'; +import { Password } from 'primeng/password'; +import { IConsumerAccountRequest, IConsumerAccountResponse } from '../../models'; +import { PartnerConsumerAccountsService } from '../../services/accounts.service'; + +@Component({ + selector: 'partner-consumer-account-form', + templateUrl: './form.component.html', + imports: [ + ReactiveFormsModule, + Dialog, + InputComponent, + FormFooterActionsComponent, + UikitFieldComponent, + Password, + EnumSelectComponent, + ], +}) +export class ConsumerAccountFormComponent extends AbstractFormDialog< + IConsumerAccountRequest, + IConsumerAccountResponse +> { + private readonly service = inject(PartnerConsumerAccountsService); + + @Input({ required: true }) consumerId!: string; + @Input() accountId!: string; + + initForm = () => { + if (this.editMode) { + return this.fb.group( + { + username: [this.initialValues?.username || '', [Validators.required]], + password: ['', [password()]], + confirmPassword: [''], + }, + { + validators: [MustMatch('password', 'confirmPassword')], + }, + ); + } + return this.fb.group( + { + username: [this.initialValues?.username || '', [Validators.required]], + role: ['', [Validators.required]], + password: ['', [Validators.required, password()]], + confirmPassword: ['', [Validators.required]], + }, + { + validators: [MustMatch('password', 'confirmPassword')], + }, + ) as any; + }; + + form = this.initForm(); + + override ngOnChanges(): void { + this.form = this.initForm(); + } + + submitForm() { + const formValue = this.form.value as IConsumerAccountRequest; + // @ts-ignore + const { confirmPassword, ...rest } = formValue; + if (this.editMode) { + return this.service.update(this.consumerId, this.accountId, rest); + } + return this.service.create(this.consumerId, rest); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/accounts/list.component.html b/src/app/domains/partner/modules/consumers/components/accounts/list.component.html new file mode 100644 index 0000000..63600a9 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/accounts/list.component.html @@ -0,0 +1,22 @@ + + + diff --git a/src/app/domains/partner/modules/consumers/components/accounts/list.component.ts b/src/app/domains/partner/modules/consumers/components/accounts/list.component.ts new file mode 100644 index 0000000..12a7030 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/accounts/list.component.ts @@ -0,0 +1,50 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { AbstractList } from '@/shared/abstractClasses/abstract-list'; +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, inject, Input } from '@angular/core'; +import { IConsumerAccountResponse } from '../../models'; +import { PartnerConsumerAccountsService } from '../../services/accounts.service'; +import { ConsumerAccountFormComponent } from './form.component'; + +@Component({ + selector: 'partner-consumer-account-list', + templateUrl: './list.component.html', + imports: [PageDataListComponent, ConsumerAccountFormComponent], +}) +export class ConsumerAccountListComponent extends AbstractList { + @Input({ required: true }) consumerId!: string; + @Input() fullHeight?: boolean; + @Input() header: IColumn[] = [ + { field: 'id', header: 'شناسه', type: 'id' }, + { + field: 'username', + header: 'نام کاربری', + type: 'nested', + nestedPath: 'account.username', + }, + { field: 'role', header: 'نوع حساب' }, + { + field: 'status', + header: 'وضعیت', + type: 'nested', + nestedPath: 'account.status', + }, + { + field: 'created_at', + header: 'تاریخ ایجاد', + type: 'date', + }, + ]; + private readonly service = inject(PartnerConsumerAccountsService); + + override setColumns(): void { + this.columns = this.header; + } + + override getDataRequest() { + return this.service.getAll(this.consumerId); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.html b/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.html new file mode 100644 index 0000000..838f5dd --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.html @@ -0,0 +1,15 @@ + +
+ + + + + +
diff --git a/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.ts b/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.ts new file mode 100644 index 0000000..2b5913d --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/businessActivities/form.component.ts @@ -0,0 +1,57 @@ +// import { CatalogRolesComponent } from '@/shared/catalog/roles'; +import { AbstractFormDialog } from '@/shared/abstractClasses'; +import { CatalogGuildSelectComponent } from '@/shared/catalog/guild/components/select.component'; +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 { IBusinessActivityRequest, IBusinessActivityResponse } from '../../models'; +import { PartnerConsumerBusinessActivitiesService } from '../../services/businessActivities.service'; + +@Component({ + selector: 'partner-consumer-businessActivities-form', + templateUrl: './form.component.html', + imports: [ + ReactiveFormsModule, + Dialog, + InputComponent, + FormFooterActionsComponent, + CatalogGuildSelectComponent, + ], +}) +export class ConsumerBusinessActivitiesFormComponent extends AbstractFormDialog< + IBusinessActivityRequest, + IBusinessActivityResponse +> { + private readonly service = inject(PartnerConsumerBusinessActivitiesService); + + @Input({ required: true }) consumerId!: string; + @Input() businessActivityId!: string; + + initForm = () => { + return this.fb.group({ + name: [this.initialValues?.name || '', [Validators.required]], + economic_code: [this.initialValues?.economic_code || '', [Validators.required]], + guild_id: [this.initialValues?.guild?.id || '', [Validators.required]], + }); + }; + + form = this.initForm(); + + get preparedTitle() { + return `${this.editMode ? 'ویرایش' : 'ایجاد'} فعالیت اقتصادی`; + } + + override ngOnChanges(): void { + this.form = this.initForm(); + } + + submitForm() { + const formValue = this.form.value as IBusinessActivityRequest; + if (this.editMode) { + return this.service.update(this.consumerId, this.businessActivityId, formValue); + } + return this.service.create(this.consumerId, formValue); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/businessActivities/layout.component.html b/src/app/domains/partner/modules/consumers/components/businessActivities/layout.component.html new file mode 100644 index 0000000..5416fe1 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/businessActivities/layout.component.html @@ -0,0 +1,5 @@ +@if (loading()) { + +} @else { + +} diff --git a/src/app/domains/partner/modules/consumers/components/businessActivities/layout.component.ts b/src/app/domains/partner/modules/consumers/components/businessActivities/layout.component.ts new file mode 100644 index 0000000..4f1d446 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/businessActivities/layout.component.ts @@ -0,0 +1,30 @@ +import { PageLoadingComponent } from '@/shared/components/page-loading.component'; +import pageParamsUtils from '@/utils/page-params.utils'; +import { Component, computed, inject } from '@angular/core'; +import { ActivatedRoute, RouterOutlet } from '@angular/router'; +import { BusinessActivityStore } from '../../store/businessActivity.store'; + +@Component({ + selector: 'partner-user-businessActivity-layout', + templateUrl: './layout.component.html', + imports: [PageLoadingComponent, RouterOutlet], +}) +export class PartnerUserBusinessActivityLayoutComponent { + private readonly store = inject(BusinessActivityStore); + private readonly route = inject(ActivatedRoute); + + readonly loading = computed(() => this.store.loading()); + readonly businessActivity = computed(() => this.store.entity()); + readonly pageParams = computed(() => pageParamsUtils(this.route)); + + readonly consumerId = computed(() => this.pageParams()['consumerId']!); + readonly businessId = computed(() => this.pageParams()['businessActivityId']!); + + getData() { + this.store.getData(this.consumerId(), this.businessId()); + } + + ngOnInit() { + this.getData(); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/businessActivities/list.component.html b/src/app/domains/partner/modules/consumers/components/businessActivities/list.component.html new file mode 100644 index 0000000..0733330 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/businessActivities/list.component.html @@ -0,0 +1,25 @@ + + + diff --git a/src/app/domains/partner/modules/consumers/components/businessActivities/list.component.ts b/src/app/domains/partner/modules/consumers/components/businessActivities/list.component.ts new file mode 100644 index 0000000..5220b2d --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/businessActivities/list.component.ts @@ -0,0 +1,52 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { AbstractList } from '@/shared/abstractClasses/abstract-list'; +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, inject, Input } from '@angular/core'; +import { Router } from '@angular/router'; +import { partnerConsumerBusinessActivitiesNamedRoutes } from '../../constants/routes/businessActivities'; +import { IBusinessActivityResponse } from '../../models'; +import { PartnerConsumerBusinessActivitiesService } from '../../services/businessActivities.service'; +import { ConsumerBusinessActivitiesFormComponent } from './form.component'; + +@Component({ + selector: 'partner-consumer-businessActivities-list', + templateUrl: './list.component.html', + imports: [PageDataListComponent, ConsumerBusinessActivitiesFormComponent], +}) +export class ConsumerBusinessActivitiesComponent extends AbstractList { + @Input({ required: true }) consumerId!: string; + @Input() fullHeight?: boolean; + @Input() header: IColumn[] = [ + { field: 'id', header: 'شناسه', type: 'id' }, + { field: 'name', header: 'عنوان' }, + { field: 'guild', header: 'صنف', type: 'nested', nestedPath: 'name' }, + { + field: 'created_at', + header: 'تاریخ ایجاد', + type: 'date', + }, + ]; + + private readonly service = inject(PartnerConsumerBusinessActivitiesService); + private readonly router = inject(Router); + + override setColumns(): void { + this.columns = this.header; + } + + override getDataRequest() { + return this.service.getAll(this.consumerId); + } + + toSinglePage(item: IBusinessActivityResponse) { + this.router.navigateByUrl( + partnerConsumerBusinessActivitiesNamedRoutes.businessActivity.meta.pagePath!( + this.consumerId, + item.id, + ), + ); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/complexes/form.component.html b/src/app/domains/partner/modules/consumers/components/complexes/form.component.html new file mode 100644 index 0000000..248f2ba --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/complexes/form.component.html @@ -0,0 +1,15 @@ + +
+ + + + + +
diff --git a/src/app/domains/partner/modules/consumers/components/complexes/form.component.ts b/src/app/domains/partner/modules/consumers/components/complexes/form.component.ts new file mode 100644 index 0000000..ab17160 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/complexes/form.component.ts @@ -0,0 +1,56 @@ +// import { CatalogRolesComponent } from '@/shared/catalog/roles'; +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 { IComplexRequest, IComplexResponse } from '../../models'; +import { PartnerComplexesService } from '../../services/complexes.service'; + +@Component({ + selector: 'partner-consumer-complex-form', + templateUrl: './form.component.html', + imports: [ReactiveFormsModule, Dialog, InputComponent, FormFooterActionsComponent], +}) +export class ConsumerComplexFormComponent extends AbstractFormDialog< + IComplexRequest, + IComplexResponse +> { + private readonly service = inject(PartnerComplexesService); + + @Input({ required: true }) consumerId!: string; + @Input() businessActivityId!: string; + @Input() complexId!: string; + + initForm = () => { + return this.fb.group({ + name: [this.initialValues?.name || '', [Validators.required]], + branch_code: [this.initialValues?.branch_code || ''], + address: [this.initialValues?.address || '', [Validators.required]], + }); + }; + + form = this.initForm(); + + get preparedTitle() { + return `${this.editMode ? 'ویرایش' : 'ایجاد'} شعبه`; + } + + override ngOnChanges(): void { + this.form = this.initForm(); + } + + submitForm() { + const formValue = this.form.value as IComplexRequest; + if (this.editMode) { + return this.service.update( + this.consumerId, + this.businessActivityId, + this.complexId, + formValue, + ); + } + return this.service.create(this.consumerId, this.businessActivityId, formValue); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/complexes/layout.component.html b/src/app/domains/partner/modules/consumers/components/complexes/layout.component.html new file mode 100644 index 0000000..5416fe1 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/complexes/layout.component.html @@ -0,0 +1,5 @@ +@if (loading()) { + +} @else { + +} diff --git a/src/app/domains/partner/modules/consumers/components/complexes/layout.component.ts b/src/app/domains/partner/modules/consumers/components/complexes/layout.component.ts new file mode 100644 index 0000000..73dc59c --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/complexes/layout.component.ts @@ -0,0 +1,30 @@ +import { PageLoadingComponent } from '@/shared/components/page-loading.component'; +import pageParamsUtils from '@/utils/page-params.utils'; +import { Component, computed, inject } from '@angular/core'; +import { ActivatedRoute, RouterOutlet } from '@angular/router'; +import { ComplexStore } from '../../store/complex.store'; + +@Component({ + selector: 'partner-consumer-complex-layout', + templateUrl: './layout.component.html', + imports: [PageLoadingComponent, RouterOutlet], +}) +export class PartnerConsumerComplexLayoutComponent { + private readonly store = inject(ComplexStore); + private readonly route = inject(ActivatedRoute); + + readonly loading = computed(() => this.store.loading()); + readonly pageParams = computed(() => pageParamsUtils(this.route)); + + readonly consumerId = computed(() => this.pageParams()['consumerId']!); + readonly businessId = computed(() => this.pageParams()['businessActivityId']!); + readonly complexId = computed(() => this.pageParams()['complexId']!); + + getData() { + this.store.getData(this.consumerId(), this.businessId(), this.complexId()); + } + + ngOnInit() { + this.getData(); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/complexes/list.component.html b/src/app/domains/partner/modules/consumers/components/complexes/list.component.html new file mode 100644 index 0000000..726af40 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/complexes/list.component.html @@ -0,0 +1,26 @@ + + + diff --git a/src/app/domains/partner/modules/consumers/components/complexes/list.component.ts b/src/app/domains/partner/modules/consumers/components/complexes/list.component.ts new file mode 100644 index 0000000..2dabd7b --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/complexes/list.component.ts @@ -0,0 +1,53 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { AbstractList } from '@/shared/abstractClasses/abstract-list'; +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, inject, Input } from '@angular/core'; +import { Router } from '@angular/router'; +import { partnerConsumerComplexesNamedRoutes } from '../../constants/routes/complexes'; +import { IComplexResponse } from '../../models'; +import { PartnerComplexesService } from '../../services/complexes.service'; +import { ConsumerComplexFormComponent } from './form.component'; + +@Component({ + selector: 'partner-consumer-complexes-list', + templateUrl: './list.component.html', + imports: [PageDataListComponent, ConsumerComplexFormComponent], +}) +export class ConsumerComplexesComponent extends AbstractList { + @Input() consumerId!: string; + @Input() businessId!: string; + @Input() fullHeight?: boolean; + @Input() header: IColumn[] = [ + { field: 'id', header: 'شناسه', type: 'id' }, + { field: 'name', header: 'عنوان' }, + { + field: 'created_at', + header: 'تاریخ ایجاد', + type: 'date', + }, + ]; + + private readonly service = inject(PartnerComplexesService); + private readonly router = inject(Router); + + override setColumns(): void { + this.columns = this.header; + } + + override getDataRequest() { + return this.service.getAll(this.consumerId, this.businessId); + } + + toSinglePage(item: IComplexResponse) { + this.router.navigateByUrl( + partnerConsumerComplexesNamedRoutes.complex.meta.pagePath!( + this.consumerId, + this.businessId, + item.id, + ), + ); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/form.component.html b/src/app/domains/partner/modules/consumers/components/form.component.html new file mode 100644 index 0000000..a5c261b --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/form.component.html @@ -0,0 +1,58 @@ + +
+ + + + + + @if (!editMode) { + اطلاعات ورود + + + + + + رمز باید حداقل ۸ کاراکتر بوده و شامل حداقل یک حرف بزرگ، یک حرف کوچک، یک عدد و یک کاراکتر ویژه باشد. + + + + + + + اطلاعات لایسنس + + } + + + +
diff --git a/src/app/domains/partner/modules/consumers/components/form.component.ts b/src/app/domains/partner/modules/consumers/components/form.component.ts new file mode 100644 index 0000000..a6392e8 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/form.component.ts @@ -0,0 +1,121 @@ +import { mobileValidator, MustMatch } from '@/core/validators'; +import { nationalIdValidator } from '@/core/validators/national-id.validator'; +import { AbstractFormDialog } from '@/shared/abstractClasses'; +import { InputComponent } from '@/shared/components'; +import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; +import { UikitFieldComponent, UikitFlatpickrJalaliComponent } from '@/uikit'; +import { nowJalali } from '@/utils'; +import { Component, computed, inject, Input } from '@angular/core'; +import { ReactiveFormsModule, Validators } from '@angular/forms'; +import { Dialog } from 'primeng/dialog'; +import { Divider } from 'primeng/divider'; +import { Password } from 'primeng/password'; +import { IConsumerRequest, IConsumerResponse } from '../models'; +import { ConsumersService } from '../services/main.service'; + +@Component({ + selector: 'partner-consumer-form', + templateUrl: './form.component.html', + imports: [ + ReactiveFormsModule, + Dialog, + InputComponent, + FormFooterActionsComponent, + Divider, + UikitFieldComponent, + Password, + UikitFlatpickrJalaliComponent, + ], +}) +export class ConsumerUserFormComponent extends AbstractFormDialog< + IConsumerRequest, + IConsumerResponse +> { + @Input() consumerId?: string; + private service = inject(ConsumersService); + + preparedTitle = computed(() => `${this.editMode ? 'ویرایش' : 'ایجاد'} مشتری`); + + initForm = () => { + const form = this.fb.group({ + first_name: [this.initialValues?.first_name || '', [Validators.required]], + last_name: [this.initialValues?.last_name || '', [Validators.required]], + mobile_number: [ + this.initialValues?.mobile_number || '', + [Validators.required, mobileValidator()], + ], + national_code: [ + this.initialValues?.national_code || '', + [Validators.required, nationalIdValidator()], + ], + username: [''], + password: [''], + confirmPassword: [''], + license_starts_at: [nowJalali(), [Validators.required]], + }); + + if (this.editMode) { + // @ts-ignore + form.removeControl('username'); + // @ts-ignore + form.removeControl('password'); + // @ts-ignore + form.removeControl('confirmPassword'); + // @ts-ignore + form.removeControl('license_starts_at'); + form.removeValidators([MustMatch('password', 'confirmPassword')]); + } else { + form.addControl( + 'username', + this.fb.control('', { + nonNullable: true, + validators: [Validators.required], + }), + ); + form.addControl( + 'password', + this.fb.control('', { + nonNullable: true, + validators: [Validators.required], + }), + ); + form.addControl( + 'confirmPassword', + this.fb.control('', { + nonNullable: true, + validators: [Validators.required], + }), + ); + form.addControl( + 'license_starts_at', + this.fb.control(nowJalali(), { + nonNullable: true, + validators: [Validators.required], + }), + ); + form.addValidators([MustMatch('password', 'confirmPassword')]); + } + + return form; + }; + + form = this.initForm(); + + override ngOnChanges() { + this.form.patchValue(this.initialValues || {}); + if (this.editMode && !this.consumerId) { + throw 'missing some arguments'; + } + + this.form = this.initForm(); + } + + override submitForm(payload: IConsumerRequest) { + if (this.editMode) { + return this.service.update(this.consumerId!, payload); + } + // @ts-ignore + const { confirmPassword, ...rest } = payload; + return this.service.create(rest); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/layout.component.html b/src/app/domains/partner/modules/consumers/components/layout.component.html new file mode 100644 index 0000000..5416fe1 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/layout.component.html @@ -0,0 +1,5 @@ +@if (loading()) { + +} @else { + +} diff --git a/src/app/domains/partner/modules/consumers/components/layout.component.ts b/src/app/domains/partner/modules/consumers/components/layout.component.ts new file mode 100644 index 0000000..fab8f41 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/layout.component.ts @@ -0,0 +1,27 @@ +import { PageLoadingComponent } from '@/shared/components/page-loading.component'; +import { Component, computed, inject, signal } from '@angular/core'; +import { ActivatedRoute, RouterOutlet } from '@angular/router'; +import { ConsumerStore } from '../store/consumer.store'; + +@Component({ + selector: 'partner-consumer-layout', + templateUrl: './layout.component.html', + imports: [PageLoadingComponent, RouterOutlet], +}) +export class ConsumerLayoutComponent { + private readonly store = inject(ConsumerStore); + private readonly route = inject(ActivatedRoute); + + readonly consumerId = signal(this.route.snapshot.paramMap.get('consumerId')!); + + readonly loading = computed(() => this.store.loading()); + readonly consumer = computed(() => this.store.entity()); + + getData() { + this.store.getData(this.consumerId()); + } + + ngOnInit() { + this.getData(); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/licenses/form.component.html b/src/app/domains/partner/modules/consumers/components/licenses/form.component.html new file mode 100644 index 0000000..2b160b1 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/licenses/form.component.html @@ -0,0 +1,19 @@ + +
+ + + + +
diff --git a/src/app/domains/partner/modules/consumers/components/licenses/form.component.ts b/src/app/domains/partner/modules/consumers/components/licenses/form.component.ts new file mode 100644 index 0000000..560fbbd --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/licenses/form.component.ts @@ -0,0 +1,51 @@ +import { AbstractFormDialog } from '@/shared/abstractClasses'; +import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; +import { UikitFlatpickrJalaliComponent } from '@/uikit'; +import { Component, computed, inject, Input } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { Dialog } from 'primeng/dialog'; +import { ILicenseRequest, ILicenseResponse } from '../../models'; +import { LicensesService } from '../../services/licenses.service'; + +@Component({ + selector: 'partner-consumer-license-form', + templateUrl: './form.component.html', + imports: [ReactiveFormsModule, Dialog, FormFooterActionsComponent, UikitFlatpickrJalaliComponent], +}) +export class ConsumerLicenseFormComponent extends AbstractFormDialog< + ILicenseRequest, + ILicenseResponse +> { + @Input({ required: true }) consumerId!: string; + @Input() licenseId?: string; + private service = inject(LicensesService); + + preparedTitle = computed(() => `${this.editMode ? 'ویرایش' : 'ایجاد'} لایسنس`); + + initForm = () => { + const form = this.fb.group({ + starts_at: [this.initialValues?.starts_at || ''], + partner_id: [this.initialValues?.partner?.id || ''], + }); + + return form; + }; + + form = this.initForm(); + + override ngOnChanges() { + this.form.patchValue({ ...this.initialValues }); + if (this.editMode && !this.licenseId) { + throw 'missing some arguments'; + } + + this.form = this.initForm(); + } + + override submitForm(payload: ILicenseRequest) { + if (this.editMode) { + return this.service.update(this.consumerId!, this.licenseId!, payload); + } + return this.service.create(this.consumerId, payload); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/poses/form.component.html b/src/app/domains/partner/modules/consumers/components/poses/form.component.html new file mode 100644 index 0000000..d902c50 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/poses/form.component.html @@ -0,0 +1,20 @@ + +
+ + + + + @if (form.controls.pos_type.value === "PSP") { + + + } + + +
diff --git a/src/app/domains/partner/modules/consumers/components/poses/form.component.ts b/src/app/domains/partner/modules/consumers/components/poses/form.component.ts new file mode 100644 index 0000000..dc3c8bd --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/poses/form.component.ts @@ -0,0 +1,87 @@ +// import { CatalogRolesComponent } from '@/shared/catalog/roles'; +import { AbstractFormDialog } from '@/shared/abstractClasses'; +import { EnumSelectComponent } from '@/shared/apiEnum/select.component'; +import { CatalogProviderSelectComponent } from '@/shared/catalog'; +import { CatalogDeviceSelectComponent } from '@/shared/catalog/devices'; +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 { IPosRequest, IPosResponse } from '../../models'; +import { PartnerPosesService } from '../../services/poses.service'; + +@Component({ + selector: 'partner-consumer-pos-form', + templateUrl: './form.component.html', + imports: [ + ReactiveFormsModule, + Dialog, + InputComponent, + FormFooterActionsComponent, + CatalogDeviceSelectComponent, + CatalogProviderSelectComponent, + EnumSelectComponent, + ], +}) +export class ConsumerPosFormComponent extends AbstractFormDialog { + private readonly service = inject(PartnerPosesService); + + @Input({ required: true }) consumerId!: string; + @Input({ required: true }) businessActivityId!: string; + @Input({ required: true }) complexId!: string; + @Input() posId!: string; + + initForm = () => { + const form = this.fb.group({ + name: [this.initialValues?.name || '', [Validators.required]], + serial: [this.initialValues?.serial || '', [Validators.required]], + // model: [this.initialValues?.model || '', [Validators.required]], + pos_type: [this.initialValues?.pos_type || '', [Validators.required]], + device_id: [this.initialValues?.device?.id || ''], + provider_id: [this.initialValues?.provider?.id || ''], + }); + form.controls.pos_type.valueChanges.subscribe((value) => { + if (value === 'PSP') { + form.addControl( + 'device_id', + this.fb.control(this.initialValues?.device?.id ?? '', { + nonNullable: true, + validators: [Validators.required], + }), + ); + form.addControl( + 'provider_id', + this.fb.control(this.initialValues?.provider?.id ?? '', { + nonNullable: true, + validators: [Validators.required], + }), + ); + } else { + // @ts-ignore + form.removeControl('device_id'); + // @ts-ignore + form.removeControl('provider_id'); + } + }); + return form; + }; + + form = this.initForm(); + + get preparedTitle() { + return `${this.editMode ? 'ویرایش' : 'ایجاد'} پایانه فروش`; + } + + override ngOnChanges(): void { + this.form = this.initForm(); + } + + submitForm() { + const formValue = this.form.value as IPosRequest; + if (this.editMode) { + return this.service.update(this.businessActivityId, this.complexId, this.posId, formValue); + } + return this.service.create(this.businessActivityId, this.complexId, formValue); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/poses/layout.component.html b/src/app/domains/partner/modules/consumers/components/poses/layout.component.html new file mode 100644 index 0000000..5416fe1 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/poses/layout.component.html @@ -0,0 +1,5 @@ +@if (loading()) { + +} @else { + +} diff --git a/src/app/domains/partner/modules/consumers/components/poses/layout.component.ts b/src/app/domains/partner/modules/consumers/components/poses/layout.component.ts new file mode 100644 index 0000000..7af0a21 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/poses/layout.component.ts @@ -0,0 +1,31 @@ +import { PageLoadingComponent } from '@/shared/components/page-loading.component'; +import pageParamsUtils from '@/utils/page-params.utils'; +import { Component, computed, inject } from '@angular/core'; +import { ActivatedRoute, RouterOutlet } from '@angular/router'; +import { PosStore } from '../../store/pos.store'; + +@Component({ + selector: 'partner-consumer-pos-layout', + templateUrl: './layout.component.html', + imports: [PageLoadingComponent, RouterOutlet], +}) +export class PartnerConsumerPosLayoutComponent { + private readonly store = inject(PosStore); + private readonly route = inject(ActivatedRoute); + + readonly loading = computed(() => this.store.loading()); + readonly pageParams = computed(() => pageParamsUtils(this.route)); + + readonly consumerId = computed(() => this.pageParams()['consumerId']!); + readonly businessId = computed(() => this.pageParams()['businessActivityId']!); + readonly complexId = computed(() => this.pageParams()['complexId']!); + readonly posId = computed(() => this.pageParams()['posId']!); + + getData() { + this.store.getData(this.consumerId(), this.businessId(), this.complexId(), this.posId()); + } + + ngOnInit() { + this.getData(); + } +} diff --git a/src/app/domains/partner/modules/consumers/components/poses/list.component.html b/src/app/domains/partner/modules/consumers/components/poses/list.component.html new file mode 100644 index 0000000..621fb24 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/poses/list.component.html @@ -0,0 +1,27 @@ + + + diff --git a/src/app/domains/partner/modules/consumers/components/poses/list.component.ts b/src/app/domains/partner/modules/consumers/components/poses/list.component.ts new file mode 100644 index 0000000..9ee367d --- /dev/null +++ b/src/app/domains/partner/modules/consumers/components/poses/list.component.ts @@ -0,0 +1,60 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { AbstractList } from '@/shared/abstractClasses/abstract-list'; +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, inject, Input } from '@angular/core'; +import { Router } from '@angular/router'; +import { partnerConsumerPosesNamedRoutes } from '../../constants/routes/poses'; +import { IPosResponse } from '../../models'; +import { PartnerPosesService } from '../../services/poses.service'; +import { ConsumerPosFormComponent } from './form.component'; + +@Component({ + selector: 'partner-consumer-poses-list', + templateUrl: './list.component.html', + imports: [PageDataListComponent, ConsumerPosFormComponent], +}) +export class ConsumerPosesComponent extends AbstractList { + @Input({ required: true }) consumerId!: string; + @Input({ required: true }) businessId!: string; + @Input({ required: true }) complexId!: string; + @Input() fullHeight?: boolean; + @Input() header: IColumn[] = [ + { field: 'id', header: 'شناسه', type: 'id' }, + { field: 'name', header: 'عنوان' }, + { field: 'serial', header: 'شماره سریال' }, + { field: 'device', header: 'دستگاه', type: 'nested', nestedPath: 'device.name' }, + { field: 'pos_type', header: 'نوع دستگاه' }, + { field: 'provider', header: 'ارایه‌دهنده', type: 'nested', nestedPath: 'provider.name' }, + { field: 'status', header: 'وضعیت' }, + { + field: 'created_at', + header: 'تاریخ ایجاد', + type: 'date', + }, + ]; + + private readonly service = inject(PartnerPosesService); + private readonly router = inject(Router); + + override setColumns(): void { + this.columns = this.header; + } + + override getDataRequest() { + return this.service.getAll(this.businessId, this.complexId); + } + + toSinglePage(item: IPosResponse) { + this.router.navigateByUrl( + partnerConsumerPosesNamedRoutes.pos.meta.pagePath!( + this.consumerId, + this.businessId, + this.complexId, + item.id, + ), + ); + } +} diff --git a/src/app/domains/partner/modules/consumers/constants/apiRoutes/accounts.ts b/src/app/domains/partner/modules/consumers/constants/apiRoutes/accounts.ts new file mode 100644 index 0000000..57fea62 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/apiRoutes/accounts.ts @@ -0,0 +1,6 @@ +const baseUrl = (consumerId: string) => `/api/v1/partner/consumers/${consumerId}/accounts`; + +export const CONSUMER_ACCOUNTS_API_ROUTES = { + list: (consumerId: string) => `${baseUrl(consumerId)}`, + single: (consumerId: string, accountId: string) => `${baseUrl(consumerId)}/${accountId}`, +}; diff --git a/src/app/domains/partner/modules/consumers/constants/apiRoutes/businessActivities.ts b/src/app/domains/partner/modules/consumers/constants/apiRoutes/businessActivities.ts new file mode 100644 index 0000000..059f420 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/apiRoutes/businessActivities.ts @@ -0,0 +1,7 @@ +const baseUrl = (consumerId: string) => `/api/v1/partner/consumers/${consumerId}/business_activities`; + +export const BUSINESS_ACTIVITIES_API_ROUTES = { + list: (consumerId: string) => `${baseUrl(consumerId)}`, + single: (consumerId: string, business_activity_id: string) => + `${baseUrl(consumerId)}/${business_activity_id}`, +}; diff --git a/src/app/domains/partner/modules/consumers/constants/apiRoutes/businessActivityComplexes.ts b/src/app/domains/partner/modules/consumers/constants/apiRoutes/businessActivityComplexes.ts new file mode 100644 index 0000000..8962cb2 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/apiRoutes/businessActivityComplexes.ts @@ -0,0 +1,9 @@ +const baseUrl = (consumerId: string, business_activity_id: string) => + `/api/v1/partner/consumers/${consumerId}/business_activities/${business_activity_id}/complexes`; + +export const BUSINESS_ACTIVITY_COMPLEXES_API_ROUTES = { + list: (consumerId: string, business_activity_id: string) => + `${baseUrl(consumerId, business_activity_id)}`, + single: (consumerId: string, business_activity_id: string, complex_id: string) => + `${baseUrl(consumerId, business_activity_id)}/${complex_id}`, +}; diff --git a/src/app/domains/partner/modules/consumers/constants/apiRoutes/complexPoses.ts b/src/app/domains/partner/modules/consumers/constants/apiRoutes/complexPoses.ts new file mode 100644 index 0000000..894e1ce --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/apiRoutes/complexPoses.ts @@ -0,0 +1,9 @@ +const baseUrl = (business_activity_id: string, complex_id: string) => + `/api/v1/partner/business_activities/${business_activity_id}/complexes/${complex_id}/poses`; + +export const COMPLEX_POSES_API_ROUTES = { + list: (business_activity_id: string, complex_id: string) => + `${baseUrl(business_activity_id, complex_id)}`, + single: (business_activity_id: string, complex_id: string, posId: string) => + `${baseUrl(business_activity_id, complex_id)}/${posId}`, +}; diff --git a/src/app/domains/partner/modules/consumers/constants/apiRoutes/index.ts b/src/app/domains/partner/modules/consumers/constants/apiRoutes/index.ts new file mode 100644 index 0000000..6fcbeb7 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/apiRoutes/index.ts @@ -0,0 +1,12 @@ +export * from './accounts'; +export * from './businessActivities'; +export * from './businessActivityComplexes'; +export * from './complexPoses'; +export * from './licenses'; + +const baseUrl = '/api/v1/partner/consumers'; + +export const CONSUMERS_API_ROUTES = { + list: () => `${baseUrl}`, + single: (id: string) => `${baseUrl}/${id}`, +}; diff --git a/src/app/domains/partner/modules/consumers/constants/apiRoutes/licenses.ts b/src/app/domains/partner/modules/consumers/constants/apiRoutes/licenses.ts new file mode 100644 index 0000000..9336187 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/apiRoutes/licenses.ts @@ -0,0 +1,6 @@ +const baseUrl = (consumerId: string) => `/api/v1/partner/consumers/${consumerId}/licenses`; + +export const CONSUMER_LICENSES_API_ROUTES = { + list: (consumerId: string) => baseUrl(consumerId), + single: (consumerId: string, licenseId: string) => `${baseUrl(consumerId)}/${licenseId}`, +}; diff --git a/src/app/domains/partner/modules/consumers/constants/index.ts b/src/app/domains/partner/modules/consumers/constants/index.ts new file mode 100644 index 0000000..ee61bd7 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/index.ts @@ -0,0 +1,2 @@ +export * from './apiRoutes'; +export * from './routes'; diff --git a/src/app/domains/partner/modules/consumers/constants/routes/accounts.ts b/src/app/domains/partner/modules/consumers/constants/routes/accounts.ts new file mode 100644 index 0000000..ded340b --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/routes/accounts.ts @@ -0,0 +1,29 @@ +import { NamedRoutes } from '@/core'; +import { Routes } from '@angular/router'; + +export type TAccountsRouteNames = 'accounts' | 'account'; + +export const partnerConsumerAccountsNamedRoutes: NamedRoutes = { + accounts: { + path: 'accounts', + loadComponent: () => + import('../../views/accounts/list.component').then((m) => m.ConsumerAccountsComponent), + // @ts-ignore + meta: { + title: 'حساب‌های کاربری', + pagePath: (consumerId: string) => `/partner/consumers/${consumerId}/accounts`, + }, + }, + account: { + path: 'accounts/:accountId', + meta: { + title: 'حساب‌ کاربری', + pagePath: (consumerId: string, accountId: string) => + `/partner/consumers/${consumerId}/accounts/${accountId}`, + }, + }, +}; + +export const PARTNER_CONSUMER_ACCOUNTS_ROUTES: Routes = [ + partnerConsumerAccountsNamedRoutes.accounts, +]; diff --git a/src/app/domains/partner/modules/consumers/constants/routes/businessActivities.ts b/src/app/domains/partner/modules/consumers/constants/routes/businessActivities.ts new file mode 100644 index 0000000..e544ab6 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/routes/businessActivities.ts @@ -0,0 +1,54 @@ +import { NamedRoutes } from '@/core'; +import { Routes } from '@angular/router'; +import { PARTNER_CONSUMER_COMPLEXES_ROUTES } from './complexes'; + +export type TBusinessActivitiesRouteNames = 'businessActivities' | 'businessActivity'; + +export const partnerConsumerBusinessActivitiesNamedRoutes: NamedRoutes = + { + businessActivities: { + path: 'business_activities', + loadComponent: () => + import('../../views/businessActivities/list.component').then( + (m) => m.PartnerUserBusinessActivitiesComponent, + ), + // @ts-ignore + meta: { + title: 'فعالیت‌های اقتصادی', + pagePath: (consumerId: string) => + `/partner/consumers/${consumerId}/business_activities`, + }, + }, + businessActivity: { + path: 'business_activities/:businessActivityId', + loadComponent: () => + import('../../views/businessActivities/single.component').then( + (m) => m.PartnerUserBusinessActivityComponent, + ), + // @ts-ignore + meta: { + title: 'فعالیت اقتصادی', + pagePath: (consumerId: string, businessId: string) => + `/partner/consumers/${consumerId}/business_activities/${businessId}`, + }, + }, + }; + +export const PARTNER_CONSUMER_BUSINESS_ACTIVITIES_ROUTES: Routes = [ + partnerConsumerBusinessActivitiesNamedRoutes.businessActivities, + { + path: partnerConsumerBusinessActivitiesNamedRoutes.businessActivity.path, + loadComponent: () => + import('../../components/businessActivities/layout.component').then( + (m) => m.PartnerUserBusinessActivityLayoutComponent, + ), + children: [ + { + path: '', + loadComponent: + partnerConsumerBusinessActivitiesNamedRoutes.businessActivity.loadComponent, + }, + ...PARTNER_CONSUMER_COMPLEXES_ROUTES, + ], + }, +]; diff --git a/src/app/domains/partner/modules/consumers/constants/routes/complexes.ts b/src/app/domains/partner/modules/consumers/constants/routes/complexes.ts new file mode 100644 index 0000000..da5c07d --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/routes/complexes.ts @@ -0,0 +1,48 @@ +import { NamedRoutes } from '@/core'; +import { Routes } from '@angular/router'; +import { PARTNER_CONSUMER_POSES_ROUTES } from './poses'; + +export type TComplexesRouteNames = 'complexes' | 'complex'; + +const baseUrl = (consumerId: string, businessId: string) => + `/partner/consumers/${consumerId}/business_activities/${businessId}/complexes`; + +export const partnerConsumerComplexesNamedRoutes: NamedRoutes = { + complexes: { + path: 'complexes', + loadComponent: () => + import('../../views/complexes/list.component').then((m) => m.PartnerUserComplexesComponent), + meta: { + title: 'شعب', + pagePath: (consumerId: string, businessId: string) => baseUrl(consumerId, businessId), + }, + }, + complex: { + path: 'complexes/:complexId', + loadComponent: () => + import('../../views/complexes/single.component').then((m) => m.PartnerUserComplexComponent), + meta: { + title: 'شعبه', + pagePath: (consumerId: string, businessId: string, complexId: string) => + `${baseUrl(consumerId, businessId)}/${complexId}`, + }, + }, +}; + +export const PARTNER_CONSUMER_COMPLEXES_ROUTES: Routes = [ + partnerConsumerComplexesNamedRoutes.complexes, + { + path: partnerConsumerComplexesNamedRoutes.complex.path, + loadComponent: () => + import('../../components/complexes/layout.component').then( + (m) => m.PartnerConsumerComplexLayoutComponent, + ), + children: [ + { + path: '', + loadComponent: partnerConsumerComplexesNamedRoutes.complex.loadComponent, + }, + ...PARTNER_CONSUMER_POSES_ROUTES, + ], + }, +]; diff --git a/src/app/domains/partner/modules/consumers/constants/routes/index.ts b/src/app/domains/partner/modules/consumers/constants/routes/index.ts new file mode 100644 index 0000000..8fc4b12 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/routes/index.ts @@ -0,0 +1,44 @@ +import { NamedRoutes } from '@/core'; +import { Routes } from '@angular/router'; +import { PARTNER_CONSUMER_ACCOUNTS_ROUTES } from './accounts'; +import { PARTNER_CONSUMER_BUSINESS_ACTIVITIES_ROUTES } from './businessActivities'; + +export type TConsumersRouteNames = 'consumers' | 'consumer'; + +export const partnerConsumersNamedRoutes: NamedRoutes = { + consumers: { + path: 'consumers', + loadComponent: () => import('../../views/list.component').then((m) => m.ConsumersComponent), + meta: { + title: 'مشتریان', + pagePath: () => '/partner/consumers', + }, + }, + consumer: { + path: 'consumers/:consumerId', + loadComponent: () => import('../../views/single.component').then((m) => m.ConsumerComponent), + meta: { + title: 'مشتری', + pagePath: (guildId: string) => `/partner/consumers/${guildId}`, + }, + }, +}; + +export const PARTNER_CONSUMERS_ROUTES: Routes = [ + partnerConsumersNamedRoutes.consumers, + { + path: 'consumers/:consumerId', + loadComponent: () => + import('../../components/layout.component').then((m) => m.ConsumerLayoutComponent), + + children: [ + { + path: '', + loadComponent: () => + import('../../views/single.component').then((m) => m.ConsumerComponent), + }, + ...PARTNER_CONSUMER_ACCOUNTS_ROUTES, + ...PARTNER_CONSUMER_BUSINESS_ACTIVITIES_ROUTES, + ], + }, +]; diff --git a/src/app/domains/partner/modules/consumers/constants/routes/poses.ts b/src/app/domains/partner/modules/consumers/constants/routes/poses.ts new file mode 100644 index 0000000..44244b1 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/constants/routes/poses.ts @@ -0,0 +1,49 @@ +import { NamedRoutes } from '@/core'; +import { Routes } from '@angular/router'; + +export type TPosesRouteNames = 'poses' | 'pos'; + +const baseUrl = (consumerId: string, businessId: string, complexId: string) => + `/partner/consumers/${consumerId}/business_activities/${businessId}/complexes/${complexId}/poses`; + +export const partnerConsumerPosesNamedRoutes: NamedRoutes = { + poses: { + path: 'poses', + loadComponent: () => + import('../../views/poses/list.component').then((m) => m.PartnerUserPosesComponent), + // @ts-ignore + meta: { + title: 'پایانه‌های فروش', + pagePath: (consumerId: string, businessId: string, complexId: string) => + baseUrl(consumerId, businessId, complexId), + }, + }, + pos: { + path: 'poses/:posId', + loadComponent: () => + import('../../views/poses/single.component').then((m) => m.PartnerUserPosComponent), + // @ts-ignore + meta: { + title: 'پایانه‌ی فروش', + pagePath: (consumerId: string, businessId: string, complexId: string, posId: string) => + `${baseUrl(consumerId, businessId, complexId)}/${posId}`, + }, + }, +}; + +export const PARTNER_CONSUMER_POSES_ROUTES: Routes = [ + partnerConsumerPosesNamedRoutes.poses, + { + path: partnerConsumerPosesNamedRoutes.pos.path, + loadComponent: () => + import('../../components/poses/layout.component').then( + (m) => m.PartnerConsumerPosLayoutComponent, + ), + children: [ + { + path: '', + loadComponent: partnerConsumerPosesNamedRoutes.pos.loadComponent, + }, + ], + }, +]; diff --git a/src/app/domains/partner/modules/consumers/models/accounts_io.d.ts b/src/app/domains/partner/modules/consumers/models/accounts_io.d.ts new file mode 100644 index 0000000..f95fd73 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/models/accounts_io.d.ts @@ -0,0 +1,13 @@ +import { TAccountType } from '@/core/constants/accountTypes.const'; + +export interface IConsumerAccountRawResponse { + username: string; + id: string; +} +export interface IConsumerAccountResponse extends IConsumerAccountRawResponse {} + +export interface IConsumerAccountRequest { + username: string; + password?: string; + type: TAccountType; +} diff --git a/src/app/domains/partner/modules/consumers/models/businessActivities_io.d.ts b/src/app/domains/partner/modules/consumers/models/businessActivities_io.d.ts new file mode 100644 index 0000000..7ca3553 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/models/businessActivities_io.d.ts @@ -0,0 +1,15 @@ +import ISummary from '@/core/models/summary'; + +export interface IBusinessActivityRawResponse { + name: string; + economic_code: string; + guild: ISummary; + id: string; +} +export interface IBusinessActivityResponse extends IBusinessActivityRawResponse {} + +export interface IBusinessActivityRequest { + name: string; + economic_code: string; + guild_id: string; +} diff --git a/src/app/domains/partner/modules/consumers/models/complexes_io.d.ts b/src/app/domains/partner/modules/consumers/models/complexes_io.d.ts new file mode 100644 index 0000000..8ea2421 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/models/complexes_io.d.ts @@ -0,0 +1,13 @@ +export interface IComplexRawResponse { + name: string; + address: string; + branch_code: string; + id: string; +} +export interface IComplexResponse extends IComplexRawResponse {} + +export interface IComplexRequest { + name: string; + address: string; + branch_code: string; +} diff --git a/src/app/domains/partner/modules/consumers/models/index.ts b/src/app/domains/partner/modules/consumers/models/index.ts new file mode 100644 index 0000000..3fd584e --- /dev/null +++ b/src/app/domains/partner/modules/consumers/models/index.ts @@ -0,0 +1,6 @@ +export * from './accounts_io'; +export * from './businessActivities_io'; +export * from './complexes_io'; +export * from './io'; +export * from './licenses_io'; +export * from './poses_io'; diff --git a/src/app/domains/partner/modules/consumers/models/io.d.ts b/src/app/domains/partner/modules/consumers/models/io.d.ts new file mode 100644 index 0000000..e1f95ea --- /dev/null +++ b/src/app/domains/partner/modules/consumers/models/io.d.ts @@ -0,0 +1,28 @@ +export interface IConsumerRawResponse { + id: string; + first_name: string; + last_name: string; + mobile_number: string; + national_code: string; + status: string; + created_at: string; + fullname: string; + license_info: ILicenseInfo; +} +export interface IConsumerResponse extends IConsumerRawResponse {} + +export interface IConsumerRequest { + first_name: string; + last_name: string; + mobile_number: string; + national_code: string; + username: string; + password: string; + license_starts_at: string; +} + +interface ILicenseInfo { + id: string; + starts_at: string; + expires_at: string; +} diff --git a/src/app/domains/partner/modules/consumers/models/licenses_io.d.ts b/src/app/domains/partner/modules/consumers/models/licenses_io.d.ts new file mode 100644 index 0000000..48b8389 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/models/licenses_io.d.ts @@ -0,0 +1,17 @@ +import ISummary from '@/core/models/summary'; + +export interface ILicenseRawResponse { + id: string; + starts_at: string; + expires_at: string; + // status: TLicenseStatus; + partner?: ISummary; +} +export interface ILicenseResponse extends ILicenseRawResponse {} + +export interface ILicenseRequest { + starts_at: string; + expires_at?: string; + // status: TLicenseStatus; + partner_id: string; +} diff --git a/src/app/domains/partner/modules/consumers/models/poses_io.d.ts b/src/app/domains/partner/modules/consumers/models/poses_io.d.ts new file mode 100644 index 0000000..1c76cae --- /dev/null +++ b/src/app/domains/partner/modules/consumers/models/poses_io.d.ts @@ -0,0 +1,24 @@ +import ISummary from '@/core/models/summary'; + +export interface IPosRawResponse { + id: string; + name: string; + serial: string; + model?: string; + status: string; + pos_type: string; + complex: ISummary; + device?: ISummary; + provider?: ISummary; +} +export interface IPosResponse extends IPosRawResponse {} + +export interface IPosRequest { + name: string; + serial: string; + model?: string; + status: string; + pos_type: string; + device_id: string; + provider_id: string; +} diff --git a/src/app/domains/partner/modules/consumers/services/accounts.service.ts b/src/app/domains/partner/modules/consumers/services/accounts.service.ts new file mode 100644 index 0000000..9de9745 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/services/accounts.service.ts @@ -0,0 +1,41 @@ +import { IPaginatedResponse } from '@/core/models/service.model'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { CONSUMER_ACCOUNTS_API_ROUTES } from '../constants'; +import { + IConsumerAccountRawResponse, + IConsumerAccountRequest, + IConsumerAccountResponse, +} from '../models'; + +@Injectable({ providedIn: 'root' }) +export class PartnerConsumerAccountsService { + constructor(private http: HttpClient) {} + + private apiRoutes = CONSUMER_ACCOUNTS_API_ROUTES; + + getAll(consumerId: string): Observable> { + return this.http.get>( + this.apiRoutes.list(consumerId), + ); + } + getSingle(consumerId: string, accountId: string): Observable { + return this.http.get(this.apiRoutes.single(consumerId, accountId)); + } + + create(consumerId: string, data: IConsumerAccountRequest): Observable { + return this.http.post(this.apiRoutes.list(consumerId), data); + } + + update( + consumerId: string, + accountId: string, + data: IConsumerAccountRequest, + ): Observable { + return this.http.patch( + this.apiRoutes.single(consumerId, accountId), + data, + ); + } +} diff --git a/src/app/domains/partner/modules/consumers/services/businessActivities.service.ts b/src/app/domains/partner/modules/consumers/services/businessActivities.service.ts new file mode 100644 index 0000000..d86f6f9 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/services/businessActivities.service.ts @@ -0,0 +1,46 @@ +import { IPaginatedResponse } from '@/core/models/service.model'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BUSINESS_ACTIVITIES_API_ROUTES } from '../constants/apiRoutes/businessActivities'; +import { + IBusinessActivityRawResponse, + IBusinessActivityRequest, + IBusinessActivityResponse, +} from '../models'; + +@Injectable({ providedIn: 'root' }) +export class PartnerConsumerBusinessActivitiesService { + constructor(private http: HttpClient) {} + + private apiRoutes = BUSINESS_ACTIVITIES_API_ROUTES; + + getAll(consumerId: string): Observable> { + return this.http.get>( + this.apiRoutes.list(consumerId), + ); + } + getSingle(consumerId: string, businessActivityId: string): Observable { + return this.http.get( + this.apiRoutes.single(consumerId, businessActivityId), + ); + } + + create( + consumerId: string, + data: IBusinessActivityRequest, + ): Observable { + return this.http.post(this.apiRoutes.list(consumerId), data); + } + + update( + consumerId: string, + businessActivityId: string, + data: IBusinessActivityRequest, + ): Observable { + return this.http.patch( + this.apiRoutes.single(consumerId, businessActivityId), + data, + ); + } +} diff --git a/src/app/domains/partner/modules/consumers/services/complexes.service.ts b/src/app/domains/partner/modules/consumers/services/complexes.service.ts new file mode 100644 index 0000000..715b5f5 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/services/complexes.service.ts @@ -0,0 +1,54 @@ +import { IPaginatedResponse } from '@/core/models/service.model'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BUSINESS_ACTIVITY_COMPLEXES_API_ROUTES } from '../constants/apiRoutes/businessActivityComplexes'; +import { IComplexRawResponse, IComplexRequest, IComplexResponse } from '../models'; + +@Injectable({ providedIn: 'root' }) +export class PartnerComplexesService { + constructor(private http: HttpClient) {} + + private apiRoutes = BUSINESS_ACTIVITY_COMPLEXES_API_ROUTES; + + getAll( + consumerId: string, + businessActivityId: string, + ): Observable> { + return this.http.get>( + this.apiRoutes.list(consumerId, businessActivityId), + ); + } + getSingle( + consumerId: string, + businessActivityId: string, + complexId: string, + ): Observable { + return this.http.get( + this.apiRoutes.single(consumerId, businessActivityId, complexId), + ); + } + + create( + consumerId: string, + businessActivityId: string, + data: IComplexRequest, + ): Observable { + return this.http.post( + this.apiRoutes.list(consumerId, businessActivityId), + data, + ); + } + + update( + consumerId: string, + businessActivityId: string, + complexId: string, + data: IComplexRequest, + ): Observable { + return this.http.patch( + this.apiRoutes.single(consumerId, businessActivityId, complexId), + data, + ); + } +} diff --git a/src/app/domains/partner/modules/consumers/services/licenses.service.ts b/src/app/domains/partner/modules/consumers/services/licenses.service.ts new file mode 100644 index 0000000..7faeb68 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/services/licenses.service.ts @@ -0,0 +1,24 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { CONSUMER_LICENSES_API_ROUTES } from '../constants'; +import { ILicenseRawResponse, ILicenseRequest, ILicenseResponse } from '../models'; + +@Injectable({ providedIn: 'root' }) +export class LicensesService { + constructor(private http: HttpClient) {} + + private apiRoutes = CONSUMER_LICENSES_API_ROUTES; + + create(consumerId: string, data: ILicenseRequest): Observable { + return this.http.post(this.apiRoutes.list(consumerId), data); + } + + update( + consumerId: string, + licenseId: string, + data: ILicenseRequest, + ): Observable { + return this.http.patch(this.apiRoutes.single(consumerId, licenseId), data); + } +} diff --git a/src/app/domains/partner/modules/consumers/services/main.service.ts b/src/app/domains/partner/modules/consumers/services/main.service.ts new file mode 100644 index 0000000..8fe9cd6 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/services/main.service.ts @@ -0,0 +1,28 @@ +import { IPaginatedResponse } from '@/core/models/service.model'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { CONSUMERS_API_ROUTES } from '../constants'; +import { IConsumerRawResponse, IConsumerRequest, IConsumerResponse } from '../models'; + +@Injectable({ providedIn: 'root' }) +export class ConsumersService { + constructor(private http: HttpClient) {} + + private apiRoutes = CONSUMERS_API_ROUTES; + + getAll(): Observable> { + return this.http.get>(this.apiRoutes.list()); + } + getSingle(consumerId: string): Observable { + return this.http.get(this.apiRoutes.single(consumerId)); + } + + create(userData: IConsumerRequest): Observable { + return this.http.post(this.apiRoutes.list(), userData); + } + + update(consumerId: string, userData: IConsumerRequest): Observable { + return this.http.patch(this.apiRoutes.single(consumerId), userData); + } +} diff --git a/src/app/domains/partner/modules/consumers/services/posAccounts.service.ts b/src/app/domains/partner/modules/consumers/services/posAccounts.service.ts new file mode 100644 index 0000000..5326ca5 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/services/posAccounts.service.ts @@ -0,0 +1,38 @@ +// import { IPaginatedResponse } from '@/core/models/service.model'; +// import { HttpClient } from '@angular/common/http'; +// import { Injectable } from '@angular/core'; +// import { Observable } from 'rxjs'; +// import { POS_ACCOUNTS_API_ROUTES } from '../constants'; +// import { IAccountRawResponse, IAccountRequest, IAccountResponse } from '../../users/models'; + +// @Injectable({ providedIn: 'root' }) +// export class PartnerPosesService { +// constructor(private http: HttpClient) {} + +// private apiRoutes = POS_ACCOUNTS_API_ROUTES; + +// getAll(complexId: string, posId: string): Observable> { +// return this.http.get>( +// this.apiRoutes.list(complexId, posId), +// ); +// } +// getSingle(complexId: string, posId: string, accountId: string): Observable { +// return this.http.get(this.apiRoutes.single(complexId, posId, accountId)); +// } + +// create(complexId: string, posId: string, data: IAccountRequest): Observable { +// return this.http.post(this.apiRoutes.list(complexId, posId), data); +// } + +// update( +// complexId: string, +// posId: string, +// accountId: string, +// data: IAccountRequest, +// ): Observable { +// return this.http.patch( +// this.apiRoutes.single(complexId, posId, accountId), +// data, +// ); +// } +// } diff --git a/src/app/domains/partner/modules/consumers/services/poses.service.ts b/src/app/domains/partner/modules/consumers/services/poses.service.ts new file mode 100644 index 0000000..cb466e5 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/services/poses.service.ts @@ -0,0 +1,54 @@ +import { IPaginatedResponse } from '@/core/models/service.model'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { COMPLEX_POSES_API_ROUTES } from '../constants/apiRoutes/complexPoses'; +import { IPosRawResponse, IPosRequest, IPosResponse } from '../models'; + +@Injectable({ providedIn: 'root' }) +export class PartnerPosesService { + constructor(private http: HttpClient) {} + + private apiRoutes = COMPLEX_POSES_API_ROUTES; + + getAll( + businessActivityId: string, + complexId: string, + ): Observable> { + return this.http.get>( + this.apiRoutes.list(businessActivityId, complexId), + ); + } + getSingle( + businessActivityId: string, + complexId: string, + posId: string, + ): Observable { + return this.http.get( + this.apiRoutes.single(businessActivityId, complexId, posId), + ); + } + + create( + businessActivityId: string, + complexId: string, + data: IPosRequest, + ): Observable { + return this.http.post( + this.apiRoutes.list(businessActivityId, complexId), + data, + ); + } + + update( + businessActivityId: string, + complexId: string, + posId: string, + data: IPosRequest, + ): Observable { + return this.http.patch( + this.apiRoutes.single(businessActivityId, complexId, posId), + data, + ); + } +} diff --git a/src/app/domains/partner/modules/consumers/store/businessActivity.store.ts b/src/app/domains/partner/modules/consumers/store/businessActivity.store.ts new file mode 100644 index 0000000..d5e860d --- /dev/null +++ b/src/app/domains/partner/modules/consumers/store/businessActivity.store.ts @@ -0,0 +1,82 @@ +import { EntityState, EntityStore } from '@/core/state'; +import { computed, inject, Injectable } from '@angular/core'; +import { MenuItem } from 'primeng/api'; +import { catchError, finalize } from 'rxjs'; +import { partnerConsumerBusinessActivitiesNamedRoutes } from '../constants/routes/businessActivities'; +import { IBusinessActivityResponse } from '../models'; +import { PartnerConsumerBusinessActivitiesService } from '../services/businessActivities.service'; + +interface BusinessActivityState extends EntityState { + breadcrumbItems: MenuItem[]; +} + +@Injectable({ + providedIn: 'root', +}) +export class BusinessActivityStore extends EntityStore< + IBusinessActivityResponse, + BusinessActivityState +> { + private readonly service = inject(PartnerConsumerBusinessActivitiesService); + constructor() { + super({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + breadcrumbItems: [], + }); + } + + breadcrumbItems = computed(() => this._state().breadcrumbItems); + + private setBreadcrumb(consumerId: string, businessId: string) { + this.patchState({ + breadcrumbItems: [ + { + ...partnerConsumerBusinessActivitiesNamedRoutes.businessActivities.meta, + routerLink: + partnerConsumerBusinessActivitiesNamedRoutes.businessActivities.meta.pagePath!( + consumerId, + ), + }, + { + title: this.entity()?.name, + routerLink: partnerConsumerBusinessActivitiesNamedRoutes.businessActivity.meta + .pagePath!(consumerId, businessId), + }, + ], + }); + } + + getData(consumerId: string, businessId: string) { + this.patchState({ loading: true }); + this.service + .getSingle(consumerId, businessId) + .pipe( + finalize(() => { + this.patchState({ loading: false }); + }), + catchError((error) => { + this.setError(error); + throw error; + }), + ) + .subscribe((entity) => { + this.patchState({ entity }); + this.setBreadcrumb(consumerId, businessId); + }); + } + + override reset(): void { + this.setState({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + breadcrumbItems: [], + }); + } +} diff --git a/src/app/domains/partner/modules/consumers/store/complex.store.ts b/src/app/domains/partner/modules/consumers/store/complex.store.ts new file mode 100644 index 0000000..efce4d0 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/store/complex.store.ts @@ -0,0 +1,82 @@ +import { EntityState, EntityStore } from '@/core/state'; +import { computed, inject, Injectable } from '@angular/core'; +import { MenuItem } from 'primeng/api'; +import { catchError, finalize } from 'rxjs'; +import { partnerConsumerComplexesNamedRoutes } from '../constants/routes/complexes'; +import { IComplexResponse } from '../models'; +import { PartnerComplexesService } from '../services/complexes.service'; + +interface ComplexState extends EntityState { + breadcrumbItems: MenuItem[]; +} + +@Injectable({ + providedIn: 'root', +}) +export class ComplexStore extends EntityStore { + private readonly service = inject(PartnerComplexesService); + constructor() { + super({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + breadcrumbItems: [], + }); + } + + breadcrumbItems = computed(() => this._state().breadcrumbItems); + + private setBreadcrumb(consumerId: string, businessId: string, complexId: string) { + this.patchState({ + breadcrumbItems: [ + { + ...partnerConsumerComplexesNamedRoutes.complexes.meta, + routerLink: partnerConsumerComplexesNamedRoutes.complexes.meta.pagePath!( + consumerId, + businessId, + ), + }, + { + title: this.entity()?.name, + routerLink: partnerConsumerComplexesNamedRoutes.complex.meta.pagePath!( + consumerId, + businessId, + complexId, + ), + }, + ], + }); + } + + getData(consumerId: string, businessId: string, complexId: string) { + this.patchState({ loading: true }); + this.service + .getSingle(consumerId, businessId, complexId) + .pipe( + finalize(() => { + this.patchState({ loading: false }); + }), + catchError((error) => { + this.setError(error); + throw error; + }), + ) + .subscribe((entity) => { + this.patchState({ entity }); + this.setBreadcrumb(consumerId, businessId, complexId); + }); + } + + override reset(): void { + this.setState({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + breadcrumbItems: [], + }); + } +} diff --git a/src/app/domains/partner/modules/consumers/store/consumer.store.ts b/src/app/domains/partner/modules/consumers/store/consumer.store.ts new file mode 100644 index 0000000..0efcc5f --- /dev/null +++ b/src/app/domains/partner/modules/consumers/store/consumer.store.ts @@ -0,0 +1,64 @@ +import { EntityState, EntityStore } from '@/core/state'; +import { computed, inject, Injectable } from '@angular/core'; +import { MenuItem } from 'primeng/api'; +import { catchError, finalize } from 'rxjs'; +import { partnerConsumersNamedRoutes } from '../constants'; +import { IConsumerResponse } from '../models'; +import { ConsumersService } from '../services/main.service'; + +interface ConsumerState extends EntityState { + breadcrumbItems: MenuItem[]; +} + +@Injectable({ + providedIn: 'root', +}) +export class ConsumerStore extends EntityStore { + private readonly service = inject(ConsumersService); + constructor() { + super({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + breadcrumbItems: [], + }); + } + + breadcrumbItems = computed(() => this._state().breadcrumbItems); + + private setBreadcrumb(consumerId: string) { + this.patchState({ + breadcrumbItems: [ + { + ...partnerConsumersNamedRoutes.consumers.meta, + routerLink: partnerConsumersNamedRoutes.consumers.meta.pagePath!(), + }, + { + title: this.entity()?.fullname, + routerLink: partnerConsumersNamedRoutes.consumer.meta.pagePath!(consumerId), + }, + ], + }); + } + + getData(consumerId: string) { + this.patchState({ loading: true }); + this.service + .getSingle(consumerId) + .pipe( + finalize(() => { + this.patchState({ loading: false }); + }), + catchError((error) => { + this.setError(error); + throw error; + }), + ) + .subscribe((entity) => { + this.patchState({ entity }); + this.setBreadcrumb(consumerId); + }); + } +} diff --git a/src/app/domains/partner/modules/consumers/store/pos.store.ts b/src/app/domains/partner/modules/consumers/store/pos.store.ts new file mode 100644 index 0000000..6ad0abf --- /dev/null +++ b/src/app/domains/partner/modules/consumers/store/pos.store.ts @@ -0,0 +1,85 @@ +import { EntityState, EntityStore } from '@/core/state'; +import { computed, inject, Injectable } from '@angular/core'; +import { MenuItem } from 'primeng/api'; +import { catchError, finalize } from 'rxjs'; +import { partnerConsumerPosesNamedRoutes } from '../constants/routes/poses'; +import { IPosResponse } from '../models'; +import { PartnerPosesService } from '../services/poses.service'; + +interface PosState extends EntityState { + breadcrumbItems: MenuItem[]; +} + +@Injectable({ + providedIn: 'root', +}) +export class PosStore extends EntityStore { + private readonly service = inject(PartnerPosesService); + constructor() { + super({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + breadcrumbItems: [], + }); + } + + breadcrumbItems = computed(() => this._state().breadcrumbItems); + + private setBreadcrumb(consumerId: string, businessId: string, complexId: string, posId: string) { + this.patchState({ + breadcrumbItems: [ + { + title: partnerConsumerPosesNamedRoutes.poses.meta.title, + routerLink: partnerConsumerPosesNamedRoutes.poses.meta.pagePath!( + consumerId, + businessId, + complexId, + ), + }, + + { + title: this.entity()?.name, + routerLink: partnerConsumerPosesNamedRoutes.pos.meta.pagePath!( + consumerId, + businessId, + complexId, + posId, + ), + }, + ], + }); + } + + getData(consumerId: string, businessId: string, complexId: string, posId: string) { + this.patchState({ loading: true }); + this.service + .getSingle(businessId, complexId, posId) + .pipe( + finalize(() => { + this.patchState({ loading: false }); + }), + catchError((error) => { + this.setError(error); + throw error; + }), + ) + .subscribe((entity) => { + this.patchState({ entity }); + this.setBreadcrumb(consumerId, businessId, complexId, posId); + }); + } + + override reset(): void { + this.setState({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + breadcrumbItems: [], + }); + } +} diff --git a/src/app/domains/partner/modules/consumers/views/accounts/index.ts b/src/app/domains/partner/modules/consumers/views/accounts/index.ts new file mode 100644 index 0000000..576a89e --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/accounts/index.ts @@ -0,0 +1 @@ +export * from './list.component'; diff --git a/src/app/domains/partner/modules/consumers/views/accounts/list.component.html b/src/app/domains/partner/modules/consumers/views/accounts/list.component.html new file mode 100644 index 0000000..2a3dab5 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/accounts/list.component.html @@ -0,0 +1 @@ + diff --git a/src/app/domains/partner/modules/consumers/views/accounts/list.component.ts b/src/app/domains/partner/modules/consumers/views/accounts/list.component.ts new file mode 100644 index 0000000..cbb3620 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/accounts/list.component.ts @@ -0,0 +1,33 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { BreadcrumbService } from '@/core/services'; +import { Component, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ConsumerAccountListComponent } from '../../components/accounts/list.component'; +import { partnerConsumerAccountsNamedRoutes } from '../../constants/routes/accounts'; +import { ConsumerStore } from '../../store/consumer.store'; + +@Component({ + selector: 'partner-consumer-accounts', + templateUrl: './list.component.html', + imports: [ConsumerAccountListComponent], +}) +export class ConsumerAccountsComponent { + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + private readonly store = inject(ConsumerStore); + + consumerId = signal(this.route.snapshot.params['consumerId']); + + ngOnInit() { + this.setBreadcrumb(); + } + + setBreadcrumb() { + this.breadcrumbService.setItems([ + ...this.store.breadcrumbItems(), + { + title: partnerConsumerAccountsNamedRoutes.accounts.meta.title, + }, + ]); + } +} diff --git a/src/app/domains/partner/modules/consumers/views/businessActivities/index.ts b/src/app/domains/partner/modules/consumers/views/businessActivities/index.ts new file mode 100644 index 0000000..576a89e --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/businessActivities/index.ts @@ -0,0 +1 @@ +export * from './list.component'; diff --git a/src/app/domains/partner/modules/consumers/views/businessActivities/list.component.html b/src/app/domains/partner/modules/consumers/views/businessActivities/list.component.html new file mode 100644 index 0000000..ce646ee --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/businessActivities/list.component.html @@ -0,0 +1 @@ + diff --git a/src/app/domains/partner/modules/consumers/views/businessActivities/list.component.ts b/src/app/domains/partner/modules/consumers/views/businessActivities/list.component.ts new file mode 100644 index 0000000..7dcebd7 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/businessActivities/list.component.ts @@ -0,0 +1,35 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { BreadcrumbService } from '@/core/services'; +import pageParamsUtils from '@/utils/page-params.utils'; +import { Component, computed, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ConsumerBusinessActivitiesComponent } from '../../components/businessActivities/list.component'; +import { partnerConsumerBusinessActivitiesNamedRoutes } from '../../constants/routes/businessActivities'; +import { ConsumerStore } from '../../store/consumer.store'; + +@Component({ + selector: 'partner-user-businessActivities', + templateUrl: './list.component.html', + imports: [ConsumerBusinessActivitiesComponent], +}) +export class PartnerUserBusinessActivitiesComponent { + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + private readonly consumerStore = inject(ConsumerStore); + + pageParams = computed(() => pageParamsUtils(this.route)); + consumerId = signal(this.pageParams()['consumerId']); + + ngOnInit() { + this.setBreadcrumb(); + } + + setBreadcrumb() { + this.breadcrumbService.setItems([ + ...this.consumerStore.breadcrumbItems(), + { + title: partnerConsumerBusinessActivitiesNamedRoutes.businessActivities.meta.title, + }, + ]); + } +} diff --git a/src/app/domains/partner/modules/consumers/views/businessActivities/single.component.html b/src/app/domains/partner/modules/consumers/views/businessActivities/single.component.html new file mode 100644 index 0000000..e53c363 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/businessActivities/single.component.html @@ -0,0 +1,22 @@ +
+ +
+
+ + + +
+
+
+ + + + +
diff --git a/src/app/domains/partner/modules/consumers/views/businessActivities/single.component.ts b/src/app/domains/partner/modules/consumers/views/businessActivities/single.component.ts new file mode 100644 index 0000000..30e8f97 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/businessActivities/single.component.ts @@ -0,0 +1,55 @@ +import { BreadcrumbService } from '@/core/services'; +import { AppCardComponent, KeyValueComponent } from '@/shared/components'; +import pageParamsUtils from '@/utils/page-params.utils'; +import { Component, computed, effect, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { ConsumerBusinessActivitiesFormComponent } from '../../components/businessActivities/form.component'; +import { ConsumerComplexesComponent } from '../../components/complexes/list.component'; +import { BusinessActivityStore } from '../../store/businessActivity.store'; +import { ConsumerStore } from '../../store/consumer.store'; + +@Component({ + selector: 'partner-user-businessActivity', + templateUrl: './single.component.html', + imports: [ + AppCardComponent, + KeyValueComponent, + ConsumerBusinessActivitiesFormComponent, + ConsumerComplexesComponent, + ], +}) +export class PartnerUserBusinessActivityComponent { + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + private readonly store = inject(BusinessActivityStore); + private readonly consumerStore = inject(ConsumerStore); + + pageParams = computed(() => pageParamsUtils(this.route)); + + readonly consumerId = signal(this.pageParams()['consumerId']!); + readonly businessId = signal(this.pageParams()['businessActivityId']!); + editMode = signal(false); + + readonly loading = computed(() => this.store.loading()); + readonly businessActivity = computed(() => this.store.entity()); + + constructor() { + effect(() => { + if (this.businessActivity()?.id) { + this.setBreadcrumb(); + } + }); + } + + getData() { + this.store.getData(this.consumerId(), this.businessId()); + } + + setBreadcrumb() { + this.breadcrumbService.setItems([ + ...this.consumerStore.breadcrumbItems(), + ...this.store.breadcrumbItems(), + ]); + } +} diff --git a/src/app/domains/partner/modules/consumers/views/complexes/index.ts b/src/app/domains/partner/modules/consumers/views/complexes/index.ts new file mode 100644 index 0000000..576a89e --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/complexes/index.ts @@ -0,0 +1 @@ +export * from './list.component'; diff --git a/src/app/domains/partner/modules/consumers/views/complexes/list.component.html b/src/app/domains/partner/modules/consumers/views/complexes/list.component.html new file mode 100644 index 0000000..ce702d5 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/complexes/list.component.html @@ -0,0 +1 @@ + diff --git a/src/app/domains/partner/modules/consumers/views/complexes/list.component.ts b/src/app/domains/partner/modules/consumers/views/complexes/list.component.ts new file mode 100644 index 0000000..35884ed --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/complexes/list.component.ts @@ -0,0 +1,43 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { BreadcrumbService } from '@/core/services'; +import pageParamsUtils from '@/utils/page-params.utils'; +import { Component, computed, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ConsumerComplexesComponent } from '../../components/complexes/list.component'; +import { partnerConsumerComplexesNamedRoutes } from '../../constants/routes/complexes'; +import { BusinessActivityStore } from '../../store/businessActivity.store'; +import { ConsumerStore } from '../../store/consumer.store'; + +@Component({ + selector: 'partner-user-complexes', + templateUrl: './list.component.html', + imports: [ConsumerComplexesComponent], +}) +export class PartnerUserComplexesComponent { + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + private readonly consumerStore = inject(ConsumerStore); + private readonly businessStore = inject(BusinessActivityStore); + + pageParams = computed(() => pageParamsUtils(this.route)); + consumerId = signal(this.pageParams()['consumerId']); + businessId = signal(this.pageParams()['businessActivityId']); + + ngAfterViewInit() { + this.setBreadcrumb(); + } + + setBreadcrumb() { + this.breadcrumbService.setItems([ + ...this.consumerStore.breadcrumbItems(), + ...this.businessStore.breadcrumbItems(), + { + title: partnerConsumerComplexesNamedRoutes.complexes.meta.title, + routerLink: partnerConsumerComplexesNamedRoutes.complexes.meta.pagePath!( + this.consumerId(), + this.businessId(), + ), + }, + ]); + } +} diff --git a/src/app/domains/partner/modules/consumers/views/complexes/single.component.html b/src/app/domains/partner/modules/consumers/views/complexes/single.component.html new file mode 100644 index 0000000..68be6af --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/complexes/single.component.html @@ -0,0 +1,22 @@ +
+ +
+
+ + +
+
+
+ + + + +
diff --git a/src/app/domains/partner/modules/consumers/views/complexes/single.component.ts b/src/app/domains/partner/modules/consumers/views/complexes/single.component.ts new file mode 100644 index 0000000..819ddcd --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/complexes/single.component.ts @@ -0,0 +1,59 @@ +import { BreadcrumbService } from '@/core/services'; +import { AppCardComponent, KeyValueComponent } from '@/shared/components'; +import pageParamsUtils from '@/utils/page-params.utils'; +import { Component, computed, effect, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ConsumerComplexFormComponent } from '../../components/complexes/form.component'; +import { ConsumerPosesComponent } from '../../components/poses/list.component'; +import { BusinessActivityStore } from '../../store/businessActivity.store'; +import { ComplexStore } from '../../store/complex.store'; +import { ConsumerStore } from '../../store/consumer.store'; + +@Component({ + selector: 'partner-user-complex', + templateUrl: './single.component.html', + imports: [ + AppCardComponent, + KeyValueComponent, + ConsumerComplexFormComponent, + ConsumerPosesComponent, + ], +}) +export class PartnerUserComplexComponent { + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + private readonly store = inject(ComplexStore); + private readonly consumerStore = inject(ConsumerStore); + private readonly businessStore = inject(BusinessActivityStore); + + pageParams = computed(() => pageParamsUtils(this.route)); + + readonly consumerId = signal(this.pageParams()['consumerId']!); + readonly businessId = signal(this.pageParams()['businessActivityId']!); + readonly complexId = signal(this.pageParams()['complexId']!); + + editMode = signal(false); + + readonly loading = computed(() => this.store.loading()); + readonly complex = computed(() => this.store.entity()); + + constructor() { + effect(() => { + if (this.complex()?.id) { + this.setBreadcrumb(); + } + }); + } + + getData() { + this.store.getData(this.consumerId(), this.businessId(), this.complexId()); + } + + setBreadcrumb() { + this.breadcrumbService.setItems([ + ...this.consumerStore.breadcrumbItems(), + ...this.businessStore.breadcrumbItems(), + ...this.store.breadcrumbItems(), + ]); + } +} diff --git a/src/app/domains/partner/modules/consumers/views/index.ts b/src/app/domains/partner/modules/consumers/views/index.ts new file mode 100644 index 0000000..bc9dfc9 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/index.ts @@ -0,0 +1,2 @@ +export * from './list.component'; +export * from './single.component'; diff --git a/src/app/domains/partner/modules/consumers/views/list.component.html b/src/app/domains/partner/modules/consumers/views/list.component.html new file mode 100644 index 0000000..fd238c8 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/list.component.html @@ -0,0 +1,23 @@ + + diff --git a/src/app/domains/partner/modules/consumers/views/list.component.ts b/src/app/domains/partner/modules/consumers/views/list.component.ts new file mode 100644 index 0000000..6ffb6be --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/list.component.ts @@ -0,0 +1,52 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { AbstractList } from '@/shared/abstractClasses/abstract-list'; +import { PageDataListComponent } from '@/shared/components/pageDataList/page-data-list.component'; +import { formatJalali } from '@/utils'; +import { Component, inject } from '@angular/core'; +import { Router } from '@angular/router'; +import { ConsumerUserFormComponent } from '../components/form.component'; +import { partnerConsumersNamedRoutes } from '../constants'; +import { IConsumerResponse } from '../models'; +import { ConsumersService } from '../services/main.service'; + +@Component({ + selector: 'partner-consumers', + templateUrl: './list.component.html', + imports: [PageDataListComponent, ConsumerUserFormComponent], +}) +export class ConsumersComponent extends AbstractList { + private readonly service = inject(ConsumersService); + private readonly router = inject(Router); + + override setColumns(): void { + this.columns = [ + { field: 'id', header: 'شناسه', type: 'id' }, + { field: 'fullname', header: 'نام' }, + { field: 'mobile_number', header: 'شماره موبایل' }, + { field: 'status', header: 'وضعیت' }, + { + field: 'license_expires_at', + header: 'تاریخ انقضای لایسنس', + customDataModel(item) { + if (item.license_info) { + return formatJalali(item.license_info.expires_at); + } + return 'بدون لایسنس'; + }, + }, + { + field: 'created_at', + header: 'تاریخ ایجاد', + type: 'date', + }, + ]; + } + + override getDataRequest() { + return this.service.getAll(); + } + + toSinglePage(consumer: IConsumerResponse) { + this.router.navigateByUrl(partnerConsumersNamedRoutes.consumer.meta.pagePath!(consumer.id)); + } +} diff --git a/src/app/domains/partner/modules/consumers/views/poses/index.ts b/src/app/domains/partner/modules/consumers/views/poses/index.ts new file mode 100644 index 0000000..576a89e --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/poses/index.ts @@ -0,0 +1 @@ +export * from './list.component'; diff --git a/src/app/domains/partner/modules/consumers/views/poses/list.component.html b/src/app/domains/partner/modules/consumers/views/poses/list.component.html new file mode 100644 index 0000000..6d25289 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/poses/list.component.html @@ -0,0 +1 @@ + diff --git a/src/app/domains/partner/modules/consumers/views/poses/list.component.ts b/src/app/domains/partner/modules/consumers/views/poses/list.component.ts new file mode 100644 index 0000000..4062089 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/poses/list.component.ts @@ -0,0 +1,48 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { BreadcrumbService } from '@/core/services'; +import pageParamsUtils from '@/utils/page-params.utils'; +import { Component, computed, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ConsumerPosesComponent } from '../../components/poses/list.component'; +import { partnerConsumerPosesNamedRoutes } from '../../constants/routes/poses'; +import { BusinessActivityStore } from '../../store/businessActivity.store'; +import { ComplexStore } from '../../store/complex.store'; +import { ConsumerStore } from '../../store/consumer.store'; + +@Component({ + selector: 'partner-user-poses', + templateUrl: './list.component.html', + imports: [ConsumerPosesComponent], +}) +export class PartnerUserPosesComponent { + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + private readonly consumerStore = inject(ConsumerStore); + private readonly businessStore = inject(BusinessActivityStore); + private readonly complexStore = inject(ComplexStore); + + pageParams = computed(() => pageParamsUtils(this.route)); + consumerId = signal(this.pageParams()['consumerId']); + businessId = signal(this.pageParams()['businessActivityId']); + complexId = signal(this.pageParams()['complexId']); + + ngOnInit() { + this.setBreadcrumb(); + } + + setBreadcrumb() { + this.breadcrumbService.setItems([ + ...this.consumerStore.breadcrumbItems(), + ...this.businessStore.breadcrumbItems(), + ...this.complexStore.breadcrumbItems(), + { + title: partnerConsumerPosesNamedRoutes.poses.meta.title, + routerLink: partnerConsumerPosesNamedRoutes.poses.meta.pagePath!( + this.consumerId(), + this.businessId(), + this.complexId(), + ), + }, + ]); + } +} diff --git a/src/app/domains/partner/modules/consumers/views/poses/single.component.html b/src/app/domains/partner/modules/consumers/views/poses/single.component.html new file mode 100644 index 0000000..fe9d277 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/poses/single.component.html @@ -0,0 +1,20 @@ +
+ +
+
+ +
+
+
+ + +
diff --git a/src/app/domains/partner/modules/consumers/views/poses/single.component.ts b/src/app/domains/partner/modules/consumers/views/poses/single.component.ts new file mode 100644 index 0000000..2bbdc71 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/poses/single.component.ts @@ -0,0 +1,56 @@ +import { BreadcrumbService } from '@/core/services'; +import { AppCardComponent, KeyValueComponent } from '@/shared/components'; +import pageParamsUtils from '@/utils/page-params.utils'; +import { Component, computed, effect, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ConsumerPosFormComponent } from '../../components/poses/form.component'; +import { BusinessActivityStore } from '../../store/businessActivity.store'; +import { ComplexStore } from '../../store/complex.store'; +import { ConsumerStore } from '../../store/consumer.store'; +import { PosStore } from '../../store/pos.store'; + +@Component({ + selector: 'partner-user-pos', + templateUrl: './single.component.html', + imports: [AppCardComponent, KeyValueComponent, ConsumerPosFormComponent], +}) +export class PartnerUserPosComponent { + private readonly consumerStore = inject(ConsumerStore); + private readonly businessStore = inject(BusinessActivityStore); + private readonly complexStore = inject(ComplexStore); + private readonly store = inject(PosStore); + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + + pageParams = computed(() => pageParamsUtils(this.route)); + + readonly consumerId = signal(this.pageParams()['consumerId']!); + readonly businessId = signal(this.pageParams()['businessActivityId']!); + readonly complexId = signal(this.pageParams()['complexId']!); + readonly posId = signal(this.pageParams()['posId']!); + editMode = signal(false); + + constructor() { + effect(() => { + if (this.pos()?.id) { + this.setBreadcrumb(); + } + }); + } + + readonly loading = computed(() => this.store.loading()); + readonly pos = computed(() => this.store.entity()); + + getData() { + this.store.getData(this.consumerId(), this.businessId(), this.complexId(), this.posId()); + } + + setBreadcrumb() { + this.breadcrumbService.setItems([ + ...this.consumerStore.breadcrumbItems(), + ...this.businessStore.breadcrumbItems(), + ...this.complexStore.breadcrumbItems(), + ...this.store.breadcrumbItems(), + ]); + } +} diff --git a/src/app/domains/partner/modules/consumers/views/single.component.html b/src/app/domains/partner/modules/consumers/views/single.component.html new file mode 100644 index 0000000..d3a48c6 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/single.component.html @@ -0,0 +1,51 @@ +
+ + +
+
+ + + + @if (licenseStatus() === "EXPIRED") { + + + منقضی شده در + + + + } @else if (licenseStatus() === "ACTIVE") { + + + تا تاریخ + + + + } @else { + + ارایه نشده + + } +
+
+
+ + + + + + + +
diff --git a/src/app/domains/partner/modules/consumers/views/single.component.ts b/src/app/domains/partner/modules/consumers/views/single.component.ts new file mode 100644 index 0000000..0ae73e6 --- /dev/null +++ b/src/app/domains/partner/modules/consumers/views/single.component.ts @@ -0,0 +1,64 @@ +import { BreadcrumbService } from '@/core/services'; +import { AppCardComponent, KeyValueComponent } from '@/shared/components'; +import { JalaliDateDirective } from '@/shared/directives'; +import { getLicenseStatus } from '@/utils'; +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 { ConsumerBusinessActivitiesComponent } from '../components/businessActivities/list.component'; +import { ConsumerUserFormComponent } from '../components/form.component'; +import { ConsumerLicenseFormComponent } from '../components/licenses/form.component'; +import { ConsumerStore } from '../store/consumer.store'; + +@Component({ + selector: 'consumer-user', + templateUrl: './single.component.html', + imports: [ + AppCardComponent, + KeyValueComponent, + ConsumerUserFormComponent, + ConsumerAccountListComponent, + ConsumerBusinessActivitiesComponent, + Button, + JalaliDateDirective, + ConsumerLicenseFormComponent, + ], +}) +export class ConsumerComponent { + private readonly store = inject(ConsumerStore); + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + + readonly consumerId = signal(this.route.snapshot.paramMap.get('consumerId')!); + editMode = signal(false); + + visibleLicenseForm = signal(false); + + readonly loading = computed(() => this.store.loading()); + readonly consumer = computed(() => this.store.entity()); + readonly license = computed(() => this.store.entity()?.license_info); + readonly licenseStatus = computed(() => + getLicenseStatus(this.store.entity()?.license_info?.expires_at), + ); + + constructor() { + effect(() => { + if (this.consumer()?.id) { + this.setBreadcrumb(); + } + }); + } + + getData() { + this.store.getData(this.consumerId()); + } + + setBreadcrumb() { + this.breadcrumbService.setItems(this.store.breadcrumbItems()); + } + + openLicenseForm() { + // this.visibleLicenseForm.set(true); + } +} diff --git a/src/app/domains/partner/routes.ts b/src/app/domains/partner/routes.ts index 72120ea..0da7cf7 100644 --- a/src/app/domains/partner/routes.ts +++ b/src/app/domains/partner/routes.ts @@ -1,6 +1,6 @@ import { Route } from '@angular/router'; import { PARTNER_ACCOUNTS_ROUTES } from './modules/accounts/constants'; -import { PARTNER_CUSTOMERS_ROUTES } from './modules/customers/constants'; +import { PARTNER_CONSUMERS_ROUTES } from './modules/consumers/constants'; export const PARTNER_ROUTES = { path: 'partner', @@ -12,6 +12,6 @@ export const PARTNER_ROUTES = { import('./modules/dashboard/views/index.component').then((m) => m.DashboardComponent), }, ...PARTNER_ACCOUNTS_ROUTES, - ...PARTNER_CUSTOMERS_ROUTES, + ...PARTNER_CONSUMERS_ROUTES, ], } as Route; diff --git a/src/app/domains/pos/layouts/layout.component.html b/src/app/domains/pos/layouts/layout.component.html index ebaf9e5..bddad05 100644 --- a/src/app/domains/pos/layouts/layout.component.html +++ b/src/app/domains/pos/layouts/layout.component.html @@ -8,7 +8,7 @@ Logo
@if (posInfo()) { - {{ posInfo()?.name }} - فروشگاه {{ posInfo()?.complex?.name }} + {{ posInfo()?.name }} - شعبه {{ posInfo()?.complex?.name }} }
diff --git a/src/app/domains/pos/models/pos.io.ts b/src/app/domains/pos/models/pos.io.ts index ffa07b2..82ca4c2 100644 --- a/src/app/domains/pos/models/pos.io.ts +++ b/src/app/domains/pos/models/pos.io.ts @@ -5,16 +5,10 @@ export interface IPosInfoRawResponse { complex: { id: string; name: string; - tax_id: string; - }; - businessActivity: { - id: string; - name: string; - }; - guild: { - id: string; - name: string; + branch_code: string; }; + businessActivity: ISummary; + guild: ISummary; } export interface IPosInfoResponse extends IPosInfoRawResponse {} diff --git a/src/app/domains/superAdmin/modules/consumers/components/complexes/form.component.html b/src/app/domains/superAdmin/modules/consumers/components/complexes/form.component.html index 394ad56..248f2ba 100644 --- a/src/app/domains/superAdmin/modules/consumers/components/complexes/form.component.html +++ b/src/app/domains/superAdmin/modules/consumers/components/complexes/form.component.html @@ -8,7 +8,7 @@ >
- + diff --git a/src/app/domains/superAdmin/modules/consumers/components/complexes/form.component.ts b/src/app/domains/superAdmin/modules/consumers/components/complexes/form.component.ts index fa20e61..f6e8c72 100644 --- a/src/app/domains/superAdmin/modules/consumers/components/complexes/form.component.ts +++ b/src/app/domains/superAdmin/modules/consumers/components/complexes/form.component.ts @@ -26,7 +26,7 @@ export class ConsumerComplexFormComponent extends AbstractFormDialog< initForm = () => { return this.fb.group({ name: [this.initialValues?.name || '', [Validators.required]], - tax_id: [this.initialValues?.tax_id || '', [Validators.required]], + branch_code: [this.initialValues?.branch_code || ''], address: [this.initialValues?.address || '', [Validators.required]], }); }; @@ -34,7 +34,7 @@ export class ConsumerComplexFormComponent extends AbstractFormDialog< form = this.initForm(); get preparedTitle() { - return `${this.editMode ? 'ویرایش' : 'ایجاد'} فروشگاه`; + return `${this.editMode ? 'ویرایش' : 'ایجاد'} شعبه`; } override ngOnChanges(): void { diff --git a/src/app/domains/superAdmin/modules/consumers/components/complexes/list.component.html b/src/app/domains/superAdmin/modules/consumers/components/complexes/list.component.html index b1a1dfa..43caa30 100644 --- a/src/app/domains/superAdmin/modules/consumers/components/complexes/list.component.html +++ b/src/app/domains/superAdmin/modules/consumers/components/complexes/list.component.html @@ -1,10 +1,10 @@ m.SuperAdminUserComplexesComponent, ), meta: { - title: 'فروشگاه‌ها', + title: 'شعب', pagePath: (consumerId: string, businessId: string) => baseUrl(consumerId, businessId), }, }, @@ -26,7 +26,7 @@ export const superAdminConsumerComplexesNamedRoutes: NamedRoutes m.SuperAdminUserComplexComponent, ), meta: { - title: 'فروشگاه', + title: 'شعبه', pagePath: (consumerId: string, businessId: string, complexId: string) => `${baseUrl(consumerId, businessId)}/${complexId}`, }, diff --git a/src/app/domains/superAdmin/modules/consumers/models/complexes_io.d.ts b/src/app/domains/superAdmin/modules/consumers/models/complexes_io.d.ts index ba9ebe0..8ea2421 100644 --- a/src/app/domains/superAdmin/modules/consumers/models/complexes_io.d.ts +++ b/src/app/domains/superAdmin/modules/consumers/models/complexes_io.d.ts @@ -1,7 +1,7 @@ export interface IComplexRawResponse { name: string; address: string; - tax_id: string; + branch_code: string; id: string; } export interface IComplexResponse extends IComplexRawResponse {} @@ -9,5 +9,5 @@ export interface IComplexResponse extends IComplexRawResponse {} export interface IComplexRequest { name: string; address: string; - tax_id: string; + branch_code: string; } diff --git a/src/app/domains/superAdmin/modules/consumers/views/complexes/single.component.html b/src/app/domains/superAdmin/modules/consumers/views/complexes/single.component.html index c3c9790..01192fb 100644 --- a/src/app/domains/superAdmin/modules/consumers/views/complexes/single.component.html +++ b/src/app/domains/superAdmin/modules/consumers/views/complexes/single.component.html @@ -1,9 +1,8 @@
- +
-
diff --git a/src/app/domains/superAdmin/modules/consumers/views/single.component.html b/src/app/domains/superAdmin/modules/consumers/views/single.component.html index d9793dc..6f77378 100644 --- a/src/app/domains/superAdmin/modules/consumers/views/single.component.html +++ b/src/app/domains/superAdmin/modules/consumers/views/single.component.html @@ -19,7 +19,7 @@ تا تاریخ - + } @else { ارایه نشده diff --git a/src/app/domains/superAdmin/modules/partners/components/chargeAccount/charge-account-form-dialog.component.html b/src/app/domains/superAdmin/modules/partners/components/chargeAccount/charge-account-form-dialog.component.html new file mode 100644 index 0000000..b08ad5d --- /dev/null +++ b/src/app/domains/superAdmin/modules/partners/components/chargeAccount/charge-account-form-dialog.component.html @@ -0,0 +1,19 @@ + +
+ + + + +
diff --git a/src/app/domains/superAdmin/modules/partners/components/chargeAccount/charge-account-form-dialog.component.ts b/src/app/domains/superAdmin/modules/partners/components/chargeAccount/charge-account-form-dialog.component.ts new file mode 100644 index 0000000..0df0b11 --- /dev/null +++ b/src/app/domains/superAdmin/modules/partners/components/chargeAccount/charge-account-form-dialog.component.ts @@ -0,0 +1,41 @@ +import { AbstractFormDialog } from '@/shared/abstractClasses'; +import { InputComponent } from '@/shared/components'; +import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; +import { UikitFlatpickrJalaliComponent } from '@/uikit'; +import { nowJalali } from '@/utils'; +import { Component, inject, Input } from '@angular/core'; +import { ReactiveFormsModule, Validators } from '@angular/forms'; +import { Dialog } from 'primeng/dialog'; +import { IPartnerChargeAccountRequest } from '../../models/chargeAccount_io'; +import { AdminPartnerChargeAccountService } from '../../services/chargeAccount.service'; + +@Component({ + selector: 'partner-charge-account-form-dialog', + templateUrl: './charge-account-form-dialog.component.html', + imports: [ + Dialog, + ReactiveFormsModule, + InputComponent, + FormFooterActionsComponent, + UikitFlatpickrJalaliComponent, + ], +}) +export class PartnerChargeAccountFormDialogComponent extends AbstractFormDialog< + IPartnerChargeAccountRequest, + any +> { + @Input({ required: true }) partnerId!: string; + + private readonly service = inject(AdminPartnerChargeAccountService); + + form = this.fb.group({ + quantity: [0, [Validators.required, Validators.min(1)]], + activated_expires_at: ['', [Validators.required]], + }); + + minDate = nowJalali(); + + submitForm(payload: IPartnerChargeAccountRequest) { + return this.service.charge(this.partnerId, payload); + } +} diff --git a/src/app/domains/superAdmin/modules/partners/components/chargeAccount/list.component.html b/src/app/domains/superAdmin/modules/partners/components/chargeAccount/list.component.html new file mode 100644 index 0000000..c56f20a --- /dev/null +++ b/src/app/domains/superAdmin/modules/partners/components/chargeAccount/list.component.html @@ -0,0 +1,8 @@ + + diff --git a/src/app/domains/superAdmin/modules/partners/components/chargeAccount/list.component.ts b/src/app/domains/superAdmin/modules/partners/components/chargeAccount/list.component.ts new file mode 100644 index 0000000..ec47171 --- /dev/null +++ b/src/app/domains/superAdmin/modules/partners/components/chargeAccount/list.component.ts @@ -0,0 +1,45 @@ +import { AbstractList } from '@/shared/abstractClasses/abstract-list'; +import { PageDataListComponent } from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, inject, Input } from '@angular/core'; +import { IPartnerChargeAccountRawResponse } from '../../models'; +import { AdminPartnerChargeAccountService } from '../../services/chargeAccount.service'; + +@Component({ + selector: 'admin-partner-chargeAccount-list', + templateUrl: './list.component.html', + imports: [PageDataListComponent], +}) +export class AdminPartnerChargeAccountListComponent extends AbstractList { + @Input({ required: true }) partnerId!: string; + + private readonly service = inject(AdminPartnerChargeAccountService); + + override setColumns(): void { + this.columns = [ + { field: 'tracking_code', header: 'کد پیگیری' }, + { field: 'charged_license_count', header: 'تعداد شارژ کاربر' }, + { field: 'remained_license_count', header: 'شارژ باقی مانده' }, + { + field: 'activation_count', + header: 'مقدار مصرف شده', + }, + { + field: 'activation_expires_at', + header: 'تاریخ انقضا', + type: 'date', + dateOption: { + expiredMode: true, + }, + }, + { + field: 'created_at', + header: 'تاریخ ایجاد', + type: 'date', + }, + ]; + } + + override getDataRequest() { + return this.service.getAll(this.partnerId); + } +} diff --git a/src/app/domains/superAdmin/modules/partners/components/chargeLicenseTransactions/list.component.ts b/src/app/domains/superAdmin/modules/partners/components/chargeLicenseTransactions/list.component.ts index 082f299..e5977d6 100644 --- a/src/app/domains/superAdmin/modules/partners/components/chargeLicenseTransactions/list.component.ts +++ b/src/app/domains/superAdmin/modules/partners/components/chargeLicenseTransactions/list.component.ts @@ -21,7 +21,7 @@ export class AdminPartnerChargeLicenseTransactionListComponent extends AbstractL { field: 'charged_license_count', header: 'لایسنس‌های خریداری شده' }, { field: 'remained_license_count', header: 'لایسنس‌های باقی‌مانده' }, { - field: 'activated_license_count', + field: 'activation_count', header: 'لایسنس‌های فروخته شده', }, { diff --git a/src/app/domains/superAdmin/modules/partners/components/licenses/list.component.ts b/src/app/domains/superAdmin/modules/partners/components/licenses/list.component.ts index 2a20d39..2d85202 100644 --- a/src/app/domains/superAdmin/modules/partners/components/licenses/list.component.ts +++ b/src/app/domains/superAdmin/modules/partners/components/licenses/list.component.ts @@ -21,8 +21,8 @@ export class AdminPartnerLicensesComponent extends AbstractList + `/api/v1/admin/partners/${partnerId}/charge-account-transactions`; + +export const PARTNER_CHARGE_ACCOUNT_API_ROUTES = { + single: (partnerId: string) => `${baseUrl(partnerId)}`, +}; diff --git a/src/app/domains/superAdmin/modules/partners/constants/apiRoutes/index.ts b/src/app/domains/superAdmin/modules/partners/constants/apiRoutes/index.ts index 9afbefd..037b8dc 100644 --- a/src/app/domains/superAdmin/modules/partners/constants/apiRoutes/index.ts +++ b/src/app/domains/superAdmin/modules/partners/constants/apiRoutes/index.ts @@ -1,5 +1,6 @@ export * from './accounts'; export * from './activatedLicenses'; +export * from './chargeAccount'; export * from './chargeLicenseTransactions'; const baseUrl = '/api/v1/admin/partners'; @@ -7,5 +8,6 @@ const baseUrl = '/api/v1/admin/partners'; export const PARTNERS_API_ROUTES = { list: () => `${baseUrl}`, single: (id: string) => `${baseUrl}/${id}`, + accountCharge: (id: string) => `${baseUrl}/${id}/charge-account-transactions`, licenseCharge: (id: string) => `${baseUrl}/${id}/charge-license`, }; diff --git a/src/app/domains/superAdmin/modules/partners/models/activatedLicenses_io.d.ts b/src/app/domains/superAdmin/modules/partners/models/activatedLicenses_io.d.ts index 0a2e23a..c1995d0 100644 --- a/src/app/domains/superAdmin/modules/partners/models/activatedLicenses_io.d.ts +++ b/src/app/domains/superAdmin/modules/partners/models/activatedLicenses_io.d.ts @@ -1,11 +1,19 @@ +import ISummary from '@/core/models/summary'; + export interface IPartnerActivatedLicenseRawResponse { id: string; starts_at: string; expires_at: string; - consumer: { - first_name: string; - last_name: string; - mobile_number: string; - }; + business_activity: BusinessActivity; } export interface IPartnerActivatedLicenseResponse extends IPartnerActivatedLicenseRawResponse {} + +interface BusinessActivity extends ISummary { + consumer: Consumer; +} + +interface Consumer { + id: string; + first_name: string; + last_name: string; +} diff --git a/src/app/domains/superAdmin/modules/partners/models/chargeAccount_io.d.ts b/src/app/domains/superAdmin/modules/partners/models/chargeAccount_io.d.ts new file mode 100644 index 0000000..2982f90 --- /dev/null +++ b/src/app/domains/superAdmin/modules/partners/models/chargeAccount_io.d.ts @@ -0,0 +1,16 @@ +export interface IPartnerChargeAccountRawResponse { + id: string; + created_at: string; + tracking_code: string; + activation_expires_at: string; + charged_license_count: number; + activated_license_count: number; + remained_license_count: number; +} + +export interface IPartnerChargeAccountResponse extends IPartnerChargeAccountRawResponse {} + +export interface IPartnerChargeAccountRequest { + quantity: number; + activated_expires_at: string; +} diff --git a/src/app/domains/superAdmin/modules/partners/models/index.ts b/src/app/domains/superAdmin/modules/partners/models/index.ts index 2a352fb..5b5f186 100644 --- a/src/app/domains/superAdmin/modules/partners/models/index.ts +++ b/src/app/domains/superAdmin/modules/partners/models/index.ts @@ -1,4 +1,5 @@ export * from './accounts_io'; export * from './activatedLicenses_io'; +export * from './chargeAccount_io'; export * from './chargeLicenseTransactions_io'; export * from './io'; diff --git a/src/app/domains/superAdmin/modules/partners/models/io.d.ts b/src/app/domains/superAdmin/modules/partners/models/io.d.ts index d62470d..e2b47ea 100644 --- a/src/app/domains/superAdmin/modules/partners/models/io.d.ts +++ b/src/app/domains/superAdmin/modules/partners/models/io.d.ts @@ -9,6 +9,11 @@ export interface IPartnerRawResponse { used: number; expired: number; }; + account_quota_status: { + total: number; + used: number; + expired: number; + }; } export interface IPartnerResponse extends IPartnerRawResponse {} diff --git a/src/app/domains/superAdmin/modules/partners/services/chargeAccount.service.ts b/src/app/domains/superAdmin/modules/partners/services/chargeAccount.service.ts new file mode 100644 index 0000000..6d41840 --- /dev/null +++ b/src/app/domains/superAdmin/modules/partners/services/chargeAccount.service.ts @@ -0,0 +1,30 @@ +import { IPaginatedResponse } from '@/core/models/service.model'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { PARTNER_CHARGE_ACCOUNT_API_ROUTES } from '../constants'; +import { + IPartnerChargeAccountRawResponse, + IPartnerChargeAccountRequest, + IPartnerChargeAccountResponse, +} from '../models'; + +@Injectable({ providedIn: 'root' }) +export class AdminPartnerChargeAccountService { + constructor(private http: HttpClient) {} + + private apiRoutes = PARTNER_CHARGE_ACCOUNT_API_ROUTES; + + getAll(partnerId: string): Observable> { + return this.http.get>( + this.apiRoutes.single(partnerId), + ); + } + + charge( + partnerId: string, + data: IPartnerChargeAccountRequest, + ): Observable { + return this.http.post(this.apiRoutes.single(partnerId), data); + } +} diff --git a/src/app/domains/superAdmin/modules/partners/views/single.component.html b/src/app/domains/superAdmin/modules/partners/views/single.component.html index 97dc7f8..b0b93ea 100644 --- a/src/app/domains/superAdmin/modules/partners/views/single.component.html +++ b/src/app/domains/superAdmin/modules/partners/views/single.component.html @@ -1,12 +1,14 @@
+ شارژ کاربر شارژ لایسنس‌
+ اطلاعات لایسنس‌ها @@ -18,6 +20,18 @@ (partner()?.licenses_status?.expired || 0) " /> + اطلاعات شارژ کاربران + + + +
@@ -30,6 +44,10 @@
+
+ +
+
@@ -48,3 +66,9 @@ [partnerId]="partnerId()" (onSubmit)="getData()" /> + + diff --git a/src/app/domains/superAdmin/modules/partners/views/single.component.ts b/src/app/domains/superAdmin/modules/partners/views/single.component.ts index 6a49f67..cb1fc73 100644 --- a/src/app/domains/superAdmin/modules/partners/views/single.component.ts +++ b/src/app/domains/superAdmin/modules/partners/views/single.component.ts @@ -3,8 +3,11 @@ 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 { Divider } from 'primeng/divider'; import { ConsumerAccountListComponent } from '../components/accounts/list.component'; import { PartnerChargeLicenseFormDialogComponent } from '../components/charge-license-form-dialog.component'; +import { PartnerChargeAccountFormDialogComponent } from '../components/chargeAccount/charge-account-form-dialog.component'; +import { AdminPartnerChargeAccountListComponent } from '../components/chargeAccount/list.component'; import { AdminPartnerChargeLicenseTransactionListComponent } from '../components/chargeLicenseTransactions/list.component'; import { GuildFormComponent } from '../components/form.component'; import { AdminPartnerLicensesComponent } from '../components/licenses/list.component'; @@ -20,9 +23,12 @@ import { PartnerStore } from '../store/partner.store'; GuildFormComponent, ConsumerAccountListComponent, Button, + AdminPartnerChargeAccountListComponent, + PartnerChargeAccountFormDialogComponent, PartnerChargeLicenseFormDialogComponent, AdminPartnerLicensesComponent, AdminPartnerChargeLicenseTransactionListComponent, + Divider, ], }) export class PartnerComponent { @@ -36,6 +42,7 @@ export class PartnerComponent { readonly loading = computed(() => this.store.loading()); readonly partner = computed(() => this.store.entity()); visibleChargeFormDialog = signal(false); + visibleChargeAccountFormDialog = signal(false); constructor() { effect(() => { @@ -64,4 +71,8 @@ export class PartnerComponent { openChargeDialog() { this.visibleChargeFormDialog.set(true); } + + openChargeAccountDialog() { + this.visibleChargeAccountFormDialog.set(true); + } } diff --git a/src/app/modules/pos/views/pos.component.html b/src/app/modules/pos/views/pos.component.html index 472e418..d55d784 100644 --- a/src/app/modules/pos/views/pos.component.html +++ b/src/app/modules/pos/views/pos.component.html @@ -4,7 +4,7 @@
Logo
- {{ info()?.name }} - فروشگاه {{ info()?.inventory?.name }} + {{ info()?.name }} - شعبه {{ info()?.inventory?.name }}