From 5b49586da35654ae849518661a31ec4783e95949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asger=20Juul=20Brunsh=C3=B8j?= Date: Mon, 19 Jun 2023 10:53:14 +0200 Subject: [PATCH] admin view --- crates/frontend/src/components/achievement.rs | 19 -- .../src/components/achievement_reveal_time.rs | 125 --------- .../components/achievement_reveal_times.rs | 32 --- crates/frontend/src/components/admin.rs | 253 +++++++++++++++++- crates/frontend/src/components/milestone.rs | 22 -- crates/frontend/src/components/mod.rs | 2 - crates/frontend/src/components/root.rs | 23 +- crates/frontend/src/lib.rs | 8 +- 8 files changed, 253 insertions(+), 231 deletions(-) delete mode 100644 crates/frontend/src/components/achievement_reveal_time.rs delete mode 100644 crates/frontend/src/components/achievement_reveal_times.rs diff --git a/crates/frontend/src/components/achievement.rs b/crates/frontend/src/components/achievement.rs index 379f474..a89d15c 100644 --- a/crates/frontend/src/components/achievement.rs +++ b/crates/frontend/src/components/achievement.rs @@ -1,7 +1,5 @@ -use crate::services::confirm::ConfirmService; use crate::services::rest::RestService; use common::Achievement; -use common::DeleteAchievement; use common::ToggleAchievement; use wasm_bindgen_futures::spawn_local; use yew::classes; @@ -38,20 +36,6 @@ pub fn AchievementComponent(props: &Props) -> Html { }); }); - let onclick_delete = Callback::from(move |_| { - if !ConfirmService::confirm("Are you sure you want to delete?") { - return; - } - log::info!("Delete achievement confirmed."); - - spawn_local(async move { - match RestService::delete_achievement(DeleteAchievement { uuid }).await { - Ok(_response) => {} - Err(_err) => {} - } - }); - }); - let toggle_button_class = if *completed { "button-primary color-secondary" } else { @@ -69,9 +53,6 @@ pub fn AchievementComponent(props: &Props) -> Html {

{goal}

-
- -
} } diff --git a/crates/frontend/src/components/achievement_reveal_time.rs b/crates/frontend/src/components/achievement_reveal_time.rs deleted file mode 100644 index 318d074..0000000 --- a/crates/frontend/src/components/achievement_reveal_time.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::services::rest::RestService; -use common::Achievement; -use common::UpdateAchievementTimeOfReveal; -use wasm_bindgen::JsCast; -use wasm_bindgen_futures::spawn_local; -use yew::function_component; -use yew::html; -use yew::use_state; -use yew::Callback; -use yew::Html; -use yew::Properties; - -#[derive(Properties, PartialEq)] -pub struct Props { - pub achievement: Achievement, - pub number: usize, -} - -#[function_component] -pub fn AchievementRevealTime(props: &Props) -> Html { - let achievement = &props.achievement; - let uuid = achievement.uuid; - - let time_of_reveal: Option = achievement - .time_of_reveal - .map(|naive_time| naive_time.format("%H:%M").to_string()); - - let timed_reveal_enabled = use_state(|| time_of_reveal.is_some()); - let input_time = use_state(|| time_of_reveal.clone().unwrap_or("".to_string())); - let awaiting_response = use_state(|| false); - - let onsubmit = { - let awaiting_response = awaiting_response.clone(); - let timed_reveal_enabled = timed_reveal_enabled.clone(); - let input_time = input_time.clone(); - Callback::from(move |e: web_sys::SubmitEvent| { - e.prevent_default(); - - let new_time_of_reveal = if *timed_reveal_enabled { - if let Ok(naive_time) = chrono::NaiveTime::parse_from_str(&input_time, "%H:%M") { - Some(naive_time) - } else { - // TODO: show UI error - log::debug!("Could not parse time: {}", *input_time); - return; - } - } else { - None - }; - - let payload = UpdateAchievementTimeOfReveal { - time_of_reveal: new_time_of_reveal, - uuid, - }; - awaiting_response.set(true); - let awaiting_response = awaiting_response.clone(); - spawn_local(async move { - let res = RestService::update_time_of_reveal(payload).await; - awaiting_response.set(false); - }); - }) - }; - - let oninput_time = { - let input_time = input_time.clone(); - Callback::from(move |e: web_sys::InputEvent| { - let Some(input) = e - .target() - .and_then(|t| t.dyn_into::().ok()) else { unreachable!() }; - log::debug!("{:?}", input.value()); - input_time.set(input.value()); - }) - }; - - let oninput_timed_reveal_checkbox = { - let timed_reveal_enabled = timed_reveal_enabled.clone(); - Callback::from(move |e: web_sys::InputEvent| { - let Some(input) = e - .target() - .and_then(|t| t.dyn_into::().ok()) else { unreachable!() }; - timed_reveal_enabled.set(input.checked()); - }) - }; - - let new_value: Option<&str> = timed_reveal_enabled.then_some(&**input_time); - let show_submit_button: bool = time_of_reveal.as_deref() != new_value; - - html! { -
- -
- // Achievement number -
-

{format!("{}.", props.number)}

-
- - // Achievement text -
-

{&achievement.goal}

-
-
- - // Enable timed reveal checkbox - - - { if *timed_reveal_enabled { html! { - // Time input -
- - -
- }} else { html! {}}} - - // Submit button - { if show_submit_button { html! { - - }} else { html! {}}} - -
-
- } -} diff --git a/crates/frontend/src/components/achievement_reveal_times.rs b/crates/frontend/src/components/achievement_reveal_times.rs deleted file mode 100644 index 973dc02..0000000 --- a/crates/frontend/src/components/achievement_reveal_times.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::components::achievement_reveal_time::AchievementRevealTime; -use yew::functional::*; -use yew::prelude::*; -use yew_router::prelude::*; - -#[function_component] -pub fn AchievementRevealTimes() -> Html { - let nav = use_navigator().expect("cannot get navigator"); - let app_state = use_context::().expect("no app state ctx found"); - - let achievements = app_state - .state - .achievements - .iter() - .cloned() - .enumerate() - .map(|(idx, a)| (idx + 1, a)) - .map(|(n, a)| { - html! { - - } - }) - .collect::(); - - html! { - <> -

{"Achievement Timed Reveals"}

-
- {achievements} - - } -} diff --git a/crates/frontend/src/components/admin.rs b/crates/frontend/src/components/admin.rs index 7f7206c..a4458bf 100644 --- a/crates/frontend/src/components/admin.rs +++ b/crates/frontend/src/components/admin.rs @@ -1,7 +1,252 @@ +use crate::services::confirm::ConfirmService; +use crate::services::rest::RestService; +use common::DeleteAchievement; +use common::DeleteMilestone; +use common::UpdateAchievementTimeOfReveal; +use wasm_bindgen::JsCast; +use wasm_bindgen_futures::spawn_local; +use yew::function_component; use yew::functional::*; -use yew::prelude::*; +use yew::html; +use yew::use_state; +use yew::Callback; +use yew::Html; +use yew::Properties; +use yew_router::prelude::use_navigator; -#[function_component(Admin)] -pub fn admin() -> Html { - html! {} +#[function_component] +pub fn Admin() -> Html { + let nav = use_navigator().expect("cannot get navigator"); + let app_state = use_context::().expect("no app state ctx found"); + + let achievements = app_state + .state + .achievements + .iter() + .cloned() + .enumerate() + .map(|(idx, a)| (idx + 1, a)) + .map(|(n, a)| { + html! { + + } + }) + .collect::(); + + let onclick_create_achievement = { + let nav = nav.clone(); + Callback::from(move |_: web_sys::MouseEvent| { + nav.push(&crate::Route::CreateAchievement); + }) + }; + + let onclick_create_milestone = Callback::from(move |_: web_sys::MouseEvent| { + nav.push(&crate::Route::CreateMilestone); + }); + + let mut milestones = app_state.state.milestones.clone(); + milestones.sort_by_key(|m| m.goal); + let milestones = milestones + .into_iter() + .map(|m| html! { }) + .collect::(); + + html! { + <> +

{"Admin View"}

+ +
+ +
+
+

{"Milestones"}

+
+ +
+ +
+
+ {milestones} + +
+ +
+
+

{"Achievements"}

+
+ +
+ +
+
+ + {achievements} + + } +} + +#[derive(Properties, PartialEq)] +struct AchievementProps { + achievement: common::Achievement, + number: usize, +} + +#[function_component] +fn Achievement(props: &AchievementProps) -> Html { + let achievement = &props.achievement; + let uuid = achievement.uuid; + + let time_of_reveal: Option = achievement + .time_of_reveal + .map(|naive_time| naive_time.format("%H:%M").to_string()); + + let timed_reveal_enabled = use_state(|| time_of_reveal.is_some()); + let input_time = use_state(|| time_of_reveal.clone().unwrap_or("".to_string())); + let awaiting_response = use_state(|| false); + + let onsubmit_timed_reveal = { + let awaiting_response = awaiting_response.clone(); + let timed_reveal_enabled = timed_reveal_enabled.clone(); + let input_time = input_time.clone(); + Callback::from(move |e: web_sys::SubmitEvent| { + e.prevent_default(); + + let new_time_of_reveal = if *timed_reveal_enabled { + if let Ok(naive_time) = chrono::NaiveTime::parse_from_str(&input_time, "%H:%M") { + Some(naive_time) + } else { + // TODO: show UI error + log::debug!("Could not parse time: {}", *input_time); + return; + } + } else { + None + }; + + let payload = UpdateAchievementTimeOfReveal { + time_of_reveal: new_time_of_reveal, + uuid, + }; + awaiting_response.set(true); + let awaiting_response = awaiting_response.clone(); + spawn_local(async move { + let res = RestService::update_time_of_reveal(payload).await; + awaiting_response.set(false); + }); + }) + }; + + let oninput_time = { + let input_time = input_time.clone(); + Callback::from(move |e: web_sys::InputEvent| { + let Some(input) = e + .target() + .and_then(|t| t.dyn_into::().ok()) else { unreachable!() }; + log::debug!("{:?}", input.value()); + input_time.set(input.value()); + }) + }; + + let oninput_timed_reveal_checkbox = { + let timed_reveal_enabled = timed_reveal_enabled.clone(); + Callback::from(move |e: web_sys::InputEvent| { + let Some(input) = e + .target() + .and_then(|t| t.dyn_into::().ok()) else { unreachable!() }; + timed_reveal_enabled.set(input.checked()); + }) + }; + + let onclick_delete = Callback::from(move |_| { + if !ConfirmService::confirm("Are you sure you want to delete?") { + return; + } + log::info!("Delete achievement confirmed."); + + spawn_local(async move { + match RestService::delete_achievement(DeleteAchievement { uuid }).await { + Ok(_response) => {} + Err(_err) => {} + } + }); + }); + + let new_value: Option<&str> = timed_reveal_enabled.then_some(&**input_time); + let show_submit_button: bool = time_of_reveal.as_deref() != new_value; + + html! { +
+
+ // Achievement number +
+

{format!("{}.", props.number)}

+
+ + // Achievement text +
+

{&achievement.goal}

+
+ + // Delete button + +
+ + // Timed reveal form +
+ // Timed reveal: Enable checkbox + + +
+ // Time input + { if *timed_reveal_enabled { html! { +
+ + +
+ }} else { html! {}}} + + // Timed reveal form submit button + { if show_submit_button { html! { + + }} else { html! {}}} +
+ + + +
+
+ } +} + +#[function_component] +fn Milestone(props: &MilestoneProps) -> Html { + let uuid = props.milestone.uuid; + let onclick_delete = Callback::from(move |_| { + if !ConfirmService::confirm("Are you sure you want to delete?") { + return; + } + spawn_local(async move { + match RestService::delete_milestone(DeleteMilestone { uuid }).await { + Ok(_response) => {} + Err(_err) => {} + } + }); + }); + + html! { +
+

{format!("Goal: {} achievements", props.milestone.goal)}

+ +
+ +
+
+ } +} +#[derive(Properties, Clone, PartialEq)] +struct MilestoneProps { + milestone: common::Milestone, } diff --git a/crates/frontend/src/components/milestone.rs b/crates/frontend/src/components/milestone.rs index 587d7d3..4d65288 100644 --- a/crates/frontend/src/components/milestone.rs +++ b/crates/frontend/src/components/milestone.rs @@ -1,8 +1,4 @@ -use crate::services::confirm::ConfirmService; -use crate::services::rest::RestService; -use common::DeleteMilestone; use common::Milestone; -use wasm_bindgen_futures::spawn_local; use yew::prelude::*; #[derive(Properties, Clone, PartialEq)] @@ -28,21 +24,6 @@ pub fn milestone_component(props: &Props) -> Html { .take(filled) .collect::(); - let uuid = props.milestone.uuid; - let onclick_delete = Callback::from(move |_| { - if !ConfirmService::confirm("Are you sure you want to delete?") { - return; - } - log::info!("Delete achievement confirmed."); - - spawn_local(async move { - match RestService::delete_milestone(DeleteMilestone { uuid }).await { - Ok(_response) => {} - Err(_err) => {} - } - }); - }); - html! {

@@ -73,9 +54,6 @@ pub fn milestone_component(props: &Props) -> Html { {filled_stars} {unfilled_stars}

-
- -
} } diff --git a/crates/frontend/src/components/mod.rs b/crates/frontend/src/components/mod.rs index d362d4c..ee47d61 100644 --- a/crates/frontend/src/components/mod.rs +++ b/crates/frontend/src/components/mod.rs @@ -1,6 +1,4 @@ pub mod achievement; -pub mod achievement_reveal_time; -pub mod achievement_reveal_times; pub mod admin; pub mod create_achievement; pub mod create_milestone; diff --git a/crates/frontend/src/components/root.rs b/crates/frontend/src/components/root.rs index 050c161..06e9264 100644 --- a/crates/frontend/src/components/root.rs +++ b/crates/frontend/src/components/root.rs @@ -10,17 +10,6 @@ pub fn Root() -> Html { let nav = use_navigator().expect("cannot get navigator"); let app_state = use_context::().expect("no app state ctx found"); - let onclick_create_achievement = { - let nav = nav.clone(); - Callback::from(move |_: web_sys::MouseEvent| { - nav.push(&crate::Route::CreateAchievement); - }) - }; - - let onclick_create_milestone = Callback::from(move |_: web_sys::MouseEvent| { - nav.push(&crate::Route::CreateMilestone); - }); - let current_time: chrono::NaiveTime = chrono::Local::now().time(); let achievements = app_state.state.achievements.clone(); @@ -76,11 +65,7 @@ pub fn Root() -> Html {
-

{"Milestones"}

-
- -
- +

{"Milestones"}

{milestones} @@ -88,11 +73,7 @@ pub fn Root() -> Html {
-

{"Achievements"}

-
- -
- +

{"Achievements"}

{achievements} diff --git a/crates/frontend/src/lib.rs b/crates/frontend/src/lib.rs index 9d278cd..058d6e0 100644 --- a/crates/frontend/src/lib.rs +++ b/crates/frontend/src/lib.rs @@ -2,7 +2,6 @@ use crate::components::error::error_component::ErrorComponent; use crate::components::error::error_provider::ErrorProvider; use crate::event_bus::EventBus; use crate::services::websocket::WebsocketService; -use components::achievement_reveal_times::AchievementRevealTimes; use components::admin::Admin; use components::create_achievement::CreateAchievementComponent; use components::create_milestone::CreateMilestoneComponent; @@ -23,14 +22,12 @@ pub mod util; enum Route { #[at("/")] Root, - #[at("/chat")] - Admin, #[at("/create-achievement")] CreateAchievement, #[at("/create-milestone")] CreateMilestone, - #[at("/reveal-times")] - RevealTimes, + #[at("/en-lille-nisse-rejste")] + Admin, #[not_found] #[at("/404")] NotFound, @@ -43,7 +40,6 @@ fn switch(selected_route: Route) -> Html { Route::CreateAchievement => html! {}, Route::CreateMilestone => html! {}, Route::NotFound => html! {

{"404 not found"}

}, - Route::RevealTimes => html! {}, } }