Enhance calendar functionality: display year in month header, highlight past dates, and update date selection logic

This commit is contained in:
nessar committed 2025-10-30 01:18:26 +01:00
1 parent 6bc03be89a
commit 7fc7653e6f
6 files changed
+71 -14

No files matched your search

@@ -1,5 +1,5 @@
<div class="calendar"> <div class="calendar">
<h3>{{ getMonthName() }}</h3> <h3>{{ getMonthName() }} {{ year }}</h3>
<div class="row header"> <div class="row header">
<p class="day">L</p> <p class="day">L</p>
<p class="day">M</p> <p class="day">M</p>
@@ -16,7 +16,7 @@
@if (day === null) { @if (day === null) {
<p class="day empty"></p> <p class="day empty"></p>
} @else { } @else {
<p [class.start]="selectedDates.isStart(day)" [class.end]="selectedDates.isEnd(day)" [class.selected]="selectedDates.isSelected(day)" <p [class.past]="day < getNow()" [class.start]="selectedDates.isStart(day)" [class.end]="selectedDates.isEnd(day)" [class.selected]="selectedDates.isSelected(day)"
[class]="selectedDates.getClasses(day)" class="day number" [matTooltip]="selectedDates.getTooltip(day)" [matTooltipShowDelay]="500">{{ day.getDate() }}</p> [class]="selectedDates.getClasses(day)" class="day number" [matTooltip]="selectedDates.getTooltip(day)" [matTooltipShowDelay]="500">{{ day.getDate() }}</p>
} }
} }
@@ -101,3 +101,7 @@
.other { .other {
background-color: #ff9b9b; background-color: #ff9b9b;
} }
.past {
color: #b0b0b0;
}
@@ -16,6 +16,12 @@ export class CalendarMonth implements OnInit {
@Input({ required: true }) @Input({ required: true })
year!: number; year!: number;
getNow(): Date {
const now = new Date();
now.setHours(0, 0, 0, 0);
return now;
}
currentMonth: Date = new Date(); currentMonth: Date = new Date();
weeksInAMonth: Month = []; weeksInAMonth: Month = [];
@@ -7,10 +7,10 @@
</div> </div>
</div> </div>
} }
@for (month of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; track $index) { @for (month of months; track $index) {
<mat-card> <mat-card>
<mat-card-content> <mat-card-content>
<app-calendar-month [monthIndex]="month" [year]="year" [selectedDates]="selectedDates"></app-calendar-month> <app-calendar-month [monthIndex]="month" [year]="getYear(month)" [selectedDates]="selectedDates"></app-calendar-month>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
} }
@@ -2,7 +2,7 @@ import { Component, OnInit, effect, signal } from '@angular/core';
import { UserInputService } from '../../services/user-input-service'; import { UserInputService } from '../../services/user-input-service';
import { MatCard, MatCardContent } from '@angular/material/card'; import { MatCard, MatCardContent } from '@angular/material/card';
import { CalendarMonth } from "../calendar-month/calendar-month"; import { CalendarMonth } from "../calendar-month/calendar-month";
import { CalendarService, SelectedDates, VacationsNumber } from '../../services/calendar-service'; import { CalendarService, SelectedDates } from '../../services/calendar-service';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
@Component({ @Component({
@@ -16,7 +16,7 @@ export class CalendarYear implements OnInit {
constructor(private userInput: UserInputService, private calendarService: CalendarService) { constructor(private userInput: UserInputService, private calendarService: CalendarService) {
effect(() => { effect(() => {
this.selectedDates = this.calendarService.getSelectedDatesForYear(this.year); this.selectedDates = this.calendarService.getSelectedDatesForYear();
const vacationData = this.userInput.vacationNumberSignal(); const vacationData = this.userInput.vacationNumberSignal();
this.isLoading.set(true); this.isLoading.set(true);
// Simulate server-side calculation with a small delay // Simulate server-side calculation with a small delay
@@ -31,9 +31,15 @@ export class CalendarYear implements OnInit {
protected selectedDates: SelectedDates = new SelectedDates(); protected selectedDates: SelectedDates = new SelectedDates();
protected year: number = 2026; getYear(monthIndex: number): number {
const offset = new Date().getMonth() <= monthIndex ? 0 : 1;
return new Date().getFullYear() + offset;
}
// months starting from actual date
protected months: number[] = Array.from({ length: 12 }, (_, i) => (new Date().getMonth() + i) % 12);
ngOnInit(): void { ngOnInit(): void {
this.selectedDates = this.calendarService.getSelectedDatesForYear(this.year); this.selectedDates = this.calendarService.getSelectedDatesForYear();
} }
} }
+47 -6
View File
@@ -13,9 +13,17 @@ const allTypesOptions: HolidaysTypes.Options = {
}) })
export class CalendarService { export class CalendarService {
getSelectedDatesForYear(year: number): SelectedDates { // Get selected dates from current date to the next year
const holidays = this.getHolidays(year); getSelectedDatesFromNow(): SelectedDates {
const monthInAYear = CalendarService.monthsInYear(year); const holidays = this.getHolidays();
let selectedDates: SelectedDates = new SelectedDates();
// Logic to populate selectedDates from now until the next year
return selectedDates;
}
getSelectedDatesForYear(): SelectedDates {
const holidays = this.getHolidays();
const monthInAYear = CalendarService.monthsInAYearFromNow();
let selectedDates: SelectedDates = new SelectedDates(); let selectedDates: SelectedDates = new SelectedDates();
for (const weeksInAMonth of monthInAYear) { for (const weeksInAMonth of monthInAYear) {
for (const daysInAWeek of weeksInAMonth) { for (const daysInAWeek of weeksInAMonth) {
@@ -45,10 +53,12 @@ export class CalendarService {
} }
getHolidays(year: number): Date[] { getHolidays(): Date[] {
// Logic to return holidays for the given year // Logic to return holidays for the given year
const hd = new Holidays('FR', allTypesOptions); const hd = new Holidays('FR', allTypesOptions);
const holidays = hd.getHolidays(year, lang); const holidays = hd.getHolidays(new Date().getFullYear(), lang);
const holidaysPlusOne = hd.getHolidays(new Date().getFullYear() + 1, lang);
holidays.push(...holidaysPlusOne);
let holidaysDate: Date[] = holidays.map(holiday => new Date(holiday.date)); let holidaysDate: Date[] = holidays.map(holiday => new Date(holiday.date));
return holidaysDate; return holidaysDate;
} }
@@ -97,6 +107,19 @@ export class CalendarService {
} }
return months; return months;
} }
static monthsInAYearFromNow(): Year {
const months: Year = [];
const currentMonthIndex = new Date().getMonth();
const currentYear = new Date().getFullYear();
for (let i = 0; i < 12; i++) {
const monthIndex = (currentMonthIndex + i) % 12;
const year = currentYear + Math.floor((currentMonthIndex + i) / 12);
months.push(this.weeksInMonth(monthIndex, year));
}
return months;
}
} }
export type VacationsNumber = { export type VacationsNumber = {
@@ -548,7 +571,22 @@ export class SelectedDates implements SelectedDateInterface {
} }
lookForVacationRec(vacType: DayType): { apply: () => void; heuristic: number } { lookForVacationRec(vacType: DayType): { apply: () => void; heuristic: number } {
const daysOfYear = CalendarService.monthsInYear(2026); const daysOfYear = CalendarService.monthsInAYearFromNow();
const now = new Date();
now.setHours(0, 0, 0, 0);
daysOfYear.forEach(month => {
month.forEach(week => {
week.forEach(day => {
if (day) {
if (day)
day.setHours(0, 0, 0, 0);
if (day && day < now) {
week[week.indexOf(day)] = null;
}
}
});
});
});
const tempDatesBackup = [...this._datesSelected]; const tempDatesBackup = [...this._datesSelected];
let strategies: { apply: () => void; heuristic: number; value: Date }[] = []; let strategies: { apply: () => void; heuristic: number; value: Date }[] = [];
for (const month of daysOfYear) { for (const month of daysOfYear) {
@@ -582,6 +620,9 @@ export class SelectedDates implements SelectedDateInterface {
const bestStrategy = strategies.reduce((best, current) => const bestStrategy = strategies.reduce((best, current) =>
current.heuristic > best.heuristic ? current : best current.heuristic > best.heuristic ? current : best
); );
strategies.forEach(strategy => {
console.log(`Strategy for ${strategy.value.toDateString()} has heuristic ${strategy.heuristic}`);
});
bestStrategy.apply(); bestStrategy.apply();
return bestStrategy; return bestStrategy;
} }