jana_sessions_webpage/src/webpage.rs
2025-02-15 02:01:18 +01:00

115 lines
2.8 KiB
Rust

use crate::localize_day;
use crate::session_date_calculator::{DayIter, NthWeekday};
use chrono::Weekday;
use leptos::prelude::*;
use leptos::server_fn::request::browser::Request;
use serde::{Deserialize, Serialize};
#[component]
pub fn App() -> impl IntoView {
let session_config =
LocalResource::new(|| async { load_config::<SessionConfig>("session_config").await });
let session_dates = move || {
session_config
.get()
.as_deref()
.cloned()
.map(|config| match config {
Ok(config) => {
let config = config.unwrap_or_default();
view! { <Sessions config /> }.into_any()
}
Err(e) => view! {
<div class="box error-background">
<h1>"Error"</h1>
<p>{e}</p>
</div>
}
.into_any(),
})
};
view! {
<div class="background">
<Suspense fallback=|| "Laden...">{session_dates}</Suspense>
</div>
}
}
#[component]
fn Sessions(config: SessionConfig) -> impl IntoView {
let mut session_iter = DayIter::default().filter(move |day| {
config
.sessions
.iter()
.any(|session_day| session_day.matches(day))
});
let (session_dates, set_session_dates) =
signal(session_iter.by_ref().take(2).collect::<Vec<_>>());
view! {
<div class="column">
<div class="wide box elem-background">
<h1>"Anstehende Proben Termine"</h1>
<p>{config.motd}</p>
</div>
<For
each=move || session_dates.get()
key=|day| day.date
children=move |day| view! { <div class="box elem-background">{localize_day(&day)}</div> }
/>
<div
class="box button elem-background"
on:click=move |_| {
set_session_dates.write().extend(session_iter.by_ref().take(3));
}
>
"Mehr anzeigen"
</div>
</div>
}
}
async fn load_config<T>(name: &str) -> Result<Option<T>, String>
where
T: for<'a> Deserialize<'a>,
{
let response = Request::get(&format!("/{name}.json"))
.send()
.await
.map_err(|e| format!("HTTP error: {e}"))?;
if response
.headers()
.get("content-type")
.is_none_or(|content_type| content_type != "application/json")
{
return Ok(None);
}
let config = response
.json()
.await
.map_err(|e| format!("JSON error: {e}"))?;
Ok(Some(config))
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct SessionConfig {
pub motd: Option<String>,
pub sessions: Vec<NthWeekday>,
}
impl Default for SessionConfig {
fn default() -> Self {
Self {
motd: Some("Probe jeden ersten Sonntag im Monat um 10:00 Uhr und jeden dritten Dienstag im Monat um 18:30 Uhr".to_string()),
sessions: vec![
NthWeekday::new(1, Weekday::Sun),
NthWeekday::new(3, Weekday::Tue),
],
}
}
}