Add card table loading

This commit is contained in:
2024-09-04 01:43:57 -04:00
parent 4674289473
commit 20d7f62f33
10 changed files with 93 additions and 61 deletions

View File

@@ -11,6 +11,14 @@ use crate::{
use perseus::prelude::*;
use sycamore::prelude::*;
cfg_if::cfg_if! {
if #[cfg(client)] {
use crate::endpoints::CARD_INFO;
use crate::templates::get_api_path;
use crate::models::card::CardTable;
}
}
#[derive(Prop)]
pub struct LayoutProps<'a, G: Html> {
pub content_state: ContentState,
@@ -51,12 +59,42 @@ pub fn Layout<'a, G: Html>(
let content_state_header = content_state.clone();
#[cfg(client)]
{
// TODO -> try to use suspense
spawn_local_scoped(cx, async move {
let global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
let card_table_loaded = (*global_state.constants.is_loaded.get()).clone();
if !card_table_loaded {
let client = reqwest::Client::new();
let response = client
.get(get_api_path(CARD_INFO).as_str())
.send()
.await
.unwrap();
// TODO add error handling
let response = response.json::<CardTable>().await.unwrap();
global_state.constants.card_table.set(Some(response));
global_state.constants.is_loaded.set(true);
}
});
}
view! { cx,
// Main page header, including login functionality
Header(content_state = content_state_header)
// Modals
section(class = "flex-2") {
(match (*global_state.constants.card_table.get()).clone() {
Some(card_table) => { view!{ cx,
p { "DONE" }
} },
None => { view!{ cx, p { "Loading cards" } } },
})
(match *global_state.modals_open.login.get() {
OpenState::Open => {
view! { cx,

View File

@@ -4,3 +4,4 @@ pub const LOGIN: &str = "/api/login";
#[cfg(engine)]
pub const LOGIN_TEST: &str = "/api/login-test";
pub const FORGOT_PASSWORD: &str = "/api/forgot-password";
pub const CARD_INFO: &str = "/api/card-info";

View File

@@ -4,13 +4,16 @@ use perseus::{prelude::*, state::GlobalStateCreator};
use serde::{Deserialize, Serialize};
use crate::{
models::auth::WebAuthInfo,
models::{auth::WebAuthInfo, card::CardTable},
state_enums::{LoginState, OpenState},
};
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
#[rx(alias = "AppStateRx")]
pub struct AppState {
#[rx(nested)]
pub constants: ConstData,
#[rx(nested)]
pub auth: AuthData,
#[rx(nested)]
@@ -19,6 +22,13 @@ pub struct AppState {
pub style: StyleData,
}
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
#[rx(alias = "ConstDataRx")]
pub struct ConstData {
pub is_loaded: bool,
pub card_table: Option<CardTable>,
}
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
#[rx(alias = "AuthDataRx")]
pub struct AuthData {
@@ -58,6 +68,10 @@ pub fn get_global_state_creator() -> GlobalStateCreator {
#[engine_only_fn]
pub async fn get_build_state() -> AppState {
AppState {
constants: ConstData {
is_loaded: false,
card_table: None
},
auth: AuthData {
state: LoginState::Unknown,
pending_username: String::new(),

View File

@@ -34,6 +34,7 @@ pub enum MonsterAttribute {
Light,
Water,
Wind,
None,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
@@ -51,13 +52,14 @@ pub enum TrapType {
Normal,
Continuous,
Counter,
Unknown,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum CardTypeInfo {
Monster {
level: u32, // level/rank/link rating
atk: u32,
level: Option<u32>, // level/rank/link rating
atk: Option<u32>,
def: Option<u32>,
pendulum_scale: Option<u32>,
attribute: MonsterAttribute,
@@ -170,16 +172,16 @@ impl CardTable {
"Continuous" => TrapType::Continuous,
"Counter" => TrapType::Counter,
"Normal" => TrapType::Normal,
unknown => panic!("Unknown trap type {}", unknown),
_ => TrapType::Unknown,
},
}
} else {
CardTypeInfo::Monster {
level: row[level_idx].try_extract().unwrap(),
atk: row[atk_idx].try_extract().unwrap(),
level: row[level_idx].try_extract().ok(),
atk: row[atk_idx].try_extract().ok(),
def: row[def_idx].try_extract().ok(),
pendulum_scale: row[pendulum_scale_idx].try_extract().ok(),
attribute: match row[attribute_idx].get_str().unwrap() {
attribute: match row[attribute_idx].get_str().unwrap_or("NONE") {
"DARK" => MonsterAttribute::Dark,
"DIVINE" => MonsterAttribute::Divine,
"EARTH" => MonsterAttribute::Earth,
@@ -187,6 +189,7 @@ impl CardTable {
"LIGHT" => MonsterAttribute::Light,
"WATER" => MonsterAttribute::Water,
"WIND" => MonsterAttribute::Wind,
"NONE" => MonsterAttribute::None,
unknown => panic!("Unknown attribute {}", unknown),
},
monster_type: row[monster_type_idx]
@@ -390,18 +393,14 @@ impl CardTable {
"frameType",
"ygoprodeck_url",
"linkval",
"race"
"race",
])])
// Remove link markers, unless it's needed later
.select([col("*").exclude(["linkmarkers"])])
// TODO add banlist support
.select([col("*").exclude(["banlist_info"])])
// TODO readd
.select([col("*").exclude([
"card_sets",
"card_images",
"card_prices",
])])
.select([col("*").exclude(["card_sets", "card_images", "card_prices"])])
// Filter out "Skill Card"
.filter(col("type").str().contains(lit("Skill Card"), false).not())
// Filters for testing

View File

@@ -0,0 +1,18 @@
use std::path::Path;
use lazy_static::lazy_static;
use crate::server::server_state::ServerState;
use axum::{debug_handler, extract::State, http::StatusCode, Json};
use crate::models::card::CardTable;
lazy_static! {
static ref CARD_TABLE: CardTable =
CardTable::new_from_server_json(Path::new("./data/cardinfo.json"));
}
#[debug_handler]
pub async fn get_card_table(State(_): State<ServerState>) -> Result<Json<CardTable>, StatusCode> {
Ok(Json(CARD_TABLE.clone()))
}

View File

@@ -0,0 +1 @@
pub mod card_table;

View File

@@ -1,3 +1,4 @@
pub mod auth;
pub mod constants;
pub mod routes;
pub mod server_state;

View File

@@ -1,6 +1,6 @@
// (Server only) Routes
use crate::endpoints::{FORGOT_PASSWORD, LOGIN, LOGIN_TEST, REGISTER};
use axum::routing::{post, Router};
use crate::endpoints::{CARD_INFO, FORGOT_PASSWORD, LOGIN, LOGIN_TEST, REGISTER};
use axum::routing::{get, post, Router};
use super::{
auth::{
@@ -8,6 +8,7 @@ use super::{
login::{post_login_user, post_test_login},
register::post_register_user,
},
constants::card_table::get_card_table,
server_state::ServerState,
};
@@ -17,5 +18,6 @@ pub fn get_api_router(state: ServerState) -> Router {
.route(LOGIN, post(post_login_user))
.route(LOGIN_TEST, post(post_test_login))
.route(FORGOT_PASSWORD, post(post_forgot_password))
.route(CARD_INFO, get(get_card_table))
.with_state(state)
}

View File

@@ -1,45 +0,0 @@
// Not a page, global state that is shared between all pages
use perseus::{prelude::*, state::GlobalStateCreator};
use serde::{Deserialize, Serialize};
use crate::data::card::CardTable;
cfg_if::cfg_if! {
if #[cfg(engine)] {
use std::thread;
use std::ops::Deref;
use crate::data::store::DATA;
}
}
#[derive(Serialize, Deserialize, ReactiveState, Clone)]
#[rx(alias = "AppStateRx")]
pub struct AppState {
pub card_table: CardTable,
}
pub fn get_global_state_creator() -> GlobalStateCreator {
GlobalStateCreator::new()
.build_state_fn(get_build_state)
.request_state_fn(get_request_state)
}
#[engine_only_fn]
fn get_state() -> AppState {
let card_table = thread::spawn(move || DATA.lock().unwrap().deref().card_table.clone())
.join()
.unwrap();
AppState { card_table }
}
#[engine_only_fn]
pub async fn get_build_state() -> AppState {
get_state()
}
#[engine_only_fn]
pub async fn get_request_state(_req: Request) -> AppState {
get_state()
}