diff --git a/src/app/components/calendar-year/calendar-year.ts b/src/app/components/calendar-year/calendar-year.ts index 4f7829c..804949c 100644 --- a/src/app/components/calendar-year/calendar-year.ts +++ b/src/app/components/calendar-year/calendar-year.ts @@ -7,6 +7,7 @@ import { CommonModule } from '@angular/common'; import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { CalendarSettingsService } from '../../services/calendar-settings-service'; import { DateCacheService } from '../../services/date-cache.service'; +import { LoggerService } from '../../services/logger.service'; @Component({ selector: 'app-calendar-year', @@ -19,6 +20,7 @@ export class CalendarYear { private userInput = inject(UserInputService); private calendarService = inject(CalendarService); private calendarSettingsService = inject(CalendarSettingsService); + private logger = inject(LoggerService); protected isLoading = signal(true); protected loadingProgress = signal(0); @@ -53,6 +55,7 @@ export class CalendarYear { (progress: number) => { this.loadingProgress.set(progress); }, + this.logger, ); // Update the remaining vacation days signal this.userInput.remainingVacationDaysSignal.set(remainingDays); diff --git a/src/app/services/calendar-service.ts b/src/app/services/calendar-service.ts index 019a8a9..a660c56 100644 --- a/src/app/services/calendar-service.ts +++ b/src/app/services/calendar-service.ts @@ -6,6 +6,7 @@ import weekOfYear from 'dayjs/plugin/weekOfYear'; import isoWeek from 'dayjs/plugin/isoWeek'; import { CalendarSettingsService } from './calendar-settings-service'; import { DateCacheService } from './date-cache.service'; +import { LoggerService } from './logger.service'; dayjs.extend(weekOfYear); dayjs.extend(isoWeek); @@ -21,6 +22,7 @@ const allTypesOptions: HolidaysTypes.Options = { }) export class CalendarService { private dateCache = inject(DateCacheService); + private logger = inject(LoggerService); // Cache for holiday timestamps private holidayTimestampsCache: Set | null = null; @@ -541,6 +543,7 @@ export class SelectedDates implements SelectedDateInterface { calendarSettingsService: CalendarSettingsService, calendarService: CalendarService, progressCallback?: (progress: number) => void, + logger?: LoggerService, ): Promise { if (calendarSettingsService.get('samediMalin')()) this.samediMalin(vacationsNumber); @@ -600,8 +603,8 @@ export class SelectedDates implements SelectedDateInterface { // Inform user if not all days were placed const remainingDays = vacationsNumber.cp + vacationsNumber.rtt + vacationsNumber.other; - if (remainingDays > 0) { - console.warn( + if (remainingDays > 0 && logger) { + logger.warn( `Optimization stopped: ${remainingDays} of ${totalDays} vacation days remain unplaced. ` + `Too many days have equivalent placement quality - please place remaining days manually.`, ); diff --git a/src/app/services/logger.service.spec.ts b/src/app/services/logger.service.spec.ts new file mode 100644 index 0000000..d72010c --- /dev/null +++ b/src/app/services/logger.service.spec.ts @@ -0,0 +1,52 @@ +import { TestBed } from '@angular/core/testing'; +import { LoggerService } from './logger.service'; + +describe('LoggerService', () => { + let service: LoggerService; + let consoleLogSpy: jasmine.Spy; + let consoleWarnSpy: jasmine.Spy; + let consoleErrorSpy: jasmine.Spy; + let consoleDebugSpy: jasmine.Spy; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(LoggerService); + + // Spy on console methods + consoleLogSpy = spyOn(console, 'log'); + consoleWarnSpy = spyOn(console, 'warn'); + consoleErrorSpy = spyOn(console, 'error'); + consoleDebugSpy = spyOn(console, 'debug'); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should log messages', () => { + service.log('test message'); + expect(consoleLogSpy).toHaveBeenCalledWith('test message'); + }); + + it('should log warnings', () => { + service.warn('test warning'); + expect(consoleWarnSpy).toHaveBeenCalledWith('test warning'); + }); + + it('should log errors', () => { + service.error('test error'); + expect(consoleErrorSpy).toHaveBeenCalledWith('test error'); + }); + + it('should log debug messages', () => { + service.debug('test debug'); + expect(consoleDebugSpy).toHaveBeenCalledWith('test debug'); + }); + + it('should pass additional arguments to console methods', () => { + const arg1 = { key: 'value' }; + const arg2 = [1, 2, 3]; + service.log('test', arg1, arg2); + expect(consoleLogSpy).toHaveBeenCalledWith('test', arg1, arg2); + }); +}); diff --git a/src/app/services/logger.service.ts b/src/app/services/logger.service.ts new file mode 100644 index 0000000..7649634 --- /dev/null +++ b/src/app/services/logger.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; + +/** + * Logger service that wraps console methods. + * Can be configured to disable logging in production environments. + */ +@Injectable({ + providedIn: 'root', +}) +export class LoggerService { + private isProduction = false; // Can be configured based on environment + + /** + * Log an informational message + */ + log(message: string, ...args: unknown[]): void { + if (!this.isProduction) { + console.log(message, ...args); + } + } + + /** + * Log a warning message + */ + warn(message: string, ...args: unknown[]): void { + if (!this.isProduction) { + console.warn(message, ...args); + } + } + + /** + * Log an error message + */ + error(message: string, ...args: unknown[]): void { + // Always log errors, even in production + console.error(message, ...args); + } + + /** + * Log a debug message + */ + debug(message: string, ...args: unknown[]): void { + if (!this.isProduction) { + console.debug(message, ...args); + } + } +}