import { Injectable, WritableSignal, Injector, inject } from '@angular/core'; import { SelectableDayType } from './calendar-service'; import { storedSignal } from '../shared/utils/stored-signal'; export enum RuleType { IF_THEN = 'if_then', TIME_WINDOW = 'time_window', } export interface BaseRule { id: string; name: string; type: RuleType; enabled: boolean; } export type PlacementStrategy = 'before' | 'after' | 'around' | 'auto'; export interface IfThenRule extends BaseRule { type: RuleType.IF_THEN; dayOfWeek: number; // 0-6, where 0 is Sunday, 6 is Saturday placeDays: number; placeType: SelectableDayType; placement: PlacementStrategy; rewardDays: number; rewardType: SelectableDayType; } export interface TimeWindowRule extends BaseRule { type: RuleType.TIME_WINDOW; startDate: Date; endDate: Date; placeDays: number; placeType: SelectableDayType; } export type VacationRule = IfThenRule | TimeWindowRule; interface SerializedRule { id: string; name: string; type: RuleType; enabled: boolean; dayOfWeek?: number; placeDays: number; placeType: SelectableDayType; placement?: PlacementStrategy; rewardDays?: number; rewardType?: SelectableDayType; startDate?: string | Date; endDate?: string | Date; } @Injectable({ providedIn: 'root', }) export class RuleService { private readonly injector = inject(Injector); private readonly defaultRules: VacationRule[] = [ { id: 'default-samedi-malin', name: 'Samedi Malin', type: RuleType.IF_THEN, enabled: true, dayOfWeek: 6, // Saturday placeDays: 2, placeType: SelectableDayType.CP, placement: 'auto', rewardDays: 1, rewardType: SelectableDayType.OTHER, }, { id: 'default-christmas', name: 'Vacances de Noël', type: RuleType.TIME_WINDOW, enabled: true, startDate: new Date(new Date().getFullYear(), 11, 20), // Dec 20 endDate: new Date(new Date().getFullYear() + 1, 0, 3), // Jan 3 next year placeDays: 5, placeType: SelectableDayType.ANY, }, ]; private rawRulesSignal: WritableSignal; constructor() { this.rawRulesSignal = storedSignal( 'vacationRules', this.defaultRules as unknown as SerializedRule[], this.injector, ); } public get rules(): VacationRule[] { const raw = this.rawRulesSignal(); return raw.map((rule) => { if (rule.type === RuleType.TIME_WINDOW) { return { ...rule, startDate: new Date(rule.startDate as string), endDate: new Date(rule.endDate as string), } as TimeWindowRule; } return rule as IfThenRule; }); } public addRule(rule: VacationRule): void { this.rawRulesSignal.update((rules) => [...rules, rule as unknown as SerializedRule]); } public updateRule(updatedRule: VacationRule): void { this.rawRulesSignal.update((rules) => rules.map((rule) => rule.id === updatedRule.id ? (updatedRule as unknown as SerializedRule) : rule, ), ); } public deleteRule(id: string): void { this.rawRulesSignal.update((rules) => rules.filter((rule) => rule.id !== id)); } public toggleRule(id: string): void { this.rawRulesSignal.update((rules) => rules.map((rule) => (rule.id === id ? { ...rule, enabled: !rule.enabled } : rule)), ); } public reorderRules(previousIndex: number, currentIndex: number): void { this.rawRulesSignal.update((rules) => { const updatedRules = [...rules]; const [movedRule] = updatedRules.splice(previousIndex, 1); updatedRules.splice(currentIndex, 0, movedRule); return updatedRules; }); } }