feat: refactor dialog components to use light-bottomsheet for improved UX
- Replaced SharedDialogComponent with SharedLightBottomsheetComponent in customer-dialog, order-submitted-dialog, payment form-dialog, and pre-invoice-dialog components. - Updated styles and properties for light-bottomsheet to enhance responsiveness and usability. - Modified payload form components to use measure units instead of unit types for better clarity. - Adjusted form controls to use consistent naming conventions for amounts and percentages. - Enhanced support for overlay options in select components to manage z-index dynamically. - Improved support for RTL layouts in input groups and other components.
This commit is contained in:
+3
-3
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
|
||||
"appData": {
|
||||
"appVersion": "0.0.9",
|
||||
"buildDate": "2026-05-13T06:42:17.700Z",
|
||||
"buildNumber": 9
|
||||
"appVersion": "0.0.10",
|
||||
"buildDate": "2026-05-13T09:21:01.165Z",
|
||||
"buildNumber": 10
|
||||
},
|
||||
"assetGroups": [
|
||||
{
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { TCustomerInfo, TPosOrderGoodPayload } from '@/domains/pos/modules/landing/models';
|
||||
import { UnitType } from '@/utils';
|
||||
|
||||
export interface ISalesInvoicesRawResponse {
|
||||
id: string;
|
||||
@@ -29,7 +28,7 @@ interface Payment {
|
||||
}
|
||||
|
||||
interface Item {
|
||||
unit_type: UnitType;
|
||||
measure_unit: ISummary;
|
||||
discount: string;
|
||||
quantity: string;
|
||||
total_amount: string;
|
||||
@@ -46,6 +45,6 @@ interface Good {
|
||||
barcode: null;
|
||||
local_sku: null;
|
||||
pricing_model: string;
|
||||
unit_type: string;
|
||||
measure_unit: ISummary;
|
||||
category: ISummary;
|
||||
}
|
||||
|
||||
@@ -31,14 +31,14 @@
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
@if (isPwaBuild) {
|
||||
<div class="mt-auto">
|
||||
<hr class="mb-4 mx-4 border-t border-0 border-surface" />
|
||||
@if (isPwaBuild) {
|
||||
<div class="px-6 pb-6 text-sm text-muted-color">
|
||||
نسخه برنامه : <span class="font-semibold">{{ appVersion }}</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</ng-template>
|
||||
</p-drawer>
|
||||
|
||||
@@ -53,7 +53,7 @@ export class PosMainMenuSidebarComponent extends AbstractDialog {
|
||||
icon: 'pi pi-fw pi-cog',
|
||||
},
|
||||
{
|
||||
label: 'درباره ما',
|
||||
label: 'درباره نرمافزار',
|
||||
routerLink: posAboutNamedRoutes.about.meta.pagePath!(),
|
||||
icon: 'pi pi-fw pi-info-circle',
|
||||
},
|
||||
|
||||
@@ -2,15 +2,7 @@ import { AuthService } from '@/core';
|
||||
import { LayoutService } from '@/layout/service/layout.service';
|
||||
import { PageLoadingComponent } from '@/shared/components/page-loading.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
TemplateRef,
|
||||
ViewChild,
|
||||
computed,
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import { Component, TemplateRef, ViewChild, computed, inject, signal } from '@angular/core';
|
||||
import { RouterLinkWithHref, RouterOutlet } from '@angular/router';
|
||||
import { MenuItem } from 'primeng/api';
|
||||
import { Button, ButtonDirective } from 'primeng/button';
|
||||
@@ -38,7 +30,7 @@ import { PosChooseCardsComponent } from './choose-pos.component';
|
||||
RouterOutlet,
|
||||
],
|
||||
})
|
||||
export class PosPagesLayoutComponent implements AfterViewInit {
|
||||
export class PosPagesLayoutComponent {
|
||||
constructor() {}
|
||||
|
||||
// private readonly nativeBridgeService = inject(NativeBridgeService);
|
||||
@@ -118,9 +110,6 @@ export class PosPagesLayoutComponent implements AfterViewInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.layoutService.changeIsFullPage(true);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.layoutService.setTopbarStartSlot(this.topbarStart);
|
||||
this.layoutService.setTopbarCenterSlot(this.topbarCenter);
|
||||
this.layoutService.setTopbarEndSlot(this.topbarEnd);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { UnitType } from '@/utils';
|
||||
|
||||
export interface IGoodRawResponse {
|
||||
id: string;
|
||||
@@ -10,7 +9,7 @@ export interface IGoodRawResponse {
|
||||
name: string;
|
||||
};
|
||||
category: ISummary;
|
||||
unit_type: UnitType;
|
||||
measure_unit: ISummary;
|
||||
pricing_model: string;
|
||||
description?: string;
|
||||
image_url: string;
|
||||
|
||||
@@ -1,6 +1,55 @@
|
||||
<div class="w-full h-full min-h-[60svh] flex items-center justify-center p-4">
|
||||
<div class="text-center">
|
||||
<h2 class="text-xl font-semibold mb-2">درباره سیستم</h2>
|
||||
<p class="text-muted-color">این صفحه به زودی تکمیل می شود.</p>
|
||||
<div class="w-full min-h-[60svh] p-4 md:p-6">
|
||||
<section class="mx-auto max-w-3xl overflow-hidden rounded-2xl border border-surface-200 bg-white">
|
||||
<div class="bg-gradient-to-l from-emerald-50 via-teal-50 to-cyan-50 p-5 md:p-7">
|
||||
<p class="mb-2 inline-flex items-center rounded-full bg-white px-3 py-1 text-xs font-semibold text-emerald-700">
|
||||
{{ brandingInfo.appTitle }}
|
||||
</p>
|
||||
<span class="block mb-4 text-xl font-bold text-surface-900 md:text-3xl">درباره نسخه تیس</span>
|
||||
<p class="mt-3 max-w-2xl text-sm leading-7 text-surface-700 md:text-base">
|
||||
این نسخه برای استفاده روزانه روی دستگاه های PSP بهینه شده است تا عملیات ثبت و صدور صورتحسابهای مالیاتی با سرعت
|
||||
بالاتر، پایداری بیشتر و تجربه کاربری ساده تر انجام شود.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-3 p-4 md:grid-cols-3 md:gap-4 md:p-6">
|
||||
<!-- <article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
|
||||
<h2 class="mb-2 text-sm font-bold text-surface-900">پایداری در وب ویو</h2>
|
||||
<p class="text-sm leading-6 text-surface-700">
|
||||
رفتار رابط کاربری برای محیط WebView تنظیم شده تا روی سخت افزارهای ضعیف تر هم اجرای روان تری داشته باشد.
|
||||
</p>
|
||||
</article> -->
|
||||
|
||||
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
|
||||
<span class="block mb-4 text-xl font-bold text-surface-900">تمرکز بر سرعت عملیات</span>
|
||||
<p class="text-sm leading-6 text-surface-700">
|
||||
مسیرهای کلیدی مانند انتخاب کالا، ورود مقادیر و ثبت نهایی برای کاهش تاخیر و افزایش سرعت کاربر بهینه شده اند.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
|
||||
<span class="block mb-4 text-xl font-bold text-surface-900">سازگار با سناریوهای فروش</span>
|
||||
<p class="text-sm leading-6 text-surface-700">
|
||||
طراحی این نسخه بر مبنای سناریوهای واقعی فروشگاه انجام شده تا اپراتور با کمترین کلیک فرآیند را تکمیل کند.
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="mx-4 mb-4 rounded-xl border border-surface-200 bg-surface-50 p-4 md:mx-6">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div class="text-sm text-surface-700">
|
||||
نسخه برنامه:
|
||||
<span class="font-semibold text-surface-900">{{ appVersion() }}</span>
|
||||
</div>
|
||||
<button pButton type="button" [outlined]="!hasUpdate()" [disabled]="isCheckingUpdate()" (click)="onUpdateCtaClick()">
|
||||
{{ updateCtaLabel() }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-t border-surface-200 bg-surface-50 px-4 py-4 md:px-6">
|
||||
<p class="text-xs leading-6 text-surface-600 md:text-sm">
|
||||
در صورت نیاز به راهنمایی بیشتر، به صفحهی راهنمای استفاده مراجعه کنید یا با پشتیبانی تماس بگیرید.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,87 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { brandingConfig } from '@/branding/branding.config';
|
||||
import { Component, computed, inject, signal } from '@angular/core';
|
||||
import { SwUpdate, VersionReadyEvent } from '@angular/service-worker';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { filter } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'pos-about-page',
|
||||
templateUrl: './root.component.html',
|
||||
imports: [ButtonDirective],
|
||||
})
|
||||
export class PosAboutPageComponent {}
|
||||
export class PosAboutPageComponent {
|
||||
private readonly swUpdate = inject(SwUpdate);
|
||||
|
||||
brandingInfo = brandingConfig;
|
||||
appVersion = signal('0.0.0');
|
||||
isPwaBuild = this.swUpdate.isEnabled;
|
||||
isCheckingUpdate = signal(false);
|
||||
hasUpdate = signal(false);
|
||||
isUpdated = signal(false);
|
||||
|
||||
updateCtaLabel = computed(() => {
|
||||
if (!this.isPwaBuild) return 'به روزرسانی فقط در نسخه PWA';
|
||||
if (this.isUpdated()) return 'به روز است';
|
||||
if (this.hasUpdate()) return 'به روزرسانی برنامه';
|
||||
if (this.isCheckingUpdate()) return 'در حال بررسی...';
|
||||
return 'بررسی به روزرسانی';
|
||||
});
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.isPwaBuild) return;
|
||||
|
||||
this.loadVersion();
|
||||
this.swUpdate.versionUpdates
|
||||
.pipe(filter((event): event is VersionReadyEvent => event.type === 'VERSION_READY'))
|
||||
.subscribe((event) => {
|
||||
const appData = event.latestVersion.appData as { appVersion?: string } | undefined;
|
||||
this.appVersion.set(appData?.appVersion || this.appVersion());
|
||||
this.hasUpdate.set(true);
|
||||
this.isUpdated.set(false);
|
||||
});
|
||||
}
|
||||
|
||||
async onUpdateCtaClick() {
|
||||
if (!this.isPwaBuild || this.isCheckingUpdate()) return;
|
||||
|
||||
if (this.hasUpdate()) {
|
||||
await this.applyUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
await this.checkForUpdate();
|
||||
}
|
||||
|
||||
private async checkForUpdate() {
|
||||
this.isCheckingUpdate.set(true);
|
||||
this.isUpdated.set(false);
|
||||
try {
|
||||
const hasUpdate = await this.swUpdate.checkForUpdate();
|
||||
this.hasUpdate.set(hasUpdate);
|
||||
this.isUpdated.set(!hasUpdate);
|
||||
} finally {
|
||||
this.isCheckingUpdate.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async applyUpdate() {
|
||||
this.isCheckingUpdate.set(true);
|
||||
try {
|
||||
await this.swUpdate.activateUpdate();
|
||||
this.isUpdated.set(true);
|
||||
this.hasUpdate.set(false);
|
||||
window.location.reload();
|
||||
} finally {
|
||||
this.isCheckingUpdate.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
private loadVersion() {
|
||||
fetch('/ngsw.json')
|
||||
.then((res) => res.json())
|
||||
.then((data: { appData?: { appVersion?: string } }) => {
|
||||
this.appVersion.set(data?.appData?.appVersion || this.appVersion());
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -1,4 +1,9 @@
|
||||
<shared-dialog [(visible)]="visible" header="اطلاعات مشتری" [modal]="true" [style]="{ width: '560px' }">
|
||||
<shared-light-bottomsheet
|
||||
[(visible)]="visible"
|
||||
header="اطلاعات مشتری"
|
||||
[modal]="true"
|
||||
[style]="{ 'max-height': '90svh', height: 'auto' }"
|
||||
>
|
||||
<div class="card p-2! flex justify-center">
|
||||
<p-selectbutton [options]="customerTypes" [(ngModel)]="selectedCustomerType" optionValue="value">
|
||||
<ng-template #item let-item>
|
||||
@@ -13,4 +18,4 @@
|
||||
} @else if (selectedCustomerType() === "LEGAL") {
|
||||
<pos-customer-legal-form (onSubmit)="onSubmitCustomer()" (onClose)="close()" />
|
||||
}
|
||||
</shared-dialog>
|
||||
</shared-light-bottomsheet>
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { SharedLightBottomsheetComponent } from '@/shared/components/dialog/light-bottomsheet.component';
|
||||
import { CustomerType } from '@/shared/localEnum/constants/customerTypes';
|
||||
import { Component, EventEmitter, inject, Output, signal } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
@@ -13,7 +13,7 @@ import { CustomerUnknownFormComponent } from './unknown/form.component';
|
||||
selector: 'pos-order-customer-dialog',
|
||||
templateUrl: './customer-dialog.component.html',
|
||||
imports: [
|
||||
SharedDialogComponent,
|
||||
SharedLightBottomsheetComponent,
|
||||
CustomerIndividualFormComponent,
|
||||
FormsModule,
|
||||
CustomerLegalFormComponent,
|
||||
|
||||
+3
-1
@@ -16,7 +16,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<span class="text-sm text-ellipsis text-nowrap overflow-hidden">
|
||||
{{ inOrderGood.quantity }} {{ enumTranslator(inOrderGood.good.unit_type) }}
|
||||
{{ inOrderGood.quantity }} {{ inOrderGood.good.measure_unit.name }}
|
||||
</span>
|
||||
</div>
|
||||
@if (!inOrderGood.discount_amount) {
|
||||
@@ -53,9 +53,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (visible()) {
|
||||
<pos-payload-form-dialog
|
||||
[(visible)]="visible"
|
||||
[good]="inOrderGood.good"
|
||||
[initialValues]="inOrderGood"
|
||||
[orderItemId]="inOrderGood.id"
|
||||
/>
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
<shared-dialog
|
||||
<shared-light-bottomsheet
|
||||
[(visible)]="visible"
|
||||
header="ثبت موفقیتآمیز"
|
||||
[modal]="true"
|
||||
[style]="{ width: '420px' }"
|
||||
[style]="{ 'max-height': '90svh', height: 'auto' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
@@ -15,4 +15,4 @@
|
||||
<button pButton type="button" outlined (click)="sendInvoice()">ارسال به سامانه مودیان</button>
|
||||
<button pButton type="button" outlined (click)="openOrderDetails()">جزئیات</button>
|
||||
</div>
|
||||
</shared-dialog>
|
||||
</shared-light-bottomsheet>
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import { NativeBridgeService } from '@/core/services';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { PosInfoStore } from '@/domains/pos/store';
|
||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||
import { SharedDialogComponent } from '@/shared/components';
|
||||
import { SharedLightBottomsheetComponent } from '@/shared/components/dialog/light-bottomsheet.component';
|
||||
import { formatJalali } from '@/utils';
|
||||
import { Component, computed, inject, Input, signal } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
@@ -15,7 +15,7 @@ import { IPosOrderResponse } from '../../models';
|
||||
@Component({
|
||||
selector: 'pos-order-submitted-dialog',
|
||||
templateUrl: 'order-submitted-dialog.component.html',
|
||||
imports: [SharedDialogComponent, ButtonDirective],
|
||||
imports: [SharedLightBottomsheetComponent, ButtonDirective],
|
||||
})
|
||||
export class PosOrderSubmittedDialogComponent extends AbstractDialog {
|
||||
@Input({ required: true }) invoice!: IPosOrderResponse;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
} @else if (isStandardMode()) {
|
||||
<pos-standard-payload-form
|
||||
[initialValues]="standardPayload()"
|
||||
[unitType]="good.unit_type"
|
||||
[measureUnit]="good.measure_unit"
|
||||
[editMode]="editMode()"
|
||||
(onSubmit)="submit($event)"
|
||||
/>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.payload.controls.wages_percentage"
|
||||
[amountControl]="form.controls.payload.controls.wages_amount"
|
||||
[amountControl]="form.controls.payload.controls.wages"
|
||||
[baseAmount]="unitWithQuantity()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="unitWithQuantity()"
|
||||
@@ -15,7 +15,7 @@
|
||||
/>
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.payload.controls.commission_percentage"
|
||||
[amountControl]="form.controls.payload.controls.commission_amount"
|
||||
[amountControl]="form.controls.payload.controls.commission"
|
||||
[baseAmount]="unitWithQuantity()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="unitWithQuantity()"
|
||||
@@ -24,7 +24,7 @@
|
||||
/>
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.payload.controls.profit_percentage"
|
||||
[amountControl]="form.controls.payload.controls.profit_amount"
|
||||
[amountControl]="form.controls.payload.controls.profit"
|
||||
[baseAmount]="totalAmountBeforeProfit()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="totalAmountBeforeProfit()"
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<app-amount-percentage-input
|
||||
[percentageControl]="form.controls.discount_percentage"
|
||||
[amountControl]="form.controls.discount_amount"
|
||||
[amountControl]="form.controls.discount"
|
||||
[baseAmount]="baseAmountForDiscountCalculation()"
|
||||
[minAmount]="0"
|
||||
[maxAmount]="baseAmountForDiscountCalculation()"
|
||||
@@ -59,7 +59,7 @@
|
||||
<pos-form-dialog-amount-card-template
|
||||
[totalAmount]="totalAmount()"
|
||||
[baseTotalAmount]="baseTotalAmount()"
|
||||
[discountAmount]="form.controls.discount_amount.value || 0"
|
||||
[discountAmount]="form.controls.discount.value || 0"
|
||||
[taxAmount]="taxAmount()"
|
||||
/>
|
||||
<button pButton class="sm:w-auto w-full" (click)="submit()">{{ preparedCTAText() }}</button>
|
||||
|
||||
@@ -31,6 +31,17 @@ export class PosGoldPayloadFormComponent extends AbstractForm<
|
||||
IPosOrderItem<IGoldPayload>,
|
||||
IPosOrderItem<IGoldPayload>
|
||||
> {
|
||||
override defaultValues: Partial<IPosOrderItem<IGoldPayload>> = {
|
||||
unit_price: 200_000_000,
|
||||
quantity: 2,
|
||||
payload: {
|
||||
commission: 10_000,
|
||||
wages: 10_000,
|
||||
profit: 10_000,
|
||||
karat: '18' as TGoldKarat,
|
||||
} as any,
|
||||
};
|
||||
|
||||
@Output() onSubmitForm = new EventEmitter<IGoldPayload>();
|
||||
@Output() onChangeTotalAmount = new EventEmitter<number>();
|
||||
|
||||
@@ -59,14 +70,14 @@ export class PosGoldPayloadFormComponent extends AbstractForm<
|
||||
const form = this.fb.group({
|
||||
unit_price: [this.initialValues?.unit_price || 0, [Validators.required]],
|
||||
quantity: [this.initialValues?.quantity || 0, [Validators.required, greaterThanValidator(0)]],
|
||||
discount_amount: [this.initialValues?.discount || 0],
|
||||
discount: [this.initialValues?.discount || 0],
|
||||
discount_percentage: [0, [Validators.max(100), Validators.min(0)]],
|
||||
payload: this.fb.group({
|
||||
commission_amount: [this.initialValues?.payload?.commission || 0, [Validators.required]],
|
||||
commission: [this.initialValues?.payload?.commission || 0, [Validators.required]],
|
||||
commission_percentage: [0, [Validators.required, Validators.max(100), Validators.min(0)]],
|
||||
wages_amount: [this.initialValues?.payload?.wages || 0, [Validators.required]],
|
||||
wages: [this.initialValues?.payload?.wages || 0, [Validators.required]],
|
||||
wages_percentage: [0, [Validators.required, Validators.max(100), Validators.min(0)]],
|
||||
profit_amount: [this.initialValues?.payload?.profit || 0, [Validators.required]],
|
||||
profit: [this.initialValues?.payload?.profit || 0, [Validators.required]],
|
||||
profit_percentage: [0, [Validators.required, Validators.max(100), Validators.min(0)]],
|
||||
karat: [this.initialValues?.payload?.karat || '', [Validators.required]],
|
||||
}),
|
||||
@@ -76,17 +87,15 @@ export class PosGoldPayloadFormComponent extends AbstractForm<
|
||||
this.updateCalculateAmount(value as any);
|
||||
});
|
||||
|
||||
form.controls.payload.controls.profit_amount.valueChanges
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe(() => {
|
||||
form.controls.payload.controls.profit.valueChanges.pipe(takeUntilDestroyed()).subscribe(() => {
|
||||
// if ((form.controls.discount_amount.value || 0) > (value || 0)) {
|
||||
form.controls.discount_amount.setValue(0, { emitEvent: false });
|
||||
form.controls.discount.setValue(0, { emitEvent: false });
|
||||
// }
|
||||
});
|
||||
form.controls.payload.controls.profit_percentage.valueChanges
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe(() => {
|
||||
form.controls.discount_amount.setValue(0, { emitEvent: false });
|
||||
form.controls.discount.setValue(0, { emitEvent: false });
|
||||
});
|
||||
|
||||
return form;
|
||||
@@ -101,19 +110,19 @@ export class PosGoldPayloadFormComponent extends AbstractForm<
|
||||
base_total_amount: this.baseTotalAmount(),
|
||||
tax_amount: this.taxAmount(),
|
||||
payload: {
|
||||
commission: this.form.controls.payload.controls.commission_amount.value || 0,
|
||||
commission: this.form.controls.payload.controls.commission.value || 0,
|
||||
karat: this.form.controls.payload.controls.karat.value as TGoldKarat,
|
||||
profit: this.form.controls.payload.controls.profit_amount.value || 0,
|
||||
wages: this.form.controls.payload.controls.wages_amount.value || 0,
|
||||
profit: this.form.controls.payload.controls.profit.value || 0,
|
||||
wages: this.form.controls.payload.controls.wages.value || 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
updateCalculateAmount(payload: Partial<IPosOrderItem<any>>) {
|
||||
const commissionAmount = Number(payload.payload?.commission_amount ?? '0');
|
||||
const wageAmount = Number(payload.payload?.wages_amount ?? '0');
|
||||
const discountAmount = Number(payload.discount_amount ?? '0');
|
||||
const profitAmount = Number(payload.payload?.profit_amount ?? '0');
|
||||
const commissionAmount = Number(payload.payload?.commission ?? '0');
|
||||
const wageAmount = Number(payload.payload?.wages ?? '0');
|
||||
const discountAmount = Number(payload.discount ?? '0');
|
||||
const profitAmount = Number(payload.payload?.profit ?? '0');
|
||||
const unitPrice = Number(payload.unit_price ?? '0');
|
||||
const quantity = Number(payload.quantity ?? '0');
|
||||
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@
|
||||
<app-input
|
||||
[control]="form.controls.quantity"
|
||||
name="quantity"
|
||||
[label]="preparedFormVisuals().quantityLabel"
|
||||
[label]="measureUnit.name"
|
||||
type="number"
|
||||
[suffix]="preparedFormVisuals().quantitySymbolText"
|
||||
[suffix]="measureUnit.name"
|
||||
[min]="0"
|
||||
/>
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { AbstractForm } from '@/shared/abstractClasses';
|
||||
import { InputComponent } from '@/shared/components';
|
||||
import { AmountPercentageInputComponent } from '@/shared/components/amountPercentageInput/amount-percentage-input.component';
|
||||
import { formatWithCurrency, getGoodUnitTypeProperties, UnitType } from '@/utils';
|
||||
import { formatWithCurrency } from '@/utils';
|
||||
import { Component, computed, EventEmitter, Input, Output, signal } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
@@ -24,7 +25,7 @@ export class PosStandardPayloadFormComponent extends AbstractForm<
|
||||
IPosOrderItem<IStandardPayload>,
|
||||
IPosOrderItem<IStandardPayload>
|
||||
> {
|
||||
@Input({ required: true }) unitType!: UnitType;
|
||||
@Input({ required: true }) measureUnit!: ISummary;
|
||||
@Output() onChangeTotalAmount = new EventEmitter<number>();
|
||||
|
||||
private readonly initialForm = () => {
|
||||
@@ -53,8 +54,6 @@ export class PosStandardPayloadFormComponent extends AbstractForm<
|
||||
});
|
||||
}
|
||||
|
||||
preparedFormVisuals = computed(() => getGoodUnitTypeProperties(this.unitType));
|
||||
|
||||
baseTotalAmount = signal<number>(0);
|
||||
totalAmount = signal<number>(0);
|
||||
discountAmount = signal<number>(0);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<shared-dialog
|
||||
<shared-light-bottomsheet
|
||||
[(visible)]="visible"
|
||||
header="اطلاعات پرداخت"
|
||||
[modal]="true"
|
||||
[style]="{ width: '500px' }"
|
||||
[style]="{ 'max-height': '90svh', height: 'auto' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
@@ -71,4 +71,4 @@
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</shared-dialog>
|
||||
</shared-light-bottomsheet>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { NativeBridgeService } from '@/core/services';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
||||
import { InputComponent, KeyValueComponent } from '@/shared/components';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { SharedLightBottomsheetComponent } from '@/shared/components/dialog/light-bottomsheet.component';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, computed, inject, signal } from '@angular/core';
|
||||
@@ -27,7 +27,7 @@ import { PosLandingStore } from '../../store/main.store';
|
||||
FormFooterActionsComponent,
|
||||
KeyValueComponent,
|
||||
ButtonDirective,
|
||||
SharedDialogComponent,
|
||||
SharedLightBottomsheetComponent,
|
||||
Select,
|
||||
UikitFieldComponent,
|
||||
],
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<shared-dialog
|
||||
<shared-light-bottomsheet
|
||||
[(visible)]="visible"
|
||||
header="پیش فاکتور"
|
||||
[modal]="true"
|
||||
[style]="{ width: '500px' }"
|
||||
[style]="{ 'max-height': '90svh', height: 'auto' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
<form [formGroup]="form"></form>
|
||||
<uikit-datepicker [control]="form.controls.invoiceDate" label="تاریخ فاکتور" />
|
||||
</shared-dialog>
|
||||
</shared-light-bottomsheet>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||
import { SharedLightBottomsheetComponent } from '@/shared/components/dialog/light-bottomsheet.component';
|
||||
import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { PosLandingStore } from '../store/main.store';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'pos-pre-invoice-dialog',
|
||||
templateUrl: './pre-invoice-dialog.component.html',
|
||||
imports: [SharedDialogComponent, UikitFlatpickrJalaliComponent, ReactiveFormsModule],
|
||||
imports: [SharedLightBottomsheetComponent, UikitFlatpickrJalaliComponent, ReactiveFormsModule],
|
||||
})
|
||||
export class PosPreInvoiceDialogComponent extends AbstractDialog {
|
||||
private readonly store = inject(PosLandingStore);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
import { IGoodResponse } from '@/domains/pos/models/good.io';
|
||||
import { UnitType } from '@/utils';
|
||||
import { TPosOrderGoodPayload } from './payload';
|
||||
|
||||
export interface IPosOrderItem<T = TPosOrderGoodPayload> {
|
||||
@@ -7,7 +7,7 @@ export interface IPosOrderItem<T = TPosOrderGoodPayload> {
|
||||
quantity: number;
|
||||
total_amount: number;
|
||||
discount_amount: number;
|
||||
unit_type: UnitType;
|
||||
measure_unit: ISummary;
|
||||
good_id?: string;
|
||||
service_id?: string;
|
||||
notes?: string;
|
||||
|
||||
@@ -221,7 +221,7 @@ export class PosLandingStore {
|
||||
items: this.inOrderGoods().map(({ good, ...rest }) => ({
|
||||
...rest,
|
||||
good_id: good.id,
|
||||
unit_type: good.unit_type,
|
||||
measure_unit: good.measure_unit,
|
||||
})),
|
||||
invoice_date: new Date().toISOString(),
|
||||
payments: this.payments(),
|
||||
|
||||
@@ -34,17 +34,11 @@
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
<shared-dialog
|
||||
[(visible)]="showInvoiceBottomSheet"
|
||||
position="bottom"
|
||||
[modal]="true"
|
||||
[closable]="true"
|
||||
header="فاکتور"
|
||||
>
|
||||
<shared-light-bottomsheet [(visible)]="showInvoiceBottomSheet" [modal]="true" [closable]="true" header="فاکتور">
|
||||
@if (showInvoiceBottomSheet()) {
|
||||
<pos-order-section (onAddMoreGoods)="closeInvoiceBottomSheet()" (onSuccess)="onSuccessSubmit($event)" />
|
||||
}
|
||||
</shared-dialog>
|
||||
</shared-light-bottomsheet>
|
||||
|
||||
@if (responseInvoice()) {
|
||||
<pos-order-submitted-dialog [(visible)]="isVisibleSuccessDialog" [invoice]="responseInvoice()!" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { PosInfoStore } from '@/domains/pos/store/pos.store';
|
||||
import { AbstractIsMobileComponent } from '@/shared/abstractClasses/abstract-is-mobile';
|
||||
import { SharedDialogComponent } from '@/shared/components';
|
||||
import { SharedLightBottomsheetComponent } from '@/shared/components/dialog/light-bottomsheet.component';
|
||||
import { PageLoadingComponent } from '@/shared/components/page-loading.component';
|
||||
import { PriceMaskDirective } from '@/shared/directives';
|
||||
import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core';
|
||||
@@ -24,7 +24,7 @@ import { PosLandingStore } from '../store/main.store';
|
||||
PosOrderSectionComponent,
|
||||
PageLoadingComponent,
|
||||
PriceMaskDirective,
|
||||
SharedDialogComponent,
|
||||
SharedLightBottomsheetComponent,
|
||||
ButtonDirective,
|
||||
PosOrderSubmittedDialogComponent,
|
||||
],
|
||||
|
||||
@@ -1,6 +1,47 @@
|
||||
<div class="w-full h-full min-h-[60svh] flex items-center justify-center p-4">
|
||||
<div class="text-center">
|
||||
<h2 class="text-xl font-semibold mb-2">پشتیبانی</h2>
|
||||
<p class="text-muted-color">این صفحه به زودی تکمیل می شود.</p>
|
||||
<div class="w-full min-h-[60svh] p-4 md:p-6">
|
||||
<section class="mx-auto max-w-3xl overflow-hidden rounded-2xl border border-surface-200 bg-white">
|
||||
<div class="bg-gradient-to-l from-sky-50 via-cyan-50 to-teal-50 p-5 md:p-7">
|
||||
<h1 class="text-2xl font-bold text-surface-900 md:text-3xl">پشتیبانی تیس</h1>
|
||||
<p class="mt-3 max-w-2xl text-sm leading-7 text-surface-700 md:text-base">
|
||||
در صورت بروز مشکل در ثبت سفارش، صدور صورتحساب یا تنظیمات دستگاه، تیم پشتیبانی آماده پاسخگویی است. لطفا هنگام
|
||||
تماس، نام پایانه و شماره سریال دستگاه را همراه داشته باشید.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-3 p-4 md:grid-cols-2 md:gap-4 md:p-6">
|
||||
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
|
||||
<h2 class="mb-3 text-sm font-bold text-surface-900">شماره های تماس مستقیم</h2>
|
||||
<ul class="space-y-2 text-sm text-surface-700">
|
||||
<li class="flex items-center justify-between gap-2">
|
||||
<span>واحد پشتیبانی 1</span>
|
||||
<a class="font-semibold text-primary" href="tel:02191012345" dir="ltr">021-91012345</a>
|
||||
</li>
|
||||
<li class="flex items-center justify-between gap-2">
|
||||
<span>واحد پشتیبانی 2</span>
|
||||
<a class="font-semibold text-primary" href="tel:02191012346" dir="ltr">021-91012346</a>
|
||||
</li>
|
||||
<li class="flex items-center justify-between gap-2">
|
||||
<span>پاسخگویی اضطراری</span>
|
||||
<a class="font-semibold text-primary" href="tel:09121234567" dir="ltr">0912-123-4567</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="rounded-xl border border-surface-200 bg-surface-50 p-4">
|
||||
<h2 class="mb-3 text-sm font-bold text-surface-900">راهنمای سریع قبل از تماس</h2>
|
||||
<ul class="space-y-2 text-sm leading-6 text-surface-700">
|
||||
<li>اتصال اینترنت دستگاه را بررسی کنید.</li>
|
||||
<li>یک بار برنامه را ببندید و دوباره اجرا کنید.</li>
|
||||
<li>در صفحه درباره نرم افزار، نسخه برنامه را اعلام کنید.</li>
|
||||
<li>در صورت خطا، متن خطا یا تصویر آن را برای پشتیبانی ارسال کنید.</li>
|
||||
</ul>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="border-t border-surface-200 bg-surface-50 px-4 py-4 md:px-6">
|
||||
<p class="text-xs leading-6 text-surface-600 md:text-sm">
|
||||
ساعات پاسخگویی: شنبه تا چهارشنبه 8:30 تا 17:30 و پنجشنبه 8:30 تا 13:00
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -38,6 +38,11 @@ export class AppLayout {
|
||||
public renderer: Renderer2,
|
||||
public router: Router,
|
||||
) {
|
||||
this.layoutService.headerSlot$.subscribe((tpl) => (this.topBarMoreAction = tpl));
|
||||
this.layoutService.topbarStartSlot$.subscribe((tpl) => (this.topBarStartAction = tpl));
|
||||
this.layoutService.topbarCenterSlot$.subscribe((tpl) => (this.topBarCenterAction = tpl));
|
||||
this.layoutService.topbarEndSlot$.subscribe((tpl) => (this.topBarEndAction = tpl));
|
||||
|
||||
this.overlayMenuOpenSubscription = this.layoutService.overlayOpen$.subscribe(() => {
|
||||
if (!this.menuOutsideClickListener) {
|
||||
this.menuOutsideClickListener = this.renderer.listen('document', 'click', (event) => {
|
||||
@@ -133,11 +138,6 @@ export class AppLayout {
|
||||
});
|
||||
|
||||
ngOnInit() {
|
||||
this.layoutService.headerSlot$.subscribe((tpl) => (this.topBarMoreAction = tpl));
|
||||
this.layoutService.topbarStartSlot$.subscribe((tpl) => (this.topBarStartAction = tpl));
|
||||
this.layoutService.topbarCenterSlot$.subscribe((tpl) => (this.topBarCenterAction = tpl));
|
||||
this.layoutService.topbarEndSlot$.subscribe((tpl) => (this.topBarEndAction = tpl));
|
||||
|
||||
if (window.location.pathname === '/') {
|
||||
if (!this.authService.currentAccount()) {
|
||||
this.router.navigateByUrl('auth');
|
||||
|
||||
@@ -37,14 +37,14 @@ export abstract class AbstractForm<
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.form.reset(this.initialValues ?? this.defaultValues);
|
||||
this.form.patchValue(this.initialValues ?? this.defaultValues);
|
||||
// Object.entries(this.form.controls).forEach(([key, control]) => {
|
||||
// console.log(key, control);
|
||||
// });
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.form.reset(this.initialValues ?? this.defaultValues);
|
||||
this.form.patchValue(this.initialValues ?? this.defaultValues);
|
||||
}
|
||||
|
||||
onSuccess(response: Response): void {}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[formControl]="control"
|
||||
[showClear]="showClear"
|
||||
[name]="name || type"
|
||||
[overlayOptions]="overlayOptions()"
|
||||
appendTo="body"
|
||||
/>
|
||||
</uikit-field>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, computed, inject, Input } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Component, Inject, computed, inject, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { Observable } from 'rxjs';
|
||||
@@ -19,6 +20,9 @@ export class EnumSelectComponent extends AbstractSelectComponent<string, IApiEnu
|
||||
@Input() customLabel?: string;
|
||||
|
||||
private readonly service = inject(EnumsService);
|
||||
constructor(@Inject(DOCUMENT) private readonly document: Document) {
|
||||
super();
|
||||
}
|
||||
|
||||
label = computed(() => this.customLabel ?? apiEnumTranslates[this.type]);
|
||||
|
||||
@@ -29,4 +33,20 @@ export class EnumSelectComponent extends AbstractSelectComponent<string, IApiEnu
|
||||
ngOnInit() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
overlayOptions() {
|
||||
return {
|
||||
autoZIndex: true,
|
||||
baseZIndex: this.overlayBaseZIndex(),
|
||||
};
|
||||
}
|
||||
|
||||
overlayBaseZIndex() {
|
||||
const drawers = Array.from(this.document.body.querySelectorAll('.p-drawer,[data-pc-name="drawer"]')) as HTMLElement[];
|
||||
const zIndexes = drawers
|
||||
.map((drawer) => Number.parseInt(drawer.style.zIndex || '0', 10))
|
||||
.filter((zIndex) => Number.isFinite(zIndex) && zIndex > 0);
|
||||
|
||||
return zIndexes.length ? Math.max(...zIndexes) + 2 : 1000;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -24,8 +24,8 @@
|
||||
[attr.name]="name"
|
||||
[attr.placeholder]="placeholder"
|
||||
[attr.autocomplete]="autocomplete"
|
||||
[class]="` w-full hasSuffix text-left ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
|
||||
dir="ltr"
|
||||
[inputStyle]="{ direction: 'ltr' }"
|
||||
[inputStyleClass]="` w-full hasSuffix text-left ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
|
||||
[required]="required"
|
||||
[invalid]="amountControl.invalid && (amountControl.touched || amountControl.dirty)"
|
||||
(onInput)="onPriceInput($event)"
|
||||
@@ -58,9 +58,10 @@
|
||||
<p-select
|
||||
[formControl]="selectedType"
|
||||
[options]="typeSelectOptions"
|
||||
tabindex="-1"
|
||||
optionValue="value"
|
||||
size="small"
|
||||
class="border-0!"
|
||||
class="border-none! shadow-none! w-full!"
|
||||
/>
|
||||
</p-inputgroup-addon>
|
||||
</p-inputgroup>
|
||||
|
||||
@@ -180,11 +180,16 @@ export class AmountPercentageInputComponent {
|
||||
const amountValue = Number(this.amountControl.value || 0);
|
||||
const percentageValue = Number(this.percentageControl.value || 0);
|
||||
const isPercentageType = percentageValue > 0 && amountValue <= 0;
|
||||
|
||||
console.log(amountValue, percentageValue, isPercentageType);
|
||||
|
||||
this.preparedLabel.set(this.prepareLabel(isPercentageType));
|
||||
|
||||
this.selectedType.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => {
|
||||
this.preparedLabel.set(this.prepareLabel(value === 'percentage'));
|
||||
});
|
||||
|
||||
this.selectedType.setValue(isPercentageType ? 'percentage' : 'amount');
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-3">
|
||||
<p-checkBox [formControl]="control" [name]="name" [id]="name" binary class="shrink-0"> </p-checkBox>
|
||||
<p-checkBox [formControl]="control" [name]="name" [inputId]="name" binary class="shrink-0"> </p-checkBox>
|
||||
<uikit-label [name]="name"> {{ label }} </uikit-label>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
<div class="light-bottomsheet-mask" (click)="onMaskClick()"></div>
|
||||
|
||||
<section
|
||||
class="light-bottomsheet-panel"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
[attr.aria-hidden]="!visible"
|
||||
[ngStyle]="style || { 'max-height': mobileDrawerHeight, height: 'auto' }"
|
||||
>
|
||||
<section class="light-bottomsheet-panel" [ngStyle]="style || { 'max-height': mobileDrawerHeight, height: 'auto' }">
|
||||
<div class="light-bottomsheet-content">
|
||||
@if (header || closable) {
|
||||
<header class="light-bottomsheet-header">
|
||||
<h3 class="light-bottomsheet-title">{{ header }}</h3>
|
||||
<span class="text-xl font-bold">{{ header }}</span>
|
||||
@if (closable) {
|
||||
<button type="button" class="light-bottomsheet-close" (click)="onVisibilityChange(false)" aria-label="Close">
|
||||
×
|
||||
</button>
|
||||
<p-button
|
||||
type="button"
|
||||
icon="pi pi-times"
|
||||
text
|
||||
size="small"
|
||||
class="light-bottomsheet-close"
|
||||
(click)="onVisibilityChange(false)"
|
||||
aria-label="Close"
|
||||
>
|
||||
</p-button>
|
||||
}
|
||||
</header>
|
||||
}
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
import { NgStyle } from '@angular/common';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { DOCUMENT, NgStyle } from '@angular/common';
|
||||
import {
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Inject,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
Renderer2,
|
||||
SimpleChanges,
|
||||
} from '@angular/core';
|
||||
import { Button } from 'primeng/button';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-light-bottomsheet',
|
||||
templateUrl: './light-bottomsheet.component.html',
|
||||
imports: [NgStyle],
|
||||
imports: [NgStyle, Button],
|
||||
styles: [
|
||||
`
|
||||
:host {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 11020;
|
||||
z-index: 1210;
|
||||
}
|
||||
|
||||
.light-bottomsheet-mask {
|
||||
@@ -66,8 +68,6 @@ import {
|
||||
|
||||
.light-bottomsheet-title {
|
||||
margin: 0;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.light-bottomsheet-close {
|
||||
@@ -98,11 +98,17 @@ import {
|
||||
`,
|
||||
],
|
||||
host: {
|
||||
'[attr.role]': '"complementary"',
|
||||
'[attr.aria-modal]': 'true',
|
||||
'[attr.pfocustrap]': 'true',
|
||||
'[attr.data-pc-name]': "'drawer'",
|
||||
'[attr.data-pc-section]': "'root'",
|
||||
'[attr.aria-hidden]': '!visible',
|
||||
'[style.display]': 'visible ? "block" : "none"',
|
||||
'[style.--sheet-transition]': 'transitionOptions',
|
||||
},
|
||||
})
|
||||
export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
|
||||
export class SharedLightBottomsheetComponent implements OnInit, OnDestroy, OnChanges {
|
||||
@Input() header = '';
|
||||
@Input() visible = false;
|
||||
@Output() visibleChange = new EventEmitter<boolean>();
|
||||
@@ -116,6 +122,7 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
|
||||
@Output() onHide = new EventEmitter<any>();
|
||||
|
||||
private originalParent: Node | null = null;
|
||||
private readonly defaultDrawerZIndex = 1102;
|
||||
|
||||
constructor(
|
||||
private readonly elementRef: ElementRef<HTMLElement>,
|
||||
@@ -127,9 +134,20 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
|
||||
const host = this.elementRef.nativeElement;
|
||||
this.originalParent = host.parentNode;
|
||||
this.renderer.appendChild(this.document.body, host);
|
||||
this.syncZIndex();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['visible'] && this.visible) {
|
||||
this.syncZIndex();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.removeDrawer();
|
||||
}
|
||||
|
||||
private removeDrawer() {
|
||||
const host = this.elementRef.nativeElement;
|
||||
if (this.originalParent) {
|
||||
this.renderer.appendChild(this.originalParent, host);
|
||||
@@ -139,6 +157,9 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
|
||||
onVisibilityChange(nextValue: boolean) {
|
||||
this.visible = nextValue;
|
||||
this.visibleChange.emit(nextValue);
|
||||
if (nextValue) {
|
||||
this.syncZIndex();
|
||||
}
|
||||
if (!nextValue) {
|
||||
this.onHide.emit();
|
||||
}
|
||||
@@ -149,4 +170,19 @@ export class SharedLightBottomsheetComponent implements OnInit, OnDestroy {
|
||||
this.onVisibilityChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
private syncZIndex() {
|
||||
const host = this.elementRef.nativeElement;
|
||||
const siblingDrawers = Array.from(
|
||||
this.document.body.querySelectorAll('.p-drawer'),
|
||||
) as HTMLElement[];
|
||||
const drawerZIndexes = siblingDrawers
|
||||
.map((drawer) => Number.parseInt(drawer.style.zIndex || '0', 10))
|
||||
.filter((zIndex) => Number.isFinite(zIndex) && zIndex > 0);
|
||||
|
||||
const maxDrawerZIndex = drawerZIndexes.length
|
||||
? Math.max(...drawerZIndexes)
|
||||
: this.defaultDrawerZIndex;
|
||||
this.renderer.setStyle(host, 'z-index', `${maxDrawerZIndex + 1}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[formControl]="control"
|
||||
[showClear]="showClear"
|
||||
[filter]="true"
|
||||
[overlayOptions]="overlayOptions()"
|
||||
appendTo="body"
|
||||
/>
|
||||
</uikit-field>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, computed, Input } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Component, Inject, computed, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Select } from 'primeng/select';
|
||||
import { Observable } from 'rxjs';
|
||||
@@ -16,6 +17,10 @@ export class EnumSelectComponent extends AbstractSelectComponent<ISelectItem, IS
|
||||
@Input() type!: TLocalEnum;
|
||||
@Input() customLabel?: string;
|
||||
|
||||
constructor(@Inject(DOCUMENT) private readonly document: Document) {
|
||||
super();
|
||||
}
|
||||
|
||||
label = computed(() => this.customLabel ?? LOCAL_ENUMS[this.type].label);
|
||||
|
||||
override getDataService() {
|
||||
@@ -27,4 +32,20 @@ export class EnumSelectComponent extends AbstractSelectComponent<ISelectItem, IS
|
||||
ngOnInit() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
overlayOptions() {
|
||||
return {
|
||||
autoZIndex: true,
|
||||
baseZIndex: this.overlayBaseZIndex(),
|
||||
};
|
||||
}
|
||||
|
||||
overlayBaseZIndex() {
|
||||
const drawers = Array.from(this.document.body.querySelectorAll('.p-drawer,[data-pc-name="drawer"]')) as HTMLElement[];
|
||||
const zIndexes = drawers
|
||||
.map((drawer) => Number.parseInt(drawer.style.zIndex || '0', 10))
|
||||
.filter((zIndex) => Number.isFinite(zIndex) && zIndex > 0);
|
||||
|
||||
return zIndexes.length ? Math.max(...zIndexes) + 2 : 1000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,11 +48,12 @@ input.p-inputtext {
|
||||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
|
||||
.p-inputgroup > .p-component.hasSuffix:first-child {
|
||||
.p-inputgroup > .p-component.hasSuffix:first-child,
|
||||
.p-inputgroup > .p-component > .hasSuffix {
|
||||
border-start-start-radius: 0 !important;
|
||||
border-end-start-radius: 0 !important;
|
||||
border-end-end-radius: var(--p-inputgroup-addon-border-radius);
|
||||
border-start-end-radius: var(--p-inputgroup-addon-border-radius);
|
||||
border-end-end-radius: var(--p-inputgroup-addon-border-radius) !important;
|
||||
border-start-end-radius: var(--p-inputgroup-addon-border-radius) !important;
|
||||
}
|
||||
|
||||
.p-tablist {
|
||||
|
||||
Reference in New Issue
Block a user