2 Commits
Author SHA1 Message Date
schn33fuchs 7bde1470a1 Logout button
And styling for it
2026-05-04 16:45:52 +02:00
schn33fuchs 331552b656 Some bugfixes 2026-05-04 16:45:39 +02:00
5 changed files with 57 additions and 5 deletions
+1 -1
View File
@@ -265,7 +265,7 @@ pub async fn update_user(
.bind(body.first_name.to_owned()) .bind(body.first_name.to_owned())
.bind(body.last_name.to_owned()) .bind(body.last_name.to_owned())
.bind(body.username.to_owned()) .bind(body.username.to_owned())
.bind(hashed_pwd) .bind(&hashed_pwd)
.bind(body.make_admin.to_owned()) .bind(body.make_admin.to_owned())
.bind(id) .bind(id)
.execute(&data.db) .execute(&data.db)
+1 -1
View File
@@ -27,7 +27,6 @@ pub fn create_router(state: Arc<AppState>) -> Router {
) )
.route("/api/register", post(create_user)) .route("/api/register", post(create_user))
.route("/api/users", get(get_users)) .route("/api/users", get(get_users))
.route("/api/users/current", get(get_current_user))
.route( .route(
"/api/users/{id}", "/api/users/{id}",
get(get_user_by_id).delete(delete_user).patch(update_user), get(get_user_by_id).delete(delete_user).patch(update_user),
@@ -42,6 +41,7 @@ pub fn create_router(state: Arc<AppState>) -> Router {
.route("/api/tickets", get(get_tickets)) .route("/api/tickets", get(get_tickets))
.route("/api/tickets/create", post(create_ticket)) .route("/api/tickets/create", post(create_ticket))
.route("/api/logout", get(logout)) .route("/api/logout", get(logout))
.route("/api/users/current", get(get_current_user))
.layer(middleware::from_fn_with_state( .layer(middleware::from_fn_with_state(
state.clone(), state.clone(),
validate_token, validate_token,
+1 -1
View File
@@ -1,6 +1,6 @@
[serve] [serve]
# The address to serve on LAN. # The address to serve on LAN.
addresses = ["127.0.0.1"] addresses = ["127.0.0.1"] #,"10.150.9.7"]
# The address to serve on WAN. # The address to serve on WAN.
# address = "0.0.0.0" # address = "0.0.0.0"
# The port to serve on. # The port to serve on.
+31
View File
@@ -215,6 +215,7 @@ pub fn users_menu() -> Html {
#[component(Sidebar)] #[component(Sidebar)]
pub fn sidebar() -> Html { pub fn sidebar() -> Html {
let is_admin = use_state(|| None::<bool>); let is_admin = use_state(|| None::<bool>);
let navigator = use_navigator().expect("Sidebar must be used within a Router");
{ {
let is_admin = is_admin.clone(); let is_admin = is_admin.clone();
@@ -238,6 +239,20 @@ pub fn sidebar() -> Html {
}); });
} }
let on_logout = {
let navigator = navigator.clone();
Callback::from(move |_| {
let navigator = navigator.clone();
spawn_local(async move {
let _ = Request::get("/api/logout")
.credentials(web_sys::RequestCredentials::Include)
.send()
.await;
navigator.push(&crate::Route::Login);
});
})
};
match *is_admin { match *is_admin {
None => html! { <div class="sidebar-loading">{ "Loading..." }</div> }, None => html! { <div class="sidebar-loading">{ "Loading..." }</div> },
@@ -247,6 +262,14 @@ pub fn sidebar() -> Html {
<nav class="sidebar user"> <nav class="sidebar user">
<ul> <ul>
<TicketMenu/> <TicketMenu/>
<li class="logout-item">
<button
class="logout-button"
onclick={on_logout.clone()}
>
{ "Logout" }
</button>
</li>
</ul> </ul>
</nav> </nav>
</SidebarStateProvider> </SidebarStateProvider>
@@ -260,6 +283,14 @@ pub fn sidebar() -> Html {
<TicketMenu/> <TicketMenu/>
<UsersMenu/> <UsersMenu/>
<Link<crate::Route> to={crate::Route::Diagnostics}>{ "Statistiken" }</Link<crate::Route>> <Link<crate::Route> to={crate::Route::Diagnostics}>{ "Statistiken" }</Link<crate::Route>>
<li class="logout-item">
<button
class="logout-button"
onclick={on_logout.clone()}
>
{ "Logout" }
</button>
</li>
</ul> </ul>
</nav> </nav>
</SidebarStateProvider> </SidebarStateProvider>
+23 -2
View File
@@ -5,10 +5,12 @@
width: 260px; width: 260px;
background: $color-sidebar; background: $color-sidebar;
color: #fff; color: #fff;
min-height: 100vh; min-height: 100%;
padding: $spacing-md; padding: $spacing-md;
display: flex;
flex-direction: column;
ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: $spacing-sm; } ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: $spacing-sm; flex: 1; }
a, .menu-toggle { a, .menu-toggle {
color: #fff; color: #fff;
@@ -29,6 +31,25 @@
li { padding: 4px 0; } li { padding: 4px 0; }
} }
.logout-item {
margin-top: auto;
border-top: 1px solid rgba(255,255,255,0.1);
padding-top: $spacing-sm;
}
.logout-button {
background: rgba(255,255,255,0.1);
color: #fff;
border: 1px solid rgba(255,255,255,0.2);
padding: 8px 12px;
border-radius: 4px;
width: 100%;
cursor: pointer;
text-align: left;
&:hover { background: rgba(255,255,255,0.15); }
&:active { background: rgba(255,255,255,0.2); }
}
&.user { width: 220px; background: darken($color-sidebar, 6%); } &.user { width: 220px; background: darken($color-sidebar, 6%); }
} }