membership-pdf-new #284
| @@ -140,3 +140,13 @@ CREATE TABLE IF NOT EXISTS "boat_damage" ( | |||||||
| 	"verified_at" datetime, | 	"verified_at" datetime, | ||||||
| 	"lock_boat" boolean not null default false -- if true: noone can use the boat  | 	"lock_boat" boolean not null default false -- if true: noone can use the boat  | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | CREATE TABLE IF NOT EXISTS "boathouse" ( | ||||||
|  |     "id" INTEGER PRIMARY KEY AUTOINCREMENT, | ||||||
|  |     "boat_id" INTEGER NOT NULL REFERENCES boat(id), | ||||||
|  |     "aisle" TEXT NOT NULL CHECK (aisle in ('water', 'middle', 'mountain')), | ||||||
|  |     "side" TEXT NOT NULL CHECK(side IN ('mountain', 'water')), | ||||||
|  |     "level" INTEGER NOT NULL CHECK(level BETWEEN 0 AND 3), | ||||||
|  |     CONSTRAINT unq UNIQUE (aisle, side, level) -- only 1 boat allowed to rest at each space  | ||||||
|  | ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -181,6 +181,41 @@ ORDER BY amount_seats DESC | |||||||
|         Self::boats_to_details(db, boats).await |         Self::boats_to_details(db, boats).await | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub async fn all_for_boatshouse(db: &SqlitePool) -> Vec<BoatWithDetails> { | ||||||
|  |         let boats = sqlx::query_as!( | ||||||
|  |             Boat, | ||||||
|  |             " | ||||||
|  | SELECT  | ||||||
|  |     b.id,  | ||||||
|  |     b.name,  | ||||||
|  |     b.amount_seats,  | ||||||
|  |     b.location_id,  | ||||||
|  |     b.owner,  | ||||||
|  |     b.year_built,  | ||||||
|  |     b.boatbuilder,  | ||||||
|  |     b.default_shipmaster_only_steering,  | ||||||
|  |     b.default_destination,  | ||||||
|  |     b.skull,  | ||||||
|  |     b.external | ||||||
|  | FROM  | ||||||
|  |     boat AS b | ||||||
|  | LEFT JOIN  | ||||||
|  |     boathouse AS bh ON b.id = bh.boat_id | ||||||
|  | WHERE  | ||||||
|  |     b.external = false  | ||||||
|  |     AND b.location_id = (SELECT id FROM location WHERE name = 'Linz') | ||||||
|  |     AND bh.id IS NULL -- This ensures the boat does not have an entry in the boathouse table | ||||||
|  | ORDER BY  | ||||||
|  |     b.name DESC; | ||||||
|  |         " | ||||||
|  |         ) | ||||||
|  |         .fetch_all(db) | ||||||
|  |         .await | ||||||
|  |         .unwrap(); //TODO: fixme | ||||||
|  |  | ||||||
|  |         Self::boats_to_details(db, boats).await | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub async fn for_user(db: &SqlitePool, user: &User) -> Vec<BoatWithDetails> { |     pub async fn for_user(db: &SqlitePool, user: &User) -> Vec<BoatWithDetails> { | ||||||
|         if user.has_role(db, "admin").await { |         if user.has_role(db, "admin").await { | ||||||
|             return Self::all(db).await; |             return Self::all(db).await; | ||||||
|   | |||||||
							
								
								
									
										90
									
								
								src/model/boathouse.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/model/boathouse.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | |||||||
|  | use std::collections::HashMap; | ||||||
|  |  | ||||||
|  | use rocket::serde::{Deserialize, Serialize}; | ||||||
|  | use sqlx::{FromRow, SqlitePool}; | ||||||
|  |  | ||||||
|  | use crate::tera::board::boathouse::FormBoathouseToAdd; | ||||||
|  |  | ||||||
|  | use super::boat::Boat; | ||||||
|  |  | ||||||
|  | #[derive(FromRow, Debug, Serialize, Deserialize)] | ||||||
|  | pub struct Boathouse { | ||||||
|  |     pub id: i64, | ||||||
|  |     pub boat_id: i64, | ||||||
|  |     pub aisle: String, | ||||||
|  |     pub side: String, | ||||||
|  |     pub level: i64, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Boathouse { | ||||||
|  |     pub async fn get(db: &SqlitePool) -> HashMap<&str, HashMap<&str, [Option<(i64, Boat)>; 4]>> { | ||||||
|  |         let mut ret: HashMap<&str, HashMap<&str, [Option<(i64, Boat)>; 4]>> = HashMap::new(); | ||||||
|  |  | ||||||
|  |         let mut mountain = HashMap::new(); | ||||||
|  |         mountain.insert("mountain", [None, None, None, None]); | ||||||
|  |         mountain.insert("water", [None, None, None, None]); | ||||||
|  |         ret.insert("mountain-aisle", mountain); | ||||||
|  |  | ||||||
|  |         let mut middle = HashMap::new(); | ||||||
|  |         middle.insert("mountain", [None, None, None, None]); | ||||||
|  |         middle.insert("water", [None, None, None, None]); | ||||||
|  |         ret.insert("middle-aisle", middle); | ||||||
|  |  | ||||||
|  |         let mut water = HashMap::new(); | ||||||
|  |         water.insert("mountain", [None, None, None, None]); | ||||||
|  |         water.insert("water", [None, None, None, None]); | ||||||
|  |         ret.insert("water-aisle", water); | ||||||
|  |  | ||||||
|  |         let boathouses = sqlx::query_as!( | ||||||
|  |             Boathouse, | ||||||
|  |             "SELECT id, boat_id, aisle, side, level FROM boathouse" | ||||||
|  |         ) | ||||||
|  |         .fetch_all(db) | ||||||
|  |         .await | ||||||
|  |         .unwrap(); //TODO: fixme | ||||||
|  |  | ||||||
|  |         for boathouse in boathouses { | ||||||
|  |             let aisle = ret | ||||||
|  |                 .get_mut(format!("{}-aisle", boathouse.aisle).as_str()) | ||||||
|  |                 .unwrap(); | ||||||
|  |             let side = aisle.get_mut(boathouse.side.as_str()).unwrap(); | ||||||
|  |  | ||||||
|  |             side[boathouse.level as usize] = Some(( | ||||||
|  |                 boathouse.id, | ||||||
|  |                 Boat::find_by_id(db, boathouse.boat_id as i32) | ||||||
|  |                     .await | ||||||
|  |                     .unwrap(), | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         ret | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub async fn create(db: &SqlitePool, data: FormBoathouseToAdd) -> Result<(), String> { | ||||||
|  |         sqlx::query!( | ||||||
|  |             "INSERT INTO boathouse(boat_id, aisle, side, level) VALUES (?,?,?,?)", | ||||||
|  |             data.boat_id, | ||||||
|  |             data.aisle, | ||||||
|  |             data.side, | ||||||
|  |             data.level | ||||||
|  |         ) | ||||||
|  |         .execute(db) | ||||||
|  |         .await | ||||||
|  |         .map_err(|e| e.to_string())?; | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option<Self> { | ||||||
|  |         sqlx::query_as!(Self, "SELECT * FROM boathouse WHERE id like ?", id) | ||||||
|  |             .fetch_one(db) | ||||||
|  |             .await | ||||||
|  |             .ok() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub async fn delete(&self, db: &SqlitePool) { | ||||||
|  |         sqlx::query!("DELETE FROM boathouse WHERE id=?", self.id) | ||||||
|  |             .execute(db) | ||||||
|  |             .await | ||||||
|  |             .unwrap(); //Okay, because we can only create a Boat of a valid id | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -9,6 +9,7 @@ use self::{ | |||||||
|  |  | ||||||
| pub mod boat; | pub mod boat; | ||||||
| pub mod boatdamage; | pub mod boatdamage; | ||||||
|  | pub mod boathouse; | ||||||
| pub mod family; | pub mod family; | ||||||
| pub mod location; | pub mod location; | ||||||
| pub mod log; | pub mod log; | ||||||
|   | |||||||
							
								
								
									
										85
									
								
								src/tera/board/boathouse.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/tera/board/boathouse.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | |||||||
|  | use crate::model::{ | ||||||
|  |     boat::Boat, | ||||||
|  |     boathouse::Boathouse, | ||||||
|  |     user::{AdminUser, UserWithRoles, VorstandUser}, | ||||||
|  | }; | ||||||
|  | use rocket::{ | ||||||
|  |     form::Form, | ||||||
|  |     get, post, | ||||||
|  |     request::FlashMessage, | ||||||
|  |     response::{Flash, Redirect}, | ||||||
|  |     routes, FromForm, Route, State, | ||||||
|  | }; | ||||||
|  | use rocket_dyn_templates::{tera::Context, Template}; | ||||||
|  | use sqlx::SqlitePool; | ||||||
|  |  | ||||||
|  | #[get("/boathouse")] | ||||||
|  | async fn index( | ||||||
|  |     db: &State<SqlitePool>, | ||||||
|  |     admin: VorstandUser, | ||||||
|  |     flash: Option<FlashMessage<'_>>, | ||||||
|  | ) -> Template { | ||||||
|  |     let mut context = Context::new(); | ||||||
|  |     if let Some(msg) = flash { | ||||||
|  |         context.insert("flash", &msg.into_inner()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let boats = Boat::all_for_boatshouse(db).await; | ||||||
|  |     context.insert("boats", &boats); | ||||||
|  |  | ||||||
|  |     let boathouse = Boathouse::get(db).await; | ||||||
|  |     context.insert("boathouse", &boathouse); | ||||||
|  |  | ||||||
|  |     context.insert( | ||||||
|  |         "loggedin_user", | ||||||
|  |         &UserWithRoles::from_user(admin.into(), db).await, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     Template::render("board/boathouse", context.into_json()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(FromForm)] | ||||||
|  | pub struct FormBoathouseToAdd { | ||||||
|  |     pub boat_id: i32, | ||||||
|  |     pub aisle: String, | ||||||
|  |     pub side: String, | ||||||
|  |     pub level: i32, | ||||||
|  | } | ||||||
|  | #[post("/boathouse", data = "<data>")] | ||||||
|  | async fn new<'r>( | ||||||
|  |     db: &State<SqlitePool>, | ||||||
|  |     data: Form<FormBoathouseToAdd>, | ||||||
|  |     _admin: AdminUser, | ||||||
|  | ) -> Flash<Redirect> { | ||||||
|  |     match Boathouse::create(db, data.into_inner()).await { | ||||||
|  |         Ok(_) => Flash::success(Redirect::to("/board/boathouse"), "Boot hinzugefügt"), | ||||||
|  |         Err(e) => Flash::error(Redirect::to("/board/boathouse"), e), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[get("/boathouse/<boathouse_id>/delete")] | ||||||
|  | async fn delete(db: &State<SqlitePool>, _admin: AdminUser, boathouse_id: i32) -> Flash<Redirect> { | ||||||
|  |     let boat = Boathouse::find_by_id(db, boathouse_id).await; | ||||||
|  |     match boat { | ||||||
|  |         Some(boat) => { | ||||||
|  |             boat.delete(db).await; | ||||||
|  |             Flash::success(Redirect::to("/board/boathouse"), "Bootsplatz gelöscht") | ||||||
|  |         } | ||||||
|  |         None => Flash::error(Redirect::to("/board/boathouse"), "Boatplace does not exist"), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | //#[post("/boat/new", data = "<data>")] | ||||||
|  | //async fn create( | ||||||
|  | //    db: &State<SqlitePool>, | ||||||
|  | //    data: Form<BoatToAdd<'_>>, | ||||||
|  | //    _admin: AdminUser, | ||||||
|  | //) -> Flash<Redirect> { | ||||||
|  | //    match Boat::create(db, data.into_inner()).await { | ||||||
|  | //        Ok(_) => Flash::success(Redirect::to("/admin/boat"), "Boot hinzugefügt"), | ||||||
|  | //        Err(e) => Flash::error(Redirect::to("/admin/boat"), e), | ||||||
|  | //    } | ||||||
|  | //} | ||||||
|  |  | ||||||
|  | pub fn routes() -> Vec<Route> { | ||||||
|  |     routes![index, new, delete] | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								src/tera/board/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/tera/board/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | use rocket::Route; | ||||||
|  |  | ||||||
|  | pub mod boathouse; | ||||||
|  |  | ||||||
|  | pub fn routes() -> Vec<Route> { | ||||||
|  |     let mut ret = Vec::new(); | ||||||
|  |     ret.append(&mut boathouse::routes()); | ||||||
|  |     ret | ||||||
|  | } | ||||||
| @@ -21,6 +21,7 @@ use crate::model::user::{User, UserWithRoles}; | |||||||
|  |  | ||||||
| pub(crate) mod admin; | pub(crate) mod admin; | ||||||
| mod auth; | mod auth; | ||||||
|  | pub(crate) mod board; | ||||||
| mod boatdamage; | mod boatdamage; | ||||||
| mod cox; | mod cox; | ||||||
| mod ergo; | mod ergo; | ||||||
| @@ -89,6 +90,7 @@ pub fn config(rocket: Rocket<Build>) -> Rocket<Build> { | |||||||
|         .mount("/boatdamage", boatdamage::routes()) |         .mount("/boatdamage", boatdamage::routes()) | ||||||
|         .mount("/cox", cox::routes()) |         .mount("/cox", cox::routes()) | ||||||
|         .mount("/admin", admin::routes()) |         .mount("/admin", admin::routes()) | ||||||
|  |         .mount("/board", board::routes()) | ||||||
|         .mount("/", misc::routes()) |         .mount("/", misc::routes()) | ||||||
|         .mount("/public", FileServer::from("static/")) |         .mount("/public", FileServer::from("static/")) | ||||||
|         .register("/", catchers![unauthorized_error, forbidden_error]) |         .register("/", catchers![unauthorized_error, forbidden_error]) | ||||||
|   | |||||||
| @@ -0,0 +1,9 @@ | |||||||
|  | CREATE TABLE IF NOT EXISTS "boathouse" ( | ||||||
|  |     "id" INTEGER PRIMARY KEY AUTOINCREMENT, | ||||||
|  |     "boat_id" INTEGER NOT NULL REFERENCES boat(id), | ||||||
|  |     "aisle" TEXT NOT NULL CHECK (aisle in ('water', 'middle', 'mountain')), | ||||||
|  |     "side" TEXT NOT NULL CHECK(side IN ('mountain', 'water')), | ||||||
|  |     "level" INTEGER NOT NULL CHECK(level BETWEEN 0 AND 3), | ||||||
|  |     CONSTRAINT unq UNIQUE (aisle, side, level) -- only 1 boat allowed to rest at each space  | ||||||
|  | ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| {% import "includes/forms/boat" as boat %} | {% import "includes/forms/boat" as boat %} | ||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         <h1 class="h1">Boats</h1> |         <h1 class="h1">Boats</h1> | ||||||
|         {{ boat::new() }} |         {{ boat::new() }} | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| {% import "includes/macros" as macros %} | {% import "includes/macros" as macros %} | ||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         <h1 class="h1">List</h1> |         <h1 class="h1">List</h1> | ||||||
|         <form action="/admin/list" method="post"> |         <form action="/admin/list" method="post"> | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| {% import "includes/macros" as macros %} | {% import "includes/macros" as macros %} | ||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         <h1 class="h1">List - Result</h1> |         <h1 class="h1">List - Result</h1> | ||||||
|         <ol> |         <ol> | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| {% import "includes/forms/boat" as boat %} | {% import "includes/forms/boat" as boat %} | ||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         <h1 class="h1">Mail</h1> |         <h1 class="h1">Mail</h1> | ||||||
|         <form action="/admin/mail" method="post" enctype="multipart/form-data"> |         <form action="/admin/mail" method="post" enctype="multipart/form-data"> | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|         <h1 class="h1">Schnupper Verwaltung</h1> |         <h1 class="h1">Schnupper Verwaltung</h1> | ||||||
|         <div class="grid gap-3"> |         <div class="grid gap-3"> | ||||||
|             <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5" |             <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5" | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="max-w-screen-lg w-full bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"> |     <div class="max-w-screen-lg w-full bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"> | ||||||
|         {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|         <h1 class="h1">Gebühren</h1> |         <h1 class="h1">Gebühren</h1> | ||||||
|         <!-- START filterBar --> |         <!-- START filterBar --> | ||||||
|         <div class="search-wrapper"> |         <div class="search-wrapper"> | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|         <h1 class="h1">Users</h1> |         <h1 class="h1">Users</h1> | ||||||
|         {% if allowed_to_edit %} |         {% if allowed_to_edit %} | ||||||
|             <form action="/admin/user/new" |             <form action="/admin/user/new" | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ | |||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="max-w-screen-lg w-full bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"> |     <div class="max-w-screen-lg w-full bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"> | ||||||
|         {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|         <h1 class="h1">Scheckbücher</h1> |         <h1 class="h1">Scheckbücher</h1> | ||||||
|         <!-- START filterBar --> |         <!-- START filterBar --> | ||||||
|         <div class="search-wrapper"> |         <div class="search-wrapper"> | ||||||
|   | |||||||
| @@ -25,7 +25,12 @@ | |||||||
|                 </div> |                 </div> | ||||||
|             </header> |             </header> | ||||||
|         {% endif %} |         {% endif %} | ||||||
|         <div class="flex min-h-screen {% if not loggedin_user and not show_kiosk_header %} items-center dark:bg-primary-900 {% else %} items-start {% endif %} justify-center px-4 py-12 sm:px-6 lg:px-8"> |         <div class="flex flex-wrap min-h-screen {% if not loggedin_user and not show_kiosk_header %} items-center dark:bg-primary-900 {% else %} items-start {% endif %} justify-center px-4 py-12 sm:px-6 lg:px-8"> | ||||||
|  |             {% if flash and loggedin_user %} | ||||||
|  |                 <div class="max-w-screen-lg w-full mb-3"> | ||||||
|  |                     {{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }} | ||||||
|  |                 </div> | ||||||
|  |             {% endif %} | ||||||
|             {% block content %} |             {% block content %} | ||||||
|             {% endblock content %} |             {% endblock content %} | ||||||
|         </div> |         </div> | ||||||
|   | |||||||
							
								
								
									
										54
									
								
								templates/board/boathouse.html.tera
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								templates/board/boathouse.html.tera
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | {% import "includes/macros" as macros %} | ||||||
|  | {% import "includes/forms/log" as log %} | ||||||
|  | {% import "includes/forms/boat" as boat %} | ||||||
|  | {% extends "base" %} | ||||||
|  | {% macro show_place(aisle_name, side_name, level) %} | ||||||
|  |     <li class="truncate p-2 flex relative w-full"> | ||||||
|  |         {% set aisle = aisle_name ~ "-aisle" %} | ||||||
|  |         {% set place = boathouse[aisle][side_name] %} | ||||||
|  |         {% if place[level] %} | ||||||
|  |             {{ place[level].1.name }} <a class="btn btn-primary absolute end-0" href="/board/boathouse/{{ place[level].0 }}/delete">X</a> | ||||||
|  |         {% elif boats | length > 0 %} | ||||||
|  |             <details> | ||||||
|  |                 <summary>Kein Boot</summary> | ||||||
|  |                 <form action="/board/boathouse" method="post" class="grid gap-3"> | ||||||
|  |                     {{ macros::select(label="Boot", data=boats, name="boat_id", id="boat_id", display=["name", " (","amount_seats", " x)"], wrapper_class="col-span-4") }} | ||||||
|  |                     <input type="hidden" name="aisle" value="{{ aisle_name }}" /> | ||||||
|  |                     <input type="hidden" name="side" value="{{ side_name }}" /> | ||||||
|  |                     <input type="hidden" name="level" value="{{ level }}" /> | ||||||
|  |                     <input type="submit" | ||||||
|  |                            class="btn btn-primary w-full col-span-4" | ||||||
|  |                            value="Boot eintragen" /> | ||||||
|  |                 </form> | ||||||
|  |             </details> | ||||||
|  |         {% else %} | ||||||
|  |             Kein Boot | ||||||
|  |         {% endif %} | ||||||
|  |     </li> | ||||||
|  | {% endmacro show_place %} | ||||||
|  | {% macro show_side(aisle_name, side_name) %} | ||||||
|  |     <div class="{{ side_name }}-side"> | ||||||
|  |         <ol> | ||||||
|  |             {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 0) }} | ||||||
|  |             {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 1) }} | ||||||
|  |             {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 2) }} | ||||||
|  |             {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 3) }} | ||||||
|  |         </ol> | ||||||
|  |     </div> | ||||||
|  | {% endmacro show_side %} | ||||||
|  | {% macro show_aisle(name, last=false) %} | ||||||
|  |     <div id="{{ name }}-aisle" class="grid grid-cols-2 gap-4 {% if not last %}md:border-r{% endif %}"> | ||||||
|  |         {{ self::show_side(aisle_name = name, side_name = "mountain") }} | ||||||
|  |         {{ self::show_side(aisle_name = name, side_name = "water") }} | ||||||
|  |     </div> | ||||||
|  | {% endmacro show_aisle %} | ||||||
|  | {% block content %} | ||||||
|  |     <div class="max-w-screen-lg w-full dark:text-white"> | ||||||
|  |         <h1 class="h1">Bootshaus</h1> | ||||||
|  |         <div class="grid md:grid-cols-3 gap-4"> | ||||||
|  |             {{ self::show_aisle(name = "mountain") }} | ||||||
|  |             {{ self::show_aisle(name = "middle") }} | ||||||
|  |             {{ self::show_aisle(name = "water", last = true) }} | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | {% endblock content %} | ||||||
| @@ -4,7 +4,6 @@ | |||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         <h1 class="h1">Bootschäden</h1> |         <h1 class="h1">Bootschäden</h1> | ||||||
|         {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3 mt-3") }}{% endif %} |  | ||||||
|         <h2 class="text-md font-bold tracking-wide bg-primary-900 mt-3 p-3 text-white flex justify-between items-center rounded-md"> |         <h2 class="text-md font-bold tracking-wide bg-primary-900 mt-3 p-3 text-white flex justify-between items-center rounded-md"> | ||||||
|             Neuen Schaden |             Neuen Schaden | ||||||
|             <a href="#" |             <a href="#" | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|         <h1 class="h1">Aktuelle Woche</h1> |         <h1 class="h1">Aktuelle Woche</h1> | ||||||
|         <details> |         <details> | ||||||
|             <summary>Dirty Thirty</summary> |             <summary>Dirty Thirty</summary> | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ | |||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         <h1 class="h1">Ergo Challenges</h1> |         <h1 class="h1">Ergo Challenges</h1> | ||||||
|         {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="my-3") }}{% endif %} |  | ||||||
|         <div class="grid gap-3"> |         <div class="grid gap-3"> | ||||||
|             <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5" |             <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5" | ||||||
|                  role="alert"> |                  role="alert"> | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="max-w-screen-lg w-full"> |     <div class="max-w-screen-lg w-full"> | ||||||
|         {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|         <h1 class="h1">Ruderassistent</h1> |         <h1 class="h1">Ruderassistent</h1> | ||||||
|         <div class="grid gap-3"> |         <div class="grid gap-3"> | ||||||
|             <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5" |             <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5" | ||||||
| @@ -110,6 +109,9 @@ | |||||||
|                             <li class="py-1"> |                             <li class="py-1"> | ||||||
|                                 <a href="/admin/user" class="link-primary">User</a> |                                 <a href="/admin/user" class="link-primary">User</a> | ||||||
|                             </li> |                             </li> | ||||||
|  |                             <li class="py-1"> | ||||||
|  |                                 <a href="/board/boathouse" class="link-primary">Bootshaus</a> | ||||||
|  |                             </li> | ||||||
|                         </ul> |                         </ul> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="w-full"> |     <div class="w-full"> | ||||||
|         <h1 class="h1">Logbuch</h1> |         <h1 class="h1">Logbuch</h1> | ||||||
|         {% if flash %} |         {% if flash and not loggedin_user %} | ||||||
|             <div class="pt-3 max-w-lg m-auto"> |             <div class="pt-3 max-w-lg m-auto"> | ||||||
|                 {{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }} |                 {{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }} | ||||||
|             </div> |             </div> | ||||||
|   | |||||||
| @@ -4,9 +4,6 @@ | |||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="w-full"> |     <div class="w-full"> | ||||||
|         <h1 class="h1">Logbuch</h1> |         <h1 class="h1">Logbuch</h1> | ||||||
|         {% if flash %} |  | ||||||
|             <div class="w-full">{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}</div> |  | ||||||
|         {% endif %} |  | ||||||
|         <div class="w-full grid md:grid-cols-5 gap-3 mt-5"> |         <div class="w-full grid md:grid-cols-5 gap-3 mt-5"> | ||||||
|             <div class="bg-white dark:bg-primary-900 rounded-md hidden md:block shadow"> |             <div class="bg-white dark:bg-primary-900 rounded-md hidden md:block shadow"> | ||||||
|                 <h2 class="h2">Boote</h2> |                 <h2 class="h2">Boote</h2> | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ | |||||||
| {% extends "base" %} | {% extends "base" %} | ||||||
| {% block content %} | {% block content %} | ||||||
|     <div class="max-w-screen-xl w-full grid sm:grid-cols-2 lg:grid-cols-3 gap-4"> |     <div class="max-w-screen-xl w-full grid sm:grid-cols-2 lg:grid-cols-3 gap-4"> | ||||||
|         {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} |  | ||||||
|         {% if "scheckbuch" in loggedin_user.roles %} |         {% if "scheckbuch" in loggedin_user.roles %} | ||||||
|             <div class="grid gap-3 sm:col-span-2 lg:col-span-3"> |             <div class="grid gap-3 sm:col-span-2 lg:col-span-3"> | ||||||
|                 <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5" |                 <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user