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(); readonly isOpen = signal(false); readonly selectedYear = signal(Number(nowJalali(JALALI_DATE_FORMATS.YEAR))); readonly selectedSeason = signal(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` ) ) ); } }