wip
This commit is contained in:
@@ -19,7 +19,7 @@ pub fn Problem(
|
||||
for row in 0..dim.get().rows {
|
||||
for col in 0..dim.get().cols {
|
||||
let hold_position = models::HoldPosition { row, col };
|
||||
let role = move || problem.get().holds.get(&hold_position).copied();
|
||||
let role = move || problem.read().pattern.pattern.get(&hold_position).copied();
|
||||
let role = Signal::derive(role);
|
||||
let hold = view! { <Hold role /> };
|
||||
holds.push(hold);
|
||||
|
||||
@@ -74,13 +74,12 @@ impl Pattern {
|
||||
}
|
||||
|
||||
impl UserInteraction {
|
||||
pub(crate) fn new(wall_uid: WallUid, problem_uid: ProblemUid) -> Self {
|
||||
pub(crate) fn new(wall_uid: WallUid, problem: Problem) -> Self {
|
||||
Self {
|
||||
wall_uid,
|
||||
problem_uid,
|
||||
problem,
|
||||
is_favorite: false,
|
||||
attempted_on: BTreeMap::new(),
|
||||
is_saved: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ use leptos::prelude::*;
|
||||
use leptos_router::params::Params;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::BTreeSet;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[derive(Params, PartialEq, Clone)]
|
||||
struct RouteParams {
|
||||
@@ -35,7 +36,7 @@ pub fn Page() -> impl IntoView {
|
||||
});
|
||||
|
||||
let wall = crate::resources::wall_by_uid(wall_uid);
|
||||
let user_interactions = crate::resources::user_interactions(wall_uid);
|
||||
let user_interactions = crate::resources::user_interactions_for_wall(wall_uid);
|
||||
|
||||
leptos::view! {
|
||||
<div class="min-h-screen min-w-screen bg-neutral-950">
|
||||
@@ -79,7 +80,7 @@ fn Controller(
|
||||
crate::tracing::on_enter!();
|
||||
|
||||
// Extract data from URL
|
||||
let (problem_url, set_problem_url) = leptos_router::hooks::query_signal::<models::Problem>("problem");
|
||||
let (problem, set_problem) = leptos_router::hooks::query_signal::<models::Problem>("problem");
|
||||
|
||||
// Filter
|
||||
let (filter_holds, set_filter_holds) = signal(BTreeSet::new());
|
||||
@@ -91,9 +92,8 @@ fn Controller(
|
||||
|
||||
// Derive signals
|
||||
let wall_uid = signals::wall_uid(wall);
|
||||
let problems = signals::problems(wall);
|
||||
let user_interaction = signals::user_interaction(user_interactions.into(), problem_url.into());
|
||||
let filtered_problems = signals::filtered_problems(problems, filter_holds.into());
|
||||
let user_interaction = signals::user_interaction(user_interactions.into(), problem.into());
|
||||
let filtered_problems = signals::filtered_problems(wall, filter_holds.into());
|
||||
let todays_attempt = signals::todays_attempt(user_interaction);
|
||||
let latest_attempt = signals::latest_attempt(user_interaction);
|
||||
|
||||
@@ -107,13 +107,13 @@ fn Controller(
|
||||
let cb_set_random_problem: Callback<()> = Callback::new(move |_| {
|
||||
// TODO: remove current problem from population
|
||||
let population = filtered_problems.read();
|
||||
let population = population.keys().copied();
|
||||
let population = population.deref();
|
||||
|
||||
use rand::seq::IteratorRandom;
|
||||
let mut rng = rand::rng();
|
||||
let problem_uid = population.choose(&mut rng);
|
||||
let problem = population.iter().choose(&mut rng);
|
||||
|
||||
set_problem_url.set(problem_uid);
|
||||
set_problem.set(problem.cloned());
|
||||
});
|
||||
|
||||
// Callback: On click hold, Add/Remove hold position to problem filter
|
||||
@@ -127,7 +127,7 @@ fn Controller(
|
||||
|
||||
// Set a problem when wall is set (loaded)
|
||||
Effect::new(move |_prev_value| {
|
||||
if problem_url.get().is_none() {
|
||||
if problem.read().is_none() {
|
||||
tracing::debug!("Setting initial problem");
|
||||
cb_set_random_problem.run(());
|
||||
}
|
||||
@@ -138,14 +138,14 @@ fn Controller(
|
||||
if let Some(Ok(v)) = upsert_todays_attempt.value().get() {
|
||||
let v = v.into_inner();
|
||||
user_interactions.update(|map| {
|
||||
map.insert(v.problem_uid, v);
|
||||
map.insert(v.problem.clone(), v);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
provide_context(Context {
|
||||
wall,
|
||||
problem,
|
||||
problem: problem.into(),
|
||||
cb_click_hold,
|
||||
user_interaction,
|
||||
latest_attempt,
|
||||
@@ -302,8 +302,8 @@ fn Filter() -> impl IntoView {
|
||||
let mut interaction_counters = InteractionCounters::default();
|
||||
let interaction_counters_view = {
|
||||
let user_ints = ctx.user_interactions.read();
|
||||
for problem_uid in ctx.filtered_problems.read().keys() {
|
||||
if let Some(user_int) = user_ints.get(problem_uid) {
|
||||
for problem in ctx.filtered_problems.read().iter() {
|
||||
if let Some(user_int) = user_ints.get(problem) {
|
||||
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,
|
||||
@@ -555,13 +555,13 @@ mod signals {
|
||||
}
|
||||
|
||||
pub fn user_interaction(
|
||||
user_interactions: Signal<BTreeMap<models::ProblemUid, models::UserInteraction>>,
|
||||
problem_uid: Signal<Option<models::ProblemUid>>,
|
||||
user_interactions: Signal<BTreeMap<models::Problem, models::UserInteraction>>,
|
||||
problem: Signal<Option<models::Problem>>,
|
||||
) -> Signal<Option<models::UserInteraction>> {
|
||||
Signal::derive(move || {
|
||||
let problem_uid = problem_uid.get()?;
|
||||
let problem = problem.get()?;
|
||||
let user_interactions = user_interactions.read();
|
||||
user_interactions.get(&problem_uid).cloned()
|
||||
user_interactions.get(&problem).cloned()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,14 @@ pub fn user_interaction(wall_uid: Signal<models::WallUid>, problem: Signal<Optio
|
||||
}
|
||||
|
||||
/// Returns all user interactions for a wall
|
||||
pub fn user_interactions(wall_uid: Signal<models::WallUid>) -> RonResource<BTreeMap<models::ProblemUid, models::UserInteraction>> {
|
||||
pub fn user_interactions_for_wall(wall_uid: Signal<models::WallUid>) -> RonResource<BTreeMap<models::Problem, models::UserInteraction>> {
|
||||
Resource::new_with_options(
|
||||
move || wall_uid.get(),
|
||||
move |wall_uid| async move { crate::server_functions::get_user_interactions(wall_uid).await.map(RonEncoded::into_inner) },
|
||||
move |wall_uid| async move {
|
||||
crate::server_functions::get_user_interactions_for_wall(wall_uid)
|
||||
.await
|
||||
.map(RonEncoded::into_inner)
|
||||
},
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use derive_more::Error;
|
||||
use derive_more::From;
|
||||
use leptos::prelude::*;
|
||||
use leptos::server;
|
||||
use redb::ReadableTable;
|
||||
use server_fn::ServerFnError;
|
||||
use std::collections::BTreeMap;
|
||||
use type_toppings::IteratorExt;
|
||||
@@ -123,7 +124,7 @@ pub(crate) async fn get_user_interaction(
|
||||
custom = RonEncoded
|
||||
)]
|
||||
#[tracing::instrument(err(Debug))]
|
||||
pub(crate) async fn get_user_interactions(
|
||||
pub(crate) async fn get_user_interactions_for_wall(
|
||||
wall_uid: models::WallUid,
|
||||
) -> Result<RonEncoded<BTreeMap<models::Problem, models::UserInteraction>>, ServerFnError> {
|
||||
use crate::server::db::Database;
|
||||
@@ -142,12 +143,22 @@ pub(crate) async fn get_user_interactions(
|
||||
let user_interactions = db
|
||||
.read(|txn| {
|
||||
let user_table = txn.open_table(crate::server::db::current::TABLE_USER)?;
|
||||
let range = user_table.range((wall_uid, models::ProblemUid::min())..=(wall_uid, models::ProblemUid::max()))?;
|
||||
let user_interactions = range
|
||||
let user_interactions = user_table
|
||||
.iter()?
|
||||
.filter(|guard| {
|
||||
guard
|
||||
.as_ref()
|
||||
.map(|(key, _val)| {
|
||||
let (wall_uid, _problem) = key.value();
|
||||
wall_uid
|
||||
})
|
||||
.map(|wall_uid_| wall_uid_ == wall_uid)
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.map(|guard| {
|
||||
guard.map(|(_key, val)| {
|
||||
let val = val.value();
|
||||
(val.problem_uid, val)
|
||||
(val.problem.clone(), val)
|
||||
})
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
@@ -195,11 +206,11 @@ pub(crate) async fn upsert_todays_attempt(
|
||||
.write(|txn| {
|
||||
let mut user_table = txn.open_table(crate::server::db::current::TABLE_USER)?;
|
||||
|
||||
let key = (wall_uid, problem);
|
||||
let key = (wall_uid, problem.clone());
|
||||
|
||||
// Pop or default
|
||||
let mut user_interaction = user_table
|
||||
.remove(key)?
|
||||
.remove(&key)?
|
||||
.map(|guard| guard.value())
|
||||
.unwrap_or_else(|| models::UserInteraction::new(wall_uid, problem));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user