Login and Showing of all Users implemented
At /login and /users
This commit is contained in:
@@ -15,6 +15,10 @@ enum Route {
|
|||||||
AllTickets,
|
AllTickets,
|
||||||
#[at("/register")]
|
#[at("/register")]
|
||||||
Register,
|
Register,
|
||||||
|
#[at("/login")]
|
||||||
|
Login,
|
||||||
|
#[at("/users")]
|
||||||
|
AllUsers,
|
||||||
#[not_found]
|
#[not_found]
|
||||||
#[at("/404")]
|
#[at("/404")]
|
||||||
NotFound,
|
NotFound,
|
||||||
@@ -25,9 +29,11 @@ fn switch(route: Route) -> Html {
|
|||||||
Route::Home => html! { <basic_pages::Home/>},
|
Route::Home => html! { <basic_pages::Home/>},
|
||||||
Route::NotFound => html! { <basic_pages::NotFound/> },
|
Route::NotFound => html! { <basic_pages::NotFound/> },
|
||||||
Route::Ticket => html! { <ticket::SubmitTicket/> },
|
Route::Ticket => html! { <ticket::SubmitTicket/> },
|
||||||
Route::TicketById { id } => html! { <ticket::ShowTicketByID id={id}/> },
|
Route::TicketById { id } => html! { <ticket::TicketByID id={id}/> },
|
||||||
Route::AllTickets => html! { <ticket::AllTickets/> },
|
Route::AllTickets => html! { <ticket::AllTickets/> },
|
||||||
Route::Register => html! { <user::Register/> },
|
Route::Register => html! { <user::Register/> },
|
||||||
|
Route::Login => html! { <user::Login/> },
|
||||||
|
Route::AllUsers => html! {<user::AllUsers/>},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -156,8 +156,8 @@ pub fn submit_ticket_component() -> Html {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component(ShowTicketByID)]
|
#[component(TicketByID)]
|
||||||
pub fn show_ticket_by_id_component(props: &TicketProps) -> Html {
|
pub fn ticket_by_id_component(props: &TicketProps) -> Html {
|
||||||
let ticket = use_state(|| None::<Ticket>);
|
let ticket = use_state(|| None::<Ticket>);
|
||||||
let error = use_state(|| None::<String>);
|
let error = use_state(|| None::<String>);
|
||||||
let loading = use_state(|| false);
|
let loading = use_state(|| false);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use gloo_net::http::Request;
|
use gloo_net::http::Request;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use wasm_bindgen_futures::spawn_local;
|
use wasm_bindgen_futures::spawn_local;
|
||||||
|
use web_sys::js_sys::Atomics::load;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@@ -37,6 +38,11 @@ pub struct FilteredUser {
|
|||||||
pub is_admin: bool,
|
pub is_admin: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct UserProps {
|
||||||
|
id: i16,
|
||||||
|
}
|
||||||
|
|
||||||
#[component(Register)]
|
#[component(Register)]
|
||||||
pub fn register_component() -> Html {
|
pub fn register_component() -> Html {
|
||||||
let first_name = use_state(|| "".to_string());
|
let first_name = use_state(|| "".to_string());
|
||||||
@@ -146,3 +152,138 @@ pub fn register_component() -> Html {
|
|||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[component(Login)]
|
||||||
|
pub fn login_component() -> Html {
|
||||||
|
let username = use_state(|| "".to_string());
|
||||||
|
let pwd = use_state(|| "".to_string());
|
||||||
|
let loading = use_state(|| false);
|
||||||
|
let error = use_state(|| String::new());
|
||||||
|
let success = use_state(|| false);
|
||||||
|
|
||||||
|
let onsubmit = {
|
||||||
|
let username = username.clone();
|
||||||
|
let pwd = pwd.clone();
|
||||||
|
let loading = loading.clone();
|
||||||
|
let error = error.clone();
|
||||||
|
let success = success.clone();
|
||||||
|
|
||||||
|
Callback::from(move |e: SubmitEvent| {
|
||||||
|
e.prevent_default();
|
||||||
|
let username = (*username).clone();
|
||||||
|
let pwd = (*pwd).clone();
|
||||||
|
let loading = loading.clone();
|
||||||
|
let error = error.clone();
|
||||||
|
let success = success.clone();
|
||||||
|
|
||||||
|
loading.set(true);
|
||||||
|
error.set(String::new());
|
||||||
|
success.set(false);
|
||||||
|
|
||||||
|
spawn_local(async move {
|
||||||
|
let payload = LoginScheme { username, pwd };
|
||||||
|
|
||||||
|
let response = Request::post("/api/login")
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.credentials(web_sys::RequestCredentials::Include)
|
||||||
|
.json(&payload)
|
||||||
|
.unwrap()
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
loading.set(false);
|
||||||
|
|
||||||
|
match response {
|
||||||
|
Ok(r) if r.status() == 200 => success.set(true),
|
||||||
|
Ok(r) => {
|
||||||
|
let text = r.text().await.unwrap_or_else(|_| "unknown".into());
|
||||||
|
error.set(format!("HTTP {}: {}", r.status(), text));
|
||||||
|
}
|
||||||
|
Err(err) => error.set(format!("Network error: {}", err)),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<form {onsubmit}>
|
||||||
|
<input
|
||||||
|
placeholder="username"
|
||||||
|
value={(*username).clone()}
|
||||||
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
|
username.set(input.value());
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
placeholder="password"
|
||||||
|
value={(*pwd).clone()}
|
||||||
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
|
pwd.set(input.value());
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<button type="submit" disabled={*loading}>{ if *loading { "Logging in..." } else { "Login" } }</button>
|
||||||
|
if *success { <p>{"Logged in — cookie set by server"}</p> }
|
||||||
|
if !error.is_empty() { <p style="color:red">{(*error).clone()}</p> }
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component(AllUsers)]
|
||||||
|
pub fn all_users_component() -> Html {
|
||||||
|
let users = use_state(|| Vec::<FilteredUser>::new());
|
||||||
|
let error = use_state(|| None::<String>);
|
||||||
|
let loading = use_state(|| false);
|
||||||
|
|
||||||
|
{
|
||||||
|
let users = users.clone();
|
||||||
|
let error = error.clone();
|
||||||
|
let loading = loading.clone();
|
||||||
|
|
||||||
|
use_effect_with((), move |_| {
|
||||||
|
loading.set(true);
|
||||||
|
spawn_local(async move {
|
||||||
|
let url = format!("/api/users");
|
||||||
|
match Request::get(&url).send().await {
|
||||||
|
Ok(response) if response.status() == 200 => {
|
||||||
|
match response.json::<Vec<FilteredUser>>().await {
|
||||||
|
Ok(u) => users.set(u),
|
||||||
|
Err(err) => error.set(Some(format!("Parse error: {}", err))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(response) => {
|
||||||
|
if let Ok(text) = response.text().await {
|
||||||
|
error.set(Some(text));
|
||||||
|
} else {
|
||||||
|
error.set(Some(format!("status {}", response.status())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => error.set(Some(format!("Network error: {}", err))),
|
||||||
|
}
|
||||||
|
loading.set(false);
|
||||||
|
});
|
||||||
|
|| ()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if *loading {
|
||||||
|
html! {<p>{ "Loading" }</p>}
|
||||||
|
} else if let Some(e) = &*error {
|
||||||
|
html! { <p>{ format!("Error: {}", e) }</p> }
|
||||||
|
} else {
|
||||||
|
html! {
|
||||||
|
<ul>
|
||||||
|
{ for users.iter().map(|t| html! {
|
||||||
|
<li key={t.id.to_string()}>
|
||||||
|
<h3>{ format!("{} {}- #{}", t.first_name, t.last_name, t.id) }</h3>
|
||||||
|
</li>
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#[component(UserByID)]
|
||||||
|
//pub fn user_by_id_component()
|
||||||
|
|||||||
Reference in New Issue
Block a user