Files
stl/server/src/routes/pages/weeks.rs
2021-10-22 13:00:29 +02:00

113 lines
3.3 KiB
Rust

use crate::auth::Authorized;
use crate::status_json::StatusJson;
use chrono::{Duration, Local, NaiveDate};
use itertools::Itertools;
use rocket::{get, response::content::Html, State};
use rocket_dyn_templates::Template;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::iter::{once, repeat};
pub struct BirthDate(pub NaiveDate);
#[get("/weeks")]
pub fn weeks(
_auth: Authorized,
birth_date: &State<BirthDate>,
) -> Result<Html<Template>, StatusJson> {
type Color<'a> = Cow<'a, str>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Style<'a> {
border: Color<'a>,
fill: Option<Color<'a>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct PeriodCtx<'a> {
style: Style<'a>,
weeks: Vec<()>,
}
impl<'a> Style<'a> {
fn border<C>(border: C) -> Self
where
C: Into<Cow<'a, str>>,
{
Style {
border: border.into(),
fill: None,
}
}
fn fill<C>(border: C, fill: C) -> Self
where
C: Into<Cow<'a, str>>,
{
Style {
border: border.into(),
fill: Some(fill.into()),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
struct Ctx<'a> {
weeks_left: i64,
periods: Vec<PeriodCtx<'a>>,
}
let now = Local::now().date();
let birth_date = birth_date.0;
let lived: Duration = now.naive_local() - birth_date;
let one_year = Duration::days(365);
let life_expectancy = (one_year * 81).num_weeks();
let uncertainty = (one_year * 20).num_weeks();
let childhood_end = (one_year * 12).num_weeks();
let teenage_end = (one_year * 20).num_weeks();
let color_birth = "green";
let color_child = "#ff0";
let color_teen = "#f33";
let color_adult = "#f0f";
let color_today = "wheat";
let color_future = "#eee";
let context = Ctx {
weeks_left: life_expectancy - lived.num_weeks(),
periods: once(Style::fill(color_birth, color_birth))
// childhood
.chain((1..childhood_end).map(|_| Style::border(color_child)))
// teens
.chain((childhood_end..teenage_end).map(|_| Style::border(color_teen)))
// adulthood
.chain((teenage_end..).map(|_| Style::border(color_adult)))
// take from above for lived number of weeks
.take(lived.num_weeks() as usize - 1)
// add a week for this week
.chain(once(Style::fill(color_today, color_today)))
// fill remaining weeks until death
.chain(repeat(Style::border(color_future)))
.take((life_expectancy - uncertainty * 2) as usize)
// add some fading around expected life span
.chain((0..uncertainty).rev().map(|i| {
let m = u8::MAX as i64;
let alpha = ((m * i) / (uncertainty)) as u8;
Style::border(format!("#eeeeee{:02x}", alpha))
}))
// group weeks by color to save space
.group_by(|style| style.clone())
.into_iter()
.map(|(style, weeks)| PeriodCtx {
style,
weeks: vec![(); weeks.count()],
})
.collect(),
};
Ok(Html(Template::render("weeks", &context)))
}