diff --git a/src/data/pool_match.rs b/src/data/pool_match.rs index 3ee5b55..b2ba79c 100644 --- a/src/data/pool_match.rs +++ b/src/data/pool_match.rs @@ -33,6 +33,11 @@ pub struct PoolMatchList { pub max_id: MatchId, } +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct UserList{ + pub users: Vec, +} + impl PoolMatch { pub fn new(data: MatchData, time: DateTime) -> PoolMatch { PoolMatch { id: 0, data, time } @@ -53,3 +58,17 @@ impl PoolMatchList { self.pool_matches.push(pool_match); } } + +impl UserList { + pub fn new() -> UserList { + UserList { + users: vec![], + } + } + + pub fn add_user(&mut self, user: String) -> usize { + let user_id = self.users.len(); + self.users.push(user); + user_id + } +} diff --git a/src/data/store.rs b/src/data/store.rs index 839a49b..4069df9 100644 --- a/src/data/store.rs +++ b/src/data/store.rs @@ -1,6 +1,7 @@ // (Server only) In-memory data storage and persistent storage use crate::data::pool_match::PoolMatchList; +use crate::data::pool_match::UserList; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use std::{fs, path::Path, sync::Mutex}; @@ -8,6 +9,7 @@ use std::{fs, path::Path, sync::Mutex}; #[derive(Serialize, Deserialize, Clone)] pub struct Store { pub matches: PoolMatchList, + pub users: UserList, } impl Store { @@ -16,6 +18,7 @@ impl Store { match Path::new("data/store.json").exists() { false => Store { matches: PoolMatchList::new(), + users: UserList::new(), }, true => { let contents = fs::read_to_string("data/store.json").unwrap(); diff --git a/src/endpoints.rs b/src/endpoints.rs index 5cda3da..139ed38 100644 --- a/src/endpoints.rs +++ b/src/endpoints.rs @@ -1 +1,2 @@ pub const MATCH: &str = "/api/post-match"; +pub const USER: &str = "/api/post-user"; diff --git a/src/server/routes.rs b/src/server/routes.rs index 934c557..df2cc88 100644 --- a/src/server/routes.rs +++ b/src/server/routes.rs @@ -2,10 +2,11 @@ use crate::{ data::{ - pool_match::{PoolMatch, PoolMatchList}, + pool_match::{PoolMatch, PoolMatchList, UserList}, store::DATA, }, endpoints::MATCH, + endpoints::USER, }; use axum::{ extract::Json, @@ -15,6 +16,7 @@ use std::thread; pub fn register_routes(app: Router) -> Router { let app = app.route(MATCH, post(post_match)); + let app = app.route(USER, post(post_user)); app } @@ -32,3 +34,19 @@ async fn post_match(Json(pool_match): Json) -> Json { Json(matches) } + +async fn post_user(user: String) -> Json { + // Update the store with the new match + let users = thread::spawn(move || { + // Get the store + let mut data = DATA.lock().unwrap(); + let user_id = (*data).users.add_user(user); + println!("Added new user id: {}\nAll users: {:?}", user_id, (*data).users); + (*data).users.clone() + }) + .join() + .unwrap(); + + Json(users) +} + diff --git a/src/templates/add_game_form.rs b/src/templates/add_game_form.rs index 0939d14..d89de31 100644 --- a/src/templates/add_game_form.rs +++ b/src/templates/add_game_form.rs @@ -7,9 +7,9 @@ use web_sys::Event; cfg_if::cfg_if! { if #[cfg(client)] { - use crate::data::pool_match::{PoolMatch, PoolMatchList}; + use crate::data::pool_match::{PoolMatch, PoolMatchList, UserList}; use crate::templates::global_state::AppStateRx; - use crate::endpoints::MATCH; + use crate::endpoints::{MATCH, USER}; use crate::templates::get_api_path; use chrono::Utc; } @@ -20,14 +20,15 @@ cfg_if::cfg_if! { #[derive(Serialize, Deserialize, Clone, ReactiveState)] #[rx(alias = "PageStateRx")] struct PageState { - name: String, + winner: String, + new_user: String, } fn add_game_form_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStateRx) -> View { let handle_add_match = move |_event: Event| { #[cfg(client)] { - // state.name.get().as_ref().clone() + // state.winner.get().as_ref().clone() spawn_local_scoped(cx, async move { let new_match = PoolMatch::new( MatchData { @@ -53,10 +54,37 @@ fn add_game_form_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStat } }; + let handle_add_user = move |_event: Event| { + #[cfg(client)] + { + // state.winner.get().as_ref().clone() + spawn_local_scoped(cx, async move { + let client = reqwest::Client::new(); + let new_users = client + .post(get_api_path(USER).as_str()) + .body(state.new_user.get().as_ref().clone()) + .send() + .await + .unwrap() + .json::() + .await + .unwrap(); + let global_state = Reactor::::from_cx(cx).get_global_state::(cx); + global_state.users.set(new_users); + }) + } + }; + view! { cx, Layout(title = "Add Game Results") { div (class = "flex flex-wrap") { - input (bind:value = state.name, + select { + option (value="red") + option (value="blue") + } + } + div (class = "flex flex-wrap") { + input (bind:value = state.winner, class = "appearance-none block w-full bg-gray-200 text-gray-700 border \ border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none \ focus:bg-white",) @@ -69,6 +97,20 @@ fn add_game_form_page<'a, G: Html>(cx: BoundedScope<'_, 'a>, state: &'a PageStat "Add result" } } + div (class = "flex flex-wrap") { + input (bind:value = state.new_user, + class = "appearance-none block w-full bg-gray-200 text-gray-700 border \ + border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none \ + focus:bg-white",) + } + div (class = "flex flex-wrap") { + button(on:click = handle_add_user, + class = "flex-shrink-0 bg-teal-500 hover:bg-teal-700 border-teal-500 \ + hover:border-teal-700 text-sm border-4 text-white py-1 px-2 rounded", + ) { + "Add new user" + } + } } } } @@ -79,7 +121,8 @@ async fn get_request_state( _req: Request, ) -> Result> { Ok(PageState { - name: "Ferris".to_string(), + winner: "Ferris".to_string(), + new_user: "newguy".to_string(), }) } diff --git a/src/templates/global_state.rs b/src/templates/global_state.rs index 4ac7502..8658355 100644 --- a/src/templates/global_state.rs +++ b/src/templates/global_state.rs @@ -1,6 +1,8 @@ // Not a page, global state that is shared between all pages use crate::data::pool_match::PoolMatchList; +use crate::data::pool_match::UserList; + use perseus::{prelude::*, state::GlobalStateCreator}; use serde::{Deserialize, Serialize}; @@ -16,6 +18,7 @@ cfg_if::cfg_if! { #[rx(alias = "AppStateRx")] pub struct AppState { pub matches: PoolMatchList, + pub users: UserList, } pub fn get_global_state_creator() -> GlobalStateCreator { @@ -30,7 +33,11 @@ fn get_state() -> AppState { .join() .unwrap(); - AppState { matches } + let users = thread::spawn(move || DATA.lock().unwrap().deref().users.clone()) + .join() + .unwrap(); + + AppState { matches, users } } #[engine_only_fn]