diff --git a/src/application/routes/bags.rs b/src/application/routes/bags.rs index c1ef51f..8cad783 100644 --- a/src/application/routes/bags.rs +++ b/src/application/routes/bags.rs @@ -201,20 +201,37 @@ pub(crate) async fn get_bag( Ok(Json(bag)) } -#[tracing::instrument(skip(state, _auth_user))] +#[tracing::instrument(skip(state, _auth_user, headers, query))] pub(crate) async fn update_bag( State(state): State, _auth_user: AuthenticatedUser, + headers: HeaderMap, Path(id): Path, - Json(payload): Json, -) -> Result, ApiError> { + Query(query): Query, + Query(update_params): Query, + payload: Option>, +) -> Result { + let request = query.into_request::(); + + let body_update = payload.map(|Json(p)| p).unwrap_or(UpdateBag { + remaining: None, + closed: None, + finished_at: None, + }); + + let update = UpdateBag { + remaining: body_update.remaining.or(update_params.remaining), + closed: body_update.closed.or(update_params.closed), + finished_at: body_update.finished_at.or(update_params.finished_at), + }; + let bag = state .bag_repo - .update(id, payload.clone()) + .update(id, update.clone()) .await .map_err(AppError::from)?; - if let Some(true) = payload.closed { + if let Some(true) = update.closed { // Fetch roast and roaster for timeline event if let Ok(roast) = state.roast_repo.get(bag.roast_id).await && let Ok(roaster) = state.roaster_repo.get(roast.roaster_id).await @@ -234,7 +251,13 @@ pub(crate) async fn update_bag( } } - Ok(Json(bag)) + if is_datastar_request(&headers) { + render_bag_list_fragment(state, request, true) + .await + .map_err(ApiError::from) + } else { + Ok(Json(bag).into_response()) + } } #[tracing::instrument(skip(state, _auth_user, headers, query))] @@ -257,68 +280,6 @@ pub(crate) async fn delete_bag( } } -#[tracing::instrument(skip(state, _auth_user, headers, query))] -pub(crate) async fn finish_bag( - State(state): State, - _auth_user: AuthenticatedUser, - headers: HeaderMap, - Path(id): Path, - Query(query): Query, -) -> Result { - let request = query.into_request::(); - - let bag = state - .bag_repo - .get(id) - .await - .map_err(|err| map_app_error(AppError::from(err)))?; - - let update = UpdateBag { - remaining: Some(0.0), - closed: Some(true), - finished_at: Some(chrono::Utc::now().date_naive()), - }; - - let _ = state - .bag_repo - .update(id, update) - .await - .map_err(|err| map_app_error(AppError::from(err)))?; - - // Add timeline event - if let Ok(roast) = state.roast_repo.get(bag.roast_id).await - && let Ok(roaster) = state.roaster_repo.get(roast.roaster_id).await - { - let event = NewTimelineEvent { - entity_type: "bag".to_string(), - entity_id: bag.id.into_inner(), - occurred_at: chrono::Utc::now(), - title: roast.name.to_string(), - details: vec![ - TimelineEventDetail { - label: "Roaster".to_string(), - value: roaster.name, - }, - TimelineEventDetail { - label: "Amount".to_string(), - value: format!("{:.1}g", bag.amount), - }, - ], - tasting_notes: vec![], - }; - let _ = state.timeline_repo.insert(event).await; - } - - if is_datastar_request(&headers) { - render_bag_list_fragment(state, request, true) - .await - .map_err(map_app_error) - } else { - // Fallback for non-datastar requests (though the UI uses datastar) - Ok(Redirect::to(BAG_PAGE_PATH).into_response()) - } -} - #[derive(Debug, Deserialize)] pub struct BagsQuery { pub roast_id: Option, diff --git a/src/application/routes/mod.rs b/src/application/routes/mod.rs index 371bba1..a1213ac 100644 --- a/src/application/routes/mod.rs +++ b/src/application/routes/mod.rs @@ -64,7 +64,6 @@ pub fn app_router(state: AppState) -> axum::Router { get(roasts::roast_page), ) .route("/bags", get(bags::bags_page)) - .route("/bags/:id/finish", post(bags::finish_bag)) .route("/timeline", get(timeline::timeline_page)) .route("/styles.css", get(styles)) .route("/favicon.ico", get(favicon)) diff --git a/src/application/routes/support.rs b/src/application/routes/support.rs index ad82a06..224adc6 100644 --- a/src/application/routes/support.rs +++ b/src/application/routes/support.rs @@ -118,6 +118,9 @@ pub fn render_fragment( .map_err(|err| AppError::unexpected(format!("failed to render fragment: {err}")))?; let mut response = Html(html).into_response(); + response + .headers_mut() + .insert(CONTENT_TYPE, HeaderValue::from_static("text/html")); set_datastar_patch_headers(response.headers_mut(), selector); Ok(response) } diff --git a/templates/partials/bag_list.html b/templates/partials/bag_list.html index b4460ea..3103cf5 100644 --- a/templates/partials/bag_list.html +++ b/templates/partials/bag_list.html @@ -78,7 +78,7 @@