Files
vac-optimizer/src/app/services/rule-service.ts
T

140 lines
3.5 KiB
TypeScript

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<SerializedRule[]>;
constructor() {
this.rawRulesSignal = storedSignal<SerializedRule[]>(
'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;
});
}
}