use crate::render;
use crate::ui::state::AppState;
use axum::Json;
use axum::extract::State;
use axum::http::StatusCode;
use axum::response::IntoResponse;
use serde::Deserialize;
use serde_json::{Value, json};
use std::sync::Arc;
#[derive(Deserialize)]
pub struct FlowAction {
pub title: String,
pub goto: String,
}
#[derive(Deserialize)]
pub struct FlowCard {
pub id: String,
#[serde(alias = "preset")]
pub template: String,
#[serde(default)]
pub theme: Option<String>,
pub data: Value,
#[serde(default)]
pub actions: Vec<FlowAction>,
}
#[derive(Deserialize)]
pub struct FlowBody {
pub cards: Vec<FlowCard>,
#[serde(default)]
pub theme: Option<String>,
}
pub async fn post_render_flow(
State(state): State<Arc<AppState>>,
Json(body): Json<FlowBody>,
) -> impl IntoResponse {
let mut rendered_cards = Vec::new();
for fc in &body.cards {
let theme = fc.theme.as_deref().or(body.theme.as_deref());
let response = match render::render_preset(&state.registry, &fc.template, theme, &fc.data) {
Ok(r) => r,
Err(e) => {
return (
StatusCode::BAD_REQUEST,
Json(json!({
"error": format!("card '{}': {}", fc.id, e)
})),
)
.into_response();
}
};
let mut card = response.card;
if !fc.actions.is_empty() {
let action_values: Vec<Value> = fc
.actions
.iter()
.map(|a| {
json!({
"type": "Action.Submit",
"title": a.title,
"style": "positive",
"data": { "goto": a.goto }
})
})
.collect();
card["actions"] = Value::Array(action_values);
}
rendered_cards.push(json!({
"id": fc.id,
"rendered_card": card,
}));
}
Json(json!({ "cards": rendered_cards })).into_response()
}