From 7c71ce59bd79633c217f6bb0ec9226b68ffc6ce6 Mon Sep 17 00:00:00 2001 From: philipp Date: Wed, 17 Apr 2024 13:51:47 +0200 Subject: [PATCH 01/12] show notification badge in menu --- src/model/user.rs | 17 +++++++++++++++-- src/tera/admin/boat.rs | 4 ++-- src/tera/admin/mail.rs | 4 ++-- src/tera/admin/notification.rs | 4 ++-- src/tera/admin/schnupper.rs | 8 ++++---- src/tera/admin/user.rs | 20 +++++++++++++------- src/tera/board/boathouse.rs | 4 ++-- src/tera/boatdamage.rs | 4 ++-- src/tera/boatreservation.rs | 4 ++-- src/tera/ergo.rs | 9 ++++++--- src/tera/log.rs | 10 ++++++---- src/tera/mod.rs | 12 +++++++++--- src/tera/planned.rs | 7 +++++-- src/tera/stat.rs | 6 +++--- templates/admin/mail.html.tera | 10 +++++----- templates/base.html.tera | 14 +++++++++++--- templates/includes/macros.html.tera | 12 ++++++++++++ 17 files changed, 101 insertions(+), 48 deletions(-) diff --git a/src/model/user.rs b/src/model/user.rs index 86e311a..83db24c 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -47,16 +47,18 @@ pub struct User { } #[derive(Debug, Serialize, Deserialize)] -pub struct UserWithRoles { +pub struct UserWithRolesAndNotificationCount { #[serde(flatten)] pub user: User, + pub amount_unread_notifications: i32, pub roles: Vec, } -impl UserWithRoles { +impl UserWithRolesAndNotificationCount { pub async fn from_user(user: User, db: &SqlitePool) -> Self { Self { roles: user.roles(db).await, + amount_unread_notifications: user.amount_unread_notifications(db).await, user, } } @@ -237,6 +239,17 @@ impl User { .count } + pub async fn amount_unread_notifications(&self, db: &SqlitePool) -> i32 { + sqlx::query!( + "SELECT COUNT(*) as count FROM notification WHERE user_id = ? AND read_at IS NULL", + self.id + ) + .fetch_one(db) + .await + .unwrap() + .count + } + pub async fn has_role(&self, db: &SqlitePool, role: &str) -> bool { if sqlx::query!( "SELECT * FROM user_role WHERE user_id=? AND role_id = (SELECT id FROM role WHERE name = ?)", diff --git a/src/tera/admin/boat.rs b/src/tera/admin/boat.rs index d8776f6..8af2cca 100644 --- a/src/tera/admin/boat.rs +++ b/src/tera/admin/boat.rs @@ -1,7 +1,7 @@ use crate::model::{ boat::{Boat, BoatToAdd, BoatToUpdate}, location::Location, - user::{AdminUser, User, UserWithRoles}, + user::{AdminUser, User, UserWithRolesAndNotificationCount}, }; use rocket::{ form::Form, @@ -32,7 +32,7 @@ async fn index( context.insert("users", &users); context.insert( "loggedin_user", - &UserWithRoles::from_user(admin.user, db).await, + &UserWithRolesAndNotificationCount::from_user(admin.user, db).await, ); Template::render("admin/boat/index", context.into_json()) diff --git a/src/tera/admin/mail.rs b/src/tera/admin/mail.rs index 2afcd3a..1f6f11c 100644 --- a/src/tera/admin/mail.rs +++ b/src/tera/admin/mail.rs @@ -10,7 +10,7 @@ use crate::model::log::Log; use crate::model::mail::Mail; use crate::model::role::Role; use crate::model::user::AdminUser; -use crate::model::user::UserWithRoles; +use crate::model::user::UserWithRolesAndNotificationCount; use crate::tera::Config; #[get("/mail")] @@ -27,7 +27,7 @@ async fn index( context.insert( "loggedin_user", - &UserWithRoles::from_user(admin.user, db).await, + &UserWithRolesAndNotificationCount::from_user(admin.user, db).await, ); context.insert("roles", &roles); diff --git a/src/tera/admin/notification.rs b/src/tera/admin/notification.rs index 2e36c51..0e7ab9a 100644 --- a/src/tera/admin/notification.rs +++ b/src/tera/admin/notification.rs @@ -2,7 +2,7 @@ use crate::model::{ log::Log, notification::Notification, role::Role, - user::{AdminUser, User, UserWithRoles}, + user::{AdminUser, User, UserWithRolesAndNotificationCount}, }; use rocket::{ form::Form, @@ -26,7 +26,7 @@ async fn index( } context.insert( "loggedin_user", - &UserWithRoles::from_user(user.user, db).await, + &UserWithRolesAndNotificationCount::from_user(user.user, db).await, ); context.insert("roles", &Role::all(db).await); diff --git a/src/tera/admin/schnupper.rs b/src/tera/admin/schnupper.rs index 41d536d..f08abb3 100644 --- a/src/tera/admin/schnupper.rs +++ b/src/tera/admin/schnupper.rs @@ -1,6 +1,6 @@ use crate::model::{ role::Role, - user::{SchnupperBetreuerUser, User, UserWithRoles}, + user::{SchnupperBetreuerUser, User, UserWithRolesAndNotificationCount}, }; use futures::future::join_all; use rocket::{ @@ -38,9 +38,9 @@ async fn index( let user_futures: Vec<_> = User::all_with_role(db, &schnupperant) .await .into_iter() - .map(|u| async move { UserWithRoles::from_user(u, db).await }) + .map(|u| async move { UserWithRolesAndNotificationCount::from_user(u, db).await }) .collect(); - let users: Vec = join_all(user_futures).await; + let users: Vec = join_all(user_futures).await; let mut context = Context::new(); if let Some(msg) = flash { @@ -49,7 +49,7 @@ async fn index( context.insert("schnupperanten", &users); context.insert( "loggedin_user", - &UserWithRoles::from_user(user.into(), db).await, + &UserWithRolesAndNotificationCount::from_user(user.into(), db).await, ); Template::render("admin/schnupper/index", context.into_json()) diff --git a/src/tera/admin/user.rs b/src/tera/admin/user.rs index 30c63b7..e5d9781 100644 --- a/src/tera/admin/user.rs +++ b/src/tera/admin/user.rs @@ -6,8 +6,8 @@ use crate::model::{ logbook::Logbook, role::Role, user::{ - AdminUser, User, UserWithMembershipPdf, UserWithRoles, UserWithRolesAndMembershipPdf, - VorstandUser, + AdminUser, User, UserWithMembershipPdf, UserWithRolesAndMembershipPdf, + UserWithRolesAndNotificationCount, VorstandUser, }, }; use futures::future::join_all; @@ -67,7 +67,10 @@ async fn index( context.insert("users", &users); context.insert("roles", &roles); context.insert("families", &families); - context.insert("loggedin_user", &UserWithRoles::from_user(user, db).await); + context.insert( + "loggedin_user", + &UserWithRolesAndNotificationCount::from_user(user, db).await, + ); Template::render("admin/user/index", context.into_json()) } @@ -99,7 +102,10 @@ async fn index_admin( context.insert("users", &users); context.insert("roles", &roles); context.insert("families", &families); - context.insert("loggedin_user", &UserWithRoles::from_user(user, db).await); + context.insert( + "loggedin_user", + &UserWithRolesAndNotificationCount::from_user(user, db).await, + ); Template::render("admin/user/index", context.into_json()) } @@ -127,7 +133,7 @@ async fn fees( } context.insert( "loggedin_user", - &UserWithRoles::from_user(admin.into(), db).await, + &UserWithRolesAndNotificationCount::from_user(admin.into(), db).await, ); Template::render("admin/user/fees", context.into_json()) @@ -147,7 +153,7 @@ async fn scheckbuch( for s in scheckbooks { scheckbooks_with_roles.push(( Logbook::completed_with_user(db, &s).await, - UserWithRoles::from_user(s, db).await, + UserWithRolesAndNotificationCount::from_user(s, db).await, )) } @@ -158,7 +164,7 @@ async fn scheckbuch( } context.insert( "loggedin_user", - &UserWithRoles::from_user(user.into(), db).await, + &UserWithRolesAndNotificationCount::from_user(user.into(), db).await, ); Template::render("admin/user/scheckbuch", context.into_json()) diff --git a/src/tera/board/boathouse.rs b/src/tera/board/boathouse.rs index 266f81a..fbaa16c 100644 --- a/src/tera/board/boathouse.rs +++ b/src/tera/board/boathouse.rs @@ -1,7 +1,7 @@ use crate::model::{ boat::Boat, boathouse::Boathouse, - user::{AdminUser, UserWithRoles, VorstandUser}, + user::{AdminUser, UserWithRolesAndNotificationCount, VorstandUser}, }; use rocket::{ form::Form, @@ -39,7 +39,7 @@ async fn index( context.insert( "loggedin_user", - &UserWithRoles::from_user(admin.into(), db).await, + &UserWithRolesAndNotificationCount::from_user(admin.into(), db).await, ); Template::render("board/boathouse", context.into_json()) diff --git a/src/tera/boatdamage.rs b/src/tera/boatdamage.rs index 39088af..0fca62b 100644 --- a/src/tera/boatdamage.rs +++ b/src/tera/boatdamage.rs @@ -13,7 +13,7 @@ use crate::{ model::{ boat::Boat, boatdamage::{BoatDamage, BoatDamageFixed, BoatDamageToAdd, BoatDamageVerified}, - user::{CoxUser, DonauLinzUser, TechUser, User, UserWithRoles}, + user::{CoxUser, DonauLinzUser, TechUser, User, UserWithRolesAndNotificationCount}, }, tera::log::KioskCookie, }; @@ -59,7 +59,7 @@ async fn index( context.insert("boats", &boats); context.insert( "loggedin_user", - &UserWithRoles::from_user(user.into(), db).await, + &UserWithRolesAndNotificationCount::from_user(user.into(), db).await, ); Template::render("boatdamages", context.into_json()) diff --git a/src/tera/boatreservation.rs b/src/tera/boatreservation.rs index 0cc5574..06d42b3 100644 --- a/src/tera/boatreservation.rs +++ b/src/tera/boatreservation.rs @@ -14,7 +14,7 @@ use crate::{ model::{ boat::Boat, boatreservation::{BoatReservation, BoatReservationToAdd}, - user::{DonauLinzUser, User, UserWithRoles}, + user::{DonauLinzUser, User, UserWithRolesAndNotificationCount}, }, tera::log::KioskCookie, }; @@ -74,7 +74,7 @@ async fn index( context.insert("user", &User::all(db).await); context.insert( "loggedin_user", - &UserWithRoles::from_user(user.into(), db).await, + &UserWithRolesAndNotificationCount::from_user(user.into(), db).await, ); Template::render("boatreservations", context.into_json()) diff --git a/src/tera/ergo.rs b/src/tera/ergo.rs index 8818d6b..c419781 100644 --- a/src/tera/ergo.rs +++ b/src/tera/ergo.rs @@ -18,7 +18,7 @@ use tera::Context; use crate::model::{ log::Log, - user::{AdminUser, User, UserWithRoles}, + user::{AdminUser, User, UserWithRolesAndNotificationCount}, }; #[derive(Serialize)] @@ -51,7 +51,7 @@ async fn send(db: &State, _user: AdminUser) -> Template { Template::render( "ergo.final", - context!(loggedin_user: &UserWithRoles::from_user(_user.user, db).await, thirty, dozen), + context!(loggedin_user: &UserWithRolesAndNotificationCount::from_user(_user.user, db).await, thirty, dozen), ) } @@ -120,7 +120,10 @@ async fn index(db: &State, user: User, flash: Option, user: DonauLinzUser) -> Template { Template::render( "log.completed", - context!(logs, loggedin_user: &UserWithRoles::from_user(user.into(), db).await), + context!(logs, loggedin_user: &UserWithRolesAndNotificationCount::from_user(user.into(), db).await), ) } @@ -108,7 +110,7 @@ async fn show_for_year(db: &State, user: AdminUser, year: i32) -> Te Template::render( "log.completed", - context!(logs, loggedin_user: &UserWithRoles::from_user(user.user, db).await), + context!(logs, loggedin_user: &UserWithRolesAndNotificationCount::from_user(user.user, db).await), ) } diff --git a/src/tera/mod.rs b/src/tera/mod.rs index 5f89c2b..fece01b 100644 --- a/src/tera/mod.rs +++ b/src/tera/mod.rs @@ -23,7 +23,7 @@ use tera::Context; use crate::model::{ notification::Notification, role::Role, - user::{User, UserWithRoles}, + user::{User, UserWithRolesAndNotificationCount}, }; pub(crate) mod admin; @@ -53,7 +53,10 @@ async fn index(db: &State, user: User, flash: Option, user: User, flash: Option, user: DonauLinzUser) -> Template { Template::render( "stat.boats", - context!(loggedin_user: &UserWithRoles::from_user(user.into(), db).await, stat, kiosk), + context!(loggedin_user: &UserWithRolesAndNotificationCount::from_user(user.into(), db).await, stat, kiosk), ) } @@ -38,7 +38,7 @@ async fn index(db: &State, user: DonauLinzUser, year: Option) - Template::render( "stat.people", - context!(loggedin_user: &UserWithRoles::from_user(user.into(), db).await, stat, personal, kiosk, guest_km, club_km), + context!(loggedin_user: &UserWithRolesAndNotificationCount::from_user(user.into(), db).await, stat, personal, kiosk, guest_km, club_km), ) } diff --git a/templates/admin/mail.html.tera b/templates/admin/mail.html.tera index 8f54cd1..6c97d4c 100644 --- a/templates/admin/mail.html.tera +++ b/templates/admin/mail.html.tera @@ -8,16 +8,16 @@
-- 2.45.2 From 42a3addd9a5d0f60263dc4f10a8ebca1dacedb7e Mon Sep 17 00:00:00 2001 From: philipp Date: Wed, 17 Apr 2024 13:57:24 +0200 Subject: [PATCH 02/12] make it more clear which action is required if notifications are present --- templates/index.html.tera | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/index.html.tera b/templates/index.html.tera index 8899e66..6392869 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -27,7 +27,7 @@
{% if not notification.read_at %} - -- 2.45.2 From 30756ad4aa844ce33923540e16c4251051c20af0 Mon Sep 17 00:00:00 2001 From: Marie Birner Date: Fri, 19 Apr 2024 11:09:31 +0200 Subject: [PATCH 03/12] [TASK] improve styling --- frontend/scss/app.scss | 1 + frontend/scss/components/_notification.scss | 5 ++++ templates/includes/macros.html.tera | 27 ++++++++++++--------- 3 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 frontend/scss/components/_notification.scss diff --git a/frontend/scss/app.scss b/frontend/scss/app.scss index 770dc11..02e94d7 100644 --- a/frontend/scss/app.scss +++ b/frontend/scss/app.scss @@ -13,3 +13,4 @@ @import 'components/search'; @import 'components/important'; @import 'components/searchable-table'; +@import 'components/notification'; diff --git a/frontend/scss/components/_notification.scss b/frontend/scss/components/_notification.scss new file mode 100644 index 0000000..0532299 --- /dev/null +++ b/frontend/scss/components/_notification.scss @@ -0,0 +1,5 @@ +.notification { + right: -.2rem; + top: -.1rem; + font-size: .5rem; +} diff --git a/templates/includes/macros.html.tera b/templates/includes/macros.html.tera index ba3c29c..30283e3 100644 --- a/templates/includes/macros.html.tera +++ b/templates/includes/macros.html.tera @@ -28,20 +28,25 @@
-- 2.45.2 From c528b8831ae92b9c82bb7def666ee83852b985d6 Mon Sep 17 00:00:00 2001 From: Marie Birner Date: Fri, 19 Apr 2024 11:25:25 +0200 Subject: [PATCH 04/12] [TASK] finalize notification styling --- templates/includes/macros.html.tera | 38 ++++++++++++++--------------- templates/index.html.tera | 10 ++++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/templates/includes/macros.html.tera b/templates/includes/macros.html.tera index 30283e3..59660f2 100644 --- a/templates/includes/macros.html.tera +++ b/templates/includes/macros.html.tera @@ -28,29 +28,29 @@
-
+
+ {% if loggedin_user.amount_unread_notifications > 0 %} + + + + {{ loggedin_user.amount_unread_notifications }} + + + {% endif %} -

Ruderassistent

+

Ruderassistent

-