diff --git a/crates/ascend/src/pages/routes.rs b/crates/ascend/src/pages/routes.rs index 5d7811e..d8244e3 100644 --- a/crates/ascend/src/pages/routes.rs +++ b/crates/ascend/src/pages/routes.rs @@ -55,7 +55,7 @@ pub fn Routes() -> impl IntoView { rows: wall.rows, cols: wall.cols, }; - let problems_sample = move || problems.iter().take(10).cloned().collect::>(); + let problems_sample = move || problems.values().take(10).cloned().collect::>(); Ok(view! {
diff --git a/crates/ascend/src/pages/wall.rs b/crates/ascend/src/pages/wall.rs index afe5a5e..40aa34e 100644 --- a/crates/ascend/src/pages/wall.rs +++ b/crates/ascend/src/pages/wall.rs @@ -91,7 +91,7 @@ fn WithProblem(#[prop(into)] problem: Signal) -> impl IntoView #[tracing::instrument(skip_all)] fn WithWall( #[prop(into)] wall: Signal, - #[prop(into)] problems: Signal>, + #[prop(into)] problems: Signal>, #[prop(into)] user_interactions: Signal>, ) -> impl IntoView { tracing::trace!("Enter"); @@ -100,6 +100,9 @@ fn WithWall( let (problem_uid, set_problem_uid) = leptos_router::hooks::query_signal::("problem"); + let problem = signals::problem(problems, problem_uid.into()); + let user_interaction = signals::user_interaction(user_interactions, problem_uid.into()); + // Filter let (filter_holds, set_filter_holds) = signal(BTreeSet::new()); let _filter_add_hold = move |hold_pos: models::HoldPosition| { @@ -118,22 +121,18 @@ fn WithWall( problems.with(|problems| { problems .iter() - .filter(|problem| filter_holds.iter().all(|hold_pos| problem.holds.contains_key(hold_pos))) - .cloned() - .collect::>() + .filter(|(_, problem)| filter_holds.iter().all(|hold_pos| problem.holds.contains_key(hold_pos))) + .map(|(problem_uid, problem)| (*problem_uid, problem.clone())) + .collect::>() }) }); - let problem = crate::resources::problem_by_uid_optional(wall_uid, problem_uid.into()); - let user_interaction = signals::user_interaction(user_interactions, problem_uid.into()); - let fn_next_problem = move || { let problems = filtered_problems.read(); use rand::seq::IteratorRandom; let mut rng = rand::rng(); - let problem = problems.iter().choose(&mut rng); - let problem_uid = problem.map(|p| p.uid); + let problem_uid = problems.keys().copied().choose(&mut rng); set_problem_uid.set(problem_uid); }; @@ -146,9 +145,6 @@ fn WithWall( } }); - // merge outer option (resource hasn't resolved yet) with inner option (there is no problem for the wall) - let problem_signal = Signal::derive(move || problem.get().transpose().map(Option::flatten)); - let on_click_hold = move |hold_position: models::HoldPosition| { // Add/Remove hold position to problem filter set_filter_holds.update(|set| { @@ -163,9 +159,7 @@ fn WithWall( {move || { Suspend::new(async move { tracing::debug!("executing grid suspend"); - let view = view! { - - }; + let view = view! { }; Ok::<_, ServerFnError>(view) }) }} @@ -213,8 +207,8 @@ fn WithWall( let mut interaction_counters = InteractionCounters::default(); let interaction_counters_view = { let user_ints = user_interactions.read(); - for problem in filtered_problems.read().iter() { - if let Some(user_int) = user_ints.get(&problem.uid) { + for problem_uid in filtered_problems.read().keys() { + if let Some(user_int) = user_ints.get(problem_uid) { match user_int.best_attempt().map(|da| da.attempt) { Some(models::Attempt::Flash) => interaction_counters.flash += 1, Some(models::Attempt::Send) => interaction_counters.send += 1, @@ -292,17 +286,7 @@ fn WithWall(
- - {move || Suspend::new(async move { - tracing::info!("executing problem suspend"); - let problem = problem.await?; - let view = problem - .map(|problem| { - view! { } - }); - Ok::<_, ServerFnError>(view) - })} - + {move || problem.get().map(|p| view! { })}
@@ -429,7 +413,7 @@ fn History(#[prop(into)] user_interaction: Signal, ServerFnError>>, + #[prop(into)] problem: Signal>, on_click_hold: impl Fn(models::HoldPosition) + 'static, ) -> impl IntoView { tracing::debug!("Enter"); @@ -438,8 +422,7 @@ fn Grid( let mut cells = vec![]; for (&hold_position, hold) in &wall.holds { - let role = move || problem.get().map(|o| o.and_then(|p| p.holds.get(&hold_position).copied())); - let role = Signal::derive(role); + let role = Signal::derive(move || problem.get().and_then(|p| p.holds.get(&hold_position).copied())); let on_click = { let on_click_hold = std::rc::Rc::clone(&on_click_hold); @@ -477,14 +460,14 @@ fn Hold( #[prop(optional)] #[prop(into)] - role: Option, ServerFnError>>>, + role: Option>>, ) -> impl IntoView { tracing::trace!("Enter"); move || { let mut class = "bg-sky-100 aspect-square rounded-sm hover:brightness-125".to_string(); if let Some(role) = role { - let role = role.get()?; + let role = role.get(); let role_classes = match role { Some(HoldRole::Start) => Some("outline outline-3 outline-green-500"), @@ -504,8 +487,7 @@ fn Hold( view! { } }); - let view = view! {
{img}
}; - Ok::<_, ServerFnError>(view) + view! {
{img}
} } } @@ -549,4 +531,15 @@ mod signals { user_interactions.get(&problem_uid).cloned() }) } + + pub(crate) fn problem( + problems: Signal>, + problem_uid: Signal>, + ) -> Signal> { + Signal::derive(move || { + let problem_uid = problem_uid.get()?; + let problems = problems.read(); + problems.get(&problem_uid).cloned() + }) + } } diff --git a/crates/ascend/src/resources.rs b/crates/ascend/src/resources.rs index 3335072..d60c491 100644 --- a/crates/ascend/src/resources.rs +++ b/crates/ascend/src/resources.rs @@ -38,7 +38,7 @@ pub fn problem_by_uid_optional( } /// Returns all problems for a wall -pub fn problems_for_wall(wall_uid: Signal) -> RonResource> { +pub fn problems_for_wall(wall_uid: Signal) -> RonResource> { Resource::new_with_options( move || wall_uid.get(), move |wall_uid| async move { crate::server_functions::get_problems_for_wall(wall_uid).await.map(RonEncoded::into_inner) }, diff --git a/crates/ascend/src/server_functions.rs b/crates/ascend/src/server_functions.rs index 1aa39f3..7a58cc0 100644 --- a/crates/ascend/src/server_functions.rs +++ b/crates/ascend/src/server_functions.rs @@ -9,6 +9,7 @@ use leptos::prelude::*; use leptos::server; use server_fn::ServerFnError; use std::collections::BTreeMap; +use type_toppings::IteratorExt; #[server( input = Ron, @@ -76,7 +77,9 @@ pub(crate) async fn get_wall_by_uid(wall_uid: models::WallUid) -> Result Result>, ServerFnError> { +pub(crate) async fn get_problems_for_wall( + wall_uid: models::WallUid, +) -> Result>, ServerFnError> { use crate::server::db::Database; use crate::server::db::DatabaseOperationError; use leptos::prelude::expect_context; @@ -90,7 +93,7 @@ pub(crate) async fn get_problems_for_wall(wall_uid: models::WallUid) -> Result Result, Error> { + async fn inner(wall_uid: models::WallUid) -> Result, Error> { let db = expect_context::(); let problems = db @@ -109,12 +112,15 @@ pub(crate) async fn get_problems_for_wall(wall_uid: models::WallUid) -> Result, _>>()?; + Ok(problems) }) .await?;