Files
ISA-Frontend/libs/ui/datepicker/src/lib/body/month-year-body/month-year-body.component.ts
2025-04-10 10:06:24 +00:00

167 lines
4.8 KiB
TypeScript

import {
ChangeDetectionStrategy,
Component,
computed,
inject,
} from '@angular/core';
import { format, getMonth, getYear, startOfMonth } from 'date-fns';
import { RangeDatepicker } from '../../range-datepicker';
import { ButtonComponent } from '@isa/ui/buttons';
import { isaActionCheck } from '@isa/icons';
import { NgIconComponent, provideIcons } from '@ng-icons/core';
import { DatepickerViewState } from '../../datepicker-view.state';
@Component({
selector: 'ui-month-year-body',
templateUrl: 'month-year-body.component.html',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
'[class]': "['ui-month-year-body']",
},
imports: [ButtonComponent, NgIconComponent],
providers: [
provideIcons({
isaActionCheck,
}),
],
})
export class MonthYearBodyComponent {
/**
* The injected Datepicker instance.
*/
datepicker = inject(RangeDatepicker);
/**
* The state of the Datepicker view.
*/
viewState = inject(DatepickerViewState);
/**
* The current displayed month derived from the DatepickerViewState.
*/
currentDisplayedMonth = getMonth(this.viewState.displayedDate());
/**
* The current displayed year derived from the DatepickerViewState.
*/
currentDisplayedYear = getYear(this.viewState.displayedDate());
/**
* A computed property that returns an array of month objects for the current year.
*
* Each month object contains a formatted label and the corresponding Date value.
* Months outside the min and max bounds are represented as null.
*/
months = computed(() => {
const year = this.currentDisplayedYear;
const min = this.datepicker.min();
const max = this.datepicker.max();
return Array.from({ length: 12 }, (_, i) => {
const date = new Date(year, i, 1);
const beforeMin = min && date < startOfMonth(min);
const afterMax = max && date > startOfMonth(max);
if (beforeMin || afterMax) return null;
return {
label: format(date, 'LLLL'),
value: date,
};
});
});
/**
* A computed property that returns an array of year objects within the allowed range.
*
* Each year object contains a string label and the corresponding Date value.
*/
years = computed(() => {
const min = this.datepicker.min();
const max = this.datepicker.max();
const currentYear = getYear(new Date());
const minYear = min ? getYear(min) : currentYear - 5; // Default: up to 5 years back
const maxYear = max ? getYear(max) : currentYear;
return Array.from({ length: maxYear - minYear + 1 }, (_, i) => {
const year = maxYear - i;
const date = new Date(year, 0, 1);
return {
label: year.toString(),
value: date,
};
});
});
/**
* A computed property that indicates if the currently displayed month and year
* match the displayed date in the DatepickerViewState.
*/
canSave = computed(() => {
const currentMonth = this.currentDisplayedMonth;
const currentYear = this.currentDisplayedYear;
const displayedDate = this.viewState.displayedDate();
const displayedMonth = getMonth(displayedDate);
const displayedYear = getYear(displayedDate);
return currentMonth === displayedMonth && currentYear === displayedYear;
});
/**
* Updates the displayed month in the DatepickerViewState.
*
* @param newValue - A Date object representing the new month.
*/
updateMonth(newValue: Date) {
const month = getMonth(newValue);
const year = getYear(this.viewState.displayedDate());
this.viewState.displayedDate.set(new Date(year, month));
}
/**
* Updates the displayed year in the DatepickerViewState.
*
* @param newValue - A Date object representing the new year.
*/
updateYear(newValue: Date) {
const month = getMonth(this.viewState.displayedDate());
const year = getYear(newValue);
this.viewState.displayedDate.set(new Date(year, month));
}
/**
* Rolls back the displayed month and year in the DatepickerViewState to the original values.
*/
rollbackDisplayedMonthYear() {
this.viewState.displayedDate.set(
new Date(this.currentDisplayedYear, this.currentDisplayedMonth),
);
}
/**
* Checks if the provided date's month matches the currently displayed month.
*
* @param {Date} date - The date to check.
* @returns {boolean} True if the month matches, false otherwise.
*/
isSelectedMonth(date: Date): boolean {
return getMonth(this.viewState.displayedDate()) === getMonth(date);
}
/**
* Checks if the provided date's year matches the currently displayed year.
*
* @param {Date} date - The date to check.
* @returns {boolean} True if the year matches, false otherwise.
*/
isSelectedYear(date: Date): boolean {
return getYear(this.viewState.displayedDate()) === getYear(date);
}
}