refactor
This commit is contained in:
parent
f8aa1e29a2
commit
7d95e48941
@ -1,10 +1,12 @@
|
||||
use crate::components::icons;
|
||||
use crate::models;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn Attempt(#[prop(into)] date: Signal<chrono::DateTime<chrono::Utc>>, #[prop(into)] attempt: Signal<Option<models::Attempt>>) -> impl IntoView {
|
||||
pub fn Attempt(#[prop(into)] date: Signal<DateTime<Utc>>, #[prop(into)] attempt: Signal<Option<models::Attempt>>) -> impl IntoView {
|
||||
tracing::trace!("Enter");
|
||||
|
||||
let s = time_ago(date.get());
|
||||
|
@ -16,6 +16,21 @@ pub use v2::WallDimensions;
|
||||
pub use v2::WallUid;
|
||||
pub use v3::Attempt;
|
||||
pub use v3::UserInteraction;
|
||||
pub use v4::DatedAttempt;
|
||||
|
||||
mod semantics;
|
||||
|
||||
pub mod v4 {
|
||||
use super::v3;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct DatedAttempt {
|
||||
pub date_time: DateTime<Utc>,
|
||||
pub attempt: v3::Attempt,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod v3 {
|
||||
use super::v2;
|
||||
@ -38,24 +53,6 @@ pub mod v3 {
|
||||
/// Added to personal challenges
|
||||
pub is_saved: bool,
|
||||
}
|
||||
impl UserInteraction {
|
||||
pub fn new(wall_uid: v2::WallUid, problem_uid: v2::ProblemUid) -> Self {
|
||||
Self {
|
||||
wall_uid,
|
||||
problem_uid,
|
||||
is_favorite: false,
|
||||
attempted_on: BTreeMap::new(),
|
||||
is_saved: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn best_attempt(&self) -> Option<(chrono::DateTime<chrono::Utc>, Attempt)> {
|
||||
self.attempted_on
|
||||
.iter()
|
||||
.max_by_key(|(_date, attempt)| *attempt)
|
||||
.map(|(date, attempt)| (*date, *attempt))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
|
||||
pub enum Attempt {
|
||||
@ -103,11 +100,6 @@ pub mod v2 {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, derive_more::FromStr, derive_more::Display)]
|
||||
pub struct WallUid(pub uuid::Uuid);
|
||||
impl WallUid {
|
||||
pub fn create() -> Self {
|
||||
Self(uuid::Uuid::new_v4())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Problem {
|
||||
@ -121,17 +113,6 @@ pub mod v2 {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, derive_more::FromStr, derive_more::Display)]
|
||||
pub struct ProblemUid(pub uuid::Uuid);
|
||||
impl ProblemUid {
|
||||
pub fn create() -> Self {
|
||||
Self(uuid::Uuid::new_v4())
|
||||
}
|
||||
pub fn min() -> Self {
|
||||
Self(uuid::Uuid::nil())
|
||||
}
|
||||
pub fn max() -> Self {
|
||||
Self(uuid::Uuid::max())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Display)]
|
||||
pub enum Method {
|
||||
@ -156,15 +137,6 @@ pub mod v2 {
|
||||
pub uid: ImageUid,
|
||||
pub resolutions: BTreeMap<ImageResolution, ImageFilename>,
|
||||
}
|
||||
impl Image {
|
||||
pub(crate) fn srcset(&self) -> String {
|
||||
self.resolutions
|
||||
.iter()
|
||||
.map(|(res, filename)| format!("/files/holds/{} {}w", filename.filename, res.width))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct ImageResolution {
|
||||
@ -179,11 +151,6 @@ pub mod v2 {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, derive_more::FromStr, derive_more::Display)]
|
||||
pub struct ImageUid(pub uuid::Uuid);
|
||||
impl ImageUid {
|
||||
pub fn create() -> Self {
|
||||
Self(uuid::Uuid::new_v4())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod v1 {
|
||||
|
93
crates/ascend/src/models/semantics.rs
Normal file
93
crates/ascend/src/models/semantics.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use super::*;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
impl UserInteraction {
|
||||
pub fn new(wall_uid: WallUid, problem_uid: ProblemUid) -> Self {
|
||||
Self {
|
||||
wall_uid,
|
||||
problem_uid,
|
||||
is_favorite: false,
|
||||
attempted_on: BTreeMap::new(),
|
||||
is_saved: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn latest_attempt(&self) -> Option<DatedAttempt> {
|
||||
self.attempted_on.last_key_value().map(Into::into)
|
||||
}
|
||||
|
||||
pub fn todays_attempt(&self) -> Option<Attempt> {
|
||||
self.latest_attempt()
|
||||
.filter(|latest_attempt| {
|
||||
let today_local_naive = chrono::Local::now().date_naive();
|
||||
let datetime_local_naive = latest_attempt.date_time.with_timezone(&chrono::Local).date_naive();
|
||||
datetime_local_naive == today_local_naive
|
||||
})
|
||||
.map(|dated_attempt| dated_attempt.attempt)
|
||||
}
|
||||
|
||||
pub fn best_attempt(&self) -> Option<DatedAttempt> {
|
||||
self.attempted_on.iter().max_by_key(|(_date_time, attempt)| *attempt).map(Into::into)
|
||||
}
|
||||
|
||||
pub fn attempted_on(&self) -> impl IntoIterator<Item = DatedAttempt> {
|
||||
self.attempted_on.iter().map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(DateTime<Utc>, Attempt)> for DatedAttempt {
|
||||
fn from(value: (DateTime<Utc>, Attempt)) -> Self {
|
||||
let (date_time, attempt) = value;
|
||||
DatedAttempt { date_time, attempt }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&(DateTime<Utc>, Attempt)> for DatedAttempt {
|
||||
fn from(value: &(DateTime<Utc>, Attempt)) -> Self {
|
||||
let &(date_time, attempt) = value;
|
||||
DatedAttempt { date_time, attempt }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&DateTime<Utc>, &Attempt)> for DatedAttempt {
|
||||
fn from(value: (&DateTime<Utc>, &Attempt)) -> Self {
|
||||
let (&date_time, &attempt) = value;
|
||||
DatedAttempt { date_time, attempt }
|
||||
}
|
||||
}
|
||||
|
||||
impl WallUid {
|
||||
pub fn create() -> Self {
|
||||
Self(uuid::Uuid::new_v4())
|
||||
}
|
||||
}
|
||||
|
||||
impl ProblemUid {
|
||||
pub fn create() -> Self {
|
||||
Self(uuid::Uuid::new_v4())
|
||||
}
|
||||
pub fn min() -> Self {
|
||||
Self(uuid::Uuid::nil())
|
||||
}
|
||||
pub fn max() -> Self {
|
||||
Self(uuid::Uuid::max())
|
||||
}
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub(crate) fn srcset(&self) -> String {
|
||||
self.resolutions
|
||||
.iter()
|
||||
.map(|(res, filename)| format!("/files/holds/{} {}w", filename.filename, res.width))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
}
|
||||
}
|
||||
|
||||
impl ImageUid {
|
||||
pub fn create() -> Self {
|
||||
Self(uuid::Uuid::new_v4())
|
||||
}
|
||||
}
|
@ -254,10 +254,10 @@ fn WithWall(
|
||||
let user_ints = user_interactions.read();
|
||||
for problem in filtered_problems.read().iter() {
|
||||
if let Some(user_int) = user_ints.get(&problem.uid) {
|
||||
match user_int.best_attempt() {
|
||||
Some((_, models::Attempt::Flash)) => interaction_counters.flash += 1,
|
||||
Some((_, models::Attempt::Send)) => interaction_counters.send += 1,
|
||||
Some((_, models::Attempt::Attempt)) => interaction_counters.attempt += 1,
|
||||
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,
|
||||
Some(models::Attempt::Attempt) => interaction_counters.attempt += 1,
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
@ -384,23 +384,8 @@ fn WithUserInteraction(
|
||||
}
|
||||
});
|
||||
|
||||
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 latest_attempt = signals::latest_attempt(user_interaction_rw.into());
|
||||
let todays_attempt = signals::todays_attempt(user_interaction_rw.into());
|
||||
|
||||
let ui_is_flash = RwSignal::new(false);
|
||||
let ui_is_send = RwSignal::new(false);
|
||||
@ -408,7 +393,7 @@ fn WithUserInteraction(
|
||||
let ui_is_favorite = RwSignal::new(false);
|
||||
|
||||
Effect::new(move || {
|
||||
let attempt = todays_attempt();
|
||||
let attempt = todays_attempt.get();
|
||||
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)));
|
||||
@ -440,10 +425,22 @@ fn WithUserInteraction(
|
||||
};
|
||||
|
||||
// TODO: loop over attempts in user_interaction
|
||||
let v = move || latest_attempt().map(|(date, attempt)| view! { <Attempt date attempt /> });
|
||||
let v = move || {
|
||||
user_interaction_rw
|
||||
.read()
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|x| x.attempted_on())
|
||||
.map(|dated_attempt| {
|
||||
let date = dated_attempt.date_time;
|
||||
let attempt = dated_attempt.attempt;
|
||||
view! { <Attempt date attempt /> }
|
||||
})
|
||||
.collect_view()
|
||||
};
|
||||
|
||||
let placeholder = move || {
|
||||
latest_attempt().is_none().then(|| {
|
||||
latest_attempt.read().is_none().then(|| {
|
||||
let today = chrono::Utc::now();
|
||||
view! { <Attempt date=today attempt=None /> }
|
||||
})
|
||||
@ -602,3 +599,16 @@ fn Section(children: Children, #[prop(into)] title: MaybeProp<String>) -> impl I
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
mod signals {
|
||||
use crate::models;
|
||||
use leptos::prelude::*;
|
||||
|
||||
pub fn latest_attempt(user_interaction: Signal<Option<models::UserInteraction>>) -> Signal<Option<models::DatedAttempt>> {
|
||||
Signal::derive(move || user_interaction.read().as_ref().and_then(models::UserInteraction::latest_attempt))
|
||||
}
|
||||
|
||||
pub fn todays_attempt(latest_attempt: Signal<Option<models::UserInteraction>>) -> Signal<Option<models::Attempt>> {
|
||||
Signal::derive(move || latest_attempt.read().as_ref().and_then(models::UserInteraction::todays_attempt))
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user