feat: use Dioxus query for fetching data
This commit is contained in:
		| @@ -2,12 +2,16 @@ use crate::route::Route; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_query::prelude::{use_init_query_client}; | ||||
| use crate::query::{QueryErrors, QueryKey, QueryValue}; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn App() -> Element { | ||||
|     use_init_query_client::<QueryValue, QueryErrors, QueryKey>(); | ||||
|      | ||||
|     rsx! { | ||||
|         div { | ||||
|             class: "min-h-screen text-zinc-200 bg-zinc-800", | ||||
|             class: "min-h-screen text-zinc-200 bg-zinc-800 pt-4 pb-36", | ||||
|             Router::<Route> {} | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -11,4 +11,4 @@ pub(crate) mod sticky_bottom; | ||||
| pub(crate) mod category_input; | ||||
| pub(crate) mod reoccurrence_input; | ||||
| pub(crate) mod layout; | ||||
| mod navigation_item; | ||||
| pub(crate) mod navigation_item; | ||||
|   | ||||
| @@ -1,31 +1,77 @@ | ||||
| use crate::components::bottom_panel::BottomPanel; | ||||
| use crate::components::navigation::Navigation; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::route::Route; | ||||
| use chrono::NaiveDate; | ||||
| use chrono::{Datelike, Local, Locale}; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use crate::components::create_task_button::CreateTaskButton; | ||||
| use crate::components::sticky_bottom::StickyBottom; | ||||
| use crate::components::task_form::TaskForm; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use dioxus_query::prelude::QueryResult; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::query::QueryValue; | ||||
| use crate::query::tasks::use_tasks_in_category_query; | ||||
| use crate::models::task::Task; | ||||
|  | ||||
| const CALENDAR_LENGTH_DAYS: usize = 366 * 3; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategoryCalendarPage() -> Element { | ||||
|     let tasks = use_server_future( | ||||
|         move || get_tasks_in_category(Category::Calendar { | ||||
|             date: NaiveDate::default(), | ||||
|             reoccurrence: None, | ||||
|             time: None, | ||||
|         }) | ||||
|     )?.unwrap().unwrap(); | ||||
|     let tasks = use_tasks_in_category_query(Category::Calendar { | ||||
|         date: Local::now().date_naive(), | ||||
|         reoccurrence: None, | ||||
|         time: None, | ||||
|     }); | ||||
|     let tasks_query_result = tasks.result(); | ||||
|  | ||||
|     rsx! { | ||||
|         TaskList { | ||||
|             tasks: tasks, | ||||
|             class: "pb-36" | ||||
|         match tasks_query_result.value() { | ||||
|             QueryResult::Ok(QueryValue::Tasks(tasks)) | ||||
|             | QueryResult::Loading(Some(QueryValue::Tasks(tasks))) => { | ||||
|                 let today_date = Local::now().date_naive(); | ||||
|                  | ||||
|                 rsx! { | ||||
|                     div { | ||||
|                         class: "pt-4 flex flex-col gap-8", | ||||
|                         for date_current in today_date.iter_days().take(CALENDAR_LENGTH_DAYS) { | ||||
|                             div { | ||||
|                                 class: "flex flex-col gap-4", | ||||
|                                 div { | ||||
|                                     class: "px-8 flex flex-row items-center gap-2 font-bold", | ||||
|                                     div { | ||||
|                                         class: "pt-1", | ||||
|                                         { | ||||
|                                             date_current | ||||
|                                             .format_localized( | ||||
|                                                 format!( | ||||
|                                                     "%A %-d. %B{}",  | ||||
|                                                     if date_current.year() != today_date.year() {" %Y"}  | ||||
|                                                     else {""} | ||||
|                                                 ).as_str(), | ||||
|                                                 Locale::en_US | ||||
|                                             ) | ||||
|                                             .to_string() | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                                 TaskList { | ||||
|                                     tasks: tasks.iter().filter(|task| { | ||||
|                                         if let Category::Calendar { date, .. } = task.category() { | ||||
|                                             *date == date_current | ||||
|                                         } else { | ||||
|                                             panic!("Unexpected category."); | ||||
|                                         } | ||||
|                                     }).cloned().collect::<Vec<Task>>() | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     }    | ||||
|                 } | ||||
|             }, | ||||
|             QueryResult::Loading(None) => rsx! { | ||||
|                 // TODO: Add a loading indicator. | ||||
|             }, | ||||
|             QueryResult::Err(errors) => rsx! { | ||||
|                 div { | ||||
|                     "Errors occurred: {errors:?}" | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,27 +1,14 @@ | ||||
| use crate::components::bottom_panel::BottomPanel; | ||||
| use crate::components::navigation::Navigation; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::route::Route; | ||||
| use chrono::NaiveDate; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use crate::components::create_task_button::CreateTaskButton; | ||||
| use crate::components::sticky_bottom::StickyBottom; | ||||
| use crate::components::task_form::TaskForm; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use crate::components::pages::category_page::CategoryPage; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategoryDonePage() -> Element { | ||||
|     let tasks = use_server_future( | ||||
|         move || get_tasks_in_category(Category::Done) | ||||
|     )?.unwrap().unwrap(); | ||||
|  | ||||
|     rsx! { | ||||
|         TaskList { | ||||
|             tasks: tasks, | ||||
|             class: "pb-36" | ||||
|         CategoryPage { | ||||
|             category: Category::Done, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,27 +1,14 @@ | ||||
| use crate::components::bottom_panel::BottomPanel; | ||||
| use crate::components::navigation::Navigation; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::route::Route; | ||||
| use chrono::NaiveDate; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use crate::components::create_task_button::CreateTaskButton; | ||||
| use crate::components::sticky_bottom::StickyBottom; | ||||
| use crate::components::task_form::TaskForm; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use crate::components::pages::category_page::CategoryPage; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategoryInboxPage() -> Element { | ||||
|     let tasks = use_server_future( | ||||
|         move || get_tasks_in_category(Category::Inbox) | ||||
|     )?.unwrap().unwrap(); | ||||
|  | ||||
|     rsx! { | ||||
|         TaskList { | ||||
|             tasks: tasks, | ||||
|             class: "pb-36" | ||||
|         CategoryPage { | ||||
|             category: Category::Inbox, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,27 +1,14 @@ | ||||
| use crate::components::bottom_panel::BottomPanel; | ||||
| use crate::components::navigation::Navigation; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::route::Route; | ||||
| use chrono::NaiveDate; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use crate::components::create_task_button::CreateTaskButton; | ||||
| use crate::components::sticky_bottom::StickyBottom; | ||||
| use crate::components::task_form::TaskForm; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use crate::components::pages::category_page::CategoryPage; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategoryLongTermPage() -> Element { | ||||
|     let tasks = use_server_future( | ||||
|         move || get_tasks_in_category(Category::LongTerm) | ||||
|     )?.unwrap().unwrap(); | ||||
|  | ||||
|     rsx! { | ||||
|         TaskList { | ||||
|             tasks: tasks, | ||||
|             class: "pb-36" | ||||
|         CategoryPage { | ||||
|             category: Category::LongTerm, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,27 +1,14 @@ | ||||
| use crate::components::bottom_panel::BottomPanel; | ||||
| use crate::components::navigation::Navigation; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::route::Route; | ||||
| use chrono::NaiveDate; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use crate::components::create_task_button::CreateTaskButton; | ||||
| use crate::components::sticky_bottom::StickyBottom; | ||||
| use crate::components::task_form::TaskForm; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use crate::components::pages::category_page::CategoryPage; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategoryNextStepsPage() -> Element { | ||||
|     let tasks = use_server_future( | ||||
|         move || get_tasks_in_category(Category::NextSteps) | ||||
|     )?.unwrap().unwrap(); | ||||
|  | ||||
|     rsx! { | ||||
|         TaskList { | ||||
|             tasks: tasks, | ||||
|             class: "pb-36" | ||||
|         CategoryPage { | ||||
|             category: Category::NextSteps, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										32
									
								
								src/components/pages/category_page.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/components/pages/category_page.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::query::tasks::use_tasks_in_category_query; | ||||
| use crate::query::QueryValue; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_query::prelude::QueryResult; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategoryPage(category: Category) -> Element { | ||||
|     let tasks_query = use_tasks_in_category_query(category); | ||||
|     let tasks_query_result = tasks_query.result(); | ||||
|  | ||||
|     match tasks_query_result.value() { | ||||
|         QueryResult::Ok(QueryValue::Tasks(tasks)) | ||||
|         | QueryResult::Loading(Some(QueryValue::Tasks(tasks))) => rsx! { | ||||
|             TaskList { | ||||
|                 tasks: tasks.clone(), | ||||
|                 class: "pb-36" | ||||
|             } | ||||
|         }, | ||||
|         QueryResult::Loading(None) => rsx! { | ||||
|             // TODO: Add a loading indicator. | ||||
|         }, | ||||
|         QueryResult::Err(errors) => rsx! { | ||||
|             div { | ||||
|                 "Errors occurred: {errors:?}" | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,27 +1,14 @@ | ||||
| use crate::components::bottom_panel::BottomPanel; | ||||
| use crate::components::navigation::Navigation; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::route::Route; | ||||
| use chrono::NaiveDate; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use crate::components::create_task_button::CreateTaskButton; | ||||
| use crate::components::sticky_bottom::StickyBottom; | ||||
| use crate::components::task_form::TaskForm; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use crate::components::pages::category_page::CategoryPage; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategorySomedayMaybePage() -> Element { | ||||
|     let tasks = use_server_future( | ||||
|         move || get_tasks_in_category(Category::SomedayMaybe) | ||||
|     )?.unwrap().unwrap(); | ||||
|  | ||||
|     rsx! { | ||||
|         TaskList { | ||||
|             tasks: tasks, | ||||
|             class: "pb-36" | ||||
|         CategoryPage { | ||||
|             category: Category::SomedayMaybe, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,39 +1,158 @@ | ||||
| use crate::components::bottom_panel::BottomPanel; | ||||
| use crate::components::create_task_button::CreateTaskButton; | ||||
| use crate::components::navigation::Navigation; | ||||
| use crate::components::sticky_bottom::StickyBottom; | ||||
| use crate::components::task_form::TaskForm; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::models::task::Task; | ||||
| use crate::route::Route; | ||||
| use crate::schema::tasks::category; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use chrono::{Local, NaiveDate}; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use crate::query::tasks::use_tasks_in_category_query; | ||||
| use crate::query::QueryValue; | ||||
| use chrono::{Local, Locale}; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_query::prelude::QueryResult; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategoryTodayPage() -> Element { | ||||
|     let tasks = use_server_future( | ||||
|         move || get_tasks_in_category(Category::Calendar { | ||||
|             date: NaiveDate::default(), | ||||
|             reoccurrence: None, | ||||
|             time: None, | ||||
|         }) | ||||
|     )?.unwrap().unwrap().iter().filter(|task| { | ||||
|         if let Category::Calendar { date, .. } = task.category() { | ||||
|             *date == Local::now().date_naive() | ||||
|         } else { | ||||
|             panic!("Unexpected category."); | ||||
|         } | ||||
|     }).cloned().collect::<Vec<Task>>(); | ||||
|     let today_date = Local::now().date_naive(); | ||||
|      | ||||
|     let calendar_tasks_query = use_tasks_in_category_query(Category::Calendar { | ||||
|         date: today_date, | ||||
|         reoccurrence: None, | ||||
|         time: None, | ||||
|     }); | ||||
|     let calendar_tasks_query_result = calendar_tasks_query.result(); | ||||
|  | ||||
|     let long_term_tasks_query = use_tasks_in_category_query(Category::LongTerm); | ||||
|     let long_term_tasks_query_result = long_term_tasks_query.result(); | ||||
|  | ||||
|     rsx! { | ||||
|         TaskList { | ||||
|             tasks: tasks, | ||||
|             class: "pb-36" | ||||
|         div { | ||||
|             class: "pt-4 flex flex-col gap-8", | ||||
|             match long_term_tasks_query_result.value() { | ||||
|                 QueryResult::Ok(QueryValue::Tasks(tasks)) | ||||
|                 | QueryResult::Loading(Some(QueryValue::Tasks(tasks))) => rsx! { | ||||
|                     div { | ||||
|                         class: "flex flex-col gap-4", | ||||
|                         div { | ||||
|                             class: "px-8 flex flex-row items-center gap-2 font-bold", | ||||
|                             i { | ||||
|                                 class: "fa-solid fa-water text-xl" | ||||
|                             } | ||||
|                             div { | ||||
|                                 class: "mt-1", | ||||
|                                 "Long-term" | ||||
|                             } | ||||
|                         } | ||||
|                         div { | ||||
|                             for task in tasks { | ||||
|                                 div { | ||||
|                                     key: "{task.id()}", | ||||
|                                     class: format!( | ||||
|                                         "px-8 pt-5 {} flex flex-row gap-4", | ||||
|                                         if task.deadline().is_some() { | ||||
|                                             "pb-0.5" | ||||
|                                         } else { | ||||
|                                             "pb-5" | ||||
|                                         } | ||||
|                                     ), | ||||
|                                     div { | ||||
|                                         class: "flex flex-col", | ||||
|                                         div { | ||||
|                                             class: "mt grow font-medium", | ||||
|                                             {task.title()} | ||||
|                                         }, | ||||
|                                         div { | ||||
|                                             class: "flex flex-row gap-3", | ||||
|                                             if let Some(deadline) = task.deadline() { | ||||
|                                                 div { | ||||
|                                                     class: "text-sm text-zinc-400", | ||||
|                                                     i { | ||||
|                                                         class: "fa-solid fa-bomb" | ||||
|                                                     }, | ||||
|                                                     {deadline.format(" %m. %d.").to_string()} | ||||
|                                                 } | ||||
|                                             } | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 QueryResult::Loading(None) => rsx! { | ||||
|                     // TODO: Add a loading indicator. | ||||
|                 }, | ||||
|                 QueryResult::Err(errors) => rsx! { | ||||
|                     div { | ||||
|                         "Errors occurred: {errors:?}" | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             match calendar_tasks_query_result.value() { | ||||
|                 QueryResult::Ok(QueryValue::Tasks(tasks)) | ||||
|                 | QueryResult::Loading(Some(QueryValue::Tasks(tasks))) => { | ||||
|                     let today_tasks = tasks.iter().filter(|task| { | ||||
|                         if let Category::Calendar { date, .. } = task.category() { | ||||
|                             *date == today_date | ||||
|                         } else { | ||||
|                             panic!("Unexpected category."); | ||||
|                         } | ||||
|                     }).cloned().collect::<Vec<Task>>(); | ||||
|                     let overdue_tasks = tasks.iter().filter(|task| { | ||||
|                         if let Category::Calendar { date, .. } = task.category() { | ||||
|                             *date < today_date | ||||
|                         } else { | ||||
|                             panic!("Unexpected category."); | ||||
|                         } | ||||
|                     }).cloned().collect::<Vec<Task>>(); | ||||
|          | ||||
|                     rsx! { | ||||
|                         if !overdue_tasks.is_empty() { | ||||
|                             div { | ||||
|                                 class: "flex flex-col gap-4", | ||||
|                                 div { | ||||
|                                     class: "px-8 flex flex-row items-center gap-2 font-bold", | ||||
|                                     i { | ||||
|                                         class: "fa-solid fa-calendar-xmark text-xl" | ||||
|                                     } | ||||
|                                     div { | ||||
|                                         class: "mt-1", | ||||
|                                         "Overdue" | ||||
|                                     } | ||||
|                                 } | ||||
|                                 TaskList { | ||||
|                                     tasks: overdue_tasks, | ||||
|                                     class: "pb-3" | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         div { | ||||
|                             class: "flex flex-col gap-4", | ||||
|                             div { | ||||
|                                 class: "px-8 flex flex-row items-center gap-2 font-bold", | ||||
|                                 i { | ||||
|                                     class: "fa-solid fa-calendar-check text-xl" | ||||
|                                 } | ||||
|                                 div { | ||||
|                                     class: "mt-1", | ||||
|                                     { | ||||
|                                         today_date | ||||
|                                         .format_localized("Today, %A %-d. %B", Locale::en_US) | ||||
|                                         .to_string() | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                             TaskList { | ||||
|                                 tasks: today_tasks | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 QueryResult::Loading(None) => rsx! { | ||||
|                     // TODO: Add a loading indicator. | ||||
|                 }, | ||||
|                 QueryResult::Err(errors) => rsx! { | ||||
|                     div { | ||||
|                         "Errors occurred: {errors:?}" | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,27 +1,14 @@ | ||||
| use crate::components::bottom_panel::BottomPanel; | ||||
| use crate::components::navigation::Navigation; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::route::Route; | ||||
| use chrono::NaiveDate; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use crate::components::create_task_button::CreateTaskButton; | ||||
| use crate::components::sticky_bottom::StickyBottom; | ||||
| use crate::components::task_form::TaskForm; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use crate::components::pages::category_page::CategoryPage; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategoryTrashPage() -> Element { | ||||
|     let tasks = use_server_future( | ||||
|         move || get_tasks_in_category(Category::Trash) | ||||
|     )?.unwrap().unwrap(); | ||||
|  | ||||
|     rsx! { | ||||
|         TaskList { | ||||
|             tasks: tasks, | ||||
|             class: "pb-36" | ||||
|         CategoryPage { | ||||
|             category: Category::Trash, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,27 +1,14 @@ | ||||
| use crate::components::bottom_panel::BottomPanel; | ||||
| use crate::components::navigation::Navigation; | ||||
| use crate::components::task_list::TaskList; | ||||
| use crate::models::category::Category; | ||||
| use crate::route::Route; | ||||
| use chrono::NaiveDate; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use crate::components::create_task_button::CreateTaskButton; | ||||
| use crate::components::sticky_bottom::StickyBottom; | ||||
| use crate::components::task_form::TaskForm; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use crate::components::pages::category_page::CategoryPage; | ||||
|  | ||||
| #[component] | ||||
| pub(crate) fn CategoryWaitingForPage() -> Element { | ||||
|     let tasks = use_server_future( | ||||
|         move || get_tasks_in_category(Category::WaitingFor(String::new())) | ||||
|     )?.unwrap().unwrap(); | ||||
|  | ||||
|     rsx! { | ||||
|         TaskList { | ||||
|             tasks: tasks, | ||||
|             class: "pb-36" | ||||
|         CategoryPage { | ||||
|             category: Category::WaitingFor(String::new()), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -9,3 +9,4 @@ pub(crate) mod category_done_page; | ||||
| pub(crate) mod category_trash_page; | ||||
| pub(crate) mod not_found_page; | ||||
| pub(crate) mod projects_page; | ||||
| pub(crate) mod category_page; | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| use std::fmt::Display; | ||||
| use crate::components::category_input::CategoryInput; | ||||
| use crate::components::reoccurrence_input::ReoccurrenceIntervalInput; | ||||
| use crate::models::category::{CalendarTime, Category, Reoccurrence, ReoccurrenceInterval}; | ||||
| @@ -9,6 +8,8 @@ use chrono::{Duration, NaiveDate}; | ||||
| use dioxus::core_macro::{component, rsx}; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| use dioxus_query::prelude::use_query_client; | ||||
| use crate::query::{QueryErrors, QueryKey, QueryValue}; | ||||
| use crate::route::Route; | ||||
|  | ||||
| const REMINDER_OFFSETS: [Option<Duration>; 17] = [ | ||||
| @@ -52,6 +53,8 @@ pub(crate) fn TaskForm() -> Element { | ||||
|     let mut category_calendar_has_time = use_signal(|| false); | ||||
|     let mut category_calendar_reminder_offset_index = use_signal(|| REMINDER_OFFSETS.len() - 1); | ||||
|  | ||||
|     let query_client = use_query_client::<QueryValue, QueryErrors, QueryKey>(); | ||||
|      | ||||
|     rsx! { | ||||
|         form { | ||||
|             onsubmit: move |event| { | ||||
| @@ -94,6 +97,10 @@ pub(crate) fn TaskForm() -> Element { | ||||
|                         .as_value().parse::<i32>().ok().filter(|&id| id > 0), | ||||
|                     ); | ||||
|                     let _ = create_task(new_task).await; | ||||
|                     query_client.invalidate_queries(&[ | ||||
|                         QueryKey::Tasks,  | ||||
|                         QueryKey::TasksInCategory(selected_category()) | ||||
|                     ]); | ||||
|                 } | ||||
|             }, | ||||
|             class: "p-4 flex flex-col gap-4", | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| use crate::models::category::Category; | ||||
| use crate::models::task::Task; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use dioxus::core_macro::rsx; | ||||
| use dioxus::dioxus_core::Element; | ||||
| use dioxus::prelude::*; | ||||
| @@ -9,11 +8,12 @@ use dioxus::prelude::*; | ||||
| pub(crate) fn TaskList(tasks: Vec<Task>, class: Option<&'static str>) -> Element { | ||||
|     rsx! { | ||||
|         div { | ||||
|             class: format!("pt-3 px-8 flex flex-col {}", class.unwrap_or("")), | ||||
|             class: format!("flex flex-col {}", class.unwrap_or("")), | ||||
|             for task in tasks { | ||||
|                 div { | ||||
|                     key: "{task.id()}", | ||||
|                     class: format!( | ||||
|                         "pt-5 {} flex flex-row gap-4", | ||||
|                         "px-8 pt-5 {} flex flex-row gap-4", | ||||
|                         if task.deadline().is_some() { | ||||
|                             "pb-0.5" | ||||
|                         } else if let Category::Calendar { time, .. } = task.category() { | ||||
| @@ -32,7 +32,7 @@ pub(crate) fn TaskList(tasks: Vec<Task>, class: Option<&'static str>) -> Element | ||||
|                     div { | ||||
|                         class: "flex flex-col", | ||||
|                         div { | ||||
|                             class: "mt-1 grow", | ||||
|                             class: "mt-1 grow font-medium", | ||||
|                             {task.title()} | ||||
|                         }, | ||||
|                         div { | ||||
|   | ||||
| @@ -11,7 +11,7 @@ use serde_with::DurationSeconds; | ||||
| use std::io::Write; | ||||
|  | ||||
| #[serde_with::serde_as] | ||||
| #[derive(AsExpression, FromSqlRow, Serialize, Deserialize, Clone, Debug)] | ||||
| #[derive(AsExpression, FromSqlRow, Serialize, Deserialize, Hash, Clone, Debug)] | ||||
| #[diesel(sql_type = Jsonb)] | ||||
| pub enum Category { | ||||
|     Inbox, | ||||
| @@ -51,6 +51,8 @@ impl PartialEq for Category { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Eq for Category {} | ||||
|  | ||||
| impl ToSql<Jsonb, Pg> for Category { | ||||
|     fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> diesel::serialize::Result { | ||||
|         let json = serde_json::to_string(self)?; | ||||
| @@ -74,14 +76,14 @@ impl FromSql<Jsonb, Pg> for Category { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Serialize, Deserialize, Clone, Debug)] | ||||
| #[derive(Serialize, Deserialize, Hash, Clone, Debug)] | ||||
| pub enum ReoccurrenceInterval { | ||||
|     Day, | ||||
|     Month, | ||||
|     Year, | ||||
| } | ||||
|  | ||||
| #[derive(Serialize, Deserialize, Clone, Debug)] | ||||
| #[derive(Serialize, Deserialize, Hash, Clone, Debug)] | ||||
| pub struct Reoccurrence { | ||||
|     start_date: NaiveDate, | ||||
|     interval: ReoccurrenceInterval, | ||||
| @@ -103,7 +105,7 @@ impl Reoccurrence { | ||||
| } | ||||
|  | ||||
| #[serde_with::serde_as] | ||||
| #[derive(Serialize, Deserialize, Clone, Debug)] | ||||
| #[derive(Serialize, Deserialize, Hash, Clone, Debug)] | ||||
| pub struct CalendarTime { | ||||
|     time: NaiveTime, | ||||
|     #[serde_as(as = "Option<DurationSeconds<i64>>")] | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| use std::cmp::Ordering; | ||||
| use diesel::prelude::*; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use validator::Validate; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user