From 79ac2ea4ef859d8d6eaf13cc6232a49577e6153a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asger=20Juul=20Brunsh=C3=B8j?= Date: Mon, 10 Mar 2025 22:59:38 +0100 Subject: [PATCH] wip --- crates/ascend/src/components/show_some.rs | 30 --- crates/ascend/src/lib.rs | 1 - crates/ascend/src/pages/wall.rs | 234 ++++++++++++---------- crates/ascend/src/resources.rs | 15 -- flake.nix | 1 + 5 files changed, 126 insertions(+), 155 deletions(-) delete mode 100644 crates/ascend/src/components/show_some.rs diff --git a/crates/ascend/src/components/show_some.rs b/crates/ascend/src/components/show_some.rs deleted file mode 100644 index f623a57..0000000 --- a/crates/ascend/src/components/show_some.rs +++ /dev/null @@ -1,30 +0,0 @@ -use leptos::prelude::*; - -#[component] -#[tracing::instrument(skip_all)] -pub fn ShowSome(#[prop(into)] sig: Signal>, foo: C) -> impl IntoView -where - T: Clone + Send + Sync + 'static, - C: Fn(Signal) -> IV + Sync + Send + 'static, - IV: IntoView, -{ - tracing::trace!("Enter"); - - view! { - // - // {move || { - // let new = signal() - - // sig - // .with(|opt| { - // if let Some(inner) = opt.clone() { - // let new_signal = Signal::derive(move || sig.get().unwrap()); - // .into_any() - // } else { - // view! {}.into_any() - // } - // }) - // }} - // - } -} diff --git a/crates/ascend/src/lib.rs b/crates/ascend/src/lib.rs index 0b3abee..e0a7d37 100644 --- a/crates/ascend/src/lib.rs +++ b/crates/ascend/src/lib.rs @@ -20,7 +20,6 @@ pub mod components { pub mod outlined_box; pub mod problem; pub mod problem_info; - pub mod show_some; } pub mod gradient; diff --git a/crates/ascend/src/pages/wall.rs b/crates/ascend/src/pages/wall.rs index 6904f9a..a3cd49c 100644 --- a/crates/ascend/src/pages/wall.rs +++ b/crates/ascend/src/pages/wall.rs @@ -118,15 +118,13 @@ fn WithProblem(#[prop(into)] problem: Signal) -> impl IntoView fn WithWall(#[prop(into)] wall: Signal) -> impl IntoView { tracing::trace!("Enter"); - let (problem_uid, set_problem_uid) = leptos_router::hooks::query_signal::("problem"); - let wall_uid = Signal::derive(move || wall.read().uid); + let (problem_uid, set_problem_uid) = leptos_router::hooks::query_signal::("problem"); + let problem = crate::resources::problem_by_uid_optional(wall_uid, problem_uid.into()); let user_interaction = crate::resources::user_interaction(wall_uid, problem_uid.into()); - let submit_attempt = ServerAction::>::new(); - let fn_next_problem = move |wall: &models::Wall| { set_problem_uid.set(wall.random_problem()); }; @@ -139,97 +137,6 @@ fn WithWall(#[prop(into)] wall: Signal) -> impl IntoView { } }); - let (attempt_today, set_attempt_today) = signal(None); - - let ui_is_flash = Signal::derive(move || matches!(attempt_today.get(), Some(models::Attempt::Flash))); - let ui_is_send = Signal::derive(move || matches!(attempt_today.get(), Some(models::Attempt::Send))); - let ui_is_attempt = Signal::derive(move || matches!(attempt_today.get(), Some(models::Attempt::Attempt))); - let ui_is_favorite = RwSignal::new(false); - - // On reception of user interaction state, set UI signals - Effect::new(move |_prev_value| { - if let Some(user_interaction) = user_interaction.get() { - let user_interaction = user_interaction.ok().flatten(); - - if let Some(user_interaction) = user_interaction { - ui_is_favorite.set(user_interaction.is_favorite); - } else { - ui_is_favorite.set(false); - } - } - }); - - // onclick handler helper - let set_or_deselect = |s: WriteSignal>, v: models::Attempt| { - s.update(|s| match s { - Some(x) if *x == v => { - *s = None; - } - _ => { - *s = Some(v); - } - }); - }; - let onclick_flash = move |_| { - set_or_deselect(set_attempt_today, models::Attempt::Flash); - submit_attempt.dispatch(RonEncoded(server_functions::UpsertTodaysAttempt { - wall_uid: wall_uid.get(), - problem_uid: problem.get().uid, - attempt: models::Attempt::Flash, - })); - }; - let onclick_send = move |_| { - set_or_deselect(set_attempt_today, models::Attempt::Send); - }; - let onclick_attempt = move |_| { - set_or_deselect(set_attempt_today, models::Attempt::Attempt); - }; - - let foo = move || { - Suspend::new(async move { - let user_interaction = user_interaction.await; - let user_interaction = user_interaction.ok().flatten(); - - let latest_attempt = - user_interaction.and_then(|x| x.attempted_on.last_key_value().map(|(date, attempt)| (date.clone(), attempt.clone()))); - - // let latest_attempt_text = move || { - // latest_attempt - // .map(|pair| match pair.1 { - // models::Attempt::Attempt => "Attempt", - // models::Attempt::Send => "Send", - // models::Attempt::Flash => "Flash", - // }) - // .unwrap_or("No attempt") - // .to_string() - // }; - - // let best_attempt = user_interaction.and_then(|x| x.best_attempt()); - // let best_attempt_date = move || best_attempt.map(|pair| pair.0); - // let best_attempt_attempt = move || best_attempt.map(|pair| pair.1); - - let v = latest_attempt.map(|(date, attempt)| view! { }); - - let placeholder = latest_attempt.is_none().then(|| { - let today = chrono::Utc::now(); - view! { } - }); - - let test = { - let today = chrono::Utc::now(); - view! { - - - - - } - }; - - // TODO: loop over attempts in user_interaction - view! {
{test} {placeholder} {v}
} - }) - }; - // 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)); @@ -253,7 +160,7 @@ fn WithWall(#[prop(into)] wall: Signal) -> impl IntoView { } }; - let v = view! { + view! {
{grid}
@@ -281,7 +188,7 @@ fn WithWall(#[prop(into)] wall: Signal) -> impl IntoView { let problem = problem.await?; let view = problem .map(|problem| { - view! { } + view! { } }); Ok::<_, ServerFnError>(view) })} @@ -290,21 +197,130 @@ fn WithWall(#[prop(into)] wall: Signal) -> impl IntoView { - - - - - {foo()} + + {move || { + Suspend::new(async move { + tracing::debug!("getting user interaction"); + let user_interaction: Option<_> = user_interaction.await?; + tracing::debug!("got user interaction"); + let Some(problem_uid) = problem_uid.get() else { + return Ok(view! {}.into_any()); + }; + let view = view! { + + } + .into_any(); + Ok::<_, ServerFnError>(view) + }) + }} +
+ } +} + +#[component] +#[tracing::instrument(skip_all)] +fn WithUserInteraction( + #[prop(into)] wall_uid: Signal, + #[prop(into)] problem_uid: Signal, + #[prop(into)] user_interaction: Signal>, +) -> impl IntoView { + tracing::debug!("Enter WithUserInteraction"); + + let user_interaction_rw = RwSignal::new(None); + Effect::new(move || { + let i = user_interaction.get(); + tracing::info!("setting user interaction to parent user interaction value: {i:?}"); + user_interaction_rw.set(i); + }); + + let submit_attempt = ServerAction::>::new(); + let submit_attempt_value = submit_attempt.value(); + Effect::new(move || { + tracing::info!("flaf"); + if let Some(Ok(v)) = submit_attempt_value.get() { + tracing::info!("setting user interaction to action return value: {v:?}"); + user_interaction_rw.set(Some(v.into_inner())); + } + }); + + let latest_attempt = move || -> Option<_> { + let i = user_interaction_rw.read(); + let i = (*i).as_ref(); + let i = i?; + i.attempted_on.last_key_value().map(|(date, attempt)| (date.clone(), attempt.clone())) }; + + let todays_attempt = move || -> Option<_> { + match latest_attempt() { + Some((datetime, attempt)) => { + let today_local_naive = chrono::Local::now().date_naive(); + let datetime_local_naive = datetime.with_timezone(&chrono::Local).date_naive(); + (datetime_local_naive == today_local_naive).then_some(attempt) + } + None => None, + } + }; + + let ui_is_flash = RwSignal::new(false); + let ui_is_send = RwSignal::new(false); + let ui_is_attempt = RwSignal::new(false); + let ui_is_favorite = RwSignal::new(false); + + Effect::new(move || { + let attempt = todays_attempt(); + ui_is_flash.set(matches!(attempt, Some(models::Attempt::Flash))); + ui_is_send.set(matches!(attempt, Some(models::Attempt::Send))); + ui_is_attempt.set(matches!(attempt, Some(models::Attempt::Attempt))); + }); + + let onclick_flash = move |_| { + submit_attempt.dispatch(RonEncoded(server_functions::UpsertTodaysAttempt { + wall_uid: wall_uid.get(), + problem_uid: problem_uid.get(), + attempt: models::Attempt::Flash, + })); + }; + let onclick_send = move |_| { + submit_attempt.dispatch(RonEncoded(server_functions::UpsertTodaysAttempt { + wall_uid: wall_uid.get(), + problem_uid: problem_uid.get(), + attempt: models::Attempt::Send, + })); + }; + let onclick_attempt = move |_| { + submit_attempt.dispatch(RonEncoded(server_functions::UpsertTodaysAttempt { + wall_uid: wall_uid.get(), + problem_uid: problem_uid.get(), + attempt: models::Attempt::Attempt, + })); + }; + + // TODO: loop over attempts in user_interaction + let v = move || latest_attempt().map(|(date, attempt)| view! { }); + + let placeholder = move || { + latest_attempt().is_none().then(|| { + let today = chrono::Utc::now(); + view! { } + }) + }; + + view! { + + + + +
{placeholder} {v}
+ } } #[component] diff --git a/crates/ascend/src/resources.rs b/crates/ascend/src/resources.rs index 004a4de..ca4b531 100644 --- a/crates/ascend/src/resources.rs +++ b/crates/ascend/src/resources.rs @@ -16,21 +16,6 @@ pub fn wall_by_uid(wall_uid: Signal) -> RonResource, problem_uid: Signal) -> RonResource { - Resource::new_with_options( - move || (wall_uid.get(), problem_uid.get()), - move |(wall_uid, problem_uid)| async move { - let Some(problem_uid) = problem_uid else { - return Ok(None); - }; - crate::server_functions::get_problem_by_uid(wall_uid, problem_uid) - .await - .map(RonEncoded::into_inner) - }, - false, - ) -} - /// Version of [problem_by_uid] that short circuits if the input problem_uid signal is None. pub fn problem_by_uid_optional( wall_uid: Signal, diff --git a/flake.nix b/flake.nix index 2f0e728..0fa115d 100644 --- a/flake.nix +++ b/flake.nix @@ -130,6 +130,7 @@ basecamp.mkShell pkgs { rust.enable = true; rust.toolchain.targets = [ "wasm32-unknown-unknown" ]; + rust.toolchain.components.rust-analyzer.nightly = true; packages = [ pkgs.bacon