hyaenidae/server/src/nav.rs

129 lines
4 KiB
Rust
Raw Normal View History

use crate::{
admin::Admin, extensions::ProfileExt, middleware::UserProfile,
notifications::total_for_profile, State,
};
use actix_web::{
dev::Payload,
web::{Data, Query},
FromRequest, HttpRequest,
};
use futures::future::LocalBoxFuture;
use hyaenidae_accounts::LogoutState;
use hyaenidae_toolkit::Button;
impl FromRequest for NavState {
type Config = ();
type Error = actix_web::Error;
type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
let profile = Option::<UserProfile>::extract(req);
let logout = Option::<LogoutState>::extract(req);
let query = Option::<Query<Vec<(String, String)>>>::extract(req);
let admin = Option::<Admin>::extract(req);
let path = req.uri().path().to_owned();
let state = Data::<State>::extract(req);
Box::pin(async move {
let profile = profile.await?.map(|p| p.0);
let logout = logout.await?;
let query = query.await?;
let admin = admin.await?;
let state = state.await?;
let dark = true;
let mut nav = vec![];
if let Some(logout_state) = logout {
nav.push(Button::primary("New Submission").href("/submissions/create"));
if let Some(profile) = profile.as_ref() {
nav.push(Button::secondary("Profile").href(&profile.view_path()));
} else {
nav.push(Button::secondary("Switch Profile").href("/profiles/change"));
};
if let Some(profile) = profile.as_ref() {
if let Ok(count) = total_for_profile(profile.id(), &state).await {
if count > 0 {
nav.push(Button::secondary("Notifications").href("/notifications"));
}
}
}
nav.push(Button::secondary("Account").href("/session/account"));
if admin.is_some() {
nav.push(Button::secondary("Admin").href("/admin"));
}
nav.push(logout_state.button(Button::primary_outline("Logout")));
} else {
nav.push(Button::primary_outline("Login").href("/session/auth/login"));
nav.push(Button::primary_outline("Register").href("/session/auth/register"));
}
if let Some(query) = query {
let mut is_open = false;
let query = query
.into_inner()
.into_iter()
.filter_map(|(key, value)| {
if key == "show_nav" {
is_open = true;
None
} else {
Some(format!("{}={}", key, value))
}
})
.collect::<Vec<String>>()
.join("&");
let query = if is_open {
query
} else {
format!("{}&show_nav=true", query)
};
Ok(NavState {
buttons: nav,
href: format!("{}?{}", path, query),
is_open,
dark,
})
} else {
Ok(NavState {
buttons: nav,
href: format!("{}?show_nav=true", path),
is_open: false,
dark,
})
}
})
}
}
pub struct NavState {
pub(crate) buttons: Vec<Button>,
href: String,
is_open: bool,
dark: bool,
}
impl NavState {
pub(crate) fn href(&self) -> &str {
&self.href
}
pub(crate) fn class_string(&self) -> &str {
if self.is_open {
"nav-open"
} else {
"nav-closed"
}
}
pub(crate) fn dark(&self) -> bool {
self.dark
}
}