152 lines
4.1 KiB
TypeScript
152 lines
4.1 KiB
TypeScript
// state.svelte.ts
|
||
import { CalendarDate, getDayOfWeek } from "@internationalized/date";
|
||
|
||
export interface Resident {
|
||
id: string;
|
||
name: string;
|
||
negativeShifts: CalendarDate[];
|
||
manualShifts: CalendarDate[];
|
||
maxShifts: number | undefined;
|
||
allowedTypes: string[];
|
||
reducedLoad: boolean;
|
||
}
|
||
|
||
export interface ForbiddenPair {
|
||
id1: string;
|
||
id2: string;
|
||
}
|
||
|
||
export class RotaState {
|
||
currentStep = $state(1);
|
||
residents = $state<Resident[]>([]);
|
||
selectedMonth = $state(2);
|
||
selectedYear = $state(2026);
|
||
holidays = $state<CalendarDate[]>([]);
|
||
forbiddenPairs = $state<ForbiddenPair[]>([]);
|
||
|
||
projectMonth = $state(new CalendarDate(2026, 2, 1));
|
||
|
||
syncProjectMonth() {
|
||
this.projectMonth = new CalendarDate(this.selectedYear, this.selectedMonth, 1);
|
||
}
|
||
|
||
projectMonthDays = $derived(this.projectMonth.calendar.getDaysInMonth(this.projectMonth));
|
||
daysArray = $derived(Array.from({ length: this.projectMonthDays }, (_, i) => i + 1));
|
||
emptySlots = $derived(Array.from({ length: getDayOfWeek(this.projectMonth, "en-GB") }));
|
||
|
||
solution = $state<MonthlySchedule>({} as MonthlySchedule);
|
||
|
||
addResident() {
|
||
this.residents.push({
|
||
id: crypto.randomUUID(),
|
||
name: "",
|
||
negativeShifts: [],
|
||
manualShifts: [],
|
||
maxShifts: undefined,
|
||
allowedTypes: ["Closed", "OpenFirst", "OpenSecond"],
|
||
reducedLoad: false
|
||
});
|
||
}
|
||
|
||
removeResident(id: string) {
|
||
this.residents = this.residents.filter((r) => r.id !== id);
|
||
}
|
||
|
||
findResident(id: string) {
|
||
return this.residents.find((r) => r.id === id);
|
||
}
|
||
|
||
addForbiddenPair() {
|
||
if (this.residents.length < 2) return;
|
||
this.forbiddenPairs.push({
|
||
id1: this.residents[0].id,
|
||
id2: this.residents[1].id
|
||
});
|
||
}
|
||
|
||
removeForbiddenPair(index: number) {
|
||
this.forbiddenPairs.splice(index, 1);
|
||
}
|
||
|
||
toDTO(): UserConfigDTO {
|
||
return {
|
||
month: this.selectedMonth,
|
||
year: this.selectedYear,
|
||
holidays: this.holidays.map((d) => d.day),
|
||
residents: this.residents.map((r) => ({
|
||
id: r.id,
|
||
name: r.name,
|
||
negativeShifts: r.negativeShifts.map((d) => d.day),
|
||
manualShifts: r.manualShifts.map((s) => ({
|
||
day: s.day,
|
||
position: "First"
|
||
})),
|
||
maxShifts: r.maxShifts ?? null,
|
||
allowedTypes: r.allowedTypes as ShiftType[],
|
||
reducedLoad: r.reducedLoad
|
||
})),
|
||
|
||
toxic_pairs: this.forbiddenPairs.map((pair) => [pair.id1, pair.id2])
|
||
};
|
||
}
|
||
}
|
||
|
||
export const rota = new RotaState();
|
||
|
||
export type MonthlyScheduleDTO = {
|
||
schedule: Record<number, Record<ShiftPosition, string>>;
|
||
};
|
||
|
||
export type UserConfigDTO = {
|
||
month: number;
|
||
year: number;
|
||
holidays: Array<number>;
|
||
residents: Array<ResidentDTO>;
|
||
toxic_pairs: Array<[string, string]>;
|
||
};
|
||
|
||
export type ResidentDTO = {
|
||
id: string;
|
||
name: string;
|
||
negativeShifts: Array<number>;
|
||
manualShifts: Array<{ day: number; position: ShiftPosition }>;
|
||
maxShifts: number | null;
|
||
allowedTypes: Array<ShiftType>;
|
||
reducedLoad: boolean;
|
||
};
|
||
|
||
export type ShiftType = "Closed" | "OpenFirst" | "OpenSecond";
|
||
|
||
export type ShiftPosition = "First" | "Second";
|
||
|
||
export type SlotKey = `${number}-${"First" | "Second"}`;
|
||
export type MonthlySchedule = { [key: SlotKey]: string };
|
||
|
||
export const steps = [
|
||
{
|
||
id: 1,
|
||
title: "Περίοδος",
|
||
description: "Καθόρισε την περίοδο και τις αργίες του μήνα."
|
||
},
|
||
{
|
||
id: 2,
|
||
title: "Ειδικευόμενοι",
|
||
description: "Δημιούργησε νέα εγγραφή ειδικευόμενου."
|
||
},
|
||
{
|
||
id: 3,
|
||
title: "Προχωρημένα",
|
||
description: "Επίλεξε ζευγάρια ατόμων που δεν μπορούν να κάνουν μαζί εφημερία."
|
||
},
|
||
{
|
||
id: 4,
|
||
title: "Επισκόπηση",
|
||
description: "Έλεγξε το πρόγραμμα με τις υποχρεωτικές υπάρχουσες εφημερίες."
|
||
},
|
||
{
|
||
id: 5,
|
||
title: "Δημιουργία",
|
||
description: "Τρέξε τον αλγόριθμο ανάθεσης εφημεριών, εξήγαγε τα αποτελέσματα."
|
||
}
|
||
];
|