cart and buy page

This commit is contained in:
Priec
2026-06-17 18:53:49 +02:00
parent d18bdeaf6e
commit 7be1726f1b
5 changed files with 173 additions and 85 deletions

View File

@@ -1,4 +1,5 @@
use crate::{controllers::i18n::current_lang, shared::money::format_price, models::products};
use axum::{http::HeaderMap, response::Redirect};
use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
use loco_rs::prelude::*;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
@@ -96,6 +97,8 @@ async fn add(
async fn update(
jar: CookieJar,
State(ctx): State<AppContext>,
ViewEngine(v): ViewEngine<TeraView>,
headers: HeaderMap,
Form(form): Form<UpdateForm>,
) -> Result<Response> {
let stock = published_product(&ctx, form.product_id)
@@ -110,19 +113,57 @@ async fn update(
}
items.retain(|(_, qty)| *qty > 0);
format::render()
.cookies(&[cart_cookie(serialize_cart(&items))])?
.redirect("/cart")
let jar = jar.add(cart_cookie(serialize_cart(&items)));
cart_response(&ctx, &v, jar, &headers).await
}
#[debug_handler]
async fn remove(jar: CookieJar, Form(form): Form<RemoveForm>) -> Result<Response> {
async fn remove(
jar: CookieJar,
State(ctx): State<AppContext>,
ViewEngine(v): ViewEngine<TeraView>,
headers: HeaderMap,
Form(form): Form<RemoveForm>,
) -> Result<Response> {
let mut items = parse_cart(&jar);
items.retain(|(id, _)| *id != form.product_id);
format::render()
.cookies(&[cart_cookie(serialize_cart(&items))])?
.redirect("/cart")
let jar = jar.add(cart_cookie(serialize_cart(&items)));
cart_response(&ctx, &v, jar, &headers).await
}
/// Response after a cart mutation: for an htmx request, just the `#cart-body`
/// fragment (so the page never fully reloads); otherwise a redirect back to
/// `/cart` for no-JS fallback. `jar` must already hold the updated cart cookie.
async fn cart_response(
ctx: &AppContext,
v: &TeraView,
jar: CookieJar,
headers: &HeaderMap,
) -> Result<Response> {
if !headers.contains_key("HX-Request") {
return Ok((jar, Redirect::to("/cart")).into_response());
}
let (lines, valid, total) = resolve_cart(ctx, &jar).await?;
let currency = lines
.first()
.and_then(|line| line["currency"].as_str())
.unwrap_or("EUR")
.to_string();
// Persist the re-validated cookie (drops now-invalid lines).
let jar = jar.add(cart_cookie(serialize_cart(&valid)));
let response = format::view(
v,
"shop/_cart_body.html",
json!({
"items": lines,
"total": format_price(total),
"currency": currency,
"lang": current_lang(&jar),
}),
)?;
Ok((jar, response).into_response())
}
/// Resolve the cart cookie into priced line items, dropping anything that is no