use std::ops::Deref; use anyhow::anyhow; use lan_party_core::{ components::Block, edit::IntoEdit, event::{Event, EventOutcome, EventSpec, EventUpdate}, util::WithContext, 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::{EventsExt, UsersExt}, util::api_request, }; use lan_party_core::state::{Events, Users}; 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 { let messenger = use_context::(cx); let event_spec = create_signal(cx, EventSpec::default()); let event_update = create_signal(cx, EventUpdate::default()); let event_update_name = create_signal(cx, WithContext::::from(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::(cx); let users = use_context::(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::::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 { event_outcome.set(outcome); } else { messenger.add_result( res, Option::::None, Some("Failed to load outcome"), ) } } Msg::Stop(event_name) => { let res = api_request::<(), EventOutcome>( Method::POST, &format!("/event/{}/stop", event_name), None, ) .await; messenger.add_result( res, Some("Event finished, scores were applied"), Some("Unable to finish event"), ); let _ = users.load(); } } }); }; 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.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" } (event_update_name.edit(cx)) (event_update.edit(cx)) Button( icon="mdi-check".into(), onclick=move |_| dispatch(Msg::Update( event_update_name.get().as_ref().deref().clone(), event_update.get().as_ref().clone() )) ) } } } } }