This commit is contained in:
Daan Vanoverloop 2022-09-05 19:27:41 +02:00
parent 3ca53db260
commit 277782f16b
Signed by: Danacus
GPG Key ID: F2272B50E129FC5C
2 changed files with 54 additions and 71 deletions

6
web/dist/index.html vendored
View File

@ -4,9 +4,9 @@
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet">
<title>Yew App</title> <title>Yew App</title>
<link rel="preload" href="/index-167b3e062ee4dd95_bg.wasm" as="fetch" type="application/wasm" crossorigin=""> <link rel="preload" href="/index-d56dfc869fea14a4_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
<link rel="modulepreload" href="/index-167b3e062ee4dd95.js"></head> <link rel="modulepreload" href="/index-d56dfc869fea14a4.js"></head>
<body class="base theme-dark bg-gray-900 text-gray-400"> <body class="base theme-dark bg-gray-900 text-gray-400">
<script type="module">import init from '/index-167b3e062ee4dd95.js';init('/index-167b3e062ee4dd95_bg.wasm');</script></body></html> <script type="module">import init from '/index-d56dfc869fea14a4.js';init('/index-d56dfc869fea14a4_bg.wasm');</script></body></html>

View File

@ -6,7 +6,6 @@ use crate::{
use lan_party_core::user::User; use lan_party_core::user::User;
use wasm_bindgen_futures::spawn_local; use wasm_bindgen_futures::spawn_local;
use yew::prelude::*; use yew::prelude::*;
use yew_hooks::*;
#[function_component(UsersPage)] #[function_component(UsersPage)]
pub fn users_page() -> Html { pub fn users_page() -> Html {
@ -15,30 +14,28 @@ pub fn users_page() -> Html {
let new_username = use_state(|| String::new()); let new_username = use_state(|| String::new());
let score_edit: UseStateHandle<Option<usize>> = use_state(|| Option::None); let score_edit: UseStateHandle<Option<usize>> = use_state(|| Option::None);
let current_score = use_state(|| String::new()); let current_score = use_state(|| String::new());
let users: UseAsyncHandle<Vec<User>, _> = use_async(async move { let users = use_state(|| Vec::new());
api_request::<_, Vec<User>>("GET", "/user", Option::<()>::None)
.await
.map(|inner| inner.unwrap())
.map_err(|_| "failed to load users")
});
clone!(users; use_effect_with_deps(move |_| { clone!(users; use_effect_with_deps(move |_| {
if users.data.is_none() { spawn_local(async move {
users.run(); users.set(api_request::<_, Vec<User>>("GET", "/user", Option::<()>::None)
} .await
.map(|inner| inner.unwrap())
.unwrap());
});
|| () || ()
}, ())); }, ()));
let oncheck = clone_cb!(score_edit, current_score, users; move |_| { let oncheck = clone_cb!(score_edit, current_score, users; move |_| {
clone!(score_edit, users, current_score; { clone!(score_edit, users, current_score; {
spawn_local(async move { spawn_local(async move {
if let (Some(score_edit), Some(users_inner)) = (*score_edit, &users.data) { if let Some(score_edit) = *score_edit {
if let Ok(score) = current_score.parse() { if let Ok(score) = current_score.parse() {
let user: &User = &users_inner[score_edit]; let user: &User = &users[score_edit];
api_request::<_, ()>("POST", &format!("/user/{}/score", user.name), Some(score)).await.unwrap(); api_request::<_, ()>("POST", &format!("/user/{}/score", user.name), Some(score)).await.unwrap();
let mut cloned = users_inner.clone(); let mut cloned = (*users).clone();
cloned[score_edit].score = score; cloned[score_edit].score = score;
users.update(cloned); users.set(cloned);
} }
} }
score_edit.set(None); score_edit.set(None);
@ -47,22 +44,18 @@ pub fn users_page() -> Html {
}); });
let onedit = clone_cb!(current_score, score_edit, users; i => move |_| { let onedit = clone_cb!(current_score, score_edit, users; i => move |_| {
if let Some(users) = &users.data { let user: &User = &users[i];
let user: &User = &users[i]; current_score.set(user.score.to_string());
current_score.set(user.score.to_string()); score_edit.set(Some(i));
score_edit.set(Some(i));
}
}); });
let ondelete = clone_cb!(users; i => move |_| { let ondelete = clone_cb!(users; i => move |_| {
clone!(users; { clone!(users; {
spawn_local(async move { spawn_local(async move {
if let Some(users_inner) = &users.data { let user: &User = &users[i];
let user: &User = &users_inner[i]; api_request::<_, ()>("DELETE", &format!("/user/{}", user.name), Option::<()>::None).await.unwrap();
api_request::<_, ()>("DELETE", &format!("/user/{}", user.name), Option::<()>::None).await.unwrap(); let cloned = users.iter().cloned().filter(|u| u.name != user.name).collect();
let cloned = users_inner.iter().cloned().filter(|u| u.name != user.name).collect(); users.set(cloned);
users.update(cloned);
}
}); });
}); });
}); });
@ -70,12 +63,10 @@ pub fn users_page() -> Html {
let onadd = clone_cb!(new_username, users; move |_| { let onadd = clone_cb!(new_username, users; move |_| {
clone!(new_username, users; { clone!(new_username, users; {
spawn_local(async move { spawn_local(async move {
if let Some(users_inner) = &users.data { let user = api_request::<String, User>("POST", "/user", Some((*new_username).clone())).await.unwrap();
let user = api_request::<String, User>("POST", "/user", Some((*new_username).clone())).await.unwrap(); let mut cloned = (*users).clone();
let mut cloned = users_inner.clone(); cloned.push(user.unwrap());
cloned.push(user.unwrap()); users.set(cloned);
users.update(cloned);
}
}); });
}); });
}); });
@ -83,43 +74,35 @@ pub fn users_page() -> Html {
html! { html! {
<Page> <Page>
<Table headers={headers.clone()} loading=false rows={vec![]}> <Table headers={headers.clone()} loading=false rows={vec![]}>
{ if let Some(users) = &users.data { {users.iter().enumerate().map(move |(i, user)| html! {
{users.iter().enumerate().map(move |(i, user)| html! { <tr>
<tr> <td class="whitespace-nowrap px-3 py-4 text-sm text-slate-400">{&user.name}</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-slate-400">{&user.name}</td> <td class="whitespace-nowrap px-3 text-sm text-slate-400">
<td class="whitespace-nowrap px-3 text-sm text-slate-400"> {if Some(i) == *score_edit.clone() { html! {
{if Some(i) == *score_edit.clone() { html! { <>
<> <span class="inline-block">
<span class="inline-block"> <TextInput
<TextInput class={"mx-2 appearance-none block bg-gray-700 text-slate-400 border border-gray-600 rounded py-2 px-2 w-20 leading-tight focus:outline-none focus:ring-1 focus:ring-gray-500 focus:border-gray-500"}
class={"mx-2 appearance-none block bg-gray-700 text-slate-400 border border-gray-600 rounded py-2 px-2 w-20 leading-tight focus:outline-none focus:ring-1 focus:ring-gray-500 focus:border-gray-500"} onchange={clone_cb!(current_score; move |value| current_score.set(value))}
onchange={clone_cb!(current_score; move |value| current_score.set(value))} value={(*current_score).clone()}
value={(*current_score).clone()} />
/> </span>
</span> <Button icon={"mdi-check"} onclick={oncheck.clone()} />
<Button icon={"mdi-check"} onclick={oncheck.clone()} /> </>
</> }} else { html! {
}} else { html! { <>
<> <span class="my-3 w-20">
<span class="my-3 w-20"> {user.score}
{user.score} </span>
</span> <Button icon={"mdi-pencil"} onclick={onedit.clone()(i)} />
<Button icon={"mdi-pencil"} onclick={onedit.clone()(i)} /> </>
</> }}}
}}} </td>
</td> <td class="whitespace-nowrap py-4 text-sm text-slate-400">
<td class="whitespace-nowrap py-4 text-sm text-slate-400"> <Button icon={"mdi-delete"} onclick={ondelete.clone()(i)} />
<Button icon={"mdi-delete"} onclick={ondelete.clone()(i)} /> </td>
</td> </tr>
</tr> }).collect::<Html>()}
}).collect::<Html>()}
} else {
html! {
<div class="grid place-items-center">
<Loading />
</div>
}
}}
<tr> <tr>
<td class="whitespace-nowrap px-3 text-sm text-slate-400"> <td class="whitespace-nowrap px-3 text-sm text-slate-400">
<span class="inline-block"> <span class="inline-block">