2025-07-15 20:28:29 +02:00

113 lines
3.3 KiB
Rust

use crate::components::multiselect;
use crate::util::string_into_vec;
use crate::{AppError, layouts, util::AppState};
use axum::{Form, Router, extract::State, http::StatusCode, routing::get};
use maud::{Markup, html};
use serde::Deserialize;
use uuid::Uuid;
pub fn routes() -> Router<AppState> {
Router::new().route("/", get(page).post(submit))
}
async fn page(State(state): State<AppState>) -> Result<Markup, AppError> {
let muscles = sqlx::query_as!(crate::models::Muscle, "SELECT * FROM muscles")
.fetch_all(&state.pool)
.await?;
let muscles_map: Vec<(String, String)> =
muscles.into_iter().map(|m| (m.muscle_id, m.name)).collect();
let categories = sqlx::query_as!(crate::models::Category, "SELECT * FROM categories")
.fetch_all(&state.pool)
.await?;
let categories_map: Vec<(String, String)> = categories
.into_iter()
.map(|c| (c.category_id, c.name))
.collect();
let content = html! {
form hx-post="/exercises/new" class="space-y-1" {
fieldset class="fieldset" {
legend class="fieldset-legend" { "Name" }
input required="true" name="name" class="input" {}
}
fieldset class="fieldset" {
legend class="fieldset-legend" { "Description" }
textarea required="true" name="description" class="textarea" {}
}
(multiselect(muscles_map, "muscles", "Muscles"))
(multiselect(categories_map, "categories", "Categories"))
input type="submit" class="btn" value="save" { }
}
};
Ok(layouts::desktop(content, "New Exercise", true))
}
#[derive(Deserialize, Debug)]
struct FormData {
name: String,
description: String,
muscles: String,
categories: String,
}
async fn submit(
State(state): State<AppState>,
Form(form): Form<FormData>,
) -> Result<Markup, AppError> {
let exercise_id = Uuid::new_v4();
let muscle_ids = string_into_vec(form.muscles);
let category_ids = string_into_vec(form.categories);
let mut transaction = state.pool.begin().await?;
sqlx::query!(
"INSERT INTO exercises (exercise_id, name, description) VALUES ($1, $2, $3)",
exercise_id,
form.name,
form.description
)
.execute(&mut *transaction)
.await?;
tracing::info!("{:?} and {:?}", muscle_ids, category_ids);
// Create and insert relationship between muscles and exercises
if !muscle_ids.is_empty() {
let exercise_ids = vec![exercise_id; muscle_ids.len()];
sqlx::query!(
"INSERT INTO exercise_muscles (exercise_id, muscle_id) SELECT * FROM UNNEST($1::uuid[], $2::varchar[])",
&exercise_ids,
&muscle_ids
).execute(&mut *transaction).await?;
}
// Create and insert relationship between categories and exercises
if !category_ids.is_empty() {
let exercise_ids = vec![exercise_id; category_ids.len()];
sqlx::query!(
"INSERT INTO exercise_categories (exercise_id, category_id) SELECT * FROM UNNEST($1::uuid[], $2::varchar[])",
&exercise_ids,
&category_ids
).execute(&mut *transaction).await?;
}
transaction.commit().await?;
Ok(html! {
p {
"New exercise has been created!"
}
})
}