web/pages/commodity/
list.rs1use std::sync::Arc;
2
3use askama::Template;
4use axum::{
5 Extension, Json,
6 extract::State,
7 http::{HeaderMap, StatusCode, header},
8 response::IntoResponse,
9};
10use serde::Serialize;
11use server::command::{CmdResult, FinanceEntity, commodity::ListCommodities};
12use sqlx::types::Uuid;
13
14use crate::{AppState, jwt_auth::JWTAuthMiddleware, pages::HtmlTemplate};
15
16#[derive(Template)]
17#[template(path = "pages/commodity/list.html")]
18struct CommodityListPage;
19
20pub async fn commodity_list_page() -> impl IntoResponse {
21 let template = CommodityListPage {};
22 HtmlTemplate(template)
23}
24
25struct CommodityView {
26 id: Uuid,
27 symbol: String,
28 name: String,
29}
30
31#[derive(Serialize)]
32struct CommodityJson {
33 id: String,
34 symbol: String,
35 name: String,
36}
37
38#[derive(Template)]
39#[template(path = "components/commodity/table.html")]
40struct CommodityTableTemplate {
41 commodities: Vec<CommodityView>,
42}
43
44pub async fn commodity_table(
45 State(_data): State<Arc<AppState>>,
46 Extension(jwt_auth): Extension<JWTAuthMiddleware>,
47 headers: HeaderMap,
48) -> Result<impl IntoResponse, StatusCode> {
49 let result = ListCommodities::new()
50 .user_id(jwt_auth.user.id)
51 .run()
52 .await
53 .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
54 let mut commodities = Vec::new();
55 if let Some(CmdResult::TaggedEntities { entities, .. }) = result {
56 for (entity, tags) in entities {
57 if let FinanceEntity::Commodity(commodity) = entity {
58 let (symbol, name) = if let (FinanceEntity::Tag(s), FinanceEntity::Tag(n)) =
60 (&tags["symbol"], &tags["name"])
61 {
62 (s.tag_value.clone(), n.tag_value.clone())
63 } else {
64 return Err(StatusCode::INTERNAL_SERVER_ERROR);
65 };
66
67 commodities.push(CommodityView {
68 id: commodity.id,
69 symbol,
70 name,
71 });
72 }
73 }
74 }
75
76 let wants_json = headers
77 .get(header::ACCEPT)
78 .and_then(|value| value.to_str().ok())
79 .is_some_and(|value| value.contains("application/json"));
80
81 if wants_json {
82 let commodities_json: Vec<CommodityJson> = commodities
83 .iter()
84 .map(|c| CommodityJson {
85 id: c.id.to_string(),
86 symbol: c.symbol.clone(),
87 name: c.name.clone(),
88 })
89 .collect();
90 return Ok(Json(commodities_json).into_response());
91 }
92
93 Ok(HtmlTemplate(CommodityTableTemplate { commodities }).into_response())
94}