brewlog/src/application/routes/add.rs
Jon Seager 4bdfc661f9
refactor: consolidate entity pages into unified /data and /add views
Replace per-entity pages (/roasters, /roasts, /bags, /brews, /gear,
/cafes, /cups) and detail pages with a single tabbed /data view and
a dedicated /add page for entity creation.

- Add /data route with tab-based navigation using Datastar
- Add /add route consolidating all create forms
- Remove per-entity page handlers and standalone templates
- Remove detail page routes, handlers, and templates
- Update ListNavigator to accept String paths for query-param URLs
- Update home page and timeline links to use new /data?type=X paths
- Update nav to reference /data instead of individual entity pages
2026-02-04 20:51:30 +00:00

61 lines
1.9 KiB
Rust

use axum::extract::{Query, State};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Redirect, Response};
use serde::Deserialize;
use crate::application::errors::map_app_error;
use crate::application::routes::render_html;
use crate::application::routes::support::{
load_cafe_options, load_roast_options, load_roaster_options,
};
use crate::application::server::AppState;
use crate::presentation::web::templates::AddTemplate;
use super::brews::load_brew_form_data;
#[derive(Debug, Deserialize)]
pub(crate) struct AddQuery {
#[serde(rename = "type", default = "default_type")]
entity_type: String,
}
fn default_type() -> String {
"roaster".to_string()
}
#[tracing::instrument(skip(state, cookies))]
pub(crate) async fn add_page(
State(state): State<AppState>,
cookies: tower_cookies::Cookies,
Query(query): Query<AddQuery>,
) -> Result<Response, StatusCode> {
let is_authenticated = super::is_authenticated(&state, &cookies).await;
if !is_authenticated {
return Ok(Redirect::to("/login").into_response());
}
let (roaster_options, roast_options, cafe_options, brew_form) = tokio::try_join!(
async { load_roaster_options(&state).await },
async { load_roast_options(&state).await },
async { load_cafe_options(&state).await },
async { load_brew_form_data(&state).await },
)
.map_err(map_app_error)?;
let template = AddTemplate {
nav_active: "data",
is_authenticated,
active_type: query.entity_type,
roaster_options,
roast_options,
bag_options: brew_form.bag_options,
grinder_options: brew_form.grinder_options,
brewer_options: brew_form.brewer_options,
filter_paper_options: brew_form.filter_paper_options,
cafe_options,
defaults: brew_form.defaults,
};
render_html(template).map(IntoResponse::into_response)
}