mirror of
https://github.com/kristoferssolo/echoes-of-ascension.git
synced 2025-12-31 05:32:33 +00:00
refactor
This commit is contained in:
parent
74b9b00de1
commit
b626e0a7d7
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -871,6 +871,7 @@ dependencies = [
|
|||||||
"leptos_router",
|
"leptos_router",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
|
"thiserror 2.0.11",
|
||||||
"tokio",
|
"tokio",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -20,5 +20,6 @@ codegen-units = 1
|
|||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
nursery = "warn"
|
nursery = "warn"
|
||||||
pedantic = "warn"
|
|
||||||
unwrap_used = "warn"
|
unwrap_used = "warn"
|
||||||
|
style = "warn"
|
||||||
|
perf = "warn"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::fmt::Display;
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use secrecy::{ExposeSecret, SecretString};
|
use secrecy::{ExposeSecret, SecretString};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -66,10 +66,10 @@ impl DatabaseSettings {
|
|||||||
pub fn get_config() -> Result<Settings, config::ConfigError> {
|
pub fn get_config() -> Result<Settings, config::ConfigError> {
|
||||||
let base_path = std::env::current_dir().expect("Failed to determine current directory");
|
let base_path = std::env::current_dir().expect("Failed to determine current directory");
|
||||||
let config_directory = base_path.join("backend").join("config");
|
let config_directory = base_path.join("backend").join("config");
|
||||||
let env: Environment = std::env::var("APP_ENVIRONMENT")
|
let env = std::env::var("APP_ENVIRONMENT")
|
||||||
.unwrap_or_else(|_| "local".into())
|
.unwrap_or_else(|_| "local".into())
|
||||||
.try_into()
|
.parse()
|
||||||
.expect("Failed to parse APP_ENVIRONMENT");
|
.unwrap_or(Environment::Local);
|
||||||
|
|
||||||
let env_filename = format!("{}.toml", &env);
|
let env_filename = format!("{}.toml", &env);
|
||||||
|
|
||||||
@ -97,7 +97,14 @@ impl Display for Environment {
|
|||||||
impl TryFrom<String> for Environment {
|
impl TryFrom<String> for Environment {
|
||||||
type Error = String;
|
type Error = String;
|
||||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
match value.to_lowercase().as_str() {
|
Self::from_str(&value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Environment {
|
||||||
|
type Err = String;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s.to_lowercase().as_str() {
|
||||||
"local" => Ok(Self::Local),
|
"local" => Ok(Self::Local),
|
||||||
"production" => Ok(Self::Production),
|
"production" => Ok(Self::Production),
|
||||||
other => Err(format!(
|
other => Err(format!(
|
||||||
|
|||||||
@ -7,16 +7,18 @@ edition = "2021"
|
|||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
leptos = { version = "0.7.0", features = ["nightly"] }
|
leptos = { version = "0.7", features = ["nightly"] }
|
||||||
leptos_router = { version = "0.7.0", features = ["nightly"] }
|
leptos_router = { version = "0.7", features = ["nightly"] }
|
||||||
axum = { version = "0.7", optional = true }
|
axum = { version = "0.7", optional = true }
|
||||||
console_error_panic_hook = { version = "0.1", optional = true }
|
console_error_panic_hook = { version = "0.1", optional = true }
|
||||||
leptos_axum = { version = "0.7.0", optional = true }
|
leptos_axum = { version = "0.7", optional = true }
|
||||||
leptos_meta = { version = "0.7.0" }
|
leptos_meta = { version = "0.7" }
|
||||||
tokio = { workspace = true, features = ["rt-multi-thread"], optional = true }
|
tokio = { workspace = true, features = ["rt-multi-thread"], optional = true }
|
||||||
wasm-bindgen = { version = "=0.2.100", optional = true }
|
wasm-bindgen = { version = "=0.2.100", optional = true }
|
||||||
reqwest = { version = "0.12", features = ["json"] }
|
reqwest = { version = "0.12", features = ["json"] }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
hydrate = ["leptos/hydrate", "dep:console_error_panic_hook", "dep:wasm-bindgen"]
|
hydrate = ["leptos/hydrate", "dep:console_error_panic_hook", "dep:wasm-bindgen"]
|
||||||
|
|||||||
@ -1,61 +0,0 @@
|
|||||||
use leptos::prelude::*;
|
|
||||||
use leptos_meta::{provide_meta_context, MetaTags, Stylesheet, Title};
|
|
||||||
use leptos_router::{
|
|
||||||
components::{Route, Router, Routes},
|
|
||||||
StaticSegment,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn shell(options: LeptosOptions) -> impl IntoView {
|
|
||||||
view! {
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<AutoReload options=options.clone() />
|
|
||||||
<HydrationScripts options />
|
|
||||||
<MetaTags />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<App />
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
pub fn App() -> impl IntoView {
|
|
||||||
// Provides context that manages stylesheets, titles, meta tags, etc.
|
|
||||||
provide_meta_context();
|
|
||||||
|
|
||||||
view! {
|
|
||||||
// injects a stylesheet into the document <head>
|
|
||||||
// id=leptos means cargo-leptos will hot-reload this stylesheet
|
|
||||||
<Stylesheet id="leptos" href="/pkg/frontend.css" />
|
|
||||||
|
|
||||||
// sets the document title
|
|
||||||
<Title text="Welcome to Leptos" />
|
|
||||||
|
|
||||||
// content for this welcome page
|
|
||||||
<Router>
|
|
||||||
<main>
|
|
||||||
<Routes fallback=|| "Page not found.".into_view()>
|
|
||||||
<Route path=StaticSegment("") view=HomePage />
|
|
||||||
</Routes>
|
|
||||||
</main>
|
|
||||||
</Router>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Renders the home page of your application.
|
|
||||||
#[component]
|
|
||||||
fn HomePage() -> impl IntoView {
|
|
||||||
// Creates a reactive value to update the button
|
|
||||||
let count = RwSignal::new(0);
|
|
||||||
let on_click = move |_| *count.write() += 1;
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<h1>"Welcome to Leptos!"</h1>
|
|
||||||
<button on:click=on_click>"Click Me: " {count}</button>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
33
frontend/src/components/app.rs
Normal file
33
frontend/src/components/app.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos_meta::{provide_meta_context, Stylesheet, Title};
|
||||||
|
use leptos_router::{
|
||||||
|
components::{Route, Router, Routes},
|
||||||
|
StaticSegment,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::components::{homepage::HomePage, register::RegisterForm};
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn App() -> impl IntoView {
|
||||||
|
// Provides context that manages stylesheets, titles, meta tags, etc.
|
||||||
|
provide_meta_context();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
// injects a stylesheet into the document <head>
|
||||||
|
// id=leptos means cargo-leptos will hot-reload this stylesheet
|
||||||
|
<Stylesheet id="leptos" href="/pkg/frontend.css" />
|
||||||
|
|
||||||
|
// sets the document title
|
||||||
|
<Title text="Welcome to Leptos" />
|
||||||
|
|
||||||
|
// content for this welcome page
|
||||||
|
<Router>
|
||||||
|
<main>
|
||||||
|
<Routes fallback=|| "Page not found.".into_view()>
|
||||||
|
<Route path=StaticSegment("") view=HomePage />
|
||||||
|
<Route path=StaticSegment("/register") view=RegisterForm />
|
||||||
|
</Routes>
|
||||||
|
</main>
|
||||||
|
</Router>
|
||||||
|
}
|
||||||
|
}
|
||||||
14
frontend/src/components/homepage.rs
Normal file
14
frontend/src/components/homepage.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
|
/// Renders the home page of your application.
|
||||||
|
#[component]
|
||||||
|
pub fn HomePage() -> impl IntoView {
|
||||||
|
// Creates a reactive value to update the button
|
||||||
|
let count = RwSignal::new(0);
|
||||||
|
let on_click = move |_| *count.write() += 1;
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<h1>"Welcome to Leptos!"</h1>
|
||||||
|
<button on:click=on_click>"Click Me: " {count}</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
25
frontend/src/components/mod.rs
Normal file
25
frontend/src/components/mod.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
mod app;
|
||||||
|
mod homepage;
|
||||||
|
mod register;
|
||||||
|
pub use app::App;
|
||||||
|
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos_meta::MetaTags;
|
||||||
|
|
||||||
|
pub fn shell(options: LeptosOptions) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<AutoReload options=options.clone() />
|
||||||
|
<HydrationScripts options />
|
||||||
|
<MetaTags />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<App />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
}
|
||||||
115
frontend/src/components/register.rs
Normal file
115
frontend/src/components/register.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
use leptos::{ev::SubmitEvent, prelude::*};
|
||||||
|
use reqwest::{Client, StatusCode};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct FormData {
|
||||||
|
username: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ResponseData {
|
||||||
|
username: String,
|
||||||
|
code: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[server]
|
||||||
|
async fn register(payload: FormData) -> Result<ResponseData, ServerFnError> {
|
||||||
|
let client = Client::new();
|
||||||
|
let response = client
|
||||||
|
.post("http://localhost:8000/api/v1/register")
|
||||||
|
.json(&payload)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
match response.status() {
|
||||||
|
StatusCode::CREATED => {
|
||||||
|
let response_data = response.json::<ResponseData>().await?;
|
||||||
|
Ok(response_data)
|
||||||
|
}
|
||||||
|
status => {
|
||||||
|
let error_msg = response.text().await?;
|
||||||
|
Err(ServerFnError::ServerError(format!(
|
||||||
|
"Registration failed: {} - {}",
|
||||||
|
status, error_msg
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn RegisterForm() -> impl IntoView {
|
||||||
|
let username = RwSignal::new(String::new());
|
||||||
|
let register_action = Action::new(|input: &FormData| {
|
||||||
|
let input = input.clone();
|
||||||
|
async move { register(input).await }
|
||||||
|
});
|
||||||
|
let on_submit = move |ev: SubmitEvent| {
|
||||||
|
ev.prevent_default();
|
||||||
|
let form_data = FormData {
|
||||||
|
username: username.get(),
|
||||||
|
};
|
||||||
|
register_action.dispatch(form_data);
|
||||||
|
};
|
||||||
|
let is_submitting = move || register_action.pending().get();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<form on:submit=on_submit>
|
||||||
|
<div>
|
||||||
|
<label>"Username"</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
on:input=move |ev| username.set(event_target_value(&ev))
|
||||||
|
prop:value=username
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type="submit" disabled=is_submitting>
|
||||||
|
{move || { if is_submitting() { "Registering..." } else { "Register" } }}
|
||||||
|
</button>
|
||||||
|
<ErrorBoundary fallback=move |errors| {
|
||||||
|
view! {
|
||||||
|
<div class="error-container">
|
||||||
|
<p class="error-title">"Registration Error:"</p>
|
||||||
|
<ul class="error-list">
|
||||||
|
{move || {
|
||||||
|
errors
|
||||||
|
.get()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_, e)| {
|
||||||
|
view! { <li class="error-item">{e.to_string()}</li> }
|
||||||
|
})
|
||||||
|
.collect_view()
|
||||||
|
}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
{move || {
|
||||||
|
register_action
|
||||||
|
.value()
|
||||||
|
.get()
|
||||||
|
.map(|result| {
|
||||||
|
match result {
|
||||||
|
Ok(response) => {
|
||||||
|
view! {
|
||||||
|
<div class="success-container">
|
||||||
|
<p class="success-message">"Registration successful!"</p>
|
||||||
|
<div class="registration-details">
|
||||||
|
<p>"Username: " {response.username}</p>
|
||||||
|
<p>"Your Code: " {response.code}</p>
|
||||||
|
<p class="code-notice">
|
||||||
|
"Please save this code. You will need it to login."
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
.into_any()
|
||||||
|
}
|
||||||
|
Err(e) => view! { <span>{e.to_string()}</span> }.into_any(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</ErrorBoundary>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
pub mod app;
|
pub mod components;
|
||||||
|
|
||||||
#[cfg(feature = "hydrate")]
|
#[cfg(feature = "hydrate")]
|
||||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||||
pub fn hydrate() {
|
pub fn hydrate() {
|
||||||
use crate::app::*;
|
use crate::components::*;
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
leptos::mount::hydrate_body(App);
|
leptos::mount::hydrate_body(App);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use frontend::app::*;
|
use frontend::components::*;
|
||||||
use leptos::logging::log;
|
use leptos::logging::log;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||||
|
|||||||
@ -43,4 +43,4 @@ done
|
|||||||
DATABASE_URL="postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
|
DATABASE_URL="postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
|
||||||
export DATABASE_URL
|
export DATABASE_URL
|
||||||
sqlx database create
|
sqlx database create
|
||||||
sqlx migrate run
|
sqlx migrate run --source backend/migrations
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user