From dea632f67de944ef6e54d982f66d0e01f25b9584 Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Sun, 30 Nov 2025 01:24:26 +0100
Subject: [PATCH] Fix signal immutability violations and cleanup unused code
(#62)
* Initial plan
* fix: address PR review comments for signal immutability and cleanup
Co-authored-by: THoguet <61246905+THoguet@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: THoguet <61246905+THoguet@users.noreply.github.com>
---
src/app/components/user-input/user-input.html | 2 +-
src/app/components/user-input/user-input.ts | 42 +++++++++----------
.../userInput/day-input/day-input.html | 2 +-
.../userInput/day-input/day-input.spec.ts | 11 +++++
.../userInput/day-input/day-input.ts | 10 +++--
5 files changed, 38 insertions(+), 29 deletions(-)
diff --git a/src/app/components/user-input/user-input.html b/src/app/components/user-input/user-input.html
index c2630a2..80fdb63 100644
--- a/src/app/components/user-input/user-input.html
+++ b/src/app/components/user-input/user-input.html
@@ -3,7 +3,7 @@
@for (day of daysOff; track day.id) {
}
diff --git a/src/app/components/user-input/user-input.ts b/src/app/components/user-input/user-input.ts
index 8db3317..c3c72fc 100644
--- a/src/app/components/user-input/user-input.ts
+++ b/src/app/components/user-input/user-input.ts
@@ -1,27 +1,17 @@
-import {
- Component,
- OnInit,
- OnDestroy,
- computed,
- inject,
- ChangeDetectionStrategy,
-} from '@angular/core';
+import { Component, computed, inject, ChangeDetectionStrategy } from '@angular/core';
import { MatInputModule } from '@angular/material/input';
-import { ReactiveFormsModule } from '@angular/forms';
import { UserInputService } from '../../services/user-input-service';
-import { Subject } from 'rxjs';
import { CalendarSettings } from '../calendar-settings/calendar-settings';
import { MatCard, MatCardContent } from '@angular/material/card';
import { MatIcon } from '@angular/material/icon';
import { DayInput } from '../userInput/day-input/day-input';
import { MatButtonModule } from '@angular/material/button';
-import { tooltipTypeMapping, DayType } from '../../services/calendar-service';
+import { tooltipTypeMapping, DayType, VacDay } from '../../services/calendar-service';
@Component({
selector: 'app-user-input',
imports: [
MatInputModule,
- ReactiveFormsModule,
CalendarSettings,
MatCard,
MatCardContent,
@@ -33,10 +23,8 @@ import { tooltipTypeMapping, DayType } from '../../services/calendar-service';
styleUrl: './user-input.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class UserInput implements OnInit, OnDestroy {
+export class UserInput {
private userInputService: UserInputService = inject(UserInputService);
- public daysOff = this.userInputService.vacationNumberSignal();
- private destroy$ = new Subject();
protected remainingDays = computed(() => {
const remaining = this.userInputService.remainingVacationDaysSignal();
@@ -60,23 +48,31 @@ export class UserInput implements OnInit, OnDestroy {
protected hasRemainingDays = computed(() => this.remainingDays() > 0);
- ngOnInit() {}
-
- ngOnDestroy() {
- this.destroy$.next();
- this.destroy$.complete();
+ protected get daysOff() {
+ return this.userInputService.vacationNumberSignal();
}
public addDay() {
- this.daysOff.push(this.userInputService.createVacationDay());
+ this.userInputService.vacationNumberSignal.update((days) => [
+ ...days,
+ this.userInputService.createVacationDay(),
+ ]);
}
public removeFromList(index: number) {
- this.daysOff.splice(index, 1);
+ this.userInputService.vacationNumberSignal.update((days) =>
+ days.filter((_, i) => i !== index),
+ );
+ }
+
+ public updateDay(index: number, updatedDay: VacDay) {
+ this.userInputService.vacationNumberSignal.update((days) =>
+ days.map((day, i) => (i === index ? updatedDay : day)),
+ );
}
public triggerComputation() {
// Trigger signal update by setting a new array reference
- this.userInputService.vacationNumberSignal.set([...this.daysOff]);
+ this.userInputService.vacationNumberSignal.update((days) => [...days]);
}
}
diff --git a/src/app/components/userInput/day-input/day-input.html b/src/app/components/userInput/day-input/day-input.html
index 9f83199..51bdabb 100644
--- a/src/app/components/userInput/day-input/day-input.html
+++ b/src/app/components/userInput/day-input/day-input.html
@@ -10,7 +10,7 @@
/>
-
+
@for (dayType of selectableDayTypes; track $index) {
{{ tooltipTypeMapping[dayType] }}
diff --git a/src/app/components/userInput/day-input/day-input.spec.ts b/src/app/components/userInput/day-input/day-input.spec.ts
index c09c8a8..d0b1d71 100644
--- a/src/app/components/userInput/day-input/day-input.spec.ts
+++ b/src/app/components/userInput/day-input/day-input.spec.ts
@@ -1,18 +1,29 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { DayInput } from './day-input';
+import { SelectableDayType, VacDay } from '../../../services/calendar-service';
describe('DayInput', () => {
let component: DayInput;
let fixture: ComponentFixture;
+ const mockVacDay: VacDay = {
+ id: 'test-id',
+ type: SelectableDayType.CP,
+ numberOfDays: 5,
+ expiryDate: new Date('2025-12-31'),
+ };
+
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DayInput],
+ providers: [provideAnimationsAsync()],
}).compileComponents();
fixture = TestBed.createComponent(DayInput);
component = fixture.componentInstance;
+ fixture.componentRef.setInput('day', mockVacDay);
fixture.detectChanges();
});
diff --git a/src/app/components/userInput/day-input/day-input.ts b/src/app/components/userInput/day-input/day-input.ts
index 3ec6f25..137d429 100644
--- a/src/app/components/userInput/day-input/day-input.ts
+++ b/src/app/components/userInput/day-input/day-input.ts
@@ -90,12 +90,14 @@ export class DayInput {
onInput(event: Event) {
const value = Number((event.target as HTMLInputElement).value);
- this.day().numberOfDays = value;
- this.dayChange.emit(this.day());
+ this.dayChange.emit({ ...this.day(), numberOfDays: value });
+ }
+
+ onTypeChange(type: SelectableDayType) {
+ this.dayChange.emit({ ...this.day(), type });
}
addEvent(event: MatDatepickerInputEvent) {
- this.day().expiryDate = event.value!;
- this.dayChange.emit(this.day());
+ this.dayChange.emit({ ...this.day(), expiryDate: event.value! });
}
}