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,
-        }
-    }
-}