refactor
This commit is contained in:
parent
d9406f98d1
commit
f1be2dd735
@ -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::<Vec<_>>();
|
||||
let problems_sample = move || problems.values().take(10).cloned().collect::<Vec<_>>();
|
||||
|
||||
Ok(view! {
|
||||
<div>
|
||||
|
@ -91,7 +91,7 @@ fn WithProblem(#[prop(into)] problem: Signal<models::Problem>) -> impl IntoView
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn WithWall(
|
||||
#[prop(into)] wall: Signal<models::Wall>,
|
||||
#[prop(into)] problems: Signal<Vec<models::Problem>>,
|
||||
#[prop(into)] problems: Signal<BTreeMap<models::ProblemUid, models::Problem>>,
|
||||
#[prop(into)] user_interactions: Signal<BTreeMap<models::ProblemUid, models::UserInteraction>>,
|
||||
) -> impl IntoView {
|
||||
tracing::trace!("Enter");
|
||||
@ -100,6 +100,9 @@ fn WithWall(
|
||||
|
||||
let (problem_uid, set_problem_uid) = leptos_router::hooks::query_signal::<models::ProblemUid>("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::<Vec<models::Problem>>()
|
||||
.filter(|(_, problem)| filter_holds.iter().all(|hold_pos| problem.holds.contains_key(hold_pos)))
|
||||
.map(|(problem_uid, problem)| (*problem_uid, problem.clone()))
|
||||
.collect::<BTreeMap<models::ProblemUid, models::Problem>>()
|
||||
})
|
||||
});
|
||||
|
||||
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! {
|
||||
<Grid wall=wall.get() problem=problem_signal on_click_hold />
|
||||
};
|
||||
let view = view! { <Grid wall=wall.get() problem on_click_hold /> };
|
||||
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(
|
||||
<Separator />
|
||||
|
||||
<Section title="Problem">
|
||||
<Transition fallback=|| ()>
|
||||
{move || Suspend::new(async move {
|
||||
tracing::info!("executing problem suspend");
|
||||
let problem = problem.await?;
|
||||
let view = problem
|
||||
.map(|problem| {
|
||||
view! { <WithProblem problem /> }
|
||||
});
|
||||
Ok::<_, ServerFnError>(view)
|
||||
})}
|
||||
</Transition>
|
||||
{move || problem.get().map(|p| view! { <WithProblem problem=p /> })}
|
||||
</Section>
|
||||
|
||||
<Separator />
|
||||
@ -429,7 +413,7 @@ fn History(#[prop(into)] user_interaction: Signal<Option<models::UserInteraction
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn Grid(
|
||||
wall: models::Wall,
|
||||
#[prop(into)] problem: Signal<Result<Option<models::Problem>, ServerFnError>>,
|
||||
#[prop(into)] problem: Signal<Option<models::Problem>>,
|
||||
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<Signal<Result<Option<HoldRole>, ServerFnError>>>,
|
||||
role: Option<Signal<Option<HoldRole>>>,
|
||||
) -> 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! { <img class="object-cover w-full h-full" srcset=srcset /> }
|
||||
});
|
||||
|
||||
let view = view! { <div class=class>{img}</div> };
|
||||
Ok::<_, ServerFnError>(view)
|
||||
view! { <div class=class>{img}</div> }
|
||||
}
|
||||
}
|
||||
|
||||
@ -549,4 +531,15 @@ mod signals {
|
||||
user_interactions.get(&problem_uid).cloned()
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn problem(
|
||||
problems: Signal<BTreeMap<models::ProblemUid, models::Problem>>,
|
||||
problem_uid: Signal<Option<models::ProblemUid>>,
|
||||
) -> Signal<Option<models::Problem>> {
|
||||
Signal::derive(move || {
|
||||
let problem_uid = problem_uid.get()?;
|
||||
let problems = problems.read();
|
||||
problems.get(&problem_uid).cloned()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ pub fn problem_by_uid_optional(
|
||||
}
|
||||
|
||||
/// Returns all problems for a wall
|
||||
pub fn problems_for_wall(wall_uid: Signal<models::WallUid>) -> RonResource<Vec<models::Problem>> {
|
||||
pub fn problems_for_wall(wall_uid: Signal<models::WallUid>) -> RonResource<BTreeMap<models::ProblemUid, models::Problem>> {
|
||||
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) },
|
||||
|
@ -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<RonEnco
|
||||
custom = RonEncoded
|
||||
)]
|
||||
#[tracing::instrument(err(Debug))]
|
||||
pub(crate) async fn get_problems_for_wall(wall_uid: models::WallUid) -> Result<RonEncoded<Vec<models::Problem>>, ServerFnError> {
|
||||
pub(crate) async fn get_problems_for_wall(
|
||||
wall_uid: models::WallUid,
|
||||
) -> Result<RonEncoded<BTreeMap<models::ProblemUid, models::Problem>>, 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<R
|
||||
DatabaseOperation(DatabaseOperationError),
|
||||
}
|
||||
|
||||
async fn inner(wall_uid: models::WallUid) -> Result<Vec<models::Problem>, Error> {
|
||||
async fn inner(wall_uid: models::WallUid) -> Result<BTreeMap<models::ProblemUid, models::Problem>, Error> {
|
||||
let db = expect_context::<Database>();
|
||||
|
||||
let problems = db
|
||||
@ -109,12 +112,15 @@ pub(crate) async fn get_problems_for_wall(wall_uid: models::WallUid) -> Result<R
|
||||
let problems_table = txn.open_table(crate::server::db::current::TABLE_PROBLEMS)?;
|
||||
tracing::debug!("opened problems table");
|
||||
|
||||
let mut problems = Vec::new();
|
||||
for &problem_uid in &wall.problems {
|
||||
if let Some(problem) = problems_table.get((wall_uid, problem_uid))? {
|
||||
problems.push(problem.value());
|
||||
}
|
||||
}
|
||||
let problems = wall
|
||||
.problems
|
||||
.iter()
|
||||
.map(|problem_uid| problems_table.get(&(wall_uid, *problem_uid)))
|
||||
.filter_map(|res| res.transpose())
|
||||
.map_res(|guard| guard.value())
|
||||
.map_res(|problem| (problem.uid, problem))
|
||||
.collect::<Result<BTreeMap<models::ProblemUid, models::Problem>, _>>()?;
|
||||
|
||||
Ok(problems)
|
||||
})
|
||||
.await?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user