diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs index b867144..1994406 100644 --- a/src-tauri/src/config.rs +++ b/src-tauri/src/config.rs @@ -60,17 +60,10 @@ pub struct UserConfig { impl UserConfig { pub fn new(month: u8, year: i32) -> Self { let month = Month::try_from(month).unwrap(); - let total_days = month.num_days(year).unwrap(); - - let total_slots = (1..=total_days) - .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) - .sum(); - - let total_holiday_slots = (1..=total_days) - .filter(|&d| Day(d).is_weekend(month.number_from_month(), year)) - .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) - .sum(); + let total_slots = compute_total_slots(total_days); + let total_holiday_slots = + compute_total_holiday_slots(total_days, month.number_from_month(), year, &[]); Self { month, @@ -86,7 +79,12 @@ impl UserConfig { pub fn with_holidays(mut self, holidays: Vec) -> Self { self.holidays = holidays; - self.total_holiday_slots = self.total_holiday_slots(); + self.total_holiday_slots = compute_total_holiday_slots( + self.total_days, + self.month.number_from_month(), + self.year, + &self.holidays, + ); self } @@ -106,21 +104,14 @@ impl UserConfig { pub fn update_month(&mut self, month: u8) { self.month = Month::try_from(month).unwrap(); - self.total_days = self.month.num_days(self.year).unwrap(); - - self.total_slots = (1..=self.total_days) - .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) - .sum(); - - self.total_holiday_slots = self.total_holiday_slots() - } - - fn total_holiday_slots(&self) -> u8 { - (1..=self.total_days) - .filter(|&d| self.is_holiday_or_weekend(Day(d))) - .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) - .sum() + self.total_slots = compute_total_slots(self.total_days); + self.total_holiday_slots = compute_total_holiday_slots( + self.total_days, + self.month.number_from_month(), + self.year, + &self.holidays, + ); } pub fn is_holiday_or_weekend(&self, day: Day) -> bool { @@ -159,17 +150,10 @@ impl UserConfig { impl Default for UserConfig { fn default() -> Self { let month = Month::try_from(MONTH).unwrap(); - let total_days = month.num_days(YEAR).unwrap(); - - let total_slots = (1..=total_days) - .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) - .sum(); - - let total_holiday_slots = (1..=total_days) - .filter(|&d| Day(d).is_weekend(month.number_from_month(), YEAR)) - .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) - .sum(); + let total_slots = compute_total_slots(total_days); + let total_holiday_slots = + compute_total_holiday_slots(total_days, month.number_from_month(), YEAR, &[]); Self { month, @@ -189,20 +173,14 @@ impl TryFrom for UserConfig { fn try_from(value: UserConfigDTO) -> Result { let month = Month::try_from(value.month)?; - let total_days = month.num_days(value.year).context("Failed to parse")?; - - let total_slots = (1..=total_days) - .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) - .sum(); - - let total_holiday_slots = (1..=total_days) - .filter(|&d| { - Day(d).is_weekend(month.number_from_month(), value.year) - || value.holidays.contains(&d) - }) - .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) - .sum(); + let total_slots = compute_total_slots(total_days); + let total_holiday_slots = compute_total_holiday_slots( + total_days, + month.number_from_month(), + value.year, + &value.holidays, + ); Ok(Self { month, @@ -221,6 +199,19 @@ impl TryFrom for UserConfig { } } +fn compute_total_slots(total_days: u8) -> u8 { + (1..=total_days) + .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) + .sum() +} + +fn compute_total_holiday_slots(total_days: u8, month_num: u32, year: i32, holidays: &[u8]) -> u8 { + (1..=total_days) + .filter(|&d| Day(d).is_weekend(month_num, year) || holidays.contains(&d)) + .map(|d| if Day(d).is_open_shift() { 2 } else { 1 }) + .sum() +} + #[cfg(test)] mod tests { use crate::{ diff --git a/src-tauri/src/export.rs b/src-tauri/src/export.rs index a6f1895..42b0605 100644 --- a/src-tauri/src/export.rs +++ b/src-tauri/src/export.rs @@ -181,6 +181,6 @@ fn month_to_greek(month: u32) -> &'static str { 10 => "Οκτώβριος", 11 => "Νοέμβριος", 12 => "Δεκέμβριος", - _ => panic!("Unable to find translation for month {}", month), + _ => unreachable!("Invalid month: {}", month), } } diff --git a/src-tauri/src/scheduler.rs b/src-tauri/src/scheduler.rs index b16281b..d1ce3f2 100644 --- a/src-tauri/src/scheduler.rs +++ b/src-tauri/src/scheduler.rs @@ -65,7 +65,7 @@ impl Scheduler { let solved_in_thread = AtomicBool::new(false); - let sovled_state = valid_resident_ids.par_iter().find_map_any(|&id| { + let solved_state = valid_resident_ids.par_iter().find_map_any(|&id| { let mut local_schedule = schedule.clone(); let mut local_tracker = tracker.clone(); @@ -90,7 +90,7 @@ impl Scheduler { } }); - if let Some((solved_schedule, solved_tracker)) = sovled_state { + if let Some((solved_schedule, solved_tracker)) = solved_state { *schedule = solved_schedule; *tracker = solved_tracker; return Ok(true); diff --git a/src-tauri/src/workload.rs b/src-tauri/src/workload.rs index 4af0d58..3540dfb 100644 --- a/src-tauri/src/workload.rs +++ b/src-tauri/src/workload.rs @@ -30,7 +30,7 @@ impl WorkloadBounds { bounds } - pub fn calculate_max_workloads(&mut self, residents: &Vec, total_slots: u8) { + pub fn calculate_max_workloads(&mut self, residents: &[Resident], total_slots: u8) { let non_manual_residents: Vec<_> = residents .iter() .filter(|r| r.max_shifts.is_none()) @@ -64,7 +64,7 @@ impl WorkloadBounds { pub fn calculate_max_holiday_shifts( &mut self, - residents: &Vec, + residents: &[Resident], total_holiday_slots: u8, ) { let total_residents = residents.len(); @@ -74,7 +74,7 @@ impl WorkloadBounds { } } - pub fn calculate_max_by_shift_type(&mut self, residents: &Vec) { + pub fn calculate_max_by_shift_type(&mut self, residents: &[Resident]) { let mut upper_limits = HashMap::new(); let shift_types = [ ShiftType::OpenFirst, diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index c16cdc2..5ad2f4c 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -72,7 +72,7 @@ {#if rota.metrics.length > 0}
-
+

Δικαιωσυνη

@@ -169,7 +169,7 @@
{/if} -
+
rota.syncProjectMonth()} class="w-full appearance-none rounded-xl border border-zinc-200 bg-white px-4 py-3 font-semibold text-zinc-700 transition-all outline-none focus:border-zinc-400 focus:ring-4 focus:ring-zinc-100" > {#each yearOptions as year} diff --git a/src/routes/components/schedule/generate.svelte b/src/routes/components/schedule/generate.svelte index 8d01ab6..d13a892 100644 --- a/src/routes/components/schedule/generate.svelte +++ b/src/routes/components/schedule/generate.svelte @@ -50,6 +50,7 @@ let config = rota.toDTO(); rota.engineStatus = EngineStatus.Running; rota.lastMessage = ""; + await new Promise((resolve) => setTimeout(resolve, 50)); try { rota.solution = await invoke("generate", { config }); diff --git a/src/routes/state.svelte.ts b/src/routes/state.svelte.ts index a5bbe9b..1ddc058 100644 --- a/src/routes/state.svelte.ts +++ b/src/routes/state.svelte.ts @@ -39,13 +39,9 @@ export class RotaState { metrics: ResidentMetrics[] = $state([]); - projectMonth = $state(new CalendarDate(2026, 2, 1)); - - syncProjectMonth() { - this.projectMonth = new CalendarDate(this.selectedYear, this.selectedMonth, 1); - } - + projectMonth = $derived(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") }));