From f88c38a054c5cd48e2d22734e75a4f171135657f Mon Sep 17 00:00:00 2001 From: marcantoinem <marc-antoine.m@outlook.com> Date: Tue, 30 Jul 2024 20:31:49 -0400 Subject: [PATCH] improve context utilisation --- .../components/options/courses_selector.rs | 2 +- .../src/frontend/components/options/form.rs | 15 ++---- .../frontend/components/options/personal.rs | 2 +- .../src/frontend/components/options/state.rs | 48 +++++++++++++++++ .../src/frontend/components/options/todo.rs | 17 +++--- .../src/frontend/components/schedules.rs | 7 ++- .../src/frontend/pages/generator.rs | 53 ++++--------------- 7 files changed, 73 insertions(+), 71 deletions(-) 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 63ef907..c0f062a 100644 --- a/aep-schedule-website/src/frontend/components/options/courses_selector.rs +++ b/aep-schedule-website/src/frontend/components/options/courses_selector.rs @@ -28,7 +28,7 @@ fn GroupsChips<F>( where F: Fn() + Copy + 'static, { - let set_modal = use_context::<SetModal>().unwrap().0; + let set_modal = SetModal::from_context(); view! { <div on:click=move |_| { diff --git a/aep-schedule-website/src/frontend/components/options/form.rs b/aep-schedule-website/src/frontend/components/options/form.rs index d7d6efa..2f12062 100644 --- a/aep-schedule-website/src/frontend/components/options/form.rs +++ b/aep-schedule-website/src/frontend/components/options/form.rs @@ -12,20 +12,13 @@ use aep_schedule_generator::algorithm::{generation::SchedulesOptions, schedule:: use leptos::*; #[component] -pub fn OptionsForms<F>( - action: Action<SchedulesOptions, Vec<Schedule>>, - step: ReadSignal<u8>, - validate: F, -) -> impl IntoView -where - F: Fn(OptionState) + Copy + 'static, -{ - let state: OptionState = use_context().unwrap(); +pub fn OptionsForms(action: Action<SchedulesOptions, Vec<Schedule>>) -> impl IntoView { + let state = OptionState::from_context(); let first_generation_done: FirstGenerationDone = use_context().unwrap(); let submit = move || { - validate(state); - if !first_generation_done.0.get() || step.get() != 5 { + state.validate(); + if !first_generation_done.0.get() || state.step.get() != 5 { return; } action.dispatch((&state).into()); diff --git a/aep-schedule-website/src/frontend/components/options/personal.rs b/aep-schedule-website/src/frontend/components/options/personal.rs index 81cf017..bcfebc1 100644 --- a/aep-schedule-website/src/frontend/components/options/personal.rs +++ b/aep-schedule-website/src/frontend/components/options/personal.rs @@ -59,7 +59,7 @@ where } }; view! { - <Schedule col_height="0.35em"> + <Schedule col_height="0.4em"> {(0..5).into_iter().map(|i| { (0..26).into_iter().map(|j| { let j = 2 * j; diff --git a/aep-schedule-website/src/frontend/components/options/state.rs b/aep-schedule-website/src/frontend/components/options/state.rs index 8c9989b..2d974f4 100644 --- a/aep-schedule-website/src/frontend/components/options/state.rs +++ b/aep-schedule-website/src/frontend/components/options/state.rs @@ -16,6 +16,51 @@ pub struct OptionState { 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)] @@ -77,6 +122,9 @@ impl Default for OptionState { 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), } } } diff --git a/aep-schedule-website/src/frontend/components/options/todo.rs b/aep-schedule-website/src/frontend/components/options/todo.rs index 6ba9845..b32e50f 100644 --- a/aep-schedule-website/src/frontend/components/options/todo.rs +++ b/aep-schedule-website/src/frontend/components/options/todo.rs @@ -10,7 +10,7 @@ use crate::frontend::{ #[component] pub fn Step( n: u8, - step: ReadSignal<u8>, + step: RwSignal<u8>, title: &'static str, description: &'static str, #[prop(optional)] children: Option<Children>, @@ -48,13 +48,8 @@ pub fn Step( } #[component] -pub fn Todo( - action: Action<SchedulesOptions, Vec<Schedule>>, - step: ReadSignal<u8>, - section_error: RwSignal<String>, - personal_error: RwSignal<String>, -) -> impl IntoView { - let state: OptionState = use_context().unwrap(); +pub fn Todo(action: Action<SchedulesOptions, Vec<Schedule>>) -> impl IntoView { + let state = OptionState::from_context(); let first_generation_done: FirstGenerationDone = use_context().unwrap(); let submit = move |_| { @@ -62,6 +57,8 @@ pub fn Todo( action.dispatch((&state).into()) }; + let step = state.step; + let disab = move || { let step = step.get(); match step { @@ -76,10 +73,10 @@ pub fn Todo( <div class="lg:py-6 lg:pr-16"> <Step n=1 step title="Ajoutez vos cours" description="Utilisez la barre de recherche à gauche pour trouver et sélectionner vos cours. Une fois les cours sélectionnés, ils apparaîtront comme un onglet."/> <Step n=2 step title="Ouvrez des sections" description="Assurez d'avoir au moins une section d'ouverte pour la théorie et la pratique. En sélectionnant l'onglet du cours et en appuyant sur les sections."> - <span class="text-red-800">{section_error}</span> + <span class="text-red-800">{state.section_error}</span> </Step> <Step n=3 step title="Forcer des heures libres" description="Sélectionnez une plage de temps à avoir absolument libre en pressant et relâchant sur votre horaire personnel."> - <span class="text-red-800">{personal_error}</span> + <span class="text-red-800">{state.personal_error}</span> </Step> <Step n=4 step title="Ajustez les paramètres" description="Bougez les curseurs en bas pour ajuster vos préférences. Vous pouvez choisir d'avoir plus de congés, de commencer en moyenne les cours plus tôt ou plus tard, ou de finir en moyenne plus tôt."/> <div class="flex items-center"> diff --git a/aep-schedule-website/src/frontend/components/schedules.rs b/aep-schedule-website/src/frontend/components/schedules.rs index 0b2b70a..a1ec911 100644 --- a/aep-schedule-website/src/frontend/components/schedules.rs +++ b/aep-schedule-website/src/frontend/components/schedules.rs @@ -1,5 +1,6 @@ use std::rc::Rc; +use crate::frontend::components::options::state::OptionState; use crate::frontend::components::options::todo::Todo; use crate::{backend::routes::get_calendar, frontend::components::schedule::ScheduleComponent}; use aep_schedule_generator::algorithm::generation::SchedulesOptions; @@ -10,10 +11,8 @@ use leptos::*; pub fn SchedulesComponent( read_signal: RwSignal<Option<Vec<Schedule>>>, action: Action<SchedulesOptions, Vec<Schedule>>, - section_error: RwSignal<String>, - personal_error: RwSignal<String>, - step: ReadSignal<u8>, ) -> impl IntoView { + let step = OptionState::from_context().step; view! { <Await future=get_calendar @@ -35,7 +34,7 @@ pub fn SchedulesComponent( } }, _ => view ! { - <Todo action step section_error personal_error/> + <Todo action/> } } } diff --git a/aep-schedule-website/src/frontend/pages/generator.rs b/aep-schedule-website/src/frontend/pages/generator.rs index cfc00c4..52f0d6b 100644 --- a/aep-schedule-website/src/frontend/pages/generator.rs +++ b/aep-schedule-website/src/frontend/pages/generator.rs @@ -7,7 +7,13 @@ use aep_schedule_generator::data::group_sigle::SigleGroup; use leptos::*; #[derive(Clone, Copy)] -pub struct SetModal(pub WriteSignal<Option<SigleGroup>>); +pub struct SetModal(WriteSignal<Option<SigleGroup>>); + +impl SetModal { + pub fn from_context() -> WriteSignal<Option<SigleGroup>> { + use_context::<Self>().unwrap().0 + } +} #[derive(Clone, Copy)] pub struct FirstGenerationDone(pub RwSignal<bool>); @@ -17,8 +23,6 @@ pub fn GeneratorPage() -> impl IntoView { let (hide, set_hide) = create_signal(false); let first_generation_done = create_rw_signal(false); - let (step, set_step) = create_signal(1); - // Creates a reactive value to update the button let action = create_action(move |s: &SchedulesOptions| { let mut s = s.clone(); @@ -31,55 +35,16 @@ pub fn GeneratorPage() -> impl IntoView { let state = OptionState::default(); - let section_error = create_rw_signal("".to_string()); - let personal_error = create_rw_signal("".to_string()); - - let validate = move |state: OptionState| { - let mut options: SchedulesOptions = (&state).into(); - if options.courses_to_take.is_empty() { - set_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."); - section_error.set(error); - set_step.set(2); - return; - } - 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."); - personal_error.set(error); - set_step.set(3); - return; - } - personal_error.set("".to_string()); - set_step.set(5); - }; - provide_context(state); provide_context(SetModal(set_modal)); provide_context(FirstGenerationDone(first_generation_done)); view! { <aside class="left-panel" class=("hide-left-panel", hide)> - <OptionsForms action validate step/> + <OptionsForms action/> </aside> <section class="right-panel"> - <SchedulesComponent section_error personal_error action=action read_signal=action.value() step/> + <SchedulesComponent action=action read_signal=action.value()/> </section> <Notifications modal set_modal/> <button on:click=move |_| {set_hide(false)} id="go-back"><CaretDoubleRight weight=IconWeight::Regular size="3vh"/></button> -- GitLab