diff --git a/src/app/components/calendar-year/calendar-year.ts b/src/app/components/calendar-year/calendar-year.ts index e5b3a9b..4813176 100644 --- a/src/app/components/calendar-year/calendar-year.ts +++ b/src/app/components/calendar-year/calendar-year.ts @@ -272,11 +272,10 @@ export class CalendarYear { const horizon = this.calendarHorizon(); if (!horizon) return undefined; if (this.declarationEntry()) - return this.calendarService.project({ - placements: [], - horizon, - declaredDays: this.userInput.declaredDaysSignal(), - }); + return this.calendarService.project( + { placements: [], horizon, declaredDays: this.userInput.declaredDaysSignal() }, + { fixedMonths: true }, + ); const plan = this.displayedPlan(); return this.calendarService.project( plan ? { ...plan, horizon: plan.horizon ?? horizon } : { placements: [], horizon }, diff --git a/src/app/services/calendar-service.spec.ts b/src/app/services/calendar-service.spec.ts index 1df7ce3..51a34a3 100644 --- a/src/app/services/calendar-service.spec.ts +++ b/src/app/services/calendar-service.spec.ts @@ -216,6 +216,29 @@ describe('CalendarService', () => { ]); }); + it('keeps fixed months when an edge declaration widens the projection', () => { + const plan = { + placements: [], + horizon: { start: '2024-07-01', end: '2025-01-04' }, + declaredDays: [{ date: '2024-07-01', type: 'cp' as const }], + }; + const months = (projection: ReturnType) => + projection.months.map(({ monthIndex, year }) => `${year}-${monthIndex}`); + expect(months(service.project(plan))[0]).toBe('2024-5'); + const fixed = service.project(plan, { fixedMonths: true }); + expect(months(fixed)).toEqual([ + '2024-6', + '2024-7', + '2024-8', + '2024-9', + '2024-10', + '2024-11', + '2025-0', + ]); + expect(fixed.selections.dayTypes(day('2024-06-30'))).toContain(DayType.WEEKEND); + expect(fixed.selections.isStart(day('2024-07-01'))).toBe(false); + }); + it('includes the final partial month of a half-open one-year horizon', () => { const { selections } = project({ start: '2024-01-15', end: '2025-01-15' }); expect(selections.dayTypes(day('2025-01-04'))).toContain(DayType.WEEKEND); diff --git a/src/app/services/calendar-service.ts b/src/app/services/calendar-service.ts index cdf5d28..0ea9091 100644 --- a/src/app/services/calendar-service.ts +++ b/src/app/services/calendar-service.ts @@ -72,10 +72,14 @@ export class CalendarService { return { start, end: addPlanningYears(start, 1) }; } + /** `fixedMonths` lists only the plan horizon's months, so editing declarations never adds a month. */ project( plan: CalendarPlan & { horizon: PlanningStateSnapshot['horizon'] }, + { fixedMonths = false } = {}, ): CalendarProjection { const horizon = calendarProjectionHorizon(plan)!; + const firstMonth = plan.horizon.start.slice(0, 7); + const lastMonth = addPlanningDays(plan.horizon.end, -1).slice(0, 7); const first = new Date(`${horizon.start}T00:00:00`); const last = new Date(`${horizon.end}T00:00:00`); last.setDate(last.getDate() - 1); @@ -92,7 +96,9 @@ export class CalendarService { const cursor = new Date(first); cursor.setDate(1); while (cursor <= last) { - months.push({ monthIndex: cursor.getMonth(), year: cursor.getFullYear() }); + const month = `${cursor.getFullYear()}-${String(cursor.getMonth() + 1).padStart(2, '0')}`; + if (!fixedMonths || (month >= firstMonth && month <= lastMonth)) + months.push({ monthIndex: cursor.getMonth(), year: cursor.getFullYear() }); for (const week of CalendarService.weeksInMonth( cursor.getMonth(), cursor.getFullYear(),