diff --git a/aep-schedule-website/src/frontend/components/options/courses_selector.rs b/aep-schedule-website/src/frontend/components/options/courses_selector.rs index c0f062a24c7deb2836a10f63e32046eacc83cc8a..3b91721eb6a4f2d53dca06db874f56225131b613 100644 --- a/aep-schedule-website/src/frontend/components/options/courses_selector.rs +++ b/aep-schedule-website/src/frontend/components/options/courses_selector.rs @@ -1,5 +1,3 @@ -use super::state::OptionState; -use super::state::ReactiveCourse; use crate::backend::routes::get_courses; use crate::frontend::components::common::tab::Tab; use crate::frontend::components::icons::bell_ringing::BellRinging; @@ -8,8 +6,10 @@ use crate::frontend::components::icons::x::X; use crate::frontend::components::icons::IconWeight; use crate::frontend::components::options::personal::PersonalTimeSelector; use crate::frontend::components::options::search::SearchCourse; -use crate::frontend::components::options::state::ReactiveCourseType; use crate::frontend::pages::generator::SetModal; +use crate::frontend::state::reactive_course::ReactiveCourse; +use crate::frontend::state::reactive_course::ReactiveCourseType; +use crate::frontend::state::OptionState; use aep_schedule_generator::data::group::Group; use aep_schedule_generator::data::group_sigle::GroupType; use aep_schedule_generator::data::group_sigle::SigleGroup; diff --git a/aep-schedule-website/src/frontend/components/options/form.rs b/aep-schedule-website/src/frontend/components/options/form.rs index 2f1206275af10658be4c10c26176599f58e22a56..9555432a232f2b2c1960d2d0ab51d83c6309e6f7 100644 --- a/aep-schedule-website/src/frontend/components/options/form.rs +++ b/aep-schedule-website/src/frontend/components/options/form.rs @@ -1,12 +1,10 @@ use crate::frontend::{ components::{ common::number_input::NumberInput, - options::{ - courses_selector::CoursesSelector, optimizations::SelectOptimizations, - state::OptionState, - }, + options::{courses_selector::CoursesSelector, optimizations::SelectOptimizations}, }, pages::generator::FirstGenerationDone, + state::OptionState, }; use aep_schedule_generator::algorithm::{generation::SchedulesOptions, schedule::Schedule}; use leptos::*; diff --git a/aep-schedule-website/src/frontend/components/options/mod.rs b/aep-schedule-website/src/frontend/components/options/mod.rs index 588858cffdef257b5fcd2af607602ecfad5165cb..7a3dee47f147d46314c6b6f5d6d9443f4efe390a 100644 --- a/aep-schedule-website/src/frontend/components/options/mod.rs +++ b/aep-schedule-website/src/frontend/components/options/mod.rs @@ -3,5 +3,4 @@ pub mod form; pub mod optimizations; pub mod personal; pub mod search; -pub mod state; pub mod todo; diff --git a/aep-schedule-website/src/frontend/components/options/optimizations.rs b/aep-schedule-website/src/frontend/components/options/optimizations.rs index 207e6df64b7b9845134ab8373b43c47ed1be4aff..074d7668ec0d922ca363f982eed6a127977c633e 100644 --- a/aep-schedule-website/src/frontend/components/options/optimizations.rs +++ b/aep-schedule-website/src/frontend/components/options/optimizations.rs @@ -1,6 +1,8 @@ -use super::state::OptionState; -use crate::frontend::components::icons::{ - calendar_check::CalendarCheck, house::House, sun::Sun, sun_horizon::SunHorizon, IconWeight, +use crate::frontend::{ + components::icons::{ + calendar_check::CalendarCheck, house::House, sun::Sun, sun_horizon::SunHorizon, IconWeight, + }, + state::OptionState, }; use leptos::*; use std::cmp; diff --git a/aep-schedule-website/src/frontend/components/options/search.rs b/aep-schedule-website/src/frontend/components/options/search.rs index 02773d9c2bde40c8482d23a8fceb25b6ba7b47c3..12a223fc02b06214c21407a7fe82052901fc5239 100644 --- a/aep-schedule-website/src/frontend/components/options/search.rs +++ b/aep-schedule-website/src/frontend/components/options/search.rs @@ -1,5 +1,7 @@ -use super::state::ReactiveCourse; -use crate::frontend::components::common::autocomplete::{AutoComplete, AutoCompleteOption}; +use crate::frontend::{ + components::common::autocomplete::{AutoComplete, AutoCompleteOption}, + state::reactive_course::ReactiveCourse, +}; use aep_schedule_generator::data::course::CourseName; use leptos::*; diff --git a/aep-schedule-website/src/frontend/components/options/todo.rs b/aep-schedule-website/src/frontend/components/options/todo.rs index b32e50fcfdbab84a7230e2628fcf196da0c12a9a..14cebb269a5ae06a610f4e6073f05d7ec51ebf00 100644 --- a/aep-schedule-website/src/frontend/components/options/todo.rs +++ b/aep-schedule-website/src/frontend/components/options/todo.rs @@ -3,9 +3,7 @@ use std::cmp::Ordering; use aep_schedule_generator::algorithm::{generation::SchedulesOptions, schedule::Schedule}; use leptos::*; -use crate::frontend::{ - components::options::state::OptionState, pages::generator::FirstGenerationDone, -}; +use crate::frontend::{pages::generator::FirstGenerationDone, state::OptionState}; #[component] pub fn Step( diff --git a/aep-schedule-website/src/frontend/components/schedules.rs b/aep-schedule-website/src/frontend/components/schedules.rs index a1ec911a90e81cbbb0170677d78a48154a71f752..a89ff4b2a5b8c1ff8ebe7ce8084420a8a0da2a58 100644 --- a/aep-schedule-website/src/frontend/components/schedules.rs +++ b/aep-schedule-website/src/frontend/components/schedules.rs @@ -1,7 +1,7 @@ use std::rc::Rc; -use crate::frontend::components::options::state::OptionState; use crate::frontend::components::options::todo::Todo; +use crate::frontend::state::OptionState; use crate::{backend::routes::get_calendar, frontend::components::schedule::ScheduleComponent}; use aep_schedule_generator::algorithm::generation::SchedulesOptions; use aep_schedule_generator::algorithm::schedule::Schedule; diff --git a/aep-schedule-website/src/frontend/mod.rs b/aep-schedule-website/src/frontend/mod.rs index b84c897231a9cb3bc7791c3c7f679d2ceaab0184..db1870003e5a06d6e5e19f6b1937e5ea8389d47a 100644 --- a/aep-schedule-website/src/frontend/mod.rs +++ b/aep-schedule-website/src/frontend/mod.rs @@ -1,3 +1,4 @@ pub mod app; pub mod components; pub mod pages; +pub mod state; diff --git a/aep-schedule-website/src/frontend/pages/generator.rs b/aep-schedule-website/src/frontend/pages/generator.rs index 52f0d6ba52b4fcf93dd9771ea5075f9b1d1040df..78a231a2ded882a6273d46987da368160bb43de5 100644 --- a/aep-schedule-website/src/frontend/pages/generator.rs +++ b/aep-schedule-website/src/frontend/pages/generator.rs @@ -1,7 +1,7 @@ use crate::frontend::components::icons::{caret_double_right::CaretDoubleRight, IconWeight}; use crate::frontend::components::notifications::Notifications; -use crate::frontend::components::options::state::OptionState; use crate::frontend::components::{options::form::OptionsForms, schedules::SchedulesComponent}; +use crate::frontend::state::OptionState; use aep_schedule_generator::algorithm::generation::SchedulesOptions; use aep_schedule_generator::data::group_sigle::SigleGroup; use leptos::*; diff --git a/aep-schedule-website/src/frontend/state/mod.rs b/aep-schedule-website/src/frontend/state/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..209e2dd98629f8d3ba259878a019c7b7896c8282 --- /dev/null +++ b/aep-schedule-website/src/frontend/state/mod.rs @@ -0,0 +1,128 @@ +use aep_schedule_generator::{ + algorithm::{generation::SchedulesOptions, scores::EvaluationOption}, + data::time::week::Week, +}; +use leptos::*; +use reactive_course::ReactiveCourse; + +use crate::backend::routes::get_course; + +pub mod reactive_course; + +#[derive(Copy, Clone)] +pub struct OptionState { + pub stored_courses: StoredValue<Vec<ReactiveCourse>>, + pub action_courses: Action<String, Vec<ReactiveCourse>>, + pub week: [RwSignal<u64>; 5], + pub max_nb_conflicts: RwSignal<u8>, + pub day_off: RwSignal<u8>, + pub morning: RwSignal<i8>, + pub finish_early: RwSignal<u8>, + pub section_error: RwSignal<String>, + pub personal_error: RwSignal<String>, + pub step: RwSignal<u8>, +} + +impl OptionState { + pub fn from_context() -> Self { + use_context().unwrap() + } + + pub fn validate(self) { + let mut options: SchedulesOptions = (&self).into(); + if options.courses_to_take.is_empty() { + self.step.set(1); + return; + } + let mut impossible_courses = options.get_impossible_course().into_iter(); + if let Some(first_impossible_course) = impossible_courses.next() { + let mut error = format!("Les sections des/du cours {}", first_impossible_course); + for impossible_course in impossible_courses { + error.push_str(", "); + error.push_str(&impossible_course); + } + error.push_str(" sont toutes fermées."); + self.section_error.set(error); + self.step.set(2); + return; + } + self.section_error.set("".to_string()); + options.apply_personal_schedule(); + let mut impossible_courses = options.get_impossible_course().into_iter(); + if let Some(first_impossible_course) = impossible_courses.next() { + let mut error = format!("Les sections des/du cours {}", first_impossible_course); + for impossible_course in impossible_courses { + error.push_str(", "); + error.push_str(&impossible_course); + } + error.push_str(" sont en conflits avec les heures libres sélectionnées."); + self.personal_error.set(error); + self.step.set(3); + return; + } + self.personal_error.set("".to_string()); + self.step.set(5); + } +} + +impl Default for OptionState { + fn default() -> Self { + let stored_courses: StoredValue<Vec<ReactiveCourse>> = store_value(vec![]); + + let action_courses = create_action(move |sigle: &String| { + let sigle = sigle.clone(); + async move { + if let Ok(c) = get_course(sigle).await { + if !stored_courses + .get_value() + .iter() + .any(|react_c| react_c.sigle == c.sigle) + { + stored_courses.update_value(|courses| courses.push(c.into())); + } + } + stored_courses.get_value() + } + }); + + Self { + stored_courses, + action_courses, + max_nb_conflicts: create_rw_signal(0), + week: std::array::from_fn(|_i| create_rw_signal(0)), + day_off: create_rw_signal(3), + morning: create_rw_signal(1), + finish_early: create_rw_signal(1), + section_error: create_rw_signal("".to_string()), + personal_error: create_rw_signal("".to_string()), + step: create_rw_signal(0), + } + } +} + +impl From<&OptionState> for SchedulesOptions { + fn from(state: &OptionState) -> Self { + let courses_to_take = state + .action_courses + .value() + .get() + .unwrap_or_default() + .into_iter() + .map(|c| c.into()) + .collect(); + let max_nb_conflicts = state.max_nb_conflicts.get(); + let evaluation = EvaluationOption { + day_off: state.day_off.get(), + morning: state.morning.get(), + finish_early: state.finish_early.get(), + }; + let user_conflicts = Week::new(state.week.map(|s| s.get() << 2)); + Self { + courses_to_take, + max_nb_conflicts, + evaluation, + user_conflicts, + max_size: 10, + } + } +} diff --git a/aep-schedule-website/src/frontend/components/options/state.rs b/aep-schedule-website/src/frontend/state/reactive_course.rs similarity index 51% rename from aep-schedule-website/src/frontend/components/options/state.rs rename to aep-schedule-website/src/frontend/state/reactive_course.rs index 2d974f4f7fd42fa53be60ca0ade4fb057b56f334..3e6b0648cc46624e267b2f23da6326722139bc16 100644 --- a/aep-schedule-website/src/frontend/components/options/state.rs +++ b/aep-schedule-website/src/frontend/state/reactive_course.rs @@ -1,68 +1,7 @@ -use aep_schedule_generator::{ - algorithm::{generation::SchedulesOptions, scores::EvaluationOption}, - data::{course::Course, course_type::CourseType, groups::Groups, time::week::Week}, -}; +use aep_schedule_generator::data::{course::Course, course_type::CourseType, groups::Groups}; use compact_str::CompactString; use leptos::*; -use crate::backend::routes::get_course; - -#[derive(Copy, Clone)] -pub struct OptionState { - pub stored_courses: StoredValue<Vec<ReactiveCourse>>, - pub action_courses: Action<String, Vec<ReactiveCourse>>, - pub week: [RwSignal<u64>; 5], - pub max_nb_conflicts: RwSignal<u8>, - pub day_off: RwSignal<u8>, - pub morning: RwSignal<i8>, - pub finish_early: RwSignal<u8>, - pub section_error: RwSignal<String>, - pub personal_error: RwSignal<String>, - pub step: RwSignal<u8>, -} - -impl OptionState { - pub fn from_context() -> Self { - use_context().unwrap() - } - - pub fn validate(self) { - let mut options: SchedulesOptions = (&self).into(); - if options.courses_to_take.is_empty() { - self.step.set(1); - return; - } - let mut impossible_courses = options.get_impossible_course().into_iter(); - if let Some(first_impossible_course) = impossible_courses.next() { - let mut error = format!("Les sections des/du cours {}", first_impossible_course); - for impossible_course in impossible_courses { - error.push_str(", "); - error.push_str(&impossible_course); - } - error.push_str(" sont toutes fermées."); - self.section_error.set(error); - self.step.set(2); - return; - } - self.section_error.set("".to_string()); - options.apply_personal_schedule(); - let mut impossible_courses = options.get_impossible_course().into_iter(); - if let Some(first_impossible_course) = impossible_courses.next() { - let mut error = format!("Les sections des/du cours {}", first_impossible_course); - for impossible_course in impossible_courses { - error.push_str(", "); - error.push_str(&impossible_course); - } - error.push_str(" sont en conflits avec les heures libres sélectionnées."); - self.personal_error.set(error); - self.step.set(3); - return; - } - self.personal_error.set("".to_string()); - self.step.set(5); - } -} - #[derive(Clone, Debug)] pub enum ReactiveCourseType { TheoOnly { @@ -94,41 +33,6 @@ pub struct ReactiveCourse { pub nb_credit: usize, } -impl Default for OptionState { - fn default() -> Self { - let stored_courses: StoredValue<Vec<ReactiveCourse>> = store_value(vec![]); - - let action_courses = create_action(move |sigle: &String| { - let sigle = sigle.clone(); - async move { - if let Ok(c) = get_course(sigle).await { - if !stored_courses - .get_value() - .iter() - .any(|react_c| react_c.sigle == c.sigle) - { - stored_courses.update_value(|courses| courses.push(c.into())); - } - } - stored_courses.get_value() - } - }); - - Self { - stored_courses, - action_courses, - max_nb_conflicts: create_rw_signal(0), - week: std::array::from_fn(|_i| create_rw_signal(0)), - day_off: create_rw_signal(3), - morning: create_rw_signal(1), - finish_early: create_rw_signal(1), - section_error: create_rw_signal("".to_string()), - personal_error: create_rw_signal("".to_string()), - step: create_rw_signal(0), - } - } -} - impl From<ReactiveCourse> for Course { fn from(value: ReactiveCourse) -> Self { let course_type = match value.course_type { @@ -242,30 +146,3 @@ impl From<Course> for ReactiveCourse { } } } - -impl From<&OptionState> for SchedulesOptions { - fn from(state: &OptionState) -> Self { - let courses_to_take = state - .action_courses - .value() - .get() - .unwrap_or_default() - .into_iter() - .map(|c| c.into()) - .collect(); - let max_nb_conflicts = state.max_nb_conflicts.get(); - let evaluation = EvaluationOption { - day_off: state.day_off.get(), - morning: state.morning.get(), - finish_early: state.finish_early.get(), - }; - let user_conflicts = Week::new(state.week.map(|s| s.get() << 2)); - Self { - courses_to_take, - max_nb_conflicts, - evaluation, - user_conflicts, - max_size: 10, - } - } -}