Added the functionality to insert a workout

This commit is contained in:
2025-07-15 13:53:05 +02:00
parent 9a8cd2ed86
commit d1029485d4
23 changed files with 847 additions and 136 deletions

View File

@@ -1,21 +1,32 @@
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::MuscleGroup, "SELECT * FROM muscle_groups")
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! {
h1 class="mb-5" { "New Exercise" }
@@ -30,29 +41,9 @@ async fn page(State(state): State<AppState>) -> Result<Markup, AppError> {
textarea required="true" name="description" class="textarea" {}
}
fieldset class="fieldset" {
legend class="fieldset-legend" { "Muscle Group" }
(multiselect(muscles_map, "muscles", "Muscles"))
@for muscle in muscles {
@let name = muscle.name;
label class="label" {
input type="checkbox" class="checkbox" {}
(name)
}
}
}
fieldset class="fieldset" {
legend class="fieldset-legend" { "Category" }
@for category in categories {
@let name = category.name;
label class="label" {
input type="checkbox" class="checkbox" {}
(name)
}
}
}
(multiselect(categories_map, "categories", "Categories"))
input type="submit" class="btn" value="save" { }
}
@@ -65,13 +56,20 @@ async fn page(State(state): State<AppState>) -> Result<Markup, AppError> {
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::Uuid::new_v4();
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)",
@@ -79,9 +77,35 @@ async fn submit(
form.name,
form.description
)
.execute(&state.pool)
.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!"