b4cd4c05f2
fix: update total price info handling in correction form and ensure accurate calculations refactor: streamline sale invoice single view component by extracting info card into a separate component style: adjust button sizes in payment forms for better UI consistency feat: implement season picker navigation controls to prevent out-of-bounds selection fix: improve price formatting utility to handle undefined values gracefully chore: update environment configuration for API base URL feat: add navigation service to manage routing history and back navigation
137 lines
4.3 KiB
TypeScript
137 lines
4.3 KiB
TypeScript
import { gregorianToJalali, JALALI_DATE_FORMATS, jalaliToGregorian, nowJalali } from '@/utils';
|
|
import { CommonModule } from '@angular/common';
|
|
import { Component, EventEmitter, Input, OnInit, Output, signal } from '@angular/core';
|
|
import { Button, ButtonSeverity } from 'primeng/button';
|
|
import { SeasonPickerDialogComponent } from './season-picker-dialog.component';
|
|
|
|
type SeasonKey = 0 | 1 | 2 | 3;
|
|
|
|
interface SeasonItem {
|
|
key: SeasonKey;
|
|
label: string;
|
|
severity: ButtonSeverity;
|
|
}
|
|
|
|
@Component({
|
|
selector: 'season-picker',
|
|
templateUrl: 'season-picker.component.html',
|
|
imports: [CommonModule, Button, SeasonPickerDialogComponent],
|
|
})
|
|
export class SeasonPickerComponent implements OnInit {
|
|
@Input() minYear = 1404;
|
|
@Input() maxYear = Number(nowJalali(JALALI_DATE_FORMATS.YEAR));
|
|
@Input() value!: Date;
|
|
|
|
@Output() onChange = new EventEmitter<Date>();
|
|
|
|
readonly isOpen = signal(false);
|
|
readonly selectedYear = signal(Number(nowJalali(JALALI_DATE_FORMATS.YEAR)));
|
|
readonly selectedSeason = signal<SeasonKey>(0);
|
|
|
|
readonly seasons: SeasonItem[] = [
|
|
{ key: 0, label: 'بهار', severity: 'success' },
|
|
{ key: 1, label: 'تابستان', severity: 'danger' },
|
|
{ key: 2, label: 'پاییز', severity: 'warn' },
|
|
{ key: 3, label: 'زمستان', severity: 'info' },
|
|
];
|
|
|
|
readonly years = signal<{ year: number; value: number }[]>([]);
|
|
|
|
ngOnInit(): void {
|
|
const year = Number(gregorianToJalali(this.value, JALALI_DATE_FORMATS.YEAR));
|
|
const monthIndex = Number(gregorianToJalali(this.value, JALALI_DATE_FORMATS.MONTH)) - 1;
|
|
const season = Math.floor(monthIndex / 3) as SeasonKey;
|
|
|
|
this.selectedYear.set(year);
|
|
this.selectedSeason.set(season);
|
|
this.years.set(
|
|
Array.from({ length: this.maxYear - this.minYear + 1 }, (_, i) => ({
|
|
year: this.minYear + i,
|
|
value: this.minYear + i,
|
|
}))
|
|
);
|
|
this.emitValue();
|
|
}
|
|
|
|
currentSeason(): string {
|
|
const season = this.seasons.find((item) => item.key === this.selectedSeason());
|
|
return `${season?.label ?? ''} ${this.selectedYear()}`;
|
|
}
|
|
|
|
openPicker(): void {
|
|
this.isOpen.set(true);
|
|
}
|
|
|
|
closePicker(): void {
|
|
this.isOpen.set(false);
|
|
}
|
|
|
|
canGoPrev(): boolean {
|
|
const index = this.selectedSeason();
|
|
const currentYear = this.selectedYear();
|
|
const nextSeason = index === 0 ? 3 : ((index - 1) as SeasonKey);
|
|
const nextYear = index === 0 ? currentYear - 1 : currentYear;
|
|
return this.isWithinBounds(nextYear, nextSeason);
|
|
}
|
|
|
|
canGoNext(): boolean {
|
|
const index = this.selectedSeason();
|
|
const currentYear = this.selectedYear();
|
|
const nextSeason = index === 3 ? 0 : ((index + 1) as SeasonKey);
|
|
const nextYear = index === 3 ? currentYear + 1 : currentYear;
|
|
return this.isWithinBounds(nextYear, nextSeason);
|
|
}
|
|
|
|
prevSeason(): void {
|
|
const index = this.selectedSeason();
|
|
const currentYear = this.selectedYear();
|
|
const nextSeason = index === 0 ? 3 : ((index - 1) as SeasonKey);
|
|
const nextYear = index === 0 ? currentYear - 1 : currentYear;
|
|
|
|
if (!this.isWithinBounds(nextYear, nextSeason)) return;
|
|
|
|
this.selectedYear.set(nextYear);
|
|
this.selectedSeason.set(nextSeason);
|
|
this.emitValue();
|
|
}
|
|
|
|
nextSeason(): void {
|
|
const index = this.selectedSeason();
|
|
const currentYear = this.selectedYear();
|
|
const nextSeason = index === 3 ? 0 : ((index + 1) as SeasonKey);
|
|
const nextYear = index === 3 ? currentYear + 1 : currentYear;
|
|
|
|
if (!this.isWithinBounds(nextYear, nextSeason)) return;
|
|
|
|
this.selectedYear.set(nextYear);
|
|
this.selectedSeason.set(nextSeason);
|
|
this.emitValue();
|
|
}
|
|
|
|
submitPicker(value: { year: number; season: number }): void {
|
|
const season = value.season as SeasonKey;
|
|
if (!this.isWithinBounds(value.year, season)) return;
|
|
|
|
this.selectedYear.set(value.year);
|
|
this.selectedSeason.set(season);
|
|
this.emitValue();
|
|
}
|
|
|
|
private isWithinBounds(year: number, season: SeasonKey): boolean {
|
|
if (year < this.minYear || year > this.maxYear) return false;
|
|
// if (year === this.minYear && season < this.minSeason) return false;
|
|
// if (year === this.maxYear && season > this.maxSeason) return false;
|
|
return true;
|
|
}
|
|
|
|
private emitValue(): void {
|
|
this.onChange.emit(
|
|
new Date(
|
|
jalaliToGregorian(
|
|
`${this.selectedYear()}/${(this.selectedSeason() * 3 + 1).toString().padStart(2, '0')}/01`
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|