diff --git a/Cargo.lock b/Cargo.lock index 21288b2..64afb6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -234,8 +234,10 @@ dependencies = [ "reqwasm", "serde", "serde_json", + "wasm-bindgen", "wasm-bindgen-futures", "wasm-logger", + "web-sys", "yew", "yew-agent", "yew-router", diff --git a/crates/backend/src/main.rs b/crates/backend/src/main.rs index e9aec96..0895398 100644 --- a/crates/backend/src/main.rs +++ b/crates/backend/src/main.rs @@ -140,7 +140,7 @@ async fn ws_handler( } else { String::from("Unknown browser") }; - tracing::debug!("{user_agent} connected websocket."); + tracing::debug!("New ws connection from: {user_agent}."); ws.on_upgrade(move |socket| handle_socket(socket, state_watch_rx)) } diff --git a/crates/frontend/Cargo.toml b/crates/frontend/Cargo.toml index 4443562..a6ef6ed 100644 --- a/crates/frontend/Cargo.toml +++ b/crates/frontend/Cargo.toml @@ -16,3 +16,5 @@ reqwasm = "0.5.0" yew-agent = "0.2.0" serde.workspace = true serde_json = "1.0.96" +web-sys = "0.3.63" +wasm-bindgen = "0.2.86" diff --git a/crates/frontend/src/components/admin.rs b/crates/frontend/src/components/admin.rs index 72c7763..315ee48 100644 --- a/crates/frontend/src/components/admin.rs +++ b/crates/frontend/src/components/admin.rs @@ -1,7 +1,7 @@ -use crate::Route; + use yew::functional::*; use yew::prelude::*; -use yew_router::prelude::*; + #[function_component(Admin)] pub fn admin() -> Html { diff --git a/crates/frontend/src/components/create_achievement.rs b/crates/frontend/src/components/create_achievement.rs new file mode 100644 index 0000000..1ec8283 --- /dev/null +++ b/crates/frontend/src/components/create_achievement.rs @@ -0,0 +1,139 @@ +use common::CreateAchievement; +use reqwasm::http::Request; +use wasm_bindgen::JsCast; +use wasm_bindgen_futures::spawn_local; +use yew::html; +use yew::Callback; +use yew::Component; +use yew::Html; +use yew_router::scope_ext::RouterScopeExt; + +#[derive(Debug)] +pub enum Msg { + Submit, + Reset, + UpdateInput(String), +} + +#[derive(Default)] +pub struct CreateAchievementComponent { + input_value: String, + submitted: bool, +} +impl Component for CreateAchievementComponent { + type Message = Msg; + type Properties = (); + + fn create(_ctx: &yew::Context) -> Self { + Self::default() + } + + fn update(&mut self, _ctx: &yew::Context, msg: Self::Message) -> bool { + match msg { + Msg::Reset => { + self.input_value.clear(); + self.submitted = false; + true + } + Msg::Submit => { + log::info!("button click, creating achievement"); + + let payload = CreateAchievement { + goal: self.input_value.clone(), + }; + let payload = serde_json::to_string(&payload).unwrap(); + + spawn_local(async move { + let req = Request::post("http://127.0.0.1:4000/create") + .header("Content-Type", "application/json") + .body(payload); + let res = req.send().await; + match res { + Ok(response) => { + dbg!(response); + } + Err(err) => { + log::error!("Request failed: {err:?}"); + } + } + }); + + self.submitted = true; + + true + } + Msg::UpdateInput(value) => { + self.input_value = value; + true + } + } + } + + fn view(&self, ctx: &yew::Context) -> Html { + let link = ctx.link().clone(); + let nav = ctx.link().navigator().unwrap(); + + if self.submitted { + let onclick_go_back = Callback::from(move |_: web_sys::MouseEvent| { + nav.push(&crate::Route::Root); + }); + + let onclick_add_another = link.callback(|_: web_sys::MouseEvent| Msg::Reset); + + html! { + <> +
+
+

{"Submitted!"}

+
+
+
+
+ +
+
+ +
+
+ + } + } else { + let onclick_go_back = Callback::from(move |_: web_sys::MouseEvent| { + nav.push(&crate::Route::Root); + }); + + let onsubmit = link.callback(|e: web_sys::SubmitEvent| { + e.prevent_default(); + Msg::Submit + }); + + let oninput = link.callback(|e: web_sys::InputEvent| { + let Some(input) = e + .target() + .and_then(|t| t.dyn_into::().ok()) else { unreachable!() }; + Msg::UpdateInput(input.value()) + }); + + let input_value = self.input_value.clone(); + + html! { + <> +
+ +
+ +
+
+
+
+ + +
+
+ +
+ + } + } + } +} diff --git a/crates/frontend/src/components/mod.rs b/crates/frontend/src/components/mod.rs index 1f6ec97..9a60fc6 100644 --- a/crates/frontend/src/components/mod.rs +++ b/crates/frontend/src/components/mod.rs @@ -1,3 +1,4 @@ pub mod achievement; pub mod admin; +pub mod create_achievement; pub mod root; diff --git a/crates/frontend/src/components/root.rs b/crates/frontend/src/components/root.rs index 4d9f5de..31e4a63 100644 --- a/crates/frontend/src/components/root.rs +++ b/crates/frontend/src/components/root.rs @@ -5,6 +5,7 @@ use std::rc::Rc; use yew::prelude::*; use yew_agent::Bridge; use yew_agent::Bridged; +use yew_router::scope_ext::RouterScopeExt; pub struct Root { wss: WebsocketService, @@ -48,6 +49,13 @@ impl Component for Root { } fn view(&self, ctx: &Context) -> Html { + let link = ctx.link().clone(); + let nav = ctx.link().navigator().unwrap(); + + let onclick_create_achievement = Callback::from(move |_: web_sys::MouseEvent| { + nav.push(&crate::Route::CreateAchievement); + }); + let Some(state) = &self.state else { return html! {

{"loading..."}

@@ -66,15 +74,15 @@ impl Component for Root { .collect::(); html! { -
-
-
-

{"Achievements"}

-
-
+ <> +

{"Achievements"}

+
- {achievements} -
+ {achievements} + +
+ + } } } diff --git a/crates/frontend/src/event_bus.rs b/crates/frontend/src/event_bus.rs index a7b6b66..9841f16 100644 --- a/crates/frontend/src/event_bus.rs +++ b/crates/frontend/src/event_bus.rs @@ -30,7 +30,7 @@ impl yew_agent::Worker for EventBus { fn update(&mut self, _msg: Self::Message) {} - fn handle_input(&mut self, msg: Self::Input, id: HandlerId) { + fn handle_input(&mut self, msg: Self::Input, _id: HandlerId) { match msg { EventBusInput::EventBusMsg(s) => { for sub in &self.subscribers { diff --git a/crates/frontend/src/lib.rs b/crates/frontend/src/lib.rs index 949288f..5aa71b7 100644 --- a/crates/frontend/src/lib.rs +++ b/crates/frontend/src/lib.rs @@ -1,4 +1,5 @@ use components::admin::Admin; +use components::create_achievement::CreateAchievementComponent; use components::root::Root; use std::rc::Rc; use yew::prelude::*; @@ -16,6 +17,8 @@ enum Route { Root, #[at("/chat")] Admin, + #[at("/create-achievement")] + CreateAchievement, #[not_found] #[at("/404")] NotFound, @@ -25,6 +28,7 @@ fn switch(selected_route: Route) -> Html { match selected_route { Route::Root => html! {}, Route::Admin => html! {}, + Route::CreateAchievement => html! {}, Route::NotFound => html! {

{"404 not found"}

}, } } @@ -42,7 +46,7 @@ pub fn App() -> Html { html! { context={(*ctx).clone()}> -
+
render={switch}/>