wip
This commit is contained in:
@@ -1,30 +0,0 @@
|
|||||||
use leptos::prelude::*;
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
#[tracing::instrument(skip_all)]
|
|
||||||
pub fn ShowSome<T, C, IV>(#[prop(into)] sig: Signal<Option<T>>, foo: C) -> impl IntoView
|
|
||||||
where
|
|
||||||
T: Clone + Send + Sync + 'static,
|
|
||||||
C: Fn(Signal<T>) -> IV + Sync + Send + 'static,
|
|
||||||
IV: IntoView,
|
|
||||||
{
|
|
||||||
tracing::trace!("Enter");
|
|
||||||
|
|
||||||
view! {
|
|
||||||
// <Show when=move || sig.get().is_some() fallback=|| ()>
|
|
||||||
// {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()
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }}
|
|
||||||
// </Show>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,6 @@ pub mod components {
|
|||||||
pub mod outlined_box;
|
pub mod outlined_box;
|
||||||
pub mod problem;
|
pub mod problem;
|
||||||
pub mod problem_info;
|
pub mod problem_info;
|
||||||
pub mod show_some;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod gradient;
|
pub mod gradient;
|
||||||
|
|||||||
@@ -118,15 +118,13 @@ fn WithProblem(#[prop(into)] problem: Signal<models::Problem>) -> impl IntoView
|
|||||||
fn WithWall(#[prop(into)] wall: Signal<models::Wall>) -> impl IntoView {
|
fn WithWall(#[prop(into)] wall: Signal<models::Wall>) -> impl IntoView {
|
||||||
tracing::trace!("Enter");
|
tracing::trace!("Enter");
|
||||||
|
|
||||||
let (problem_uid, set_problem_uid) = leptos_router::hooks::query_signal::<models::ProblemUid>("problem");
|
|
||||||
|
|
||||||
let wall_uid = Signal::derive(move || wall.read().uid);
|
let wall_uid = Signal::derive(move || wall.read().uid);
|
||||||
|
|
||||||
|
let (problem_uid, set_problem_uid) = leptos_router::hooks::query_signal::<models::ProblemUid>("problem");
|
||||||
|
|
||||||
let problem = crate::resources::problem_by_uid_optional(wall_uid, problem_uid.into());
|
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 user_interaction = crate::resources::user_interaction(wall_uid, problem_uid.into());
|
||||||
|
|
||||||
let submit_attempt = ServerAction::<RonEncoded<server_functions::UpsertTodaysAttempt>>::new();
|
|
||||||
|
|
||||||
let fn_next_problem = move |wall: &models::Wall| {
|
let fn_next_problem = move |wall: &models::Wall| {
|
||||||
set_problem_uid.set(wall.random_problem());
|
set_problem_uid.set(wall.random_problem());
|
||||||
};
|
};
|
||||||
@@ -139,97 +137,6 @@ fn WithWall(#[prop(into)] wall: Signal<models::Wall>) -> 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<Option<models::Attempt>>, 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! { <Attempt date attempt /> });
|
|
||||||
|
|
||||||
let placeholder = latest_attempt.is_none().then(|| {
|
|
||||||
let today = chrono::Utc::now();
|
|
||||||
view! { <Attempt date=today attempt=None /> }
|
|
||||||
});
|
|
||||||
|
|
||||||
let test = {
|
|
||||||
let today = chrono::Utc::now();
|
|
||||||
view! {
|
|
||||||
<Attempt date=today attempt=None />
|
|
||||||
<Attempt date=today attempt=models::Attempt::Flash />
|
|
||||||
<Attempt date=today attempt=models::Attempt::Send />
|
|
||||||
<Attempt date=today attempt=models::Attempt::Attempt />
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: loop over attempts in user_interaction
|
|
||||||
view! { <Section title="History">{test} {placeholder} {v}</Section> }
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
// merge outer option (resource hasn't resolved yet) with inner option (there is no problem for the wall)
|
// 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 problem_signal = Signal::derive(move || problem.get().transpose().map(Option::flatten));
|
||||||
|
|
||||||
@@ -253,7 +160,7 @@ fn WithWall(#[prop(into)] wall: Signal<models::Wall>) -> impl IntoView {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let v = view! {
|
view! {
|
||||||
<div class="inline-grid grid-cols-1 gap-8 md:grid-cols-[auto,1fr]">
|
<div class="inline-grid grid-cols-1 gap-8 md:grid-cols-[auto,1fr]">
|
||||||
<div>{grid}</div>
|
<div>{grid}</div>
|
||||||
|
|
||||||
@@ -281,7 +188,7 @@ fn WithWall(#[prop(into)] wall: Signal<models::Wall>) -> impl IntoView {
|
|||||||
let problem = problem.await?;
|
let problem = problem.await?;
|
||||||
let view = problem
|
let view = problem
|
||||||
.map(|problem| {
|
.map(|problem| {
|
||||||
view! { <ProblemInfo problem /> }
|
view! { <WithProblem problem /> }
|
||||||
});
|
});
|
||||||
Ok::<_, ServerFnError>(view)
|
Ok::<_, ServerFnError>(view)
|
||||||
})}
|
})}
|
||||||
@@ -290,21 +197,130 @@ fn WithWall(#[prop(into)] wall: Signal<models::Wall>) -> impl IntoView {
|
|||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<AttemptRadio
|
<Suspense fallback=move || ()>
|
||||||
flash=ui_is_flash
|
{move || {
|
||||||
send=ui_is_send
|
Suspend::new(async move {
|
||||||
attempt=ui_is_attempt
|
tracing::debug!("getting user interaction");
|
||||||
onclick_flash
|
let user_interaction: Option<_> = user_interaction.await?;
|
||||||
onclick_send
|
tracing::debug!("got user interaction");
|
||||||
onclick_attempt
|
let Some(problem_uid) = problem_uid.get() else {
|
||||||
/>
|
return Ok(view! {}.into_any());
|
||||||
|
};
|
||||||
<Separator />
|
let view = view! {
|
||||||
|
<WithUserInteraction wall_uid problem_uid user_interaction />
|
||||||
<Suspense fallback=move || ()>{foo()}</Suspense>
|
}
|
||||||
|
.into_any();
|
||||||
|
Ok::<_, ServerFnError>(view)
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
fn WithUserInteraction(
|
||||||
|
#[prop(into)] wall_uid: Signal<models::WallUid>,
|
||||||
|
#[prop(into)] problem_uid: Signal<models::ProblemUid>,
|
||||||
|
#[prop(into)] user_interaction: Signal<Option<models::UserInteraction>>,
|
||||||
|
) -> 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::<RonEncoded<server_functions::UpsertTodaysAttempt>>::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! { <Attempt date attempt /> });
|
||||||
|
|
||||||
|
let placeholder = move || {
|
||||||
|
latest_attempt().is_none().then(|| {
|
||||||
|
let today = chrono::Utc::now();
|
||||||
|
view! { <Attempt date=today attempt=None /> }
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<AttemptRadio
|
||||||
|
flash=ui_is_flash
|
||||||
|
send=ui_is_send
|
||||||
|
attempt=ui_is_attempt
|
||||||
|
onclick_flash
|
||||||
|
onclick_send
|
||||||
|
onclick_attempt
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Separator />
|
||||||
|
|
||||||
|
<Section title="History">{placeholder} {v}</Section>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
|
|||||||
@@ -16,21 +16,6 @@ pub fn wall_by_uid(wall_uid: Signal<models::WallUid>) -> RonResource<models::Wal
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn problem_by_uid(wall_uid: Signal<models::WallUid>, problem_uid: Signal<models::ProblemUid>) -> RonResource<models::Problem> {
|
|
||||||
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.
|
/// Version of [problem_by_uid] that short circuits if the input problem_uid signal is None.
|
||||||
pub fn problem_by_uid_optional(
|
pub fn problem_by_uid_optional(
|
||||||
wall_uid: Signal<models::WallUid>,
|
wall_uid: Signal<models::WallUid>,
|
||||||
|
|||||||
@@ -130,6 +130,7 @@
|
|||||||
basecamp.mkShell pkgs {
|
basecamp.mkShell pkgs {
|
||||||
rust.enable = true;
|
rust.enable = true;
|
||||||
rust.toolchain.targets = [ "wasm32-unknown-unknown" ];
|
rust.toolchain.targets = [ "wasm32-unknown-unknown" ];
|
||||||
|
rust.toolchain.components.rust-analyzer.nightly = true;
|
||||||
|
|
||||||
packages = [
|
packages = [
|
||||||
pkgs.bacon
|
pkgs.bacon
|
||||||
|
|||||||
Reference in New Issue
Block a user