lan-party-backend/web/src/pages/users.rs

125 lines
5.5 KiB
Rust

use crate::{
clone, clone_cb,
components::{Button, Loading, Page, Table, TextInput},
util::api_request,
};
use lan_party_core::user::User;
use wasm_bindgen_futures::spawn_local;
use yew::prelude::*;
#[function_component(UsersPage)]
pub fn users_page() -> Html {
let headers = vec!["Username".into(), "Score".into(), "".into()];
let new_username = use_state(|| String::new());
let score_edit: UseStateHandle<Option<usize>> = use_state(|| Option::None);
let current_score = use_state(|| String::new());
let users = use_state(|| Vec::new());
clone!(users; use_effect_with_deps(move |_| {
spawn_local(async move {
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 |_| {
clone!(score_edit, users, current_score; {
spawn_local(async move {
if let Some(score_edit) = *score_edit {
if let Ok(score) = current_score.parse() {
let user: &User = &users[score_edit];
api_request::<_, ()>("POST", &format!("/user/{}/score", user.name), Some(score)).await.unwrap();
let mut cloned = (*users).clone();
cloned[score_edit].score = score;
users.set(cloned);
}
}
score_edit.set(None);
});
});
});
let onedit = clone_cb!(current_score, score_edit, users; i => move |_| {
let user: &User = &users[i];
current_score.set(user.score.to_string());
score_edit.set(Some(i));
});
let ondelete = clone_cb!(users; i => move |_| {
clone!(users; {
spawn_local(async move {
let user: &User = &users[i];
api_request::<_, ()>("DELETE", &format!("/user/{}", user.name), Option::<()>::None).await.unwrap();
let cloned = users.iter().cloned().filter(|u| u.name != user.name).collect();
users.set(cloned);
});
});
});
let onadd = clone_cb!(new_username, users; move |_| {
clone!(new_username, users; {
spawn_local(async move {
let user = api_request::<String, User>("POST", "/user", Some((*new_username).clone())).await.unwrap();
let mut cloned = (*users).clone();
cloned.push(user.unwrap());
users.set(cloned);
});
});
});
html! {
<Page>
<Table headers={headers.clone()} loading=false rows={vec![]}>
{users.iter().enumerate().map(move |(i, user)| html! {
<tr>
<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">
{if Some(i) == *score_edit.clone() { html! {
<>
<span class="inline-block">
<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"}
onchange={clone_cb!(current_score; move |value| current_score.set(value))}
value={(*current_score).clone()}
/>
</span>
<Button icon={"mdi-check"} onclick={oncheck.clone()} />
</>
}} else { html! {
<>
<span class="my-3 w-20">
{user.score}
</span>
<Button icon={"mdi-pencil"} onclick={onedit.clone()(i)} />
</>
}}}
</td>
<td class="whitespace-nowrap py-4 text-sm text-slate-400">
<Button icon={"mdi-delete"} onclick={ondelete.clone()(i)} />
</td>
</tr>
}).collect::<Html>()}
<tr>
<td class="whitespace-nowrap px-3 text-sm text-slate-400">
<span class="inline-block">
<TextInput
class={"mx-2 appearance-none block bg-gray-700 text-slate-400 border border-gray-600 rounded py-2 px-2 w-50 leading-tight focus:outline-none focus:ring-1 focus:ring-gray-500 focus:border-gray-500"}
onchange={clone_cb!(new_username; move |value| new_username.set(value))}
value={(*new_username).clone()}
/>
</span>
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-slate-400"></td>
<td class="whitespace-nowrap py-4 text-sm text-slate-400">
<Button icon={"mdi-plus"} onclick={onadd} />
</td>
</tr>
</Table>
</Page>
}
}