set own datepicker and change فاکتور to صورتحساب
This commit is contained in:
+1
-6
@@ -190,8 +190,7 @@
|
||||
"allowedCommonJsDependencies": [
|
||||
"dayjs",
|
||||
"dayjs/locale/fa",
|
||||
"dayjs/plugin/relativeTime",
|
||||
"flatpickr-wrap/dist/l10n/fa.js"
|
||||
"dayjs/plugin/relativeTime"
|
||||
],
|
||||
"assets": [
|
||||
{
|
||||
@@ -209,8 +208,6 @@
|
||||
".webp": "file"
|
||||
},
|
||||
"styles": [
|
||||
"node_modules/flatpickr-wrap/dist/flatpickr.css",
|
||||
"node_modules/flatpickr-wrap/dist/themes/confetti.css",
|
||||
"src/assets/styles.scss"
|
||||
],
|
||||
"tsConfig": "tsconfig.app.json"
|
||||
@@ -252,8 +249,6 @@
|
||||
"inlineStyleLanguage": "scss",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"styles": [
|
||||
"node_modules/flatpickr-wrap/dist/flatpickr.css",
|
||||
"node_modules/flatpickr-wrap/dist/themes/confetti.css",
|
||||
"src/assets/styles.scss"
|
||||
],
|
||||
"tsConfig": "tsconfig.spec.json"
|
||||
|
||||
Generated
-12993
File diff suppressed because it is too large
Load Diff
@@ -12,12 +12,9 @@
|
||||
"@primeng/themes": "^20.4.0",
|
||||
"@primeuix/themes": "^1.2.5",
|
||||
"@tailwindcss/postcss": "^4.2.3",
|
||||
"@zoomit/dayjs-jalali-plugin": "^0.1.11",
|
||||
"angularx-qrcode": "20.0.0",
|
||||
"chart.js": "4.4.2",
|
||||
"dayjs": "^1.11.20",
|
||||
"flatpickr": "^4.6.13",
|
||||
"flatpickr-wrap": "^1.0.0",
|
||||
"jalaliday": "^3.1.1",
|
||||
"jest-editor-support": "32.0.0-beta.1",
|
||||
"ngx-cookie-service": "^21.3.1",
|
||||
|
||||
+9
-3
@@ -12,7 +12,7 @@ import {
|
||||
withInterceptors,
|
||||
withInterceptorsFromDi,
|
||||
} from '@angular/common/http';
|
||||
import { ApplicationConfig, isDevMode, provideZonelessChangeDetection } from '@angular/core';
|
||||
import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
|
||||
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
||||
import {
|
||||
provideRouter,
|
||||
@@ -34,7 +34,7 @@ export const appConfig: ApplicationConfig = {
|
||||
anchorScrolling: 'enabled',
|
||||
scrollPositionRestoration: 'enabled',
|
||||
}),
|
||||
withEnabledBlockingInitialNavigation(),
|
||||
withEnabledBlockingInitialNavigation()
|
||||
),
|
||||
provideZonelessChangeDetection(),
|
||||
// configure HttpClient once: enable fetch and register both functional
|
||||
@@ -42,6 +42,12 @@ export const appConfig: ApplicationConfig = {
|
||||
provideAnimationsAsync(),
|
||||
// ensure PrimeNG uses our preset (applies css variables at app initialization)
|
||||
providePrimeNG({
|
||||
zIndex: {
|
||||
tooltip: 2100,
|
||||
menu: 2000,
|
||||
overlay: 2000,
|
||||
modal: 1100,
|
||||
},
|
||||
theme: {
|
||||
preset: MyPreset,
|
||||
options: { darkModeSelector: '.app-dark' },
|
||||
@@ -72,7 +78,7 @@ export const appConfig: ApplicationConfig = {
|
||||
provideHttpClient(
|
||||
withFetch(),
|
||||
withInterceptors([loggingInterceptor, authInterceptor, errorInterceptor, dedupInterceptor]),
|
||||
withInterceptorsFromDi(),
|
||||
withInterceptorsFromDi()
|
||||
),
|
||||
// provideServiceWorker('ngsw-worker.js', {
|
||||
// enabled: !isDevMode(),
|
||||
|
||||
@@ -11,8 +11,6 @@ export function greaterThanValidator(minValue: number): ValidatorFn {
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log('v', v);
|
||||
|
||||
const numericValue = typeof v === 'number' ? v : Number(v);
|
||||
if (Number.isNaN(numericValue)) {
|
||||
return { greaterThan: 'مقدار باید عددی باشد' };
|
||||
|
||||
@@ -18,7 +18,7 @@ export const CONSUMER_MENU_ITEMS = [
|
||||
routerLink: ['/consumer/poses'],
|
||||
},
|
||||
{
|
||||
label: 'فاکتورها',
|
||||
label: 'صورتحسابها',
|
||||
icon: 'pi pi-fw pi-receipt',
|
||||
routerLink: ['/consumer/sale_invoices'],
|
||||
},
|
||||
|
||||
+3
-4
@@ -1,9 +1,8 @@
|
||||
<app-page-data-list
|
||||
pageTitle="لیست فاکتورها"
|
||||
pageTitle="لیست صورتحسابها"
|
||||
[columns]="columns"
|
||||
emptyPlaceholderTitle="تا به حال فاکتور فروشی توسط این پایانه ایجاد نشده است."
|
||||
emptyPlaceholderTitle="تا به حال صورتحسابی توسط این پایانه ایجاد نشده است."
|
||||
[items]="items()"
|
||||
[loading]="loading()"
|
||||
(onRefresh)="refresh()"
|
||||
>
|
||||
(onRefresh)="refresh()">
|
||||
</app-page-data-list>
|
||||
|
||||
+3
-4
@@ -1,10 +1,9 @@
|
||||
<app-page-data-list
|
||||
[pageTitle]="'لیست فاکتورها'"
|
||||
[pageTitle]="'لیست صورتحساب'"
|
||||
[columns]="columns"
|
||||
emptyPlaceholderTitle="فاکتوری یافت نشد"
|
||||
emptyPlaceholderTitle="صورتحسابی یافت نشد"
|
||||
[items]="items()"
|
||||
[loading]="loading()"
|
||||
[showDetails]="true"
|
||||
(onDetails)="toSinglePage($event)"
|
||||
(onRefresh)="refresh()"
|
||||
/>
|
||||
(onRefresh)="refresh()" />
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ export class ConsumerCustomerSaleInvoiceListComponent extends AbstractList<ICust
|
||||
},
|
||||
{
|
||||
field: 'invoice_date',
|
||||
header: 'تاریخ فاکتور',
|
||||
header: 'تاریخ صورتحساب',
|
||||
type: 'date',
|
||||
},
|
||||
{
|
||||
@@ -63,7 +63,7 @@ export class ConsumerCustomerSaleInvoiceListComponent extends AbstractList<ICust
|
||||
|
||||
toSinglePage(item: ICustomerSaleInvoicesResponse) {
|
||||
this.router.navigateByUrl(
|
||||
consumerCustomerSaleInvoicesNamedRoutes.saleInvoice.meta.pagePath!(this.customerId, item.id),
|
||||
consumerCustomerSaleInvoicesNamedRoutes.saleInvoice.meta.pagePath!(this.customerId, item.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ export const consumerCustomerSaleInvoicesNamedRoutes: NamedRoutes<TConsumerCusto
|
||||
path: 'saleInvoices',
|
||||
loadComponent: () =>
|
||||
import('../../views/saleInvoices/list.component').then(
|
||||
(m) => m.ConsumerCustomerSaleInvoicesComponent,
|
||||
(m) => m.ConsumerCustomerSaleInvoicesComponent
|
||||
),
|
||||
meta: {
|
||||
title: 'فاکتورهای صادر شده',
|
||||
title: 'صورتحسابهای صادر شده',
|
||||
pagePath: (customerId: string) => `consumer/customers/${customerId}`,
|
||||
},
|
||||
},
|
||||
@@ -20,10 +20,10 @@ export const consumerCustomerSaleInvoicesNamedRoutes: NamedRoutes<TConsumerCusto
|
||||
path: 'saleInvoices/:invoiceId',
|
||||
loadComponent: () =>
|
||||
import('../../views/saleInvoices/single.component').then(
|
||||
(m) => m.ConsumerCustomerSaleInvoiceComponent,
|
||||
(m) => m.ConsumerCustomerSaleInvoiceComponent
|
||||
),
|
||||
meta: {
|
||||
title: 'فاکتور صادر شده',
|
||||
title: 'صورتحساب صادر شده',
|
||||
pagePath: (customerId: string, saleInvoiceId: string) =>
|
||||
`consumer/customers/${customerId}/saleInvoices/${saleInvoiceId}`,
|
||||
},
|
||||
|
||||
+4
-5
@@ -1,15 +1,14 @@
|
||||
<app-page-data-list
|
||||
pageTitle="آخرین فاکتورهای صادر شده امروز"
|
||||
pageTitle="آخرین صورتحسابهای صادر شده امروز"
|
||||
[columns]="columns"
|
||||
emptyPlaceholderTitle="تا به این لحظه فاکتوری صادر نشده است."
|
||||
emptyPlaceholderTitle="تا به این لحظه صورتحسابی صادر نشده است."
|
||||
[items]="items()"
|
||||
[showDetails]="true"
|
||||
[loading]="loading()"
|
||||
(onDetails)="toSinglePage($event)"
|
||||
(onRefresh)="refresh()"
|
||||
>
|
||||
(onRefresh)="refresh()">
|
||||
<ng-template #moreActions>
|
||||
<a routerLink pButton [routerLink]="invoicesPageRoute" outlined>تمامی فاکتورها</a>
|
||||
<a routerLink pButton [routerLink]="invoicesPageRoute" outlined>تمامی صورتحسابها</a>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #status let-item>
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ export class ConsumerStatisticsLatestInvoicesComponent extends AbstractList<ISta
|
||||
},
|
||||
{
|
||||
field: 'invoice_date',
|
||||
header: 'تاریخ فاکتور',
|
||||
header: 'تاریخ صورتحساب',
|
||||
type: 'dateTime',
|
||||
},
|
||||
{ field: 'status', header: 'وضعیت صدور', customDataModel: this.status },
|
||||
@@ -58,7 +58,7 @@ export class ConsumerStatisticsLatestInvoicesComponent extends AbstractList<ISta
|
||||
|
||||
toSinglePage(invoice: IStatisticsSaleInvoicesResponse) {
|
||||
this.router.navigateByUrl(
|
||||
consumerSaleInvoicesNamedRoutes.saleInvoice.meta.pagePath!(invoice.id),
|
||||
consumerSaleInvoicesNamedRoutes.saleInvoice.meta.pagePath!(invoice.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<app-page-data-list
|
||||
[pageTitle]="'لیست فاکتورها'"
|
||||
[pageTitle]="'لیست صورتحسابها'"
|
||||
[columns]="columns"
|
||||
emptyPlaceholderTitle="فاکتوری یافت نشد"
|
||||
emptyPlaceholderTitle="صورتحسابی یافت نشد"
|
||||
[items]="items()"
|
||||
[loading]="loading()"
|
||||
[perPage]="responseMetaData()?.perPage"
|
||||
|
||||
@@ -9,7 +9,7 @@ export const consumerSaleInvoicesNamedRoutes: NamedRoutes<TConsumerSaleInvoicesR
|
||||
loadComponent: () =>
|
||||
import('../../views/list.component').then((m) => m.ConsumerSaleInvoicesComponent),
|
||||
meta: {
|
||||
title: 'فاکتورهای صادر شده',
|
||||
title: 'صورتحسابهای صادر شده',
|
||||
pagePath: () => `/consumer/sale_invoices`,
|
||||
},
|
||||
},
|
||||
@@ -18,7 +18,7 @@ export const consumerSaleInvoicesNamedRoutes: NamedRoutes<TConsumerSaleInvoicesR
|
||||
loadComponent: () =>
|
||||
import('../../views/single.component').then((m) => m.ConsumerSaleInvoiceComponent),
|
||||
meta: {
|
||||
title: 'فاکتور صادر شده',
|
||||
title: 'صورتحساب صادر شده',
|
||||
pagePath: (saleInvoiceId: string) => `/consumer/sale_invoices/${saleInvoiceId}`,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
[modal]="true"
|
||||
[style]="{ width: '500px' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
(onHide)="close()">
|
||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||
<uikit-datepicker
|
||||
<!-- <uikit-datepicker
|
||||
label="تاریخ شروع لایسنس"
|
||||
[control]="form.controls.starts_at"
|
||||
name="starts_at"
|
||||
hint="مدت زمان لایسنسها ۱ ساله هستند."
|
||||
/>
|
||||
/> -->
|
||||
<!-- <uikit-datepicker label="تاریخ انقضا لایسنس" [control]="form.controls.expires_at" name="expires_at" /> -->
|
||||
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
|
||||
</form>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
// import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
import { Component, computed, inject, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ILicenseRequest, ILicenseResponse } from '../../models';
|
||||
@@ -10,12 +10,7 @@ import { LicensesService } from '../../services/licenses.service';
|
||||
@Component({
|
||||
selector: 'partner-consumer-license-form',
|
||||
templateUrl: './form.component.html',
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
SharedDialogComponent,
|
||||
FormFooterActionsComponent,
|
||||
UikitFlatpickrJalaliComponent,
|
||||
],
|
||||
imports: [ReactiveFormsModule, SharedDialogComponent, FormFooterActionsComponent],
|
||||
})
|
||||
export class ConsumerLicenseFormComponent extends AbstractFormDialog<
|
||||
ILicenseRequest,
|
||||
|
||||
@@ -8,7 +8,7 @@ export const CONSUMER_MENU_ITEMS = [
|
||||
routerLink: ['/'],
|
||||
},
|
||||
{
|
||||
label: 'فاکتورها',
|
||||
label: 'صورتحسابها',
|
||||
icon: 'pi pi-fw pi-home',
|
||||
},
|
||||
],
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<pos-change-password-form class="w-full" />
|
||||
<app-card-data cardTitle="تنظیمات پرینت صورتحساب" class="w-full">
|
||||
<p-message variant="text" severity="info" icon="pi pi-info-circle">
|
||||
هریک از موارد زیر را که میخواهید در چاپ فاکتور نمایش داده شوند را انتخاب کنید
|
||||
هریک از موارد زیر را که میخواهید در چاپ صورتحساب نمایش داده شوند را انتخاب کنید
|
||||
</p-message>
|
||||
<pos-config-print-form class="mt-6 block w-full" (onClose)="returnToMainPage()" />
|
||||
</app-card-data>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[modal]="true"
|
||||
[dismissible]="true"
|
||||
[showCloseIcon]="true"
|
||||
header="فیلتر فاکتورها"
|
||||
header="فیلتر صورتحسابها"
|
||||
styleClass="w-full md:w-[28rem]"
|
||||
(visibleChange)="visibleChange.emit($event)">
|
||||
<div class="flex h-full flex-col overflow-y-auto">
|
||||
@@ -24,8 +24,8 @@
|
||||
<app-input label="شناسه اقتصادی" [control]="form.controls.customer_economic_code" name="customer_economic_code" />
|
||||
|
||||
<!-- <div class="grid grid-cols-2 gap-2">
|
||||
<uikit-datepicker label="از تاریخ فاکتور" [control]="form.controls.invoice_date_from" name="invoice_date_from" />
|
||||
<uikit-datepicker label="تا تاریخ فاکتور" [control]="form.controls.invoice_date_to" name="invoice_date_to" />
|
||||
<uikit-datepicker label="از تاریخ صورتحساب" [control]="form.controls.invoice_date_from" name="invoice_date_from" />
|
||||
<uikit-datepicker label="تا تاریخ صورتحساب" [control]="form.controls.invoice_date_to" name="invoice_date_to" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="bg-surface-card">
|
||||
<app-inner-pages-header pageTitle="لیست فاکتورهای صادر شده" [backRoute]="backRoute">
|
||||
<app-inner-pages-header pageTitle="لیست صورتحسابهای صادر شده" [backRoute]="backRoute">
|
||||
<ng-template #actions>
|
||||
<div class="flex gap-1">
|
||||
<p-button
|
||||
@@ -34,7 +34,7 @@
|
||||
}
|
||||
} @else if (!items() || items().length === 0) {
|
||||
<div class="col-span-1">
|
||||
<p class="text-muted-color text-center">فاکتوری یافت نشد.</p>
|
||||
<p class="text-muted-color text-center">صورتحسابی یافت نشد.</p>
|
||||
</div>
|
||||
} @else {
|
||||
@for (item of items(); track item.id) {
|
||||
|
||||
@@ -48,8 +48,8 @@ export class PosSaleInvoiceListComponent {
|
||||
filters = signal<IPosSaleInvoicesFilterDto>({});
|
||||
activeFilters = computed(() => {
|
||||
const labels: Partial<Record<keyof IPosSaleInvoicesFilterDto, string>> = {
|
||||
invoice_date_from: 'از تاریخ فاکتور',
|
||||
invoice_date_to: 'تا تاریخ فاکتور',
|
||||
invoice_date_from: 'از تاریخ صورتحساب',
|
||||
invoice_date_to: 'تا تاریخ صورتحساب',
|
||||
created_at_from: 'از تاریخ ایجاد',
|
||||
created_at_to: 'تا تاریخ ایجاد',
|
||||
invoice_number: 'شماره صورتحساب',
|
||||
|
||||
+3
-3
@@ -9,10 +9,10 @@
|
||||
{{ preparedInvoiceType() }}
|
||||
</app-key-value>
|
||||
<app-key-value alignment="end" label="مبلغ کل" [value]="saleInvoice.total_amount" type="price" />
|
||||
<app-key-value alignment="end" label="نوع فاکتور">
|
||||
<app-key-value alignment="end" label="نوع صورتحساب">
|
||||
<catalog-invoice-type-tag [status]="saleInvoice.type.value" />
|
||||
</app-key-value>
|
||||
<app-key-value alignment="end" label="تاریخ فاکتور" [value]="saleInvoice.created_at" type="dateTime" />
|
||||
<app-key-value alignment="end" label="تاریخ صورتحساب" [value]="saleInvoice.created_at" type="date" />
|
||||
</div>
|
||||
<hr />
|
||||
<div class="flex items-center justify-center gap-4">
|
||||
@@ -27,7 +27,7 @@
|
||||
}
|
||||
@if (saleInvoice.status.value.toLowerCase() === 'not_send') {
|
||||
<p-button
|
||||
label="ارسال فاکتور"
|
||||
label="ارسال صورتحساب"
|
||||
type="button"
|
||||
(click)="sendInvoice()"
|
||||
[loading]="sendingLoading()"
|
||||
|
||||
@@ -74,12 +74,12 @@ export class SaleInvoiceCardComponent {
|
||||
.subscribe((res) => {
|
||||
if (res.status === 'SEND_FAILURE') {
|
||||
this.toastService.error({
|
||||
text: res.message || 'خطا در ارسال فاکتور رخ داده است.',
|
||||
text: res.message || 'خطا در ارسال صورتحساب رخ داده است.',
|
||||
});
|
||||
} else {
|
||||
this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
|
||||
this.toastService.success({ text: 'ارسال صورتحساب با موفقیت انجام شد.' });
|
||||
}
|
||||
// this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
|
||||
// this.toastService.success({ text: 'ارسال صورتحساب با موفقیت انجام شد.' });
|
||||
this.refreshRequested.emit();
|
||||
});
|
||||
}
|
||||
@@ -91,7 +91,7 @@ export class SaleInvoiceCardComponent {
|
||||
.pipe(finalize(() => this.gettingStatusLoading.set(false)))
|
||||
.subscribe((res) => {
|
||||
this.toastService.info({
|
||||
text: `وضعیت فعلی فاکتور شمارهی ${this.saleInvoice.invoice_number}، ${taxProviderStatusTranslatorUtil(res.status)} میباشد.`,
|
||||
text: `وضعیت فعلی صورتحساب شمارهی ${this.saleInvoice.invoice_number}، ${taxProviderStatusTranslatorUtil(res.status)} میباشد.`,
|
||||
});
|
||||
this.refreshRequested.emit();
|
||||
});
|
||||
@@ -104,9 +104,11 @@ export class SaleInvoiceCardComponent {
|
||||
.pipe(finalize(() => this.resendingLoading.set(false)))
|
||||
.subscribe((res) => {
|
||||
if (res.status === 'FAILURE') {
|
||||
this.toastService.error({ text: res.message || 'خطا در ارسال مجدد فاکتور رخ داده است.' });
|
||||
this.toastService.error({
|
||||
text: res.message || 'خطا در ارسال مجدد صورتحساب رخ داده است.',
|
||||
});
|
||||
} else {
|
||||
this.toastService.success({ text: 'ارسال مجدد فاکتور با موفقیت انجام شد.' });
|
||||
this.toastService.success({ text: 'ارسال مجدد صورتحساب با موفقیت انجام شد.' });
|
||||
}
|
||||
this.refreshRequested.emit();
|
||||
});
|
||||
@@ -118,7 +120,7 @@ export class SaleInvoiceCardComponent {
|
||||
.revoke(this.saleInvoice.id)
|
||||
.pipe(finalize(() => this.revokingInvoiceLoading.set(false)))
|
||||
.subscribe(() => {
|
||||
this.toastService.success({ text: 'ابطال فاکتور با موفقیت انجام شد.' });
|
||||
this.toastService.success({ text: 'ابطال صورتحساب با موفقیت انجام شد.' });
|
||||
this.refreshRequested.emit();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export const posSaleInvoicesNamedRoutes: NamedRoutes<TPosSaleInvoicesRouteNames>
|
||||
loadComponent: () =>
|
||||
import('../../views/list.component').then((m) => m.PosSaleInvoicesComponent),
|
||||
meta: {
|
||||
title: 'فاکتورها',
|
||||
title: 'صورتحسابها',
|
||||
pagePath: () => baseRoute,
|
||||
},
|
||||
},
|
||||
@@ -21,7 +21,7 @@ export const posSaleInvoicesNamedRoutes: NamedRoutes<TPosSaleInvoicesRouteNames>
|
||||
loadComponent: () =>
|
||||
import('../../views/single.component').then((m) => m.PosSaleInvoiceComponent),
|
||||
meta: {
|
||||
title: 'جزئیات فاکتور',
|
||||
title: 'جزئیات صورتحساب',
|
||||
pagePath: (invoiceId: string) => `${baseRoute}/${invoiceId}`,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -41,10 +41,19 @@
|
||||
<hr />
|
||||
<div class="sticky bottom-0 flex flex-col gap-4 py-2">
|
||||
<p-card class="border-surface-border border">
|
||||
<div class="flex flex-col gap-4">
|
||||
<app-datepicker
|
||||
label="تاریخ صورتحساب"
|
||||
alignment="horizontal"
|
||||
[min]="invoiceMinDate"
|
||||
[max]="invoiceMaxDate"
|
||||
[control]="invoiceDate"
|
||||
(valueChange)="changeDate($event)" />
|
||||
<div class="flex shrink-0 items-center justify-between gap-2">
|
||||
<app-key-value label="مشتری" [value]="customerNameToShow()" />
|
||||
<button pButton outlined icon="pi pi-pencil" size="small" (click)="openCustomerDialog()"></button>
|
||||
</div>
|
||||
</div>
|
||||
</p-card>
|
||||
<pos-order-price-info-card />
|
||||
<button
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// import { CustomersSelectComponent } from '@/modules/customers/components/select/select.component';
|
||||
// import { ICustomerResponse } from '@/modules/customers/models';
|
||||
import { KeyValueComponent } from '@/shared/components';
|
||||
import { MiniMonthlyCalendarComponent } from '@/uikit';
|
||||
import { formatGregorian, gregorianAddUnit } from '@/utils';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
@@ -10,7 +12,7 @@ import {
|
||||
Output,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { FormControl, FormsModule } from '@angular/forms';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { Card } from 'primeng/card';
|
||||
import images from 'src/assets/images';
|
||||
@@ -33,6 +35,7 @@ import { POSOrderPriceInfoCardComponent } from './price-info-card.component';
|
||||
PosOrderCustomerDialogComponent,
|
||||
KeyValueComponent,
|
||||
Card,
|
||||
MiniMonthlyCalendarComponent,
|
||||
],
|
||||
})
|
||||
export class PosOrderSectionComponent {
|
||||
@@ -43,6 +46,10 @@ export class PosOrderSectionComponent {
|
||||
placeholderImage = images.placeholders.default;
|
||||
|
||||
isVisibleCustomerForm = signal(false);
|
||||
invoiceMinDate = formatGregorian(gregorianAddUnit(new Date(), -7, 'days'));
|
||||
invoiceMaxDate = formatGregorian(new Date());
|
||||
|
||||
invoiceDate = new FormControl(this.store.invoiceDate());
|
||||
|
||||
inOrderGoods = computed(() => this.store.inOrderGoods());
|
||||
customer = computed(() => this.store.customer());
|
||||
@@ -88,4 +95,8 @@ export class PosOrderSectionComponent {
|
||||
}
|
||||
|
||||
submitCustomer() {}
|
||||
|
||||
changeDate(date: string) {
|
||||
this.store.setInvoiceDate(date);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -9,12 +9,14 @@
|
||||
<qrcode [qrdata]="publicInvoiceRoute()" [width]="220" [errorCorrectionLevel]="'M'"></qrcode>
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="" class="pi pi-check-circle text-xl! text-green-700"></i>
|
||||
<p class="text-lg font-bold">فاکتور شما با موفقیت ایجاد شد.</p>
|
||||
<p class="text-lg font-bold">صورتحساب شما با موفقیت ایجاد شد.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center gap-2">
|
||||
<button pButton type="button" outlined (click)="printInvoice()">چاپ</button>
|
||||
<button pButton type="button" outlined (click)="sendInvoice()">ارسال به سامانه مودیان</button>
|
||||
<button pButton type="button" outlined [loading]="sendingLoading()" (click)="sendInvoice()">
|
||||
ارسال به سامانه مودیان
|
||||
</button>
|
||||
<button pButton type="button" outlined (click)="openOrderDetails()">جزئیات</button>
|
||||
</div>
|
||||
</shared-light-bottomsheet>
|
||||
|
||||
+2
-2
@@ -53,7 +53,7 @@ export class PosOrderSubmittedDialogComponent extends AbstractDialog {
|
||||
.sendToTsp(this.invoice.id)
|
||||
.pipe(finalize(() => this.sendingLoading.set(false)))
|
||||
.subscribe(() => {
|
||||
this.toastService.success({ text: 'ارسال فاکتور با موفقیت انجام شد.' });
|
||||
this.toastService.success({ text: 'ارسال صورتحساب با موفقیت انجام شد.' });
|
||||
this.sended.set(true);
|
||||
this.close();
|
||||
});
|
||||
@@ -65,7 +65,7 @@ export class PosOrderSubmittedDialogComponent extends AbstractDialog {
|
||||
title: `فروشگاه ${this.posName()}`,
|
||||
items: [
|
||||
{
|
||||
label: 'شماره فاکتور',
|
||||
label: 'شماره صورتحساب',
|
||||
value: this.invoice.code,
|
||||
},
|
||||
{ label: 'تاریخ', value: formatJalali(this.invoice.invoice_date, 'YYYY/MM/DD') },
|
||||
|
||||
@@ -287,7 +287,7 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
|
||||
if (this.selectedSettlementType() === 'CASH') {
|
||||
if (this.remainedAmount() > 0) {
|
||||
return this.toastServices.warn({
|
||||
text: 'فاکتور تسویه نشده است. لطفا مبلغ پرداخت را کامل کنید..',
|
||||
text: 'صورتحساب تسویه نشده است. لطفا مبلغ پرداخت را کامل کنید..',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { Maybe } from '@/core';
|
||||
// import { ICustomerResponse } from '@/modules/customers/models';
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { IGoodCategoryResponse, IGoodResponse } from '@/domains/pos/models/good.io';
|
||||
import { CustomerType } from '@/shared/localEnum/constants/customerTypes';
|
||||
import { createUUID, JALALI_DATE_FORMATS, nowJalali } from '@/utils';
|
||||
import {
|
||||
createUUID,
|
||||
formatDate,
|
||||
GREGORIAN_DATE_FORMATS,
|
||||
JALALI_DATE_FORMATS,
|
||||
nowGregorian,
|
||||
} from '@/utils';
|
||||
import { computed, inject, Injectable, signal } from '@angular/core';
|
||||
import { catchError, finalize, firstValueFrom, map, throwError } from 'rxjs';
|
||||
import { ICustomer, IPayment, IPosOrderRequest, IPosOrderResponse } from '../models';
|
||||
@@ -47,7 +52,7 @@ export const INITIAL_POS_STATE: IPosLandingState = {
|
||||
customerDetails: {
|
||||
type: CustomerType.UNKNOWN,
|
||||
},
|
||||
invoiceDate: nowJalali(JALALI_DATE_FORMATS.NUMERIC_WITH_FULL_TIME),
|
||||
invoiceDate: nowGregorian(JALALI_DATE_FORMATS.FULL),
|
||||
payments: {
|
||||
cash: 0,
|
||||
set_off: 0,
|
||||
@@ -59,7 +64,6 @@ export const INITIAL_POS_STATE: IPosLandingState = {
|
||||
@Injectable({ providedIn: 'any' })
|
||||
export class PosLandingStore {
|
||||
private readonly service = inject(PosService);
|
||||
private readonly toastServices = inject(ToastService);
|
||||
|
||||
private state$ = signal<IPosLandingState>({ ...INITIAL_POS_STATE });
|
||||
|
||||
@@ -249,6 +253,10 @@ export class PosLandingStore {
|
||||
this.setState({ customerDetails: customer });
|
||||
}
|
||||
|
||||
setInvoiceDate(invoiceDate: string) {
|
||||
this.setState({ invoiceDate });
|
||||
}
|
||||
|
||||
setPayment(payments: IPayment) {
|
||||
this.setState({ payments });
|
||||
}
|
||||
@@ -259,6 +267,7 @@ export class PosLandingStore {
|
||||
|
||||
submitOrder() {
|
||||
this.setState({ submitOrderLoading: true });
|
||||
|
||||
const orderPayload: IPosOrderRequest = {
|
||||
customer_id: this.customer().customer_id,
|
||||
customer_type: this.customer().type,
|
||||
@@ -268,7 +277,9 @@ export class PosLandingStore {
|
||||
good_id: good.id,
|
||||
measure_unit: good.measure_unit,
|
||||
})),
|
||||
invoice_date: new Date().toISOString(),
|
||||
invoice_date: new Date(
|
||||
formatDate(this.invoiceDate(), 'gregory', 'en', GREGORIAN_DATE_FORMATS.FULL)
|
||||
).toISOString(),
|
||||
payments: this.payments(),
|
||||
settlement_type: this.state$().settlement_type,
|
||||
total_amount: this.orderPricingInfo().totalAmount,
|
||||
@@ -295,7 +306,7 @@ export class PosLandingStore {
|
||||
customerDetails: {
|
||||
type: CustomerType.UNKNOWN,
|
||||
},
|
||||
invoiceDate: nowJalali(JALALI_DATE_FORMATS.NUMERIC),
|
||||
invoiceDate: _res.invoice_date,
|
||||
payments: {
|
||||
cash: 0,
|
||||
set_off: 0,
|
||||
|
||||
@@ -23,17 +23,17 @@
|
||||
<!-- [style.paddingBottom]="'calc(0.75rem + {{env(safe-area-inset-bottom)}})'" -->
|
||||
<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-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>
|
||||
<span class="text-base font-medium">مشاهده صورتحساب</span>
|
||||
<i class="pi pi-chevron-up"></i>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
}
|
||||
<shared-light-bottomsheet [(visible)]="showInvoiceBottomSheet" [closable]="true" header="جزییات فاکتور">
|
||||
<shared-light-bottomsheet [(visible)]="showInvoiceBottomSheet" [closable]="true" header="جزییات صورتحساب">
|
||||
<pos-order-section (onAddMoreGoods)="closeInvoiceBottomSheet()" (onSubmit)="submitOrder()" />
|
||||
</shared-light-bottomsheet>
|
||||
|
||||
|
||||
+3
-4
@@ -4,15 +4,14 @@
|
||||
[modal]="true"
|
||||
[style]="{ width: '500px' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
(onHide)="close()">
|
||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||
<uikit-datepicker
|
||||
<!-- <uikit-datepicker
|
||||
label="تاریخ شروع لایسنس"
|
||||
[control]="form.controls.starts_at"
|
||||
name="starts_at"
|
||||
hint="مدت زمان لایسنسها ۱ ساله هستند."
|
||||
/>
|
||||
/> -->
|
||||
<!-- <uikit-datepicker label="تاریخ انقضا لایسنس" [control]="form.controls.expires_at" name="expires_at" /> -->
|
||||
<app-partner-select label="شریک تجاری" [control]="form.controls.partner_id" [showClear]="true" />
|
||||
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
// import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
import { Component, computed, inject, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { PartnerSelectComponent } from '../../../partners/shared/select.component';
|
||||
@@ -15,7 +15,7 @@ import { LicensesService } from '../../services/licenses.service';
|
||||
ReactiveFormsModule,
|
||||
SharedDialogComponent,
|
||||
FormFooterActionsComponent,
|
||||
UikitFlatpickrJalaliComponent,
|
||||
// UikitFlatpickrJalaliComponent,
|
||||
PartnerSelectComponent,
|
||||
],
|
||||
})
|
||||
|
||||
+3
-4
@@ -4,16 +4,15 @@
|
||||
[modal]="true"
|
||||
[style]="{ width: '300px' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
(onHide)="close()">
|
||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||
<app-input label="تعداد شارژ" [control]="form.controls.quantity" type="number" />
|
||||
<uikit-datepicker
|
||||
<!-- <uikit-datepicker
|
||||
label="انقضای فروش"
|
||||
[control]="form.controls.activated_expires_at"
|
||||
name="activated_expires_at"
|
||||
[minDate]="minDate"
|
||||
/>
|
||||
/> -->
|
||||
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
|
||||
</form>
|
||||
</shared-dialog>
|
||||
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
||||
import { InputComponent } from '@/shared/components';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
// import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { nowJalali } from '@/utils';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { IPartnerChargeLicenseTransactionRequest } from '../models/chargeLicenseTransactions_io';
|
||||
import { AdminPartnerChargeLicenseTransactionsService } from '../services/chargeLicenseTransactions.service';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'partner-charge-license-form-dialog',
|
||||
@@ -17,7 +17,7 @@ import { SharedDialogComponent } from '@/shared/components/dialog/dialog.compone
|
||||
ReactiveFormsModule,
|
||||
InputComponent,
|
||||
FormFooterActionsComponent,
|
||||
UikitFlatpickrJalaliComponent,
|
||||
// UikitFlatpickrJalaliComponent,
|
||||
],
|
||||
})
|
||||
export class PartnerChargeLicenseFormDialogComponent extends AbstractFormDialog<
|
||||
|
||||
+3
-4
@@ -4,16 +4,15 @@
|
||||
[modal]="true"
|
||||
[style]="{ width: '300px' }"
|
||||
[closable]="true"
|
||||
(onHide)="close()"
|
||||
>
|
||||
(onHide)="close()">
|
||||
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
|
||||
<app-input label="تعداد شارژ" [control]="form.controls.quantity" type="number" />
|
||||
<uikit-datepicker
|
||||
<!-- <uikit-datepicker
|
||||
label="انقضای فروش"
|
||||
[control]="form.controls.activated_expires_at"
|
||||
name="activated_expires_at"
|
||||
[minDate]="minDate"
|
||||
/>
|
||||
/> -->
|
||||
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
|
||||
</form>
|
||||
</shared-dialog>
|
||||
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
import { AbstractFormDialog } from '@/shared/abstractClasses';
|
||||
import { InputComponent } from '@/shared/components';
|
||||
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
|
||||
import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
// import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
import { nowJalali } from '@/utils';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { IAdminPartnerChargeAccountRequest } from '../../models/chargeAccount_io';
|
||||
import { AdminPartnerChargeAccountService } from '../../services/chargeAccount.service';
|
||||
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'admin-partner-charge-account-form-dialog',
|
||||
@@ -17,7 +17,7 @@ import { SharedDialogComponent } from '@/shared/components/dialog/dialog.compone
|
||||
ReactiveFormsModule,
|
||||
InputComponent,
|
||||
FormFooterActionsComponent,
|
||||
UikitFlatpickrJalaliComponent,
|
||||
// UikitFlatpickrJalaliComponent,
|
||||
],
|
||||
})
|
||||
export class AdminPartnerChargeAccountFormDialogComponent extends AbstractFormDialog<
|
||||
|
||||
@@ -9,7 +9,7 @@ export const publicSaleInvoicesNamedRoutes: NamedRoutes<TPublicSaleInvoicesRoute
|
||||
loadComponent: () =>
|
||||
import('../../views/single.component').then((m) => m.PublicSaleInvoiceComponent),
|
||||
meta: {
|
||||
title: 'جزئیات فاکتور',
|
||||
title: 'جزئیات صورتحساب',
|
||||
pagePath: (invoiceId: string) => `sale-invoices/${invoiceId}`,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@ import { InputComponent } from '../input/input.component';
|
||||
@Component({
|
||||
selector: 'field-invoice-number-sequence',
|
||||
template: `<app-input
|
||||
label="شروع شماره فاکتور"
|
||||
label="شروع شماره صورتحساب"
|
||||
[control]="control"
|
||||
[name]="name"
|
||||
type="number"
|
||||
|
||||
@@ -15,5 +15,5 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
export class FieldInvoiceTemplatesComponent {
|
||||
@Input({ required: true }) control = new FormControl<string>('');
|
||||
@Input() name = 'invoice-template';
|
||||
@Input() label = 'قالب فاکتور';
|
||||
@Input() label = 'قالب صورتحساب';
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'field-license-starts-at',
|
||||
template: `<uikit-datepicker
|
||||
label="تاریخ شروع لایسنس"
|
||||
[control]="control"
|
||||
[name]="name"
|
||||
hint="مدت زمان لایسنسها ۱ ساله هستند."
|
||||
/>`,
|
||||
imports: [ReactiveFormsModule, UikitFlatpickrJalaliComponent],
|
||||
// template: `<uikit-datepicker
|
||||
// label="تاریخ شروع لایسنس"
|
||||
// [control]="control"
|
||||
// [name]="name"
|
||||
// hint="مدت زمان لایسنسها ۱ ساله هستند."
|
||||
// />`,
|
||||
template: '',
|
||||
imports: [ReactiveFormsModule],
|
||||
})
|
||||
export class LicenseStartsAtComponent {
|
||||
@Input({ required: true }) control = new FormControl<string>('');
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<uikit-empty-state> </uikit-empty-state>
|
||||
} @else {
|
||||
<div class="flex flex-col gap-6">
|
||||
<app-card-data cardTitle="اطلاعات فاکتور" [editable]="false" [backRoute]="backRoute">
|
||||
<app-card-data cardTitle="اطلاعات صورتحساب" [editable]="false" [backRoute]="backRoute">
|
||||
<ng-template #moreActions>
|
||||
<div class="">
|
||||
<p-menu #menu [model]="moreActionMenuItems()" [popup]="true" appendTo="body" />
|
||||
@@ -14,8 +14,8 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="listKeyValue">
|
||||
<app-key-value label="شماره صورتحساب" [value]="invoice.invoice_number" />
|
||||
<app-key-value label="تاریخ فاکتور" [value]="invoice.invoice_date" type="dateTime" />
|
||||
<app-key-value label="تاریخ ایجاد فاکتور" [value]="invoice.created_at" type="dateTime" />
|
||||
<app-key-value label="تاریخ صورتحساب" [value]="invoice.invoice_date" type="date" />
|
||||
<app-key-value label="تاریخ ایجاد صورتحساب" [value]="invoice.created_at" type="dateTime" />
|
||||
<app-key-value label="نوع صورتحساب">
|
||||
<catalog-invoice-type-tag [status]="invoice.type.value" />
|
||||
</app-key-value>
|
||||
|
||||
@@ -86,18 +86,15 @@ export class SharedSaleInvoiceSingleViewComponent {
|
||||
|
||||
showErrors() {}
|
||||
showRevokeConfirmation() {
|
||||
console.log('this.confirmationService', this.confirmationService);
|
||||
|
||||
this.confirmationService.ask({
|
||||
header: `ابطال فاکتور شماره ${this.invoice!.invoice_number}`,
|
||||
message: `در صورت تایید ابطال فاکتور شماره ${this.invoice!.invoice_number} بر روی دکمهی ابطال کلیک کنید.`,
|
||||
header: `ابطال صورتحساب شماره ${this.invoice!.invoice_number}`,
|
||||
message: `در صورت تایید ابطال صورتحساب شماره ${this.invoice!.invoice_number} بر روی دکمهی ابطال کلیک کنید.`,
|
||||
acceptLabel: 'ابطال',
|
||||
acceptButtonProps: {
|
||||
severity: 'dangerdock',
|
||||
},
|
||||
|
||||
accept: () => {
|
||||
console.log('here');
|
||||
// this.deferredInstallPrompt.prompt();
|
||||
// this.deferredInstallPrompt.userChoice.finally(() => {
|
||||
// this.deferredInstallPrompt = null;
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
// showConfirm() {
|
||||
// this.confirmService.confirm({
|
||||
// message: 'آیا پرداخت فاکتور انجام شده است؟',
|
||||
// header: 'وضعیت پرداخت فاکتور',
|
||||
// message: 'آیا پرداخت صورتحساب انجام شده است؟',
|
||||
// header: 'وضعیت پرداخت صورتحساب',
|
||||
// acceptLabel: 'بله',
|
||||
// rejectLabel: 'خیر',
|
||||
// accept: () => {
|
||||
@@ -35,8 +35,8 @@
|
||||
// },
|
||||
// reject: () => {
|
||||
// this.toastService.info({
|
||||
// text: 'میتوانید از طریق منوی پرداخت فاکتور، در آینده اقدام به پرداخت نمایید.',
|
||||
// title: 'پرداخت فاکتور انجام نشد',
|
||||
// text: 'میتوانید از طریق منوی پرداخت صورتحساب، در آینده اقدام به پرداخت نمایید.',
|
||||
// title: 'پرداخت صورتحساب انجام نشد',
|
||||
// });
|
||||
// },
|
||||
// });
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { IListConfig } from './list-config.model';
|
||||
|
||||
export const saleInvoiceListConfig: IListConfig = {
|
||||
pageTitle: 'مدیریت فاکتورهای فروش',
|
||||
addNewCtaLabel: 'افزودن فاکتور',
|
||||
emptyPlaceholderTitle: 'فاکتوری یافت نشد',
|
||||
emptyPlaceholderDescription: 'برای افزودن فاکتور، روی دکمهٔ بالا کلیک کنید.',
|
||||
pageTitle: 'مدیریت صورتحسابهای فروش',
|
||||
addNewCtaLabel: 'افزودن صورتحساب',
|
||||
emptyPlaceholderTitle: 'صورتحسابی یافت نشد',
|
||||
emptyPlaceholderDescription: 'برای افزودن صورتحساب، روی دکمهٔ بالا کلیک کنید.',
|
||||
columns: [
|
||||
{ field: 'code', header: 'کد رهگیری' },
|
||||
{
|
||||
@@ -27,7 +27,7 @@ export const saleInvoiceListConfig: IListConfig = {
|
||||
},
|
||||
{
|
||||
field: 'invoice_date',
|
||||
header: 'تاریخ فاکتور',
|
||||
header: 'تاریخ صورتحساب',
|
||||
type: 'date',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,7 +1,58 @@
|
||||
<div #wrapper [attr.data-name]="name" class="flatWrapper w-full">
|
||||
<input data-input [attr.placeholder]="placeholder" [name]="name" class="flatpicker-field w-full" />
|
||||
<uikit-field [label]="label!" [name]="name!" [alignment]="alignment" class="w-full" (click)="op.toggle($event)">
|
||||
<input pInputText readonly [name]="name" [value]="valueToShow" class="w-full" />
|
||||
</uikit-field>
|
||||
<p-popover #op appendTo="body">
|
||||
<div #wrapperRef class="dir-rtl border-divider bg-background-paper w-full min-w-xs overflow-auto rounded-md">
|
||||
<div class="bg-primary-main sticky top-0 flex justify-center px-3">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex h-8 items-center">
|
||||
<div class="px-2">
|
||||
<i class="pi pi-chevron-right cursor-pointer" (click)="changeMonth(-1)"></i>
|
||||
</div>
|
||||
|
||||
@if (hint) {
|
||||
<small [attr.id]="name + '-help'">{{ hint }}</small>
|
||||
<div class="flex w-32 items-center justify-center px-3 font-bold select-none">
|
||||
{{ monthInfo().monthTitle }}
|
||||
</div>
|
||||
|
||||
<div class="px-2">
|
||||
<i class="pi pi-chevron-left cursor-pointer" (click)="changeMonth(1)"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-7">
|
||||
@for (dayName of daysName; track $index) {
|
||||
<div class="text-muted-color flex items-center justify-center py-2">
|
||||
{{ dayName[0] }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<div class="relative grow" style="direction: rtl">
|
||||
@for (weekDays of weekDaysDates(); track $index) {
|
||||
<div class="grid grid-cols-7">
|
||||
@for (day of weekDays; track $index) {
|
||||
<div
|
||||
class="relative flex aspect-square items-center justify-center p-1"
|
||||
[class.bg-background-default]="closedDays.includes($index)">
|
||||
@if (!(day.isNextMonth || day.isPastMonth)) {
|
||||
<span
|
||||
class="flex aspect-square w-full cursor-pointer items-center justify-center rounded px-2 py-1 transition-colors select-none"
|
||||
[ngClass]="{
|
||||
'bg-surface-ground font-bold': day.isCurrentDay,
|
||||
'bg-primary! text-primary-contrast!': isSelected(day),
|
||||
'text-muted-color! font-normal': day.isDisabled,
|
||||
}"
|
||||
(click)="selectDate(day)">
|
||||
{{ day.day }}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</p-popover>
|
||||
|
||||
@@ -1,75 +1,170 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { nowJalali } from '@/utils';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Component, EventEmitter, Input, Output, ViewChild, computed, signal } from '@angular/core';
|
||||
|
||||
import { FormControl } from '@angular/forms';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import flatpickr from 'flatpickr-wrap';
|
||||
import { Persian } from 'flatpickr-wrap/dist/l10n/fa';
|
||||
import { BaseOptions, DateOption } from 'flatpickr-wrap/dist/types/options';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import jalaliday from 'jalaliday';
|
||||
|
||||
import { Maybe } from '@/core';
|
||||
import { formatJalali } from '@/utils';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { InputText } from 'primeng/inputtext';
|
||||
import { Popover } from 'primeng/popover';
|
||||
import { UikitFieldComponent } from '../uikit-field.component';
|
||||
import {
|
||||
MonthInfo,
|
||||
MonthlyWeekDate,
|
||||
daysName,
|
||||
prepareMonthInfo,
|
||||
prepareWeekDayDates,
|
||||
} from './monthly-calendar.helper.util';
|
||||
|
||||
dayjs.extend(jalaliday);
|
||||
|
||||
@Component({
|
||||
selector: 'uikit-datepicker',
|
||||
selector: 'app-datepicker',
|
||||
standalone: true,
|
||||
imports: [CommonModule, ReactiveFormsModule, InputTextModule, UikitFieldComponent],
|
||||
templateUrl: './datepicker.component.html',
|
||||
imports: [Popover, UikitFieldComponent, InputText, CommonModule],
|
||||
})
|
||||
export class UikitFlatpickrJalaliComponent implements AfterViewInit, OnDestroy {
|
||||
@Input() control?: FormControl<Maybe<string>>;
|
||||
@Input() placeholder = 'انتخاب تاریخ';
|
||||
@Input() label = 'تاریخ';
|
||||
@Input() disabled = false;
|
||||
@Input() name: string = 'datepicker';
|
||||
@Input() options: Partial<BaseOptions> = {};
|
||||
@Input() showLabel: boolean = true;
|
||||
@Input() showErrors: boolean = true;
|
||||
@Input() hint?: string;
|
||||
@Input() minDate?: DateOption;
|
||||
@Input() maxDate?: DateOption;
|
||||
export class MiniMonthlyCalendarComponent {
|
||||
@Input() control!: FormControl<Maybe<string>>;
|
||||
@Input() alignment?: 'vertical' | 'horizontal' = 'vertical';
|
||||
@Input() name?: string = 'date';
|
||||
@Input() label?: string = 'تاریخ';
|
||||
@Input() closeOnSelect?: boolean = true;
|
||||
@Input() min?: string;
|
||||
@Input() max?: string;
|
||||
@Input() closedDays: number[] = [];
|
||||
|
||||
@Output() clickOnDayEvent = new EventEmitter<MonthlyWeekDate>();
|
||||
@Output() valueChange = new EventEmitter<string>();
|
||||
|
||||
@ViewChild('wrapper', { static: true }) wrapperRef!: ElementRef<HTMLElement>;
|
||||
@ViewChild('op') op!: Popover;
|
||||
|
||||
private fpInstance: any | null = null;
|
||||
readonly daysName = daysName;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.fpInstance = flatpickr(this.wrapperRef.nativeElement, {
|
||||
wrap: true,
|
||||
...this.options,
|
||||
locale: Persian,
|
||||
disableMobile: true,
|
||||
clickOpens: !this.disabled,
|
||||
minDate: this.minDate,
|
||||
maxDate: this.maxDate,
|
||||
now: nowJalali(),
|
||||
altInputClass: 'flatpicker-field w-full',
|
||||
altInput: true,
|
||||
dateFormat: 'Y-m-d',
|
||||
altFormat: 'Y/m/d',
|
||||
/**
|
||||
* Current displayed month
|
||||
* Gregorian YYYY-MM-DD
|
||||
*/
|
||||
private readonly activeDateSignal = signal(dayjs().format('YYYY-MM-DD'));
|
||||
|
||||
onChange: (selectedDates: Date[], dateStr: string) => {
|
||||
this.valueChange.emit(dateStr);
|
||||
if (this.control) this.control.setValue(dayjs(dateStr).toISOString());
|
||||
},
|
||||
});
|
||||
/**
|
||||
* Selected value
|
||||
* Gregorian YYYY-MM-DD
|
||||
*/
|
||||
private readonly selectedDateSignal = signal<Maybe<string>>(null);
|
||||
|
||||
disabled = false;
|
||||
|
||||
monthInfo = computed<MonthInfo>(() => prepareMonthInfo(this.activeDateSignal()));
|
||||
|
||||
weekDaysDates = computed(() => prepareWeekDayDates(this.monthInfo(), this.min, this.max));
|
||||
|
||||
// -----------------------
|
||||
// Getters
|
||||
// -----------------------
|
||||
|
||||
get value(): Maybe<string> {
|
||||
return this.selectedDateSignal();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.fpInstance?.destroy) {
|
||||
this.fpInstance.destroy();
|
||||
this.fpInstance = null;
|
||||
get valueToShow(): Maybe<string> {
|
||||
return this.selectedDateSignal() && formatJalali(this.selectedDateSignal()!);
|
||||
}
|
||||
|
||||
get activeDate(): string {
|
||||
return this.activeDateSignal();
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
// Setters
|
||||
// -----------------------
|
||||
|
||||
set value(date: Maybe<string>) {
|
||||
this.selectedDateSignal.set(date);
|
||||
this.control.setValue(date);
|
||||
|
||||
if (date) {
|
||||
this.activeDateSignal.set(date);
|
||||
}
|
||||
}
|
||||
|
||||
set activeDate(date: string) {
|
||||
this.activeDateSignal.set(date);
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
// Navigation
|
||||
// -----------------------
|
||||
|
||||
changeMonth(months: number): void {
|
||||
const newDate = dayjs(this.activeDateSignal()).add(months, 'month').format('YYYY-MM-DD');
|
||||
|
||||
this.activeDateSignal.set(newDate);
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
// Selection
|
||||
// -----------------------
|
||||
|
||||
selectDate(day: MonthlyWeekDate): void {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (day.isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.value = day.gregorianDate;
|
||||
|
||||
this.onChange(day.gregorianDate);
|
||||
|
||||
this.onTouched();
|
||||
|
||||
if (this.closeOnSelect) {
|
||||
this.op.toggle(false);
|
||||
}
|
||||
|
||||
this.clickOnDayEvent.emit(day);
|
||||
this.valueChange.emit(day.gregorianDate);
|
||||
}
|
||||
|
||||
isSelected(day: MonthlyWeekDate): boolean {
|
||||
return !!this.value && this.value === day.gregorianDate;
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
// CVA
|
||||
// -----------------------
|
||||
|
||||
private onChange: (value: Maybe<string>) => void = () => {};
|
||||
|
||||
private onTouched: () => void = () => {};
|
||||
|
||||
writeValue(value: Maybe<string>): void {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
registerOnChange(fn: (value: Maybe<string>) => void): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: () => void): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled;
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
// Helpers
|
||||
// -----------------------
|
||||
|
||||
trackByIndex(index: number): number {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import jalaliday from 'jalaliday';
|
||||
|
||||
dayjs.extend(jalaliday);
|
||||
|
||||
export interface MonthInfo {
|
||||
isCurrentMonth: boolean;
|
||||
firstDateOfMonth: dayjs.Dayjs;
|
||||
lastDateOfMonth: dayjs.Dayjs;
|
||||
monthDaysCount: number;
|
||||
firstDayOfMonth: number;
|
||||
jalaliFirstDayOfMonth: number;
|
||||
monthTitle: string;
|
||||
monthIndex: number;
|
||||
prevMonthIsDisabled: boolean;
|
||||
nextMonthIsDisabled: boolean;
|
||||
isDisabled: boolean;
|
||||
}
|
||||
|
||||
export interface MonthlyWeekDate {
|
||||
gregorianDate: string;
|
||||
date: string;
|
||||
isNextMonth: boolean;
|
||||
isPastMonth: boolean;
|
||||
isCurrentDay: boolean;
|
||||
isPastDate: boolean;
|
||||
isFutureDate: boolean;
|
||||
dayText: string;
|
||||
day: number;
|
||||
isHoliday: boolean;
|
||||
isDisabled: boolean;
|
||||
}
|
||||
|
||||
export const daysName = ['شنبه', 'یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'];
|
||||
|
||||
export function prepareMonthInfo(activeDate: string | Date, min?: string, max?: string): MonthInfo {
|
||||
const date = dayjs(activeDate).calendar('jalali');
|
||||
|
||||
const firstDayOfMonth = date.startOf('month').day();
|
||||
|
||||
return {
|
||||
isCurrentMonth: dayjs().calendar('jalali').isSame(date, 'month'),
|
||||
|
||||
firstDateOfMonth: date.startOf('month'),
|
||||
|
||||
lastDateOfMonth: date.endOf('month'),
|
||||
|
||||
monthDaysCount: date.daysInMonth(),
|
||||
|
||||
firstDayOfMonth,
|
||||
|
||||
jalaliFirstDayOfMonth: firstDayOfMonth === 6 ? 0 : firstDayOfMonth + 1,
|
||||
|
||||
monthTitle: date.locale('fa').format('MMMM YYYY'),
|
||||
|
||||
monthIndex: date.get('month'),
|
||||
|
||||
isDisabled: false,
|
||||
nextMonthIsDisabled: false,
|
||||
prevMonthIsDisabled: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function prepareWeekDayDates(
|
||||
monthInfo: MonthInfo,
|
||||
min?: string,
|
||||
max?: string
|
||||
): MonthlyWeekDate[][] {
|
||||
const weekDaysDates: MonthlyWeekDate[][] = [];
|
||||
|
||||
const { monthDaysCount, firstDateOfMonth } = monthInfo;
|
||||
|
||||
for (let i = 0; i < monthDaysCount; i++) {
|
||||
const date = firstDateOfMonth.add(i, 'day');
|
||||
|
||||
const dateDay = date.day();
|
||||
|
||||
const persianDateDay = dateDay === 6 ? 0 : dateDay + 1;
|
||||
|
||||
if (i === 0 || persianDateDay === 0) {
|
||||
weekDaysDates.push(new Array(7) as MonthlyWeekDate[]);
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
for (let j = 0; j < persianDateDay; j++) {
|
||||
weekDaysDates[0][j] = weekDateFactory(
|
||||
date.add(-persianDateDay + j, 'day'),
|
||||
monthInfo,
|
||||
min,
|
||||
max
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
weekDaysDates[weekDaysDates.length - 1][persianDateDay] = weekDateFactory(
|
||||
date,
|
||||
monthInfo,
|
||||
min,
|
||||
max
|
||||
);
|
||||
|
||||
if (i === monthDaysCount - 1) {
|
||||
for (let j = persianDateDay + 1; j < 7; j++) {
|
||||
weekDaysDates[weekDaysDates.length - 1][j] = weekDateFactory(
|
||||
date.add(j - persianDateDay, 'day'),
|
||||
monthInfo,
|
||||
min,
|
||||
max
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return weekDaysDates;
|
||||
}
|
||||
|
||||
function weekDateFactory(
|
||||
date: dayjs.Dayjs,
|
||||
monthInfo: MonthInfo,
|
||||
min?: string,
|
||||
max?: string
|
||||
): MonthlyWeekDate {
|
||||
const now = dayjs().calendar('jalali');
|
||||
|
||||
const formattedDate = date.format('YYYY-MM-DD');
|
||||
|
||||
return {
|
||||
gregorianDate: date.calendar('gregory').format('YYYY-MM-DD'),
|
||||
|
||||
date: formattedDate,
|
||||
|
||||
isNextMonth: date.month() > monthInfo.monthIndex,
|
||||
|
||||
isPastMonth: date.month() < monthInfo.monthIndex,
|
||||
|
||||
isCurrentDay: now.isSame(date, 'day'),
|
||||
|
||||
isPastDate: date.isBefore(now, 'day'),
|
||||
|
||||
isFutureDate: now.isBefore(date, 'day'),
|
||||
|
||||
dayText: date.locale('fa').format('D MMMM'),
|
||||
|
||||
day: Number(date.locale('fa').format('D')),
|
||||
|
||||
isDisabled: isDisabledDate(date, min, max),
|
||||
|
||||
// Replace with your own holiday service
|
||||
isHoliday: false,
|
||||
};
|
||||
}
|
||||
|
||||
function isDisabledDate(date: Dayjs, min?: string, max?: string) {
|
||||
if (min && date.isBefore(dayjs(min), 'day')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (max && date.isAfter(dayjs(max), 'day')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<ng-template #fieldTemplate>
|
||||
@if (showLabel) {
|
||||
<div [class]="`flex gap-1 ${alignment === 'horizontal' ? 'items-center' : 'flex-col'} ${className || ''}`">
|
||||
<div [class]="`flex shrink-0 gap-1 ${alignment === 'horizontal' ? 'items-center' : 'flex-col'} ${className || ''}`">
|
||||
@if (labelView) {
|
||||
<ng-container [ngTemplateOutlet]="labelView"> </ng-container>
|
||||
} @else {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import jalaliPlugin from '@zoomit/dayjs-jalali-plugin';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import 'dayjs/locale/fa';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import jalaliPlugin from 'jalaliday';
|
||||
|
||||
type dateInput = string | Date | Dayjs | number;
|
||||
|
||||
// Extend dayjs with plugins
|
||||
dayjs.extend(jalaliPlugin);
|
||||
@@ -80,7 +82,7 @@ export const GREGORIAN_DATE_FORMATS = {
|
||||
* formatJalali(new Date(), JALALI_DATE_FORMATS.FULL_WITH_WEEKDAY) // 'پنجشنبه، ۱۳ شهریور ۱۳۹۷'
|
||||
*/
|
||||
export function formatJalali(
|
||||
date: string | Date | Dayjs | number,
|
||||
date: dateInput,
|
||||
format: string = JALALI_DATE_FORMATS.NUMERIC
|
||||
): string {
|
||||
return dayjs(date).calendar('jalali').locale('fa').format(format);
|
||||
@@ -98,7 +100,7 @@ export function formatJalali(
|
||||
* formatGregorian(new Date(), GREGORIAN_DATE_FORMATS.NUMERIC_WITH_TIME) // '2018-09-04 16:30'
|
||||
*/
|
||||
export function formatGregorian(
|
||||
date: string | Date | Dayjs | number,
|
||||
date: dateInput,
|
||||
format: string = GREGORIAN_DATE_FORMATS.NUMERIC
|
||||
): string {
|
||||
return dayjs(date).calendar('gregory').locale('en').format(format);
|
||||
@@ -115,7 +117,7 @@ export function formatGregorian(
|
||||
* parseJalali('1398-10-17') // Dayjs instance
|
||||
* parseJalali('1398/10/17') // Dayjs instance
|
||||
*/
|
||||
export function parseJalali(jalaliDate: string | Date | Dayjs | number, format?: string): Dayjs {
|
||||
export function parseJalali(jalaliDate: dateInput, format?: string): Dayjs {
|
||||
return dayjs(jalaliDate, { jalali: true, ...(format && { format }) });
|
||||
}
|
||||
|
||||
@@ -192,7 +194,7 @@ export function nowGregorian(format: string = GREGORIAN_DATE_FORMATS.NUMERIC_WIT
|
||||
* @example
|
||||
* relativeTimeJalali(dayjs().subtract(2, 'day')) // '۲ روز پیش'
|
||||
*/
|
||||
export function relativeTimeJalali(date: string | Date | Dayjs | number): string {
|
||||
export function relativeTimeJalali(date: dateInput): string {
|
||||
return dayjs(date).locale('fa').fromNow();
|
||||
}
|
||||
|
||||
@@ -219,7 +221,7 @@ export function isValidJalaliDate(jalaliDate: string): boolean {
|
||||
* @example
|
||||
* startOfDayJalali('1398-10-17') // Dayjs instance at 00:00:00
|
||||
*/
|
||||
export function startOfDayJalali(date: string | Date | Dayjs | number): Dayjs {
|
||||
export function startOfDayJalali(date: dateInput): Dayjs {
|
||||
return dayjs(date).calendar('jalali').startOf('day');
|
||||
}
|
||||
|
||||
@@ -232,7 +234,7 @@ export function startOfDayJalali(date: string | Date | Dayjs | number): Dayjs {
|
||||
* @example
|
||||
* endOfDayJalali('1398-10-17') // Dayjs instance at 23:59:59
|
||||
*/
|
||||
export function endOfDayJalali(date: string | Date | Dayjs | number): Dayjs {
|
||||
export function endOfDayJalali(date: dateInput): Dayjs {
|
||||
return dayjs(date).calendar('jalali').endOf('day');
|
||||
}
|
||||
|
||||
@@ -250,7 +252,7 @@ export function endOfDayJalali(date: string | Date | Dayjs | number): Dayjs {
|
||||
* formatDate('2018-09-04', 'gregory', 'en', 'MMMM DD YYYY') // 'September 04 2018'
|
||||
*/
|
||||
export function formatDate(
|
||||
date: string | Date | Dayjs | number,
|
||||
date: dateInput,
|
||||
calendar: 'jalali' | 'gregory',
|
||||
locale: 'fa' | 'en',
|
||||
format: string
|
||||
@@ -302,28 +304,38 @@ export function getJalaliWeekdayName(dayNumber: number): string {
|
||||
}
|
||||
|
||||
export function jalaliDiff(
|
||||
date1: string | number | Date | Dayjs,
|
||||
date2: string | number | Date | Dayjs,
|
||||
date1: dateInput,
|
||||
date2: dateInput,
|
||||
unit: dayjs.OpUnitType = 'day'
|
||||
): number {
|
||||
return toJalali(date1).diff(toJalali(date2), unit);
|
||||
}
|
||||
|
||||
export function isJalaliBefore(
|
||||
date1: string | number | Date | Dayjs,
|
||||
date2: string | number | Date | Dayjs
|
||||
): boolean {
|
||||
export function jalaliAddUnit(
|
||||
date: dateInput,
|
||||
count: number,
|
||||
unit: dayjs.ManipulateType = 'days'
|
||||
): Dayjs {
|
||||
return dayjs(date, { jalali: true }).add(count, unit);
|
||||
}
|
||||
|
||||
export function gregorianAddUnit(
|
||||
date: dateInput,
|
||||
count: number,
|
||||
unit: dayjs.ManipulateType = 'days'
|
||||
): Dayjs {
|
||||
return dayjs(date).add(count, unit);
|
||||
}
|
||||
|
||||
export function isJalaliBefore(date1: dateInput, date2: dateInput): boolean {
|
||||
return toJalali(date1).isBefore(toJalali(date2));
|
||||
}
|
||||
|
||||
export function isJalaliAfter(
|
||||
date1: string | number | Date | Dayjs,
|
||||
date2: string | number | Date | Dayjs
|
||||
): boolean {
|
||||
export function isJalaliAfter(date1: dateInput, date2: dateInput): boolean {
|
||||
return toJalali(date1).isAfter(toJalali(date2));
|
||||
}
|
||||
|
||||
export function toJalali(date: string | number | Date | Dayjs, format = 'YYYY/MM/DD'): Dayjs {
|
||||
export function toJalali(date: dateInput, format = 'YYYY/MM/DD'): Dayjs {
|
||||
return dayjs(date).calendar('jalali');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
.flatpickr-calendar {
|
||||
direction: rtl;
|
||||
background: var(--color-surface-ground);
|
||||
}
|
||||
.flatpickr-time {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.flat {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flatpickr-calendar .hasWeeks .dayContainer {
|
||||
/*border-left: 0; */
|
||||
}
|
||||
|
||||
.flatpickr-calendar:before,
|
||||
.flatpickr-calendar:after {
|
||||
/*left: 22px; */
|
||||
}
|
||||
|
||||
.flatpickr-calendar.rightMost:before,
|
||||
.flatpickr-calendar.arrowRight:before,
|
||||
.flatpickr-calendar.rightMost:after,
|
||||
.flatpickr-calendar.arrowRight:after {
|
||||
/*left: auto;*/
|
||||
/*right: 22px;*/
|
||||
}
|
||||
|
||||
.flatpickr-calendar.arrowTop:before {
|
||||
/*border-bottom-color: #e6e6e6;*/
|
||||
}
|
||||
.flatpickr-calendar.arrowTop:after {
|
||||
/*border-bottom-color: #fff;*/
|
||||
}
|
||||
|
||||
.flatpickr-calendar.arrowBottom:before {
|
||||
/*border-top-color: #e6e6e6;*/
|
||||
}
|
||||
.flatpickr-calendar.arrowBottom:after {
|
||||
/*border-top-color: #fff;*/
|
||||
}
|
||||
|
||||
.flatpickr-months {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flatpickr-months .flatpickr-month {
|
||||
color: var(--p-text-muted-color);
|
||||
fill: var(--p-text-muted-color);
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.flatpickr-months .flatpickr-prev-month,
|
||||
.flatpickr-months .flatpickr-next-month {
|
||||
color: var(--p-text-muted-color);
|
||||
fill: var(--p-text-muted-color);
|
||||
position: relative !important;
|
||||
rotate: 180deg;
|
||||
}
|
||||
|
||||
.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month,
|
||||
.flatpickr-months .flatpickr-next-month.flatpickr-prev-month {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
.flatpickr-months .flatpickr-prev-month.flatpickr-next-month,
|
||||
.flatpickr-months .flatpickr-next-month.flatpickr-next-month {
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
.flatpickr-months .flatpickr-prev-month:hover,
|
||||
.flatpickr-months .flatpickr-next-month:hover {
|
||||
/*color: #959ea9;*/
|
||||
}
|
||||
.flatpickr-months .flatpickr-prev-month:hover svg,
|
||||
.flatpickr-months .flatpickr-next-month:hover svg {
|
||||
/*fill: #f64747;*/
|
||||
}
|
||||
.numInputWrapper span {
|
||||
right: auto;
|
||||
left: 0;
|
||||
/*border: 1px solid rgba(57,57,57,0.15);*/
|
||||
}
|
||||
|
||||
.numInputWrapper span:hover {
|
||||
/*background: rgba(0,0,0,0.1);*/
|
||||
}
|
||||
.numInputWrapper span:active {
|
||||
/*background: rgba(0,0,0,0.2);*/
|
||||
}
|
||||
|
||||
.numInputWrapper span.arrowUp:after {
|
||||
/*border-bottom: 4px solid rgba(57,57,57,0.6);*/
|
||||
}
|
||||
|
||||
.numInputWrapper span.arrowDown:after {
|
||||
/*border-top: 4px solid rgba(57,57,57,0.6);*/
|
||||
}
|
||||
|
||||
.numInputWrapper span svg path {
|
||||
/*fill: rgba(0,0,0,0.5);*/
|
||||
}
|
||||
.numInputWrapper:hover {
|
||||
/*background: rgba(0,0,0,0.05);*/
|
||||
}
|
||||
.flatpickr-current-month {
|
||||
padding: 0;
|
||||
position: relative;
|
||||
left: auto;
|
||||
right: auto;
|
||||
display: flex;
|
||||
margin: auto;
|
||||
gap: 8px;
|
||||
height: 100%;
|
||||
}
|
||||
.flatpickr-current-month > * {
|
||||
flex: 1;
|
||||
}
|
||||
.flatpickr-current-month span.cur-month {
|
||||
/*margin-left: 0.5ch;*/
|
||||
}
|
||||
.flatpickr-current-month span.cur-month:hover {
|
||||
/*background: rgba(0,0,0,0.05);*/
|
||||
}
|
||||
|
||||
.flatpickr-current-month .numInputWrapper span.arrowUp:after {
|
||||
border-bottom-color: var(--p-text-color);
|
||||
}
|
||||
.flatpickr-current-month .numInputWrapper span.arrowDown:after {
|
||||
border-top-color: var(--p-text-color);
|
||||
}
|
||||
|
||||
.flatpickr-current-month input.cur-year {
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
padding: 0 0 0 20px;
|
||||
}
|
||||
.flatpickr-current-month input.cur-year[disabled],
|
||||
.flatpickr-current-month input.cur-year[disabled]:hover {
|
||||
/*color: rgba(0,0,0,0.5);*/
|
||||
}
|
||||
|
||||
.flatpickr-current-month .flatpickr-monthDropdown-months {
|
||||
font-size: 16px;
|
||||
height: 100%;
|
||||
}
|
||||
.flatpickr-current-month .flatpickr-monthDropdown-months:hover {
|
||||
/*background: rgba(0,0,0,0.05);*/
|
||||
}
|
||||
|
||||
span.flatpickr-weekday {
|
||||
color: var(--p-text-muted-color);
|
||||
}
|
||||
|
||||
.dayContainer {
|
||||
text-align: left;
|
||||
}
|
||||
/*.dayContainer + .dayContainer {*/
|
||||
/* -webkit-box-shadow: -1px 0 0 #e6e6e6;*/
|
||||
/* box-shadow: -1px 0 0 #e6e6e6;*/
|
||||
/*}*/
|
||||
|
||||
.flatpickr-day {
|
||||
color: var(--p-text-color);
|
||||
}
|
||||
|
||||
.flatpickr-day.inRange,
|
||||
.flatpickr-day.prevMonthDay.inRange,
|
||||
.flatpickr-day.nextMonthDay.inRange,
|
||||
.flatpickr-day.today.inRange,
|
||||
.flatpickr-day.prevMonthDay.today.inRange,
|
||||
.flatpickr-day.nextMonthDay.today.inRange,
|
||||
.flatpickr-day:hover,
|
||||
.flatpickr-day.prevMonthDay:hover,
|
||||
.flatpickr-day.nextMonthDay:hover,
|
||||
.flatpickr-day:focus,
|
||||
.flatpickr-day.prevMonthDay:focus,
|
||||
.flatpickr-day.nextMonthDay:focus {
|
||||
background: var(--p-blue-300);
|
||||
border-color: var(--focus-ring-color);
|
||||
}
|
||||
|
||||
.flatpickr-day.today {
|
||||
/*border-color: #959ea9;*/
|
||||
}
|
||||
|
||||
.flatpickr-day.today:hover,
|
||||
.flatpickr-day.today:focus {
|
||||
/*border-color: #959ea9;*/
|
||||
/*background: #959ea9;*/
|
||||
/*color: #fff;*/
|
||||
}
|
||||
.flatpickr-day.selected,
|
||||
.flatpickr-day.startRange,
|
||||
.flatpickr-day.endRange,
|
||||
.flatpickr-day.selected.inRange,
|
||||
.flatpickr-day.startRange.inRange,
|
||||
.flatpickr-day.endRange.inRange,
|
||||
.flatpickr-day.selected:focus,
|
||||
.flatpickr-day.startRange:focus,
|
||||
.flatpickr-day.endRange:focus,
|
||||
.flatpickr-day.selected:hover,
|
||||
.flatpickr-day.startRange:hover,
|
||||
.flatpickr-day.endRange:hover,
|
||||
.flatpickr-day.selected.prevMonthDay,
|
||||
.flatpickr-day.startRange.prevMonthDay,
|
||||
.flatpickr-day.endRange.prevMonthDay,
|
||||
.flatpickr-day.selected.nextMonthDay,
|
||||
.flatpickr-day.startRange.nextMonthDay,
|
||||
.flatpickr-day.endRange.nextMonthDay {
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
border-color: var(--focus-ring-color);
|
||||
}
|
||||
|
||||
.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n + 1)),
|
||||
.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n + 1)),
|
||||
.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n + 1)) {
|
||||
/*-webkit-box-shadow: -10px 0 0 #569ff7;*/
|
||||
/*box-shadow: -10px 0 0 #569ff7;*/
|
||||
}
|
||||
|
||||
.flatpickr-day.inRange {
|
||||
/*-webkit-box-shadow: -5px 0 0 #e6e6e6, 5px 0 0 #e6e6e6;*/
|
||||
/* box-shadow: -5px 0 0 #e6e6e6, 5px 0 0 #e6e6e6;*/
|
||||
}
|
||||
.flatpickr-day.flatpickr-disabled,
|
||||
.flatpickr-day.flatpickr-disabled:hover,
|
||||
.flatpickr-day.prevMonthDay,
|
||||
.flatpickr-day.nextMonthDay,
|
||||
.flatpickr-day.notAllowed,
|
||||
.flatpickr-day.notAllowed.prevMonthDay,
|
||||
.flatpickr-day.notAllowed.nextMonthDay {
|
||||
color: var(--p-text-color);
|
||||
opacity: 0.4;
|
||||
}
|
||||
.flatpickr-day.flatpickr-disabled,
|
||||
.flatpickr-day.flatpickr-disabled:hover {
|
||||
/*color: rgba(57,57,57,0.1);*/
|
||||
}
|
||||
.flatpickr-day.week.selected {
|
||||
/*-webkit-box-shadow: -5px 0 0 #569ff7, 5px 0 0 #569ff7;*/
|
||||
/* box-shadow: -5px 0 0 #569ff7, 5px 0 0 #569ff7;*/
|
||||
}
|
||||
.flatpickr-weekwrapper {
|
||||
/*float: left;*/
|
||||
}
|
||||
.flatpickr-weekwrapper .flatpickr-weeks {
|
||||
/*-webkit-box-shadow: 1px 0 0 #e6e6e6;*/
|
||||
/* box-shadow: 1px 0 0 #e6e6e6;*/
|
||||
}
|
||||
.flatpickr-weekwrapper span.flatpickr-day,
|
||||
.flatpickr-weekwrapper span.flatpickr-day:hover {
|
||||
/*color: rgba(57,57,57,0.3);*/
|
||||
}
|
||||
.flatpickr-time .numInputWrapper {
|
||||
/*float: left;*/
|
||||
}
|
||||
.flatpickr-time .numInputWrapper span.arrowUp:after {
|
||||
border-bottom-color: var(--p-text-color);
|
||||
}
|
||||
.flatpickr-time .numInputWrapper span.arrowDown:after {
|
||||
border-top-color: var(--p-text-color);
|
||||
}
|
||||
.flatpickr-time input {
|
||||
color: var(--p-text-color);
|
||||
}
|
||||
.flatpickr-time .flatpickr-time-separator,
|
||||
.flatpickr-time .flatpickr-am-pm {
|
||||
/*float: left;*/
|
||||
color: var(--p-text-color);
|
||||
}
|
||||
.flatpickr-time input:hover,
|
||||
.flatpickr-time .flatpickr-am-pm:hover,
|
||||
.flatpickr-time input:focus,
|
||||
.flatpickr-time .flatpickr-am-pm:focus {
|
||||
background: var(--color-surface-hover);
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
@use "./tailwind.css";
|
||||
@use "flatpickr-wrap/dist/themes/confetti.css";
|
||||
@use "flatpickr-wrap/dist/flatpickr.css";
|
||||
@use "./flatpicker.css";
|
||||
@use "./layout/layout.scss";
|
||||
@use "primeicons/primeicons.css";
|
||||
@use "./rtlSupport.scss";
|
||||
|
||||
-15
@@ -4,21 +4,6 @@ import { appConfig } from './app.config';
|
||||
import { brandingConfig } from './app/branding/branding.config';
|
||||
import config from './config';
|
||||
|
||||
// flatpickr.localize(faLocales.fa!);
|
||||
|
||||
// // Apply default configuration requested by the project
|
||||
// if (flatpickr.defaultConfig) {
|
||||
// Object.assign(flatpickr.defaultConfig, {
|
||||
// altInput: true,
|
||||
// altFormat: 'F j, Y H:i',
|
||||
// dateFormat: 'Y-m-d',
|
||||
// time_24hr: true,
|
||||
// time_format: 'H:i',
|
||||
// wrap: true,
|
||||
// clickOpens: true,
|
||||
// });
|
||||
// }
|
||||
|
||||
document.title = brandingConfig.appTitle;
|
||||
|
||||
const manifestLink = document.querySelector('link[rel="manifest"]');
|
||||
|
||||
Reference in New Issue
Block a user