web/pages/account/
search.rs1use askama::Template;
2use axum::{Extension, Json, extract::State, response::IntoResponse};
3use serde::Deserialize;
4use server::command::{CmdResult, FinanceEntity, account::ListAccounts};
5use sqlx::types::Uuid;
6use std::sync::Arc;
7
8use crate::{AppState, jwt_auth::JWTAuthMiddleware, pages::HtmlTemplate};
9
10#[derive(Deserialize)]
11pub struct AccountSearch {
12 #[serde(rename = "parent-search")]
13 query: Option<String>,
14}
15
16#[derive(Template)]
17#[template(path = "components/account/search_results.html")]
18struct AccountSearchResults {
19 accounts: Vec<AccountView>,
20}
21
22struct AccountView {
23 id: Uuid,
24 name: String,
25}
26
27pub async fn search_accounts(
28 State(_data): State<Arc<AppState>>,
29 Extension(jwt_auth): Extension<JWTAuthMiddleware>,
30 Json(form): Json<AccountSearch>,
31) -> impl IntoResponse {
32 let result = match ListAccounts::new().user_id(jwt_auth.user.id).run().await {
33 Ok(Some(CmdResult::TaggedEntities { entities, .. })) => entities,
34 _ => return HtmlTemplate(AccountSearchResults { accounts: vec![] }),
35 };
36
37 let mut accounts = Vec::new();
38 for (entity, tags) in result {
39 if let FinanceEntity::Account(account) = entity {
40 let name = if let FinanceEntity::Tag(n) = &tags["name"] {
42 n.tag_value.clone()
43 } else {
44 continue;
45 };
46
47 if let Some(query) = &form.query {
49 if query.is_empty() || name.to_lowercase().contains(&query.to_lowercase()) {
50 accounts.push(AccountView {
51 id: account.id,
52 name,
53 });
54 }
55 } else {
56 accounts.push(AccountView {
57 id: account.id,
58 name,
59 });
60 }
61 }
62 }
63
64 HtmlTemplate(AccountSearchResults { accounts })
65}