140 lines
3.5 KiB
TypeScript
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;
|
|
});
|
|
}
|
|
}
|