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

187 lines
7.2 KiB
Rust

use anyhow::anyhow;
use lan_party_core::{
components::Block,
edit::IntoEdit,
event::{Event, EventOutcome, EventSpec, EventUpdate},
view::IntoView,
};
use log::debug;
use reqwasm::http::Method;
use sycamore::{futures::spawn_local_scoped, prelude::*};
use crate::{
components::{messages::Messenger, Button, Modal, Table},
state::Events,
util::api_request,
};
pub enum Msg {
Reload,
Add(EventSpec),
Update(String, EventUpdate),
Delete(String),
Stop(String),
ViewOutcome(String),
}
#[component]
pub fn EventsPage<'a, G: Html>(cx: Scope<'a>) -> View<G> {
let messenger = use_context::<Messenger>(cx);
let event_spec = create_signal(cx, EventSpec::default());
let event_update = create_signal(cx, EventUpdate::default());
let event_update_name = create_signal(cx, String::new());
let current_event = create_signal(cx, String::new());
let show_outcome = create_signal(cx, false);
let event_outcome = create_signal(cx, EventOutcome::default());
let events = use_context::<Events>(cx);
let dispatch = move |msg: Msg| {
spawn_local_scoped(cx, async move {
match msg {
Msg::Add(event_spec) => {
let name = event_spec.name.clone();
messenger.add_result(
events.add(event_spec).await,
Some(format!("Created a new event with name \"{}\"", name)),
Some("Error when adding an event"),
);
}
Msg::Reload => messenger.add_result(
events.load().await,
Option::<String>::None,
Some("Failed to load events"),
),
Msg::Update(event_update_name, event_update) => {
messenger.add_result(
events.update_event(&event_update_name, event_update).await,
Some(format!("Updated event with name \"{}\"", event_update_name)),
Some("Error when updating event"),
);
}
Msg::Delete(event_name) => {
messenger.add_result(
events.delete(&event_name).await,
Some(format!("Deleted event with name \"{}\"", event_name)),
Some("Error when deleting event"),
);
}
Msg::ViewOutcome(event_name) => {
show_outcome.set(true);
current_event.set(event_name.clone());
let res = api_request::<(), EventOutcome>(
Method::GET,
&format!("/event/{}/outcome", event_name),
None,
)
.await
.and_then(|inner| inner.ok_or(anyhow!("missing body")));
if let Ok(outcome) = res {
debug!("{:#?}", outcome);
event_outcome.set(outcome);
} else {
debug!("oh no");
messenger.add_result(
res,
Option::<String>::None,
Some("Failed to load outcome"),
)
}
}
_ => {}
}
});
};
dispatch(Msg::Reload);
let outcome_points = create_memo(cx, || {
let cloned = event_outcome.get().as_ref().clone();
let mut vec = cloned.points.into_iter().collect::<Vec<_>>();
vec.sort_by_key(|(_, s)| -*s);
vec
});
view! { cx,
Modal(open=show_outcome, title="Event outcome".into()) {
Table(headers=vec!["Username".into(), "Score".into()]) {
Indexed(
iterable=&outcome_points,
view=move |cx, (k, v)| {
view! { cx,
tr {
td { (k.clone()) }
td { (v.clone()) }
}
}
}
)
}
Button(text="Reload".into(), icon="mdi-refresh".into(), onclick=move |_| dispatch(Msg::ViewOutcome(current_event.get().as_ref().clone())))
}
div(class="events-cols") {
div {
Block(title="Events".into()) {
Button(text="Reload".into(), icon="mdi-refresh".into(), onclick=move |_| dispatch(Msg::Reload))
Indexed(
iterable=&events.get(),
view=move |cx, event| {
let event = create_ref(cx, event);
view! { cx,
Block(title=event.name.clone()) {
(event.description)
br()
span(class="event-action") {
Button(text="Delete".into(), icon="mdi-delete".into(), onclick=move |_| dispatch(Msg::Delete(event.name.clone())))
}
span(class="event-action") {
Button(text="View outcome".into(), onclick=move |_| dispatch(Msg::ViewOutcome(event.name.clone())))
}
span(class="event-action") {
Button(text="Finish".into(), onclick=move |_| dispatch(Msg::Stop(event.name.clone())))
}
br()
(event.event_type.view(cx))
}
br()
}
},
)
}
}
div(class="events-right") {
Block(title="Create new event".into()) {
(event_spec.edit(cx))
Button(icon="mdi-check".into(), onclick=move |_| dispatch(Msg::Add(event_spec.get().as_ref().clone())))
}
br()
Block(title="Update an event".into()) {
label { "Event name" }
select(bind:value=event_update_name) {
Indexed(
iterable=&events.get(),
view=move |cx, event| {
let event = create_ref(cx, event);
view! { cx,
option(value=event.name) { (event.name) }
}
},
)
}
(event_update.edit(cx))
Button(
icon="mdi-check".into(),
onclick=move |_| dispatch(Msg::Update(
event_update_name.get().as_ref().clone(),
event_update.get().as_ref().clone()
))
)
}
}
}
}
}