// 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([]); selectedMonth = $state(2); selectedYear = $state(2026); holidays = $state([]); forbiddenPairs = $state([]); 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({} 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>; }; export type UserConfigDTO = { month: number; year: number; holidays: Array; residents: Array; toxic_pairs: Array<[string, string]>; }; export type ResidentDTO = { id: string; name: string; negativeShifts: Array; manualShifts: Array<{ day: number; position: ShiftPosition }>; maxShifts: number | null; allowedTypes: Array; 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: "Τρέξε τον αλγόριθμο ανάθεσης εφημεριών, εξήγαγε τα αποτελέσματα." } ];