import { Component, EventEmitter, Input, Output, ViewChild, computed, effect, signal, } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormControl } from '@angular/forms'; import dayjs from 'dayjs'; import jalaliday from 'jalaliday'; import { InputText } from 'primeng/inputtext'; import { Popover } from 'primeng/popover'; import { Maybe } from '@/core'; import { formatJalali } from '@/utils'; import { UikitFieldComponent } from '../uikit-field.component'; import { MonthInfo, MonthlyWeekDate, daysName, prepareMonthInfo, prepareWeekDayDates, } from './monthly-calendar.helper.util'; dayjs.extend(jalaliday); @Component({ selector: 'app-datepicker', standalone: true, templateUrl: './datepicker.component.html', imports: [CommonModule, Popover, InputText, UikitFieldComponent], }) export class DatepickerComponent { @Input({ required: true }) control!: FormControl>; @Input() alignment: 'vertical' | 'horizontal' = 'vertical'; @Input() name = 'date'; @Input() label = 'تاریخ'; @Input() closeOnSelect = true; /** * Gregorian YYYY-MM-DD */ @Input() min?: string; /** * Gregorian YYYY-MM-DD */ @Input() max?: string; @Input() closedDays: number[] = []; @Output() valueChange = new EventEmitter(); @Output() clickOnDayEvent = new EventEmitter(); @ViewChild('op') op!: Popover; readonly daysName = daysName; /** * Currently displayed month */ private readonly activeDateSignal = signal(dayjs().format('YYYY-MM-DD')); monthInfo = computed(() => prepareMonthInfo(this.activeDateSignal())); weekDaysDates = computed(() => prepareWeekDayDates(this.monthInfo(), this.min, this.max)); constructor() { effect(() => { const value = this.value; if (value) { this.activeDateSignal.set(value); } }); } ngOnInit(): void { if (this.control?.value) { this.activeDateSignal.set(this.control.value); } this.control.valueChanges.subscribe((value) => { if (value) { this.activeDateSignal.set(value); } }); } get value(): Maybe { return this.control?.value ?? null; } get valueToShow(): Maybe { if (!this.value) { return null; } return formatJalali(this.value); } get activeDate(): string { return this.activeDateSignal(); } set activeDate(date: string) { this.activeDateSignal.set(date); } changeMonth(months: number): void { this.activeDateSignal.set( dayjs(this.activeDateSignal()).add(months, 'month').format('YYYY-MM-DD') ); } selectDate(day: MonthlyWeekDate): void { if (day.isDisabled) { return; } this.control.setValue(day.gregorianDate); this.control.markAsDirty(); this.control.markAsTouched(); this.valueChange.emit(day.gregorianDate); this.clickOnDayEvent.emit(day); if (this.closeOnSelect) { this.op.hide(); } } isSelected(day: MonthlyWeekDate): boolean { return this.value === day.gregorianDate; } trackByIndex(index: number): number { return index; } }