feat: enhance order submission flow and UI improvements
- Updated categories component to improve loading state and category display. - Modified order section to handle payment submission with event payload. - Refactored payment form dialog to emit order response on successful payment. - Adjusted order response model to enforce required fields. - Improved root component layout and added success dialog for order submission. - Enhanced sale invoice card component to use new TSP API methods. - Updated API routes for sale invoices to reflect TSP changes. - Improved user interface for business activities and partners sections. - Added card shadow styling for better visual hierarchy. - Introduced new order submitted dialog component for post-order actions. - Cleaned up console logs and improved code readability across components.
This commit is contained in:
@@ -70,19 +70,19 @@ export class NativeBridgeService {
|
||||
pay(request: INativePayRequest): any {
|
||||
if (request.amount <= 10_000) {
|
||||
const errorMessage = 'برای مقادیر زیر ۱۰۰ هزار ریال، پرداخت ممکن نیست.';
|
||||
this.toastService.error({ text: errorMessage, life: 3000 });
|
||||
this.toastService.warn({ text: errorMessage, life: 3000 });
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
};
|
||||
}
|
||||
this.toastService.info({ text: 'در حال پردازش پرداخت...', life: 3000 });
|
||||
this.toastService.info({ text: 'در حال پردازش پرداخت...' });
|
||||
try {
|
||||
// @ts-ignore
|
||||
window.NativeBridge.pay(request.amount, request.id || '');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
this.toastService.info({ text: (error as Error).message, life: 30000 });
|
||||
this.toastService.info({ text: (error as Error).message });
|
||||
return { success: false, error: (error as Error).message };
|
||||
}
|
||||
// const fn = window.NativeBridge.pay(123, 'test');
|
||||
@@ -99,7 +99,7 @@ export class NativeBridgeService {
|
||||
|
||||
// // return { success: true, data: parsed ?? raw };
|
||||
// } catch (error) {
|
||||
// this.toastService.info({ text: (error as Error).message, life: 30000 });
|
||||
// this.toastService.info({ text: (error as Error).message, });
|
||||
// return { success: false, error: (error as Error).message };
|
||||
// }
|
||||
}
|
||||
@@ -109,12 +109,16 @@ export class NativeBridgeService {
|
||||
}
|
||||
|
||||
private invokePrint(payload: INativePrintRequest): INativeBridgeResult {
|
||||
if (!this.isEnabled() || !this.canPrint()) {
|
||||
this.toastService.warn({ text: 'متاسفانه ارتباط با چاپگر برقرار نیست.' });
|
||||
return { success: false, error: 'متاسفانه ارتباط با چاپگر برقرار نیست.' };
|
||||
}
|
||||
try {
|
||||
// @ts-ignore
|
||||
window.NativeBridge.print(JSON.stringify([payload]));
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
this.toastService.info({ text: (error as Error).message, life: 30000 });
|
||||
this.toastService.warn({ text: 'متاسفانه ارتباط با چاپگر برقرار نیست.' });
|
||||
return { success: false, error: (error as Error).message };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export const CONSUMER_MENU_ITEMS = [
|
||||
routerLink: ['/consumer'],
|
||||
},
|
||||
{
|
||||
label: 'فعالیتهای اقتصادی',
|
||||
label: 'فعالیت اقتصادی',
|
||||
icon: 'pi pi-fw pi-home',
|
||||
routerLink: ['/consumer/business_activities'],
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<app-page-data-list
|
||||
pageTitle="لیست فعالیتهای اقتصادی"
|
||||
pageTitle="لیست فعالیت اقتصادی"
|
||||
[columns]="columns"
|
||||
[items]="items()"
|
||||
[loading]="loading()"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<app-page-data-list
|
||||
[pageTitle]="'لیست مشتریها'"
|
||||
[pageTitle]="'لیست مشتری'"
|
||||
[columns]="columns"
|
||||
emptyPlaceholderTitle="مشتری یافت نشد"
|
||||
[items]="items()"
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<app-page-data-list
|
||||
pageTitle="مدیریت فعالیتهای اقتصادی"
|
||||
pageTitle="مدیریت فعالیت اقتصادی"
|
||||
[addNewCtaLabel]="'افزودن فعالیت اقتصادی'"
|
||||
[columns]="columns"
|
||||
[showAdd]="true"
|
||||
|
||||
@@ -14,9 +14,8 @@ export const partnerConsumerBusinessActivitiesNamedRoutes: NamedRoutes<TBusiness
|
||||
),
|
||||
// @ts-ignore
|
||||
meta: {
|
||||
title: 'فعالیتهای اقتصادی',
|
||||
pagePath: (consumerId: string) =>
|
||||
`/partner/consumers/${consumerId}/business_activities`,
|
||||
title: 'فعالیت اقتصادی',
|
||||
pagePath: (consumerId: string) => `/partner/consumers/${consumerId}/business_activities`,
|
||||
},
|
||||
},
|
||||
businessActivity: {
|
||||
@@ -45,8 +44,7 @@ export const PARTNER_CONSUMER_BUSINESS_ACTIVITIES_ROUTES: Routes = [
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent:
|
||||
partnerConsumerBusinessActivitiesNamedRoutes.businessActivity.loadComponent,
|
||||
loadComponent: partnerConsumerBusinessActivitiesNamedRoutes.businessActivity.loadComponent,
|
||||
},
|
||||
...PARTNER_CONSUMER_COMPLEXES_ROUTES,
|
||||
],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<app-page-data-list
|
||||
pageTitle="لیست مشتریها"
|
||||
pageTitle="لیست مشتری"
|
||||
[addNewCtaLabel]="'افزودن مشتری'"
|
||||
[columns]="columns"
|
||||
[showAdd]="true"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<app-page-data-list
|
||||
[pageTitle]="'لیست مشتریها'"
|
||||
[pageTitle]="'لیست مشتری'"
|
||||
[columns]="columns"
|
||||
emptyPlaceholderTitle="مشتری یافت نشد"
|
||||
[items]="items()"
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<ng-template #topbarStart>
|
||||
<p-button (click)="toggleMenu()" icon="pi pi-bars" outlined size="large" />
|
||||
<p-button (click)="refresh()" icon="pi pi-bars" outlined size="large" />
|
||||
<p-button (click)="doPay()" icon="pi pi-bars" outlined size="large" />
|
||||
</ng-template>
|
||||
|
||||
<ng-template #topbarCenter>
|
||||
@@ -26,11 +24,34 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@if (loading()) {
|
||||
<shared-page-loading />
|
||||
} @else {
|
||||
<!-- <div class="w-svw h-svh bg-surface-ground flex flex-col gap-4 p-4"> -->
|
||||
<!-- <div class="w-full flex items-center gap-4 shrink-0 justify-between">
|
||||
<div
|
||||
class="h-full relative"
|
||||
(touchstart)="onTouchStart($event)"
|
||||
(touchmove)="onTouchMove($event)"
|
||||
(touchend)="onTouchEnd()"
|
||||
>
|
||||
@if (pullDistance() >= 0) {
|
||||
<div
|
||||
class="w-full flex justify-center items-center py-2 min-h-10 text-xs text-surface-500 overflow-hidden fixed top-0 inset-x-0 z-1000 translate-y--20px"
|
||||
[ngStyle]="{ height: pullDistance() + 'px' }"
|
||||
>
|
||||
<div
|
||||
class="inline-flex p-3 rounded-full opacity-0 transition-opacity shadow-xl bg-surface-card"
|
||||
[ngStyle]="{ opacity: pullDistance() / 100 }"
|
||||
>
|
||||
<i
|
||||
class="pi pi-refresh text-[1.25rem] text-primary"
|
||||
[ngStyle]="{ fontSize: `${1.25 + pullDistance() * 0.007}rem`, rotate: pullDistance() * 2 + 'deg' }"
|
||||
></i>
|
||||
</div>
|
||||
<!-- [ngStyle]="{ transform: 'scale(1.' + pullDistance() * 10 + ')' }" -->
|
||||
</div>
|
||||
}
|
||||
@if (loading()) {
|
||||
<shared-page-loading />
|
||||
} @else {
|
||||
<!-- <div class="w-svw h-svh bg-surface-ground flex flex-col gap-4 p-4"> -->
|
||||
<!-- <div class="w-full flex items-center gap-4 shrink-0 justify-between">
|
||||
<div class="flex gap-2 items-center">
|
||||
@if (posInfo()) {
|
||||
<div class="w-10 h-10">
|
||||
@@ -53,27 +74,28 @@
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
@if (error()) {
|
||||
@switch (error()?.status) {
|
||||
@case (412) {
|
||||
<pos-choose-cards class="h-full" (onChoose)="onChoosePos()" />
|
||||
}
|
||||
@default {
|
||||
<div class="h-full w-full flex items-center justify-center">
|
||||
<p-card class="border border-surface-border">
|
||||
<div class="flex flex-col gap-2 items-center justify-between shrink-0">
|
||||
<i class="pi pi-exclamation-triangle text-6xl! mb-3 text-error" aria-hidden="true"></i>
|
||||
<span class="text-xl font-semibold mb-2 text-error block"> عدم دسترسی </span>
|
||||
<p class="inline-block text-base">متاسفانه امکان دسترسی برای کاربر شما فراهم نیست</p>
|
||||
<button pButton outlined severity="danger" class="mt-5 w-32" (click)="logout()">خروج</button>
|
||||
</div>
|
||||
</p-card>
|
||||
</div>
|
||||
@if (error()) {
|
||||
@switch (error()?.status) {
|
||||
@case (412) {
|
||||
<pos-choose-cards class="h-full" (onChoose)="onChoosePos()" />
|
||||
}
|
||||
@default {
|
||||
<div class="h-full w-full flex items-center justify-center">
|
||||
<p-card class="border border-surface-border">
|
||||
<div class="flex flex-col gap-2 items-center justify-between shrink-0">
|
||||
<i class="pi pi-exclamation-triangle text-6xl! mb-3 text-error" aria-hidden="true"></i>
|
||||
<span class="text-xl font-semibold mb-2 text-error block"> عدم دسترسی </span>
|
||||
<p class="inline-block text-base">متاسفانه امکان دسترسی برای کاربر شما فراهم نیست</p>
|
||||
<button pButton outlined severity="danger" class="mt-5 w-32" (click)="logout()">خروج</button>
|
||||
</div>
|
||||
</p-card>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
} @else {
|
||||
<pos-main-menu-sidebar [(visible)]="mainMenuVisible" />
|
||||
<router-outlet></router-outlet>
|
||||
}
|
||||
} @else {
|
||||
<pos-main-menu-sidebar [(visible)]="mainMenuVisible" />
|
||||
<router-outlet></router-outlet>
|
||||
<!-- </div> -->
|
||||
}
|
||||
<!-- </div> -->
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { NativeBridgeService } from '@/core/services';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { LayoutService } from '@/layout/service/layout.service';
|
||||
import { PageLoadingComponent } from '@/shared/components/page-loading.component';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
@@ -34,6 +35,7 @@ import { PosMainMenuSidebarComponent } from './mainMenuSidebar/main-menu-sidebar
|
||||
Button,
|
||||
PosMainMenuSidebarComponent,
|
||||
Menu,
|
||||
CommonModule,
|
||||
],
|
||||
})
|
||||
export class PosLayoutComponent implements AfterViewInit {
|
||||
@@ -84,6 +86,10 @@ export class PosLayoutComponent implements AfterViewInit {
|
||||
placeholderLogo = images.placeholders.logo;
|
||||
|
||||
now = new Date();
|
||||
private touchStartY = 0;
|
||||
private pulling = false;
|
||||
pullDistance = signal(0);
|
||||
readonly pullThreshold = 80;
|
||||
|
||||
getData() {
|
||||
this.posProfileStore.getData().subscribe({
|
||||
@@ -101,24 +107,6 @@ export class PosLayoutComponent implements AfterViewInit {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
doPay() {
|
||||
// this.nativeBridgeService.pay({
|
||||
// amount: 10_000,
|
||||
// id: '1',
|
||||
// });
|
||||
this.nativeBridgeService.print({
|
||||
title: 'salam',
|
||||
items: [
|
||||
{
|
||||
label: 'مجموع قیمت',
|
||||
value: '10_000',
|
||||
},
|
||||
],
|
||||
});
|
||||
// @ts-ignore
|
||||
// window.NativeBridge.pay(12312, 'test');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.layoutService.changeIsFullPage(true);
|
||||
this.getData();
|
||||
@@ -137,7 +125,33 @@ export class PosLayoutComponent implements AfterViewInit {
|
||||
this.layoutService.setTopbarEndSlot(null);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
window.location.reload();
|
||||
onTouchStart(event: TouchEvent) {
|
||||
if (window.scrollY > 0 || event.touches.length !== 1) return;
|
||||
this.touchStartY = event.touches[0].clientY;
|
||||
this.pulling = true;
|
||||
}
|
||||
|
||||
onTouchMove(event: TouchEvent) {
|
||||
if (!this.pulling) return;
|
||||
const delta = event.touches[0].clientY - this.touchStartY;
|
||||
if (delta <= 0) {
|
||||
this.pullDistance.set(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const damped = Math.min(delta * 0.5, 140);
|
||||
this.pullDistance.set(damped);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
onTouchEnd() {
|
||||
if (!this.pulling) return;
|
||||
const shouldRefresh = this.pullDistance() >= this.pullThreshold;
|
||||
this.pulling = false;
|
||||
this.pullDistance.set(0);
|
||||
if (shouldRefresh) {
|
||||
this.layoutService.changeIsFullPage(true);
|
||||
this.getData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
<div class="flex gap-3 overflow-auto">
|
||||
@if (loading()) {
|
||||
@for (i of [1, 2, 3, 4, 5]; track i) {
|
||||
<p-skeleton width="6rem" height="2.5rem" />
|
||||
}
|
||||
} @else {
|
||||
@for (category of categories(); track category.id) {
|
||||
<div
|
||||
[class]="
|
||||
'h-10 rounded-lg px-3 flex items-center gap-3 border border-surface-border cursor-pointer bg-surface-100 hover:bg-surface-200 transition-all' +
|
||||
(selectedCategory() === category.id ? ' bg-surface-card' : '')
|
||||
"
|
||||
(click)="changeSelectedCategory(category)"
|
||||
>
|
||||
<span class="text-sm text-muted-color font-bold"> {{ category.name }}</span>
|
||||
<div class="overflow-x-auto">
|
||||
<div class="w-full overflow-visible flex gap-3">
|
||||
@if (loading()) {
|
||||
@for (i of [1, 2, 3, 4, 5]; track i) {
|
||||
<p-skeleton width="6rem" height="2.5rem" />
|
||||
}
|
||||
} @else {
|
||||
@for (category of categories(); track category.id) {
|
||||
<div
|
||||
[class]="
|
||||
'flex items-center justify-center py-0.5 px-2 rounded-sm bg-surface-300 text-xs text-muted-color' +
|
||||
(selectedCategory() === category.id ? ' bg-amber-400! text-white' : '')
|
||||
'h-10 rounded-lg px-3 flex items-center gap-3 border border-surface-border cursor-pointer bg-surface-100 hover:bg-surface-200 transition-all shrink-0' +
|
||||
(selectedCategory() === category.id ? ' bg-surface-card' : '')
|
||||
"
|
||||
(click)="changeSelectedCategory(category)"
|
||||
>
|
||||
<span>
|
||||
{{ category.goods_count }}
|
||||
</span>
|
||||
<span class="text-sm text-muted-color font-bold"> {{ category.name }}</span>
|
||||
<div
|
||||
[class]="
|
||||
'flex items-center justify-center py-0.5 px-2 rounded-sm bg-surface-300 text-xs text-muted-color' +
|
||||
(selectedCategory() === category.id ? ' bg-amber-400! text-white' : '')
|
||||
"
|
||||
>
|
||||
<span>
|
||||
{{ category.goods_count }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -63,4 +63,4 @@
|
||||
|
||||
<pos-order-customer-dialog [(visible)]="isVisibleCustomerForm" (onSubmit)="submitCustomer()" />
|
||||
<!-- <pos-pre-invoice-dialog [(visible)]="isVisiblePreInvoiceForm" /> -->
|
||||
<pos-payment-form-dialog [(visible)]="isVisiblePaymentForm" (onSubmit)="submitPayment()" />
|
||||
<pos-payment-form-dialog [(visible)]="isVisiblePaymentForm" (onSubmit)="submitPayment($event)" />
|
||||
|
||||
@@ -6,6 +6,7 @@ import { FormsModule } from '@angular/forms';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { Card } from 'primeng/card';
|
||||
import images from 'src/assets/images';
|
||||
import { IPosOrderResponse } from '../../models';
|
||||
import { PosLandingStore } from '../../store/main.store';
|
||||
import { PosOrderCustomerDialogComponent } from '../customers/customer-dialog.component';
|
||||
import { GoldPayloadOrderCardComponent } from '../payloads/gold/order-card.component';
|
||||
@@ -31,7 +32,7 @@ import { POSOrderPriceInfoCardComponent } from './price-info-card.component';
|
||||
export class PosOrderSectionComponent {
|
||||
private readonly store = inject(PosLandingStore);
|
||||
@Output() onAddMoreGoods = new EventEmitter<void>();
|
||||
@Output() onSuccess = new EventEmitter<void>();
|
||||
@Output() onSuccess = new EventEmitter<IPosOrderResponse>();
|
||||
|
||||
placeholderImage = images.placeholders.default;
|
||||
|
||||
@@ -84,9 +85,7 @@ export class PosOrderSectionComponent {
|
||||
}
|
||||
|
||||
submitCustomer() {}
|
||||
submitPayment() {
|
||||
console.log('submitPayment');
|
||||
|
||||
this.onSuccess.emit();
|
||||
submitPayment(invoice: IPosOrderResponse) {
|
||||
this.onSuccess.emit(invoice);
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<shared-dialog
|
||||
[(visible)]="visible"
|
||||
header="ثبت موفقیتآمیز"
|
||||
[modal]="true"
|
||||
[style]="{ width: '420px' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
<div class="text-center pt-10 pb-14 flex flex-col items-center justify-center gap-4">
|
||||
<i class="" class="pi pi-check-circle text-6xl! text-green-700"></i>
|
||||
<p class="text-lg font-bold">فاکتور شما با موفقیت ایجاد شد.</p>
|
||||
</div>
|
||||
<div class="flex gap-2 justify-center">
|
||||
<button pButton type="button" outlined (click)="printInvoice()">چاپ</button>
|
||||
<button pButton type="button" outlined (click)="sendToTsp()">ارسال به سامانه مودیان</button>
|
||||
<button pButton type="button" outlined (click)="openOrderDetails()">جزئیات</button>
|
||||
</div>
|
||||
</shared-dialog>
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
import { NativeBridgeService } from '@/core/services';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
|
||||
import { SharedDialogComponent } from '@/shared/components';
|
||||
import { Component, inject, Input, signal } from '@angular/core';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { finalize } from 'rxjs';
|
||||
import { PosSaleInvoicesService } from '../../../saleInvoices/services/main.service';
|
||||
import { IPosOrderResponse } from '../../models';
|
||||
|
||||
@Component({
|
||||
selector: 'pos-order-submitted-dialog',
|
||||
templateUrl: 'order-submitted-dialog.component.html',
|
||||
imports: [SharedDialogComponent, ButtonDirective],
|
||||
})
|
||||
export class PosOrderSubmittedDialogComponent extends AbstractDialog {
|
||||
@Input({ required: true }) invoice!: IPosOrderResponse;
|
||||
private readonly nativeBridgeService = inject(NativeBridgeService);
|
||||
private readonly service = inject(PosSaleInvoicesService);
|
||||
private readonly toastService = inject(ToastService);
|
||||
|
||||
sendingLoading = signal(false);
|
||||
sended = signal(false);
|
||||
|
||||
openOrderDetails() {
|
||||
this.close();
|
||||
}
|
||||
|
||||
sendInvoice() {
|
||||
this.sendingLoading.set(true);
|
||||
this.service
|
||||
.sendToTsp(this.invoice.id)
|
||||
.pipe(finalize(() => this.sendingLoading.set(false)))
|
||||
.subscribe(() => {
|
||||
this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
|
||||
this.sended.set(true);
|
||||
});
|
||||
}
|
||||
|
||||
printInvoice() {
|
||||
const printResult = this.nativeBridgeService.print({
|
||||
title: 'رسید پرداخت',
|
||||
items: [
|
||||
{ label: 'مبلغ کل', value: String(this.invoice.code) },
|
||||
// { label: 'نقدی', value: String(this.invoice.payment.cash || 0) },
|
||||
// { label: 'تهاتر', value: String(this.invoice.payment.set_off || 0) },
|
||||
// {
|
||||
// label: 'پایانه',
|
||||
// value: String((this.invoice.payment.terminals || []).reduce((acc, item) => acc + item, 0)),
|
||||
// },
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
sendToTsp() {}
|
||||
}
|
||||
@@ -6,12 +6,12 @@ import { InputComponent, KeyValueComponent } from '@/shared/components';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { UikitFieldComponent } from '@/uikit';
|
||||
import { Component, OnDestroy, OnInit, computed, inject, signal } from '@angular/core';
|
||||
import { Component, computed, inject, signal } from '@angular/core';
|
||||
import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { Select } from 'primeng/select';
|
||||
import { catchError, throwError } from 'rxjs';
|
||||
import { IPayment, TOrderPaymentTypes } from '../../models';
|
||||
import { IPayment, IPosOrderResponse, TOrderPaymentTypes } from '../../models';
|
||||
import { PosPaymentBridgeAbstract } from '../../services/payment-bridge.abstract';
|
||||
import { PosPaymentBridgeService } from '../../services/payment-bridge.service';
|
||||
import { PosLandingStore } from '../../store/main.store';
|
||||
@@ -32,10 +32,7 @@ import { PosLandingStore } from '../../store/main.store';
|
||||
],
|
||||
providers: [{ provide: PosPaymentBridgeAbstract, useExisting: PosPaymentBridgeService }],
|
||||
})
|
||||
export class PosPaymentFormDialogComponent
|
||||
extends AbstractFormDialog<IPayment, IPayment>
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment, IPosOrderResponse> {
|
||||
private readonly store = inject(PosLandingStore);
|
||||
private readonly paymentBridge = inject(PosPaymentBridgeAbstract);
|
||||
private readonly nativeBridgeService = inject(NativeBridgeService);
|
||||
@@ -72,8 +69,8 @@ export class PosPaymentFormDialogComponent
|
||||
|
||||
private initForm = () => {
|
||||
const form = this.fb.group({
|
||||
set_off: [this.initialValues?.set_off || 0],
|
||||
cash: [this.initialValues?.cash || 0],
|
||||
set_off: [0],
|
||||
cash: [0],
|
||||
terminals: this.fb.array([this.fb.control(0)]),
|
||||
});
|
||||
|
||||
@@ -237,10 +234,7 @@ export class PosPaymentFormDialogComponent
|
||||
)
|
||||
.subscribe((res) => {
|
||||
this.close();
|
||||
this.onSubmit.emit();
|
||||
this.toastServices.success({
|
||||
text: 'فاکتور شما با موفقیت ایجاد شد',
|
||||
});
|
||||
this.onSubmit.emit(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -289,7 +283,7 @@ export class PosPaymentFormDialogComponent
|
||||
// }
|
||||
}
|
||||
|
||||
override onSuccess(response: IPayment): void {}
|
||||
override onSuccess(response: IPosOrderResponse): void {}
|
||||
|
||||
private extractAmountFromPaymentResult(payload: unknown): number | null {
|
||||
if (!payload || typeof payload !== 'object') return null;
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ export interface IPosOrderRequest {
|
||||
}
|
||||
|
||||
export interface IPosOrderRawResponse {
|
||||
id?: string;
|
||||
code?: string;
|
||||
id: string;
|
||||
code: string;
|
||||
}
|
||||
export interface IPosOrderResponse extends IPosOrderRawResponse {}
|
||||
|
||||
@@ -1,47 +1,48 @@
|
||||
@if (loading()) {
|
||||
<shared-page-loading />
|
||||
} @else if (pos()) {
|
||||
<div class="w-full h-[calc(100dvh-5.5rem)] overflow-hidden">
|
||||
<div
|
||||
[class]="`w-full h-full flex max-md:flex-col gap-4 pb-4 pt-0 overflow-hidden ${inOrderGoods().length > 0 ? 'pb-18!' : ''}`"
|
||||
>
|
||||
<div class="grow h-full overflow-auto">
|
||||
<div class="w-full min-h-[calc(100dvh-5.5rem)] md:overflow-hidden">
|
||||
<div [class]="`w-full h-full flex max-md:flex-col gap-4 pb-4 pt-0`">
|
||||
<div class="grow min-h-[calc(100dvh-5.5rem)]">
|
||||
<pos-goods class="block h-full" />
|
||||
</div>
|
||||
<div class="md:shrink-0 md:h-full md:block hidden p-4 overflow-auto">
|
||||
<div class="md:shrink-0 h-full md:block hidden p-4 overflow-auto">
|
||||
<pos-order-section />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (inOrderGoods().length > 0) {
|
||||
<button
|
||||
type="button"
|
||||
pButton
|
||||
class="sticky! bottom-0 inset-x-0 w-full right-0 z-1200 border-t border-surface-border bg-surface-0 px-4 py-3 shadow-[0_-4px_16px_rgba(0,0,0,0.08)] md:hidden rounded-b-none!"
|
||||
[style.paddingBottom]="'calc(0.75rem + env(safe-area-inset-bottom))'"
|
||||
(click)="openInvoiceBottomSheet()"
|
||||
>
|
||||
<div class="mx-auto flex w-full max-w-3xl items-center justify-between">
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
<span class="text-base">مبلغ کل فاکتور</span>
|
||||
<span class="text-xl font-semibold" [appPriceMask]="priceInfo().totalAmount"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-base font-medium">مشاهده فاکتور</span>
|
||||
<i class="pi pi-chevron-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
|
||||
<shared-dialog
|
||||
[(visible)]="showInvoiceBottomSheet"
|
||||
position="bottom"
|
||||
[modal]="true"
|
||||
[closable]="true"
|
||||
header="فاکتور"
|
||||
>
|
||||
<pos-order-section (onAddMoreGoods)="closeInvoiceBottomSheet()" (onSuccess)="closeInvoiceBottomSheet()" />
|
||||
</shared-dialog>
|
||||
</div>
|
||||
|
||||
@if (inOrderGoods().length > 0) {
|
||||
<button
|
||||
type="button"
|
||||
pButton
|
||||
class="sticky! bottom-0 inset-x-0 w-full right-0 z-1200 border-t border-surface-border bg-surface-0 px-4 py-3 shadow-[0_-4px_16px_rgba(0,0,0,0.08)] md:hidden! rounded-b-none!"
|
||||
[style.paddingBottom]="'calc(0.75rem + env(safe-area-inset-bottom))'"
|
||||
(click)="openInvoiceBottomSheet()"
|
||||
>
|
||||
<div class="mx-auto flex w-full max-w-3xl items-center justify-between">
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
<span class="text-base">مبلغ کل فاکتور</span>
|
||||
<span class="text-xl font-semibold" [appPriceMask]="priceInfo().totalAmount"></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-base font-medium">مشاهده فاکتور</span>
|
||||
<i class="pi pi-chevron-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
<shared-dialog
|
||||
[(visible)]="showInvoiceBottomSheet"
|
||||
position="bottom"
|
||||
[modal]="true"
|
||||
[closable]="true"
|
||||
header="فاکتور"
|
||||
>
|
||||
<pos-order-section (onAddMoreGoods)="closeInvoiceBottomSheet()" (onSuccess)="onSuccessSubmit($event)" />
|
||||
</shared-dialog>
|
||||
|
||||
@if (responseInvoice()) {
|
||||
<pos-order-submitted-dialog [(visible)]="isVisibleSuccessDialog" [invoice]="responseInvoice()!" />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
||||
import { Maybe } from '@/core';
|
||||
import { PosInfoStore } from '@/domains/pos/store/pos.store';
|
||||
import { SharedDialogComponent } from '@/shared/components';
|
||||
import { PageLoadingComponent } from '@/shared/components/page-loading.component';
|
||||
@@ -7,6 +8,8 @@ import { Component, computed, inject, signal } from '@angular/core';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { PosGoodsComponent } from '../components/goods.component';
|
||||
import { PosOrderSectionComponent } from '../components/order/order-section.component';
|
||||
import { PosOrderSubmittedDialogComponent } from '../components/order/order-submitted-dialog.component';
|
||||
import { IPosOrderResponse } from '../models';
|
||||
import { PosLandingStore } from '../store/main.store';
|
||||
|
||||
@Component({
|
||||
@@ -21,12 +24,16 @@ import { PosLandingStore } from '../store/main.store';
|
||||
PriceMaskDirective,
|
||||
SharedDialogComponent,
|
||||
ButtonDirective,
|
||||
PosOrderSubmittedDialogComponent,
|
||||
],
|
||||
})
|
||||
export class PosLandingComponent {
|
||||
private readonly infoStore = inject(PosInfoStore);
|
||||
private readonly landingStore = inject(PosLandingStore);
|
||||
|
||||
isVisibleSuccessDialog = signal(false);
|
||||
responseInvoice = signal<Maybe<IPosOrderResponse>>(null);
|
||||
|
||||
readonly loading = computed(() => this.infoStore.loading());
|
||||
readonly pos = computed(() => this.infoStore.entity());
|
||||
readonly error = computed(() => this.infoStore.error());
|
||||
@@ -45,4 +52,14 @@ export class PosLandingComponent {
|
||||
closeInvoiceBottomSheet() {
|
||||
this.showInvoiceBottomSheet.set(false);
|
||||
}
|
||||
|
||||
onSuccessSubmit(invoice: IPosOrderResponse) {
|
||||
this.closeInvoiceBottomSheet();
|
||||
this.responseInvoice.set(invoice);
|
||||
this.isVisibleSuccessDialog.set(true);
|
||||
}
|
||||
|
||||
closeSuccessDialog() {
|
||||
this.isVisibleSuccessDialog.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ export class SaleInvoiceCardComponent {
|
||||
if (customer) {
|
||||
const { legal, individual } = customer;
|
||||
let text = 'نوع اول - ';
|
||||
console.log(customer);
|
||||
if (legal) {
|
||||
text += `حقوقی (${legal.company_name})`;
|
||||
}
|
||||
@@ -67,7 +66,7 @@ export class SaleInvoiceCardComponent {
|
||||
sendInvoice() {
|
||||
this.sendingLoading.set(true);
|
||||
this.service
|
||||
.sendFiscal(this.saleInvoice.id)
|
||||
.sendToTsp(this.saleInvoice.id)
|
||||
.pipe(finalize(() => this.sendingLoading.set(false)))
|
||||
.subscribe(() => {
|
||||
this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
|
||||
@@ -88,7 +87,7 @@ export class SaleInvoiceCardComponent {
|
||||
resendInvoice() {
|
||||
this.resendingLoading.set(true);
|
||||
this.service
|
||||
.retryFiscal(this.saleInvoice.id)
|
||||
.retrySendToTsp(this.saleInvoice.id)
|
||||
.pipe(finalize(() => this.resendingLoading.set(false)))
|
||||
.subscribe(() => {
|
||||
this.toastService.success({ text: 'ارسال مجدد فاکتور با موفقیت انجام شد.' });
|
||||
|
||||
@@ -3,12 +3,12 @@ const baseUrl = () => `/api/v1/pos/sales_invoices`;
|
||||
export const POS_SALE_INVOICES_API_ROUTES = {
|
||||
list: () => baseUrl(),
|
||||
single: (invoiceId: string) => `${baseUrl()}/${invoiceId}`,
|
||||
fiscal: {
|
||||
tsp: {
|
||||
send: (invoiceId: string) => `${baseUrl()}/${invoiceId}/send`,
|
||||
retry: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/retry`,
|
||||
status: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/status`,
|
||||
getInquiry: (invoiceId: string) => `${baseUrl()}/${invoiceId}/inquiry`,
|
||||
revoke: (invoiceId: string) => `${baseUrl()}/${invoiceId}/revoke`,
|
||||
retry: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/retry`,
|
||||
status: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/status`,
|
||||
attempts: (invoiceId: string) => `${baseUrl()}/${invoiceId}/fiscal/attempts`,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -32,43 +32,41 @@ export class PosSaleInvoicesService {
|
||||
return this.http.get<ISaleInvoiceFullRawResponse>(this.apiRoutes.single(invoiceId));
|
||||
}
|
||||
|
||||
sendFiscal(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
|
||||
sendToTsp(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
|
||||
return this.http.post<IPosSaleInvoiceFiscalActionResponse>(
|
||||
this.apiRoutes.fiscal.send(invoiceId),
|
||||
this.apiRoutes.tsp.send(invoiceId),
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
retryFiscal(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
|
||||
retrySendToTsp(invoiceId: string): Observable<IPosSaleInvoiceFiscalActionResponse> {
|
||||
return this.http.post<IPosSaleInvoiceFiscalActionResponse>(
|
||||
this.apiRoutes.fiscal.retry(invoiceId),
|
||||
this.apiRoutes.tsp.retry(invoiceId),
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
getFiscalStatus(invoiceId: string): Observable<IPosSaleInvoiceFiscalStatusResponse> {
|
||||
return this.http.get<IPosSaleInvoiceFiscalStatusResponse>(
|
||||
this.apiRoutes.fiscal.status(invoiceId),
|
||||
);
|
||||
return this.http.get<IPosSaleInvoiceFiscalStatusResponse>(this.apiRoutes.tsp.status(invoiceId));
|
||||
}
|
||||
|
||||
getInquiry(invoiceId: string): Observable<IPosSaleInvoiceFiscalStatusResponse> {
|
||||
return this.http.get<IPosSaleInvoiceFiscalStatusResponse>(
|
||||
this.apiRoutes.fiscal.getInquiry(invoiceId),
|
||||
this.apiRoutes.tsp.getInquiry(invoiceId),
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
revoke(invoiceId: string): Observable<IPosSaleInvoiceFiscalStatusResponse> {
|
||||
return this.http.post<IPosSaleInvoiceFiscalStatusResponse>(
|
||||
this.apiRoutes.fiscal.revoke(invoiceId),
|
||||
this.apiRoutes.tsp.revoke(invoiceId),
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
getFiscalAttempts(invoiceId: string): Observable<IPosSaleInvoiceFiscalAttemptsResponse> {
|
||||
return this.http.get<IPosSaleInvoiceFiscalAttemptsResponse>(
|
||||
this.apiRoutes.fiscal.attempts(invoiceId),
|
||||
this.apiRoutes.tsp.attempts(invoiceId),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<app-page-data-list
|
||||
pageTitle="لیست فعالیتهای اقتصادی"
|
||||
pageTitle="لیست فعالیت اقتصادی"
|
||||
[columns]="columns"
|
||||
emptyPlaceholderTitle="فعالیت اقتصادیای یافت نشد."
|
||||
[items]="items()"
|
||||
|
||||
@@ -14,7 +14,7 @@ export const superAdminConsumerBusinessActivitiesNamedRoutes: NamedRoutes<TBusin
|
||||
),
|
||||
// @ts-ignore
|
||||
meta: {
|
||||
title: 'فعالیتهای اقتصادی',
|
||||
title: 'فعالیت اقتصادی',
|
||||
pagePath: (consumerId: string) =>
|
||||
`/super_admin/consumers/${consumerId}/business_activities`,
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ export class ConsumersComponent extends AbstractList<IAdminConsumerResponse> {
|
||||
this.columns = [
|
||||
// { field: 'id', header: 'شناسه', type: 'id' },
|
||||
{ field: 'name', header: 'نام' },
|
||||
{ field: 'business_counts', header: 'تعداد فعالیتهای اقتصادی' },
|
||||
{ field: 'business_counts', header: 'تعداد فعالیت اقتصادی' },
|
||||
{
|
||||
field: 'partner',
|
||||
header: 'ایجاد شده توسط',
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<app-page-data-list
|
||||
[pageTitle]="'مدیریت دستهبندیهای کالا'"
|
||||
[pageTitle]="'مدیریت دستهبندی کالا'"
|
||||
[addNewCtaLabel]="'افزودن دستهبندی'"
|
||||
[columns]="columns"
|
||||
emptyPlaceholderTitle="دستهبندی یافت نشد"
|
||||
emptyPlaceholderDescription="برای افزودن دستهبندی، روی دکمهٔ بالا کلیک کنید."
|
||||
[items]="items()"
|
||||
[loading]="loading()"
|
||||
[showDetails]="true"
|
||||
[fullHeight]="fullHeight"
|
||||
[showAdd]="true"
|
||||
[showEdit]="true"
|
||||
[fullHeight]="fullHeight"
|
||||
[allItemsPageRoute]="allItemsPageRoute()"
|
||||
(onEdit)="onEditClick($event)"
|
||||
(onAdd)="openAddForm()"
|
||||
(onRefresh)="refresh()"
|
||||
|
||||
@@ -4,7 +4,8 @@ import {
|
||||
IColumn,
|
||||
PageDataListComponent,
|
||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { Component, computed, inject, Input } from '@angular/core';
|
||||
import { guildGoodCategoriesNamedRoutes } from '../../constants/routes/goodCategories';
|
||||
import { IGoodCategoriesResponse } from '../../models';
|
||||
import { GuildGoodCategoriesService } from '../../services/goodCategories.service';
|
||||
import { GuildGoodCategoryFormComponent } from './form.component';
|
||||
@@ -29,6 +30,10 @@ export class GuildGoodCategoriesListComponent extends AbstractList<IGoodCategori
|
||||
];
|
||||
service = inject(GuildGoodCategoriesService);
|
||||
|
||||
allItemsPageRoute = computed(() =>
|
||||
guildGoodCategoriesNamedRoutes.goodCategories.meta.pagePath!(this.guildId),
|
||||
);
|
||||
|
||||
override setColumns(): void {
|
||||
this.columns = this.header;
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ export type TGuildGoodCategoriesRouteNames = 'goodCategories';
|
||||
|
||||
export const guildGoodCategoriesNamedRoutes: NamedRoutes<TGuildGoodCategoriesRouteNames> = {
|
||||
goodCategories: {
|
||||
path: 'good_categories',
|
||||
path: 'good-categories',
|
||||
loadComponent: () =>
|
||||
import('../../views/categories/list.component').then((m) => m.GuildGoodCategoriesComponent),
|
||||
// @ts-ignore
|
||||
meta: {
|
||||
title: 'دستهبندیهای کالا',
|
||||
pagePath: (guildId: string) => `/super_admin/guilds/${guildId}/good-categories`,
|
||||
},
|
||||
},
|
||||
// goodCategory: {
|
||||
|
||||
@@ -39,26 +39,28 @@ export class GuildFormComponent extends AbstractFormDialog<IPartnerRequest, IPar
|
||||
private service = inject(PartnersService);
|
||||
|
||||
private initForm() {
|
||||
const form = this.fb.group({
|
||||
const formConfig = {
|
||||
name: fieldControl.name(this.initialValues?.name || ''),
|
||||
code: fieldControl.code(this.initialValues?.code || ''),
|
||||
username: fieldControl.username(),
|
||||
password: fieldControl.password(),
|
||||
confirmPassword: fieldControl.confirmPassword(),
|
||||
});
|
||||
username: [''],
|
||||
password: [''],
|
||||
confirmPassword: [''],
|
||||
};
|
||||
|
||||
if (!this.editMode) {
|
||||
form.controls.username.setValidators([Validators.required, usernameValidator()]);
|
||||
form.controls.username.updateValueAndValidity({ emitEvent: false });
|
||||
formConfig.username = fieldControl.username();
|
||||
formConfig.password = fieldControl.password();
|
||||
formConfig.confirmPassword = fieldControl.confirmPassword();
|
||||
}
|
||||
|
||||
const form = this.fb.group(formConfig);
|
||||
|
||||
if (!this.editMode) {
|
||||
// @ts-ignore
|
||||
form.controls['username'].setValidators([Validators.required, usernameValidator()]);
|
||||
// @ts-ignore
|
||||
form.controls['username'].updateValueAndValidity({ emitEvent: false });
|
||||
form.addValidators([MustMatch('password', 'confirmPassword')]);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
form.removeControl('username');
|
||||
// @ts-ignore
|
||||
form.removeControl('password');
|
||||
// @ts-ignore
|
||||
form.removeControl('confirmPassword');
|
||||
form.removeValidators([MustMatch('password', 'confirmPassword')]);
|
||||
}
|
||||
|
||||
return form;
|
||||
@@ -75,15 +77,18 @@ export class GuildFormComponent extends AbstractFormDialog<IPartnerRequest, IPar
|
||||
}
|
||||
|
||||
override ngOnChanges() {
|
||||
this.form.patchValue(this.initialValues ?? {});
|
||||
this.form = this.initForm();
|
||||
this.form.patchValue((this.initialValues ?? {}) as Partial<Record<string, unknown>>);
|
||||
if (this.editMode && !this.partnerId) {
|
||||
throw 'missing some arguments';
|
||||
}
|
||||
this.initForm();
|
||||
}
|
||||
|
||||
override submitForm(payload: IPartnerRequest) {
|
||||
const formData = buildFormData(this.form, { logo: this.logo() }, ['confirmPassword']);
|
||||
const skipFields = this.editMode
|
||||
? ['confirmPassword', 'username', 'password']
|
||||
: ['confirmPassword'];
|
||||
const formData = buildFormData(this.form, { logo: this.logo() }, skipFields);
|
||||
|
||||
if (this.editMode) {
|
||||
return this.service.update(this.partnerId!, formData);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { IEnumTranslate } from '@/shared/models/enum_translate.type';
|
||||
|
||||
export interface IPartnerRawResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
code: string;
|
||||
status: string;
|
||||
status: IEnumTranslate;
|
||||
created_at: string;
|
||||
logo_url: string;
|
||||
licenses_status: {
|
||||
|
||||
@@ -38,7 +38,15 @@ export class PartnersComponent extends AbstractList<IPartnerResponse> {
|
||||
header: 'تعداد لایسنس تمدیدی',
|
||||
customDataModel: this.licensesRenewStatus,
|
||||
},
|
||||
{ field: 'status', header: 'وضعیت' },
|
||||
{
|
||||
field: 'status',
|
||||
header: 'وضعیت',
|
||||
type: 'nested',
|
||||
variant: 'tag',
|
||||
nestedOption: {
|
||||
path: 'status.translate',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ export const superAdminUserAccountsNamedRoutes: NamedRoutes<TAccountsRouteNames>
|
||||
import('../../views/accounts/list.component').then((m) => m.UserAccountsComponent),
|
||||
// @ts-ignore
|
||||
meta: {
|
||||
title: 'فعالیتهای اقتصادی',
|
||||
title: 'فعالیت اقتصادی',
|
||||
pagePath: (userId: string) => `/super_admin/users/${userId}/accounts`,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@for (category of categories(); track category.id) {
|
||||
<div
|
||||
[class]="
|
||||
'h-10 rounded-lg px-3 flex items-center gap-3 border border-surface-border cursor-pointer bg-surface-100 hover:bg-surface-200 transition-all' +
|
||||
'h-10 rounded-lg px-3 flex items-center gap-3 border border-surface-border cursor-pointer bg-surface-100 hover:bg-surface-200 transition-all shrink-0' +
|
||||
(selectedCategory() === category.id ? ' bg-surface-card' : '')
|
||||
"
|
||||
(click)="changeSelectedCategory(category)"
|
||||
|
||||
@@ -237,8 +237,6 @@ export class InputComponent {
|
||||
value = this.applyFixed(value);
|
||||
}
|
||||
|
||||
console.log(value);
|
||||
|
||||
if (this.preparedMaxLength && value.length > this.preparedMaxLength) {
|
||||
value = value.slice(0, this.preparedMaxLength);
|
||||
}
|
||||
@@ -277,7 +275,6 @@ export class InputComponent {
|
||||
this.control.setValue(isIdentifierField ? value : value === '' ? '' : numericValue);
|
||||
|
||||
const viewValue = isPriceFormat && value !== '' ? numericValue.toLocaleString('en-US') : value;
|
||||
console.log('viewValue', viewValue);
|
||||
|
||||
target.value = viewValue;
|
||||
if (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="h-full overflow-auto">
|
||||
<div class="h-full overflow-auto border border-surface-border cardShadow">
|
||||
<div
|
||||
[ngClass]="{
|
||||
'px-4': captionBox,
|
||||
@@ -13,14 +13,14 @@
|
||||
}
|
||||
<div class="grid grid-cols-1 gap-3" [ngClass]="{ 'pt-4': captionBox }">
|
||||
@for (item of items; track `gridView_${$index}`) {
|
||||
<div class="card border border-surface-border bg-surface-50! mb-0! rounded-2xl p-4!">
|
||||
<div class="card border border-surface-border bg-surface-0! mb-0! rounded-2xl p-4!">
|
||||
<div class="listKeyValue">
|
||||
@for (col of columns; track `gridView_${col.field.toString()}_${$index}`) {
|
||||
@if (col.type !== "index") {
|
||||
<app-key-value [label]="col.header" [variant]="col.variant">
|
||||
@if (col.type === "thumbnail") {
|
||||
<div
|
||||
class="w-20 h-20 rounded-2xl overflow-hidden bg-surface-50 cursor-pointer"
|
||||
class="w-20 h-20 rounded-2xl overflow-hidden bg-surface-100 cursor-pointer"
|
||||
(click)="openThumbnailModal(item)"
|
||||
>
|
||||
@if (item && col?.field && item[col!.field!]) {
|
||||
@@ -46,16 +46,33 @@
|
||||
}
|
||||
</div>
|
||||
@if (showEdit || showDelete || showDetails) {
|
||||
<hr />
|
||||
<div class="flex justify-center gap-2 mt-2">
|
||||
<hr class="my-2" />
|
||||
<div class="flex justify-center gap-2 mt-4">
|
||||
@if (showEdit) {
|
||||
<p-button icon="pi pi-pencil" label="ویرایش" size="small" outlined (click)="edit(item)"> </p-button>
|
||||
<p-button
|
||||
icon="pi pi-pencil"
|
||||
label="ویرایش"
|
||||
size="small"
|
||||
outlined
|
||||
severity="secondary"
|
||||
(click)="edit(item)"
|
||||
>
|
||||
</p-button>
|
||||
}
|
||||
@if (showDelete) {
|
||||
<p-button icon="pi pi-trash" label="حذف" size="small" outlined (click)="remove(item)"> </p-button>
|
||||
<p-button icon="pi pi-trash" label="حذف" size="small" outlined severity="danger" (click)="remove(item)">
|
||||
</p-button>
|
||||
}
|
||||
@if (showDetails) {
|
||||
<p-button icon="pi pi-eye" label="مشاهده" size="small" outlined (click)="details(item)"> </p-button>
|
||||
<p-button
|
||||
icon="pi pi-eye"
|
||||
label="مشاهده"
|
||||
size="small"
|
||||
outlined
|
||||
severity="primary"
|
||||
(click)="details(item)"
|
||||
>
|
||||
</p-button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="h-full flex flex-col gap-4">
|
||||
<div class="h-full flex flex-col gap-4 cardShadow">
|
||||
<p-table
|
||||
[columns]="columns"
|
||||
[scrollable]="true"
|
||||
@@ -52,7 +52,7 @@
|
||||
<td>
|
||||
@if (col.type === "thumbnail") {
|
||||
<div
|
||||
class="w-20 h-20 rounded-2xl overflow-hidden bg-surface-50 cursor-pointer"
|
||||
class="w-20 h-20 rounded-2xl overflow-hidden bg-surface-100 cursor-pointer"
|
||||
(click)="openThumbnailModal(item)"
|
||||
>
|
||||
@if (item[col.field]) {
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
@if (showRefresh) {
|
||||
<p-button icon="pi pi-refresh" outlined size="small" (click)="refresh()"></p-button>
|
||||
}
|
||||
@if (showAll && allItemsPageRoute) {
|
||||
<a routerLink pButton [routerLink]="allItemsPageRoute" outlined size="small">نمایش همه</a>
|
||||
}
|
||||
@if (showAdd) {
|
||||
<p-button
|
||||
label="{{ addNewCtaLabel }}"
|
||||
@@ -113,15 +116,11 @@
|
||||
@if (showRefresh) {
|
||||
<p-button icon="pi pi-refresh" outlined size="small" (click)="refresh()"></p-button>
|
||||
}
|
||||
@if (showAll && allItemsPageRoute) {
|
||||
<a routerLink pButton [routerLink]="allItemsPageRoute" icon="pi pi-eye" outlined size="small"></a>
|
||||
}
|
||||
@if (showAdd) {
|
||||
<p-button
|
||||
label="{{ addNewCtaLabel }}"
|
||||
icon="pi pi-plus"
|
||||
size="small"
|
||||
class="max-sm:hidden"
|
||||
(click)="openAddForm()"
|
||||
></p-button>
|
||||
<p-button icon="pi pi-plus" size="small" class="sm:hidden" (click)="openAddForm()"></p-button>
|
||||
<p-button icon="pi pi-plus" size="small" (click)="openAddForm()"></p-button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
signal,
|
||||
TemplateRef,
|
||||
} from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { DrawerModule } from 'primeng/drawer';
|
||||
import { PaginatorModule } from 'primeng/paginator';
|
||||
@@ -85,6 +86,7 @@ export interface IColumn<T = any> {
|
||||
AppPageDataListTableView,
|
||||
AppPageDataListGridView,
|
||||
UikitEmptyStateComponent,
|
||||
RouterLink,
|
||||
],
|
||||
})
|
||||
export class PageDataListComponent<I = any> {
|
||||
@@ -117,6 +119,8 @@ export class PageDataListComponent<I = any> {
|
||||
@Input() expandColumns?: Maybe<IColumn[]> = null;
|
||||
@Input() dataKey?: string = 'items';
|
||||
@Input() showIndex?: boolean = true;
|
||||
@Input() showAll?: boolean = false;
|
||||
@Input() allItemsPageRoute?: string;
|
||||
|
||||
@ContentChild('filter', { static: true }) filter!: TemplateRef<any> | null;
|
||||
@ContentChild('caption', { static: true }) caption!: TemplateRef<any> | null;
|
||||
|
||||
@@ -42,7 +42,6 @@ export class SharedUploadFileComponent implements OnChanges, OnDestroy {
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.revokeObjectUrl();
|
||||
console.log('first');
|
||||
|
||||
if (this.initial_file_url && !this.objectUrl) {
|
||||
this.filePreview = this.initial_file_url;
|
||||
|
||||
@@ -5,3 +5,7 @@
|
||||
.listKeyValue {
|
||||
@apply grid md:grid-cols-3 sm:grid-cols-2 sm:gap-4 gap-3 items-center;
|
||||
}
|
||||
|
||||
.cardShadow {
|
||||
box-shadow: var(--p-card-shadow) !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user