From 28575bd3d1737d35207a99c2a84b41b19c33fd2a Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Tue, 14 Apr 2026 15:56:32 +0330 Subject: [PATCH] create consumer pos list page --- .../consumer/constants/components/index.ts | 3 + .../constants/components/pos/pos.model.ts | 3 + .../consumer/constants/components/pos/pos.ts | 26 +++++++ src/app/domains/consumer/constants/index.ts | 1 + .../consumer/constants/menuItems.const.ts | 5 ++ .../consumer/layouts/layout.component.ts | 2 - .../components/poses/form.component.ts | 13 ++-- .../components/poses/list.component.ts | 16 +--- .../constants/routes/poses.ts | 4 +- .../views/poses/list.component.ts | 4 +- .../views/poses/single.component.ts | 4 +- .../poses/components/form.component.html | 13 ++++ .../poses/components/form.component.ts | 40 ++++++++++ .../poses/components/layout.component.html | 5 ++ .../poses/components/layout.component.ts | 28 +++++++ .../poses/components/list.component.html | 22 ++++++ .../poses/components/list.component.ts | 78 +++++++++++++++++++ .../poses/constants/apiRoutes/index.ts | 6 ++ .../consumer/modules/poses/constants/index.ts | 2 + .../modules/poses/constants/routes/index.ts | 44 +++++++++++ .../consumer/modules/poses/models/index.ts | 1 + .../consumer/modules/poses/models/io.d.ts | 18 +++++ .../modules/poses/services/main.service.ts | 24 ++++++ .../consumer/modules/poses/store/pos.store.ts | 75 ++++++++++++++++++ .../consumer/modules/poses/views/index.ts | 2 + .../modules/poses/views/list.component.html | 1 + .../modules/poses/views/list.component.ts | 10 +++ .../modules/poses/views/single.component.html | 25 ++++++ .../modules/poses/views/single.component.ts | 55 +++++++++++++ src/app/domains/consumer/routes.ts | 2 + .../shared/abstractClasses/abstract-list.ts | 2 - 31 files changed, 502 insertions(+), 32 deletions(-) create mode 100644 src/app/domains/consumer/constants/components/index.ts create mode 100644 src/app/domains/consumer/constants/components/pos/pos.model.ts create mode 100644 src/app/domains/consumer/constants/components/pos/pos.ts create mode 100644 src/app/domains/consumer/modules/poses/components/form.component.html create mode 100644 src/app/domains/consumer/modules/poses/components/form.component.ts create mode 100644 src/app/domains/consumer/modules/poses/components/layout.component.html create mode 100644 src/app/domains/consumer/modules/poses/components/layout.component.ts create mode 100644 src/app/domains/consumer/modules/poses/components/list.component.html create mode 100644 src/app/domains/consumer/modules/poses/components/list.component.ts create mode 100644 src/app/domains/consumer/modules/poses/constants/apiRoutes/index.ts create mode 100644 src/app/domains/consumer/modules/poses/constants/index.ts create mode 100644 src/app/domains/consumer/modules/poses/constants/routes/index.ts create mode 100644 src/app/domains/consumer/modules/poses/models/index.ts create mode 100644 src/app/domains/consumer/modules/poses/models/io.d.ts create mode 100644 src/app/domains/consumer/modules/poses/services/main.service.ts create mode 100644 src/app/domains/consumer/modules/poses/store/pos.store.ts create mode 100644 src/app/domains/consumer/modules/poses/views/index.ts create mode 100644 src/app/domains/consumer/modules/poses/views/list.component.html create mode 100644 src/app/domains/consumer/modules/poses/views/list.component.ts create mode 100644 src/app/domains/consumer/modules/poses/views/single.component.html create mode 100644 src/app/domains/consumer/modules/poses/views/single.component.ts diff --git a/src/app/domains/consumer/constants/components/index.ts b/src/app/domains/consumer/constants/components/index.ts new file mode 100644 index 0000000..4043939 --- /dev/null +++ b/src/app/domains/consumer/constants/components/index.ts @@ -0,0 +1,3 @@ +import * as _pos from './pos/pos'; + +export const pos = _pos; diff --git a/src/app/domains/consumer/constants/components/pos/pos.model.ts b/src/app/domains/consumer/constants/components/pos/pos.model.ts new file mode 100644 index 0000000..61b328a --- /dev/null +++ b/src/app/domains/consumer/constants/components/pos/pos.model.ts @@ -0,0 +1,3 @@ +export interface IPosInitialValues { + name: string; +} diff --git a/src/app/domains/consumer/constants/components/pos/pos.ts b/src/app/domains/consumer/constants/components/pos/pos.ts new file mode 100644 index 0000000..19c8ad1 --- /dev/null +++ b/src/app/domains/consumer/constants/components/pos/pos.ts @@ -0,0 +1,26 @@ +import { IColumn } from '@/shared/components/pageDataList/page-data-list.component'; +import { FormBuilder, Validators } from '@angular/forms'; +import { IPosInitialValues } from './pos.model'; + +export const columns: IColumn[] = [ + // { field: 'id', header: 'شناسه', type: 'id' }, + { field: 'name', header: 'عنوان' }, + { field: 'serial', header: 'شماره سریال' }, + { field: 'pos_type', header: 'نوع دستگاه' }, + { field: 'device', header: 'دستگاه', type: 'nested', nestedPath: 'device.name' }, + { field: 'provider', header: 'ارایه‌دهنده', type: 'nested', nestedPath: 'provider.name' }, + { field: 'status', header: 'وضعیت' }, + { + field: 'created_at', + header: 'تاریخ ایجاد', + type: 'date', + }, +]; + +export const initForm = (fb: FormBuilder, initialValues?: IPosInitialValues) => { + const form = fb.group({ + name: [initialValues?.name || '', [Validators.required]], + }); + + return form; +}; diff --git a/src/app/domains/consumer/constants/index.ts b/src/app/domains/consumer/constants/index.ts index 0c680cb..f941669 100644 --- a/src/app/domains/consumer/constants/index.ts +++ b/src/app/domains/consumer/constants/index.ts @@ -1,2 +1,3 @@ export * from './apiRoutes'; +export * as CONSUMER_COMPONENTS_CONST from './components'; export * from './menuItems.const'; diff --git a/src/app/domains/consumer/constants/menuItems.const.ts b/src/app/domains/consumer/constants/menuItems.const.ts index 044ac6e..2269090 100644 --- a/src/app/domains/consumer/constants/menuItems.const.ts +++ b/src/app/domains/consumer/constants/menuItems.const.ts @@ -12,6 +12,11 @@ export const CONSUMER_MENU_ITEMS = [ icon: 'pi pi-fw pi-home', routerLink: ['/consumer/accounts'], }, + { + label: 'پایانه‌های فروش', + icon: 'pi pi-fw pi-home', + routerLink: ['/consumer/poses'], + }, { label: 'فعالیت‌های اقتصادی', icon: 'pi pi-fw pi-home', diff --git a/src/app/domains/consumer/layouts/layout.component.ts b/src/app/domains/consumer/layouts/layout.component.ts index 6f369d7..5ab9694 100644 --- a/src/app/domains/consumer/layouts/layout.component.ts +++ b/src/app/domains/consumer/layouts/layout.component.ts @@ -31,8 +31,6 @@ export class LayoutComponent { }); ngOnInit() { - console.log('first'); - this.layoutService.setMenuItems(CONSUMER_MENU_ITEMS); this.store.getData(); } diff --git a/src/app/domains/consumer/modules/businessActivities/components/poses/form.component.ts b/src/app/domains/consumer/modules/businessActivities/components/poses/form.component.ts index 2e01c33..d882069 100644 --- a/src/app/domains/consumer/modules/businessActivities/components/poses/form.component.ts +++ b/src/app/domains/consumer/modules/businessActivities/components/poses/form.component.ts @@ -1,9 +1,10 @@ // import { CatalogRolesComponent } from '@/shared/catalog/roles'; +import { CONSUMER_COMPONENTS_CONST } from '@/domains/consumer/constants'; 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 { ReactiveFormsModule } from '@angular/forms'; import { Dialog } from 'primeng/dialog'; import { IPosRequest, IPosResponse } from '../../models'; import { ConsumerPosesService } from '../../services/poses.service'; @@ -20,13 +21,9 @@ export class ConsumerPosFormComponent extends AbstractFormDialog { - const form = this.fb.group({ - name: [this.initialValues?.name || '', [Validators.required]], - }); - - return form; - }; + initForm() { + return CONSUMER_COMPONENTS_CONST.pos.initForm(this.fb, this.initialValues); + } form = this.initForm(); diff --git a/src/app/domains/consumer/modules/businessActivities/components/poses/list.component.ts b/src/app/domains/consumer/modules/businessActivities/components/poses/list.component.ts index f3df9d6..15fb69b 100644 --- a/src/app/domains/consumer/modules/businessActivities/components/poses/list.component.ts +++ b/src/app/domains/consumer/modules/businessActivities/components/poses/list.component.ts @@ -1,4 +1,5 @@ // import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { CONSUMER_COMPONENTS_CONST } from '@/domains/consumer/constants'; import { AbstractList } from '@/shared/abstractClasses/abstract-list'; import { IColumn, @@ -20,20 +21,7 @@ export class ConsumerPosesComponent extends AbstractList { @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', - }, - ]; + @Input() header: IColumn[] = CONSUMER_COMPONENTS_CONST.pos.columns; private readonly service = inject(ConsumerPosesService); private readonly router = inject(Router); diff --git a/src/app/domains/consumer/modules/businessActivities/constants/routes/poses.ts b/src/app/domains/consumer/modules/businessActivities/constants/routes/poses.ts index 62dc66a..ef7b1d2 100644 --- a/src/app/domains/consumer/modules/businessActivities/constants/routes/poses.ts +++ b/src/app/domains/consumer/modules/businessActivities/constants/routes/poses.ts @@ -10,7 +10,7 @@ export const consumerPosesNamedRoutes: NamedRoutes = { poses: { path: 'poses', loadComponent: () => - import('../../views/poses/list.component').then((m) => m.SuperAdminUserPosesComponent), + import('../../views/poses/list.component').then((m) => m.ConsumerPosListPageComponent), // @ts-ignore meta: { title: 'پایانه‌های فروش', @@ -20,7 +20,7 @@ export const consumerPosesNamedRoutes: NamedRoutes = { pos: { path: 'poses/:posId', loadComponent: () => - import('../../views/poses/single.component').then((m) => m.SuperAdminUserPosComponent), + import('../../views/poses/single.component').then((m) => m.ConsumerComplexPosPageComponent), // @ts-ignore meta: { title: 'پایانه‌ی فروش', diff --git a/src/app/domains/consumer/modules/businessActivities/views/poses/list.component.ts b/src/app/domains/consumer/modules/businessActivities/views/poses/list.component.ts index 2007634..5be7b5f 100644 --- a/src/app/domains/consumer/modules/businessActivities/views/poses/list.component.ts +++ b/src/app/domains/consumer/modules/businessActivities/views/poses/list.component.ts @@ -9,11 +9,11 @@ import { BusinessActivityStore } from '../../store/businessActivity.store'; import { ConsumerComplexStore } from '../../store/complex.store'; @Component({ - selector: 'superAdmin-user-poses', + selector: 'consumer-complex-pos-list-page', templateUrl: './list.component.html', imports: [ConsumerPosesComponent], }) -export class SuperAdminUserPosesComponent { +export class ConsumerPosListPageComponent { private readonly route = inject(ActivatedRoute); private readonly breadcrumbService = inject(BreadcrumbService); private readonly businessStore = inject(BusinessActivityStore); diff --git a/src/app/domains/consumer/modules/businessActivities/views/poses/single.component.ts b/src/app/domains/consumer/modules/businessActivities/views/poses/single.component.ts index 62fcd64..e159060 100644 --- a/src/app/domains/consumer/modules/businessActivities/views/poses/single.component.ts +++ b/src/app/domains/consumer/modules/businessActivities/views/poses/single.component.ts @@ -13,7 +13,7 @@ import { ConsumerComplexStore } from '../../store/complex.store'; import { PosStore } from '../../store/pos.store'; @Component({ - selector: 'superAdmin-user-pos', + selector: 'consumer--complex-pos-page', templateUrl: './single.component.html', imports: [ AppCardComponent, @@ -23,7 +23,7 @@ import { PosStore } from '../../store/pos.store'; ConsumerSalesInvoicesComponent, ], }) -export class SuperAdminUserPosComponent { +export class ConsumerComplexPosPageComponent { private readonly businessStore = inject(BusinessActivityStore); private readonly complexStore = inject(ConsumerComplexStore); private readonly store = inject(PosStore); diff --git a/src/app/domains/consumer/modules/poses/components/form.component.html b/src/app/domains/consumer/modules/poses/components/form.component.html new file mode 100644 index 0000000..c4d25d4 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/components/form.component.html @@ -0,0 +1,13 @@ + +
+ + + +
diff --git a/src/app/domains/consumer/modules/poses/components/form.component.ts b/src/app/domains/consumer/modules/poses/components/form.component.ts new file mode 100644 index 0000000..183cc42 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/components/form.component.ts @@ -0,0 +1,40 @@ +// import { CatalogRolesComponent } from '@/shared/catalog/roles'; +import { CONSUMER_COMPONENTS_CONST } from '@/domains/consumer/constants'; +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 } from '@angular/forms'; +import { Dialog } from 'primeng/dialog'; +import { IPosRequest, IPosResponse } from '../models'; +import { ConsumerPosesService } from '../services/main.service'; + +@Component({ + selector: 'consumer-pos-form', + templateUrl: './form.component.html', + imports: [ReactiveFormsModule, Dialog, InputComponent, FormFooterActionsComponent], +}) +export class ConsumerPosFormComponent extends AbstractFormDialog { + private readonly service = inject(ConsumerPosesService); + + @Input({ required: true }) posId!: string; + + initForm() { + return CONSUMER_COMPONENTS_CONST.pos.initForm(this.fb, this.initialValues); + } + + form = this.initForm(); + + get preparedTitle() { + return `ویرایش پایانه فروش ${this.initialValues?.name}`; + } + + override ngOnChanges(): void { + this.form = this.initForm(); + } + + submitForm() { + const formValue = this.form.value as IPosRequest; + return this.service.update(this.posId, formValue); + } +} diff --git a/src/app/domains/consumer/modules/poses/components/layout.component.html b/src/app/domains/consumer/modules/poses/components/layout.component.html new file mode 100644 index 0000000..5416fe1 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/components/layout.component.html @@ -0,0 +1,5 @@ +@if (loading()) { + +} @else { + +} diff --git a/src/app/domains/consumer/modules/poses/components/layout.component.ts b/src/app/domains/consumer/modules/poses/components/layout.component.ts new file mode 100644 index 0000000..0e2a3ac --- /dev/null +++ b/src/app/domains/consumer/modules/poses/components/layout.component.ts @@ -0,0 +1,28 @@ +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 { ConsumerPosStore } from '../store/pos.store'; + +@Component({ + selector: 'consumer-pos-layout', + templateUrl: './layout.component.html', + imports: [PageLoadingComponent, RouterOutlet], +}) +export class ConsumerPosLayoutComponent { + private readonly store = inject(ConsumerPosStore); + private readonly route = inject(ActivatedRoute); + + readonly loading = computed(() => this.store.loading()); + readonly pageParams = computed(() => pageParamsUtils(this.route)); + + readonly posId = computed(() => this.pageParams()['posId']!); + + getData() { + this.store.getData(this.posId()); + } + + ngOnInit() { + this.getData(); + } +} diff --git a/src/app/domains/consumer/modules/poses/components/list.component.html b/src/app/domains/consumer/modules/poses/components/list.component.html new file mode 100644 index 0000000..cb921f8 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/components/list.component.html @@ -0,0 +1,22 @@ + + + ورود به پایانه + + + diff --git a/src/app/domains/consumer/modules/poses/components/list.component.ts b/src/app/domains/consumer/modules/poses/components/list.component.ts new file mode 100644 index 0000000..12e5343 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/components/list.component.ts @@ -0,0 +1,78 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { CONSUMER_COMPONENTS_CONST } from '@/domains/consumer/constants'; +import { AbstractList } from '@/shared/abstractClasses/abstract-list'; +import { + IColumn, + PageDataListComponent, +} from '@/shared/components/pageDataList/page-data-list.component'; +import { Component, inject, Input, TemplateRef, ViewChild } from '@angular/core'; +import { Router } from '@angular/router'; +import { CookieService } from 'ngx-cookie-service'; +import { Button } from 'primeng/button'; +import { COOKIE_KEYS } from 'src/assets/constants'; +import { ConsumerPosesNamedRoutes } from '../constants'; +import { IPosResponse } from '../models'; +import { ConsumerPosesService } from '../services/main.service'; +import { ConsumerPosFormComponent } from './form.component'; + +@Component({ + selector: 'consumer-pos-list', + templateUrl: './list.component.html', + imports: [PageDataListComponent, ConsumerPosFormComponent, Button], +}) +export class ConsumerPosListComponent extends AbstractList { + @Input() fullHeight?: boolean; + @Input() header: IColumn[] = CONSUMER_COMPONENTS_CONST.pos.columns; + + private readonly service = inject(ConsumerPosesService); + private readonly cookieService = inject(CookieService); + private readonly router = inject(Router); + + @ViewChild('toPosLandingAction', { static: true }) toPosLandingAction!: TemplateRef; + + override setColumns(): void { + this.columns = [ + ...this.header.filter((header) => + ['name', 'status', 'pos_type'].includes(header.field as string), + ), + { + field: 'complex.business_activity', + header: 'عنوان کسب و کار', + type: 'nested', + nestedPath: 'complex.business_activity.name', + }, + { + field: 'complex', + header: 'عنوان فروشگاه', + type: 'nested', + nestedPath: 'complex.name', + }, + { + field: 'customAction', + header: '', + width: '128px', + minWidth: '128px', + customDataModel: this.toPosLandingAction, + }, + ]; + } + + override getDataRequest() { + return this.service.getAll(); + } + + toSinglePage(item: IPosResponse) { + this.router.navigateByUrl(ConsumerPosesNamedRoutes.pos.meta.pagePath!(item.id)); + } + + toPosLanding(posId: string) { + this.cookieService.set(COOKIE_KEYS.POS_ID, '', new Date()); + this.cookieService.set(COOKIE_KEYS.POS_ID, posId, { + sameSite: 'Lax', // or 'Strict' for same-site requests only + secure: false, + path: '/', + domain: 'localhost', + }); + window.open('/pos', '_blank'); + } +} diff --git a/src/app/domains/consumer/modules/poses/constants/apiRoutes/index.ts b/src/app/domains/consumer/modules/poses/constants/apiRoutes/index.ts new file mode 100644 index 0000000..df85520 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/constants/apiRoutes/index.ts @@ -0,0 +1,6 @@ +const baseUrl = () => `/api/v1/consumer/poses`; + +export const CONSUMER_POSES_API_ROUTES = { + list: () => `${baseUrl()}`, + single: (posId: string) => `${baseUrl()}/${posId}`, +}; diff --git a/src/app/domains/consumer/modules/poses/constants/index.ts b/src/app/domains/consumer/modules/poses/constants/index.ts new file mode 100644 index 0000000..ee61bd7 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/constants/index.ts @@ -0,0 +1,2 @@ +export * from './apiRoutes'; +export * from './routes'; diff --git a/src/app/domains/consumer/modules/poses/constants/routes/index.ts b/src/app/domains/consumer/modules/poses/constants/routes/index.ts new file mode 100644 index 0000000..d2dbc43 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/constants/routes/index.ts @@ -0,0 +1,44 @@ +import { NamedRoutes } from '@/core'; +import { Routes } from '@angular/router'; + +export type TPosesRouteNames = 'poses' | 'pos'; + +const baseUrl = `/consumer/poses`; + +export const ConsumerPosesNamedRoutes: NamedRoutes = { + poses: { + path: 'poses', + loadComponent: () => + import('../../views/list.component').then((m) => m.ConsumerPosListPageComponent), + // @ts-ignore + meta: { + title: 'پایانه‌های فروش', + pagePath: () => baseUrl, + }, + }, + pos: { + path: 'poses/:posId', + loadComponent: () => + import('../../views/single.component').then((m) => m.ConsumerPosPageComponent), + // @ts-ignore + meta: { + title: 'پایانه‌ی فروش', + pagePath: (posId: string) => `${baseUrl}/${posId}`, + }, + }, +}; + +export const CONSUMER_POSES_ROUTES: Routes = [ + ConsumerPosesNamedRoutes.poses, + { + path: ConsumerPosesNamedRoutes.pos.path, + loadComponent: () => + import('../../components/layout.component').then((m) => m.ConsumerPosLayoutComponent), + children: [ + { + path: '', + loadComponent: ConsumerPosesNamedRoutes.pos.loadComponent, + }, + ], + }, +]; diff --git a/src/app/domains/consumer/modules/poses/models/index.ts b/src/app/domains/consumer/modules/poses/models/index.ts new file mode 100644 index 0000000..61a518a --- /dev/null +++ b/src/app/domains/consumer/modules/poses/models/index.ts @@ -0,0 +1 @@ +export * from './io'; diff --git a/src/app/domains/consumer/modules/poses/models/io.d.ts b/src/app/domains/consumer/modules/poses/models/io.d.ts new file mode 100644 index 0000000..17d9029 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/models/io.d.ts @@ -0,0 +1,18 @@ +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; +} diff --git a/src/app/domains/consumer/modules/poses/services/main.service.ts b/src/app/domains/consumer/modules/poses/services/main.service.ts new file mode 100644 index 0000000..5ca8476 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/services/main.service.ts @@ -0,0 +1,24 @@ +import { IPaginatedResponse } from '@/core/models/service.model'; +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { CONSUMER_POSES_API_ROUTES } from '../constants'; +import { IPosRawResponse, IPosRequest, IPosResponse } from '../models'; + +@Injectable({ providedIn: 'root' }) +export class ConsumerPosesService { + constructor(private http: HttpClient) {} + + private apiRoutes = CONSUMER_POSES_API_ROUTES; + + getAll(): Observable> { + return this.http.get>(this.apiRoutes.list()); + } + getSingle(posId: string): Observable { + return this.http.get(this.apiRoutes.single(posId)); + } + + update(posId: string, data: IPosRequest): Observable { + return this.http.patch(this.apiRoutes.single(posId), data); + } +} diff --git a/src/app/domains/consumer/modules/poses/store/pos.store.ts b/src/app/domains/consumer/modules/poses/store/pos.store.ts new file mode 100644 index 0000000..50a3efb --- /dev/null +++ b/src/app/domains/consumer/modules/poses/store/pos.store.ts @@ -0,0 +1,75 @@ +import { EntityState, EntityStore } from '@/core/state'; +import { computed, inject, Injectable } from '@angular/core'; +import { MenuItem } from 'primeng/api'; +import { catchError, finalize } from 'rxjs'; +import { consumerPosesNamedRoutes } from '../../businessActivities/constants/routes/poses'; +import { IPosResponse } from '../models'; +import { ConsumerPosesService } from '../services/main.service'; + +interface ConsumerPosState extends EntityState { + breadcrumbItems: MenuItem[]; +} + +@Injectable({ + providedIn: 'root', +}) +export class ConsumerPosStore extends EntityStore { + private readonly service = inject(ConsumerPosesService); + constructor() { + super({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + breadcrumbItems: [], + }); + } + + breadcrumbItems = computed(() => this._state().breadcrumbItems); + + private setBreadcrumb(posId: string) { + this.patchState({ + breadcrumbItems: [ + { + ...consumerPosesNamedRoutes.poses.meta, + routerLink: consumerPosesNamedRoutes.poses.meta.pagePath!(), + }, + { + title: this.entity()?.name, + routerLink: consumerPosesNamedRoutes.pos.meta.pagePath!(posId), + }, + ], + }); + } + + getData(posId: string) { + this.patchState({ loading: true }); + this.service + .getSingle(posId) + .pipe( + finalize(() => { + this.patchState({ loading: false }); + }), + catchError((error) => { + this.setError(error); + throw error; + }), + ) + .subscribe((entity) => { + this.setEntity(entity); + this.setBreadcrumb(posId); + }); + } + + override reset(): void { + this.setState({ + loading: false, + error: null, + entity: null, + initialized: false, + isRefreshing: false, + breadcrumbItems: [], + }); + } +} diff --git a/src/app/domains/consumer/modules/poses/views/index.ts b/src/app/domains/consumer/modules/poses/views/index.ts new file mode 100644 index 0000000..bc9dfc9 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/views/index.ts @@ -0,0 +1,2 @@ +export * from './list.component'; +export * from './single.component'; diff --git a/src/app/domains/consumer/modules/poses/views/list.component.html b/src/app/domains/consumer/modules/poses/views/list.component.html new file mode 100644 index 0000000..59f0382 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/views/list.component.html @@ -0,0 +1 @@ + diff --git a/src/app/domains/consumer/modules/poses/views/list.component.ts b/src/app/domains/consumer/modules/poses/views/list.component.ts new file mode 100644 index 0000000..ef944a7 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/views/list.component.ts @@ -0,0 +1,10 @@ +// import { CatalogRoleTagComponent } from '@/shared/catalog/roles'; +import { Component } from '@angular/core'; +import { ConsumerPosListComponent } from '../components/list.component'; + +@Component({ + selector: 'consumer-poses', + templateUrl: './list.component.html', + imports: [ConsumerPosListComponent], +}) +export class ConsumerPosListPageComponent {} diff --git a/src/app/domains/consumer/modules/poses/views/single.component.html b/src/app/domains/consumer/modules/poses/views/single.component.html new file mode 100644 index 0000000..1687a64 --- /dev/null +++ b/src/app/domains/consumer/modules/poses/views/single.component.html @@ -0,0 +1,25 @@ +
+ + + ورود به پایانه + +
+
+ + + + + + +
+
+
+ + +
diff --git a/src/app/domains/consumer/modules/poses/views/single.component.ts b/src/app/domains/consumer/modules/poses/views/single.component.ts new file mode 100644 index 0000000..ea9eb9c --- /dev/null +++ b/src/app/domains/consumer/modules/poses/views/single.component.ts @@ -0,0 +1,55 @@ +import { BreadcrumbService } from '@/core/services'; +import { AppCardComponent, KeyValueComponent } from '@/shared/components'; +import { Component, computed, effect, inject, signal } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { CookieService } from 'ngx-cookie-service'; +import { Button } from 'primeng/button'; +import { COOKIE_KEYS } from 'src/assets/constants'; +import { ConsumerPosFormComponent } from '../components/form.component'; +import { ConsumerPosStore } from '../store/pos.store'; + +@Component({ + selector: 'consumer-pos-page', + templateUrl: './single.component.html', + imports: [AppCardComponent, KeyValueComponent, Button, ConsumerPosFormComponent], +}) +export class ConsumerPosPageComponent { + private readonly store = inject(ConsumerPosStore); + private readonly route = inject(ActivatedRoute); + private readonly breadcrumbService = inject(BreadcrumbService); + private readonly cookieService = inject(CookieService); + + readonly posId = signal(this.route.snapshot.paramMap.get('posId')!); + editMode = signal(false); + + readonly loading = computed(() => this.store.loading()); + readonly pos = computed(() => this.store.entity()); + readonly posBreadcrumb = computed(() => this.store.breadcrumbItems()); + + constructor() { + effect(() => { + if (this.pos()?.id) { + this.setBreadcrumb(); + } + }); + } + + getData() { + this.store.getData(this.posId()); + } + + setBreadcrumb() { + this.breadcrumbService.setItems(this.posBreadcrumb()); + } + + toPosLanding() { + this.cookieService.set(COOKIE_KEYS.POS_ID, '', new Date()); + this.cookieService.set(COOKIE_KEYS.POS_ID, this.posId(), { + sameSite: 'Lax', // or 'Strict' for same-site requests only + secure: false, + path: '/', + domain: 'localhost', + }); + window.open('/pos', '_blank'); + } +} diff --git a/src/app/domains/consumer/routes.ts b/src/app/domains/consumer/routes.ts index 22496aa..8fd52a3 100644 --- a/src/app/domains/consumer/routes.ts +++ b/src/app/domains/consumer/routes.ts @@ -2,6 +2,7 @@ import { Route } from '@angular/router'; import { CONSUMER_ACCOUNTS_ROUTES } from './modules/accounts/constants'; import { CONSUMER_BUSINESS_ACTIVITIES_ROUTES } from './modules/businessActivities/constants'; import { CONSUMER_CUSTOMERS_ROUTES } from './modules/customers/constants'; +import { CONSUMER_POSES_ROUTES } from './modules/poses/constants'; import { CONSUMER_SALE_INVOICES_ROUTES } from './modules/saleInvoices/constants'; export const CONSUMER_ROUTES = { @@ -17,5 +18,6 @@ export const CONSUMER_ROUTES = { ...CONSUMER_BUSINESS_ACTIVITIES_ROUTES, ...CONSUMER_CUSTOMERS_ROUTES, ...CONSUMER_SALE_INVOICES_ROUTES, + ...CONSUMER_POSES_ROUTES, ], } as Route; diff --git a/src/app/shared/abstractClasses/abstract-list.ts b/src/app/shared/abstractClasses/abstract-list.ts index e075669..5abd1d7 100644 --- a/src/app/shared/abstractClasses/abstract-list.ts +++ b/src/app/shared/abstractClasses/abstract-list.ts @@ -32,8 +32,6 @@ export abstract class AbstractList { this.getDataRequest(this.requestPayload()) ?.pipe( finalize(() => { - console.log('first'); - this.loading.set(false); }), catchError((error) => {