This commit is contained in:
Asger Juul Brunshøj 2023-06-16 22:20:51 +02:00
parent 35d53d82c6
commit 0ab1f48714
2 changed files with 174 additions and 12 deletions

View File

@ -1,5 +1,7 @@
use crate::components::achievement::AchievementComponent; use crate::components::achievement::AchievementComponent;
use crate::components::milestone::MilestoneComponent; use crate::components::milestone::MilestoneComponent;
use chrono::NaiveTime;
use common::Achievement;
use yew::functional::*; use yew::functional::*;
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
@ -20,19 +22,41 @@ pub fn Root() -> Html {
nav.push(&crate::Route::CreateMilestone); nav.push(&crate::Route::CreateMilestone);
}); });
let achievements = app_state let current_time: chrono::NaiveTime = chrono::Local::now().time();
.state
.achievements let achievements = app_state.state.achievements.clone();
.iter() let grouped_achievements = group_achievements(achievements);
.cloned()
.enumerate() let mut achievements_html: Vec<Html> = vec![];
.map(|(idx, a)| (idx + 1, a)) let mut n = 0;
.map(|(n, a)| { for (time_of_reveal, group) in grouped_achievements {
html! { if let Some(time_of_reveal) = time_of_reveal {
<AchievementComponent number={n} achievement={a} /> let s = if time_of_reveal > current_time {
format!(
"{} more revealed at {}!",
group.len(),
time_of_reveal.format("%H:%M")
)
} else {
format!("{}", time_of_reveal.format("%H:%M"))
};
let html = html! {
<p style="text-align: center; font-weight: bold">{s}</p>
};
achievements_html.push(html);
if time_of_reveal > current_time {
break;
} }
}) }
.collect::<Html>(); for a in group {
n += 1;
let html = html! {
<AchievementComponent number={n} achievement={a} />
};
achievements_html.push(html);
}
}
let achievements = achievements_html.into_iter().collect::<Html>();
let completed_achievements = app_state let completed_achievements = app_state
.state .state
@ -77,3 +101,139 @@ pub fn Root() -> Html {
</> </>
} }
} }
fn group_achievements(mut achievements: Vec<Achievement>) -> Vec<(Option<NaiveTime>, Vec<Achievement>)> {
// Sort the achievements by time_of_reveal.
achievements.sort_by_key(|a| a.time_of_reveal);
let mut grouped_achievements: Vec<(Option<NaiveTime>, Vec<Achievement>)> = Vec::new();
let mut current_time_of_reveal: Option<NaiveTime> = None;
let mut current_group: Vec<Achievement> = Vec::new();
for achievement in achievements {
if current_time_of_reveal == achievement.time_of_reveal {
current_group.push(achievement);
continue;
}
if !current_group.is_empty() {
grouped_achievements.push((current_time_of_reveal, current_group));
}
current_time_of_reveal = achievement.time_of_reveal;
current_group = vec![achievement];
}
if !current_group.is_empty() {
grouped_achievements.push((current_time_of_reveal, current_group));
}
grouped_achievements
}
#[cfg(test)]
mod tests {
use super::*;
use uuid::Uuid;
#[test]
fn test_group_achievements() {
let time1 = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
let time2 = NaiveTime::from_hms_opt(13, 0, 0).unwrap();
let mut achievements = vec![
Achievement {
goal: "Goal 1".to_string(),
completed: true,
uuid: Uuid::new_v4(),
time_of_reveal: Some(time1),
},
Achievement {
goal: "Goal 2".to_string(),
completed: false,
uuid: Uuid::new_v4(),
time_of_reveal: Some(time1),
},
Achievement {
goal: "Goal 3".to_string(),
completed: true,
uuid: Uuid::new_v4(),
time_of_reveal: Some(time2),
},
];
let grouped = group_achievements(achievements);
assert_eq!(grouped.len(), 2);
assert_eq!(grouped[0].0, Some(time1));
assert_eq!(grouped[0].1.len(), 2);
assert_eq!(grouped[1].0, Some(time2));
assert_eq!(grouped[1].1.len(), 1);
}
#[test]
fn test_group_achievements_empty_vec() {
let achievements = vec![];
let grouped = group_achievements(achievements);
assert_eq!(grouped.len(), 0);
}
#[test]
fn test_group_achievements_group_none_values() {
let time1 = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
let achievements = vec![
Achievement {
goal: "Goal 1".to_string(),
completed: true,
uuid: Uuid::new_v4(),
time_of_reveal: Some(time1),
},
Achievement {
goal: "Goal 2".to_string(),
completed: false,
uuid: Uuid::new_v4(),
time_of_reveal: None,
},
Achievement {
goal: "Goal 3".to_string(),
completed: true,
uuid: Uuid::new_v4(),
time_of_reveal: None,
},
];
let grouped = group_achievements(achievements);
assert_eq!(grouped.len(), 2);
assert_eq!(grouped[0].0, None);
assert_eq!(grouped[0].1.len(), 2);
assert_eq!(grouped[1].0, Some(time1));
assert_eq!(grouped[1].1.len(), 1);
}
#[test]
fn test_group_achievements_all_none() {
let achievements = vec![
Achievement {
goal: "Goal 1".to_string(),
completed: true,
uuid: Uuid::new_v4(),
time_of_reveal: None,
},
Achievement {
goal: "Goal 2".to_string(),
completed: false,
uuid: Uuid::new_v4(),
time_of_reveal: None,
},
Achievement {
goal: "Goal 3".to_string(),
completed: true,
uuid: Uuid::new_v4(),
time_of_reveal: None,
},
];
let grouped = group_achievements(achievements);
assert_eq!(grouped.len(), 1);
assert_eq!(grouped[0].0, None);
assert_eq!(grouped[0].1.len(), 3);
}
}

View File

@ -1,3 +1,5 @@
- UI errors from failed requests - UI errors from failed requests
- websocket reconnect - websocket reconnect
- disable timed reveal - disable timed reveal
- trigger some refresh when time exceeds next reveal
- make it an admin interface, and move the new + remove buttons there, as well as milestone management