feat: ability to complete a task #35
@ -3,70 +3,98 @@ use crate::models::task::Task;
|
|||||||
use dioxus::core_macro::rsx;
|
use dioxus::core_macro::rsx;
|
||||||
use dioxus::dioxus_core::Element;
|
use dioxus::dioxus_core::Element;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_query::prelude::use_query_client;
|
||||||
|
use crate::query::{QueryErrors, QueryKey, QueryValue};
|
||||||
|
use crate::server::tasks::complete_task;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub(crate) fn TaskList(tasks: Vec<Task>, class: Option<&'static str>) -> Element {
|
pub(crate) fn TaskList(tasks: Vec<Task>, class: Option<&'static str>) -> Element {
|
||||||
|
let query_client = use_query_client::<QueryValue, QueryErrors, QueryKey>();
|
||||||
let mut task_being_edited = use_context::<Signal<Option<Task>>>();
|
let mut task_being_edited = use_context::<Signal<Option<Task>>>();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
class: format!("flex flex-col {}", class.unwrap_or("")),
|
class: format!("flex flex-col {}", class.unwrap_or("")),
|
||||||
for task in tasks {
|
{tasks.iter().cloned().map(|task| {
|
||||||
div {
|
let task_clone = task.clone();
|
||||||
key: "{task.id()}",
|
rsx! {
|
||||||
class: format!(
|
div {
|
||||||
"px-8 pt-5 {} flex flex-row gap-4 select-none {}",
|
key: "{task.id()}",
|
||||||
if task.deadline().is_some() {
|
class: format!(
|
||||||
"pb-0.5"
|
"px-8 pt-5 {} flex flex-row gap-4 select-none {}",
|
||||||
} else if let Category::Calendar { time, .. } = task.category() {
|
if task.deadline().is_some() {
|
||||||
if time.is_some() {
|
|
||||||
"pb-0.5"
|
"pb-0.5"
|
||||||
|
} else if let Category::Calendar { time, .. } = task.category() {
|
||||||
|
if time.is_some() {
|
||||||
|
"pb-0.5"
|
||||||
|
} else {
|
||||||
|
"pb-5"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
"pb-5"
|
"pb-5"
|
||||||
}
|
},
|
||||||
} else {
|
if task_being_edited().is_some_and(|t| t.id() == task.id()) {
|
||||||
"pb-5"
|
"bg-zinc-700"
|
||||||
},
|
} else { "" }
|
||||||
if task_being_edited().is_some_and(|t| t.id() == task.id()) {
|
),
|
||||||
"bg-zinc-700"
|
onclick: move |_| task_being_edited.set(Some(task.clone())),
|
||||||
} else { "" }
|
i {
|
||||||
),
|
class: format!(
|
||||||
onclick: move |_| task_being_edited.set(Some(task.clone())),
|
"{} text-3xl text-zinc-500",
|
||||||
i {
|
if *(task_clone.category()) == Category::Done {
|
||||||
class: "fa-regular fa-square text-3xl text-zinc-600",
|
"fa solid fa-square-check"
|
||||||
},
|
} else {
|
||||||
div {
|
"fa-regular fa-square"
|
||||||
class: "flex flex-col",
|
}
|
||||||
div {
|
),
|
||||||
class: "mt-1 grow font-medium",
|
onclick: move |event| {
|
||||||
{task.title()}
|
// To prevent editing the task.
|
||||||
},
|
event.stop_propagation();
|
||||||
div {
|
let task = task_clone.clone();
|
||||||
class: "flex flex-row gap-3",
|
async move {
|
||||||
if let Some(deadline) = task.deadline() {
|
let completed_task = complete_task(task.id()).await;
|
||||||
div {
|
query_client.invalidate_queries(&[
|
||||||
class: "text-sm text-zinc-400",
|
QueryKey::Tasks,
|
||||||
i {
|
QueryKey::TasksInCategory(
|
||||||
class: "fa-solid fa-bomb"
|
completed_task.unwrap().category().clone()
|
||||||
},
|
),
|
||||||
{deadline.format(" %m. %d.").to_string()}
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Category::Calendar { time, .. } = task.category() {
|
},
|
||||||
if let Some(calendar_time) = time {
|
div {
|
||||||
|
class: "flex flex-col",
|
||||||
|
div {
|
||||||
|
class: "mt-1 grow font-medium",
|
||||||
|
{task.title()}
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
|||||||
|
class: "flex flex-row gap-3",
|
||||||
|
if let Some(deadline) = task.deadline() {
|
||||||
div {
|
div {
|
||||||
class: "text-sm text-zinc-400",
|
class: "text-sm text-zinc-400",
|
||||||
i {
|
i {
|
||||||
class: "fa-solid fa-clock"
|
class: "fa-solid fa-bomb"
|
||||||
},
|
},
|
||||||
{calendar_time.time().format(" %k:%M").to_string()}
|
{deadline.format(" %m. %d.").to_string()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Category::Calendar { time, .. } = task.category() {
|
||||||
|
if let Some(calendar_time) = time {
|
||||||
|
div {
|
||||||
|
class: "text-sm text-zinc-400",
|
||||||
|
i {
|
||||||
|
class: "fa-solid fa-clock"
|
||||||
|
},
|
||||||
|
{calendar_time.time().format(" %k:%M").to_string()}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user
Refactoring of task rendering and event handling logic.
The refactoring of the task rendering logic using
map
andclone
improves readability and immutability. The conditional rendering for task properties and CSS class determination is well-implemented and concise.The asynchronous
onclick
event handler for task completion is a significant enhancement. It correctly usesasync move
to handle the task completion without blocking the UI, followed by invalidating queries to update the UI state. This is a robust implementation that leverages modern Rust asynchronous programming practices.Consider adding error handling for the
complete_task
function within theasync move
block to manage potential failures gracefully.