Added the ability to edit user

This commit is contained in:
xeovalyte 2024-11-07 16:19:19 +01:00
parent 45c5eb0020
commit 5c30804553
Signed by: xeovalyte
SSH Key Fingerprint: SHA256:kSQDrQDmKzljJzfGYcd3m9RqHi4h8rSwkZ3sQ9kBURo
3 changed files with 160 additions and 9 deletions

View File

@ -2840,6 +2840,20 @@ details.collapse summary::-webkit-details-marker {
0 0 0 2px var(--tglbg) inset;
}
.toggle-primary:focus-visible {
outline-color: var(--fallback-p,oklch(var(--p)/1));
}
.toggle-primary:checked,
.toggle-primary[aria-checked="true"] {
border-color: var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity)));
--tw-border-opacity: 0.1;
--tw-bg-opacity: 1;
background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));
--tw-text-opacity: 1;
color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)));
}
.toggle:disabled {
cursor: not-allowed;
--tw-border-opacity: 1;

View File

@ -4,6 +4,7 @@ use crate::util::model::{session::Session, user::User};
pub fn Users() -> Element {
let users = use_resource(fetch_users);
let modal_user: Signal<Option<User>> = use_signal(|| None);
rsx! {
div {
@ -23,7 +24,7 @@ pub fn Users() -> Element {
}
tbody {
for user in res {
UserRow { user: user.clone() }
UserRow { user: user.clone(), modal_user: modal_user }
}
}
}
@ -32,25 +33,136 @@ pub fn Users() -> Element {
Some(Err(_)) => rsx! { div { "Error while loading users" } },
None => rsx! { div { "Loading..." } },
}
UserModal { user: modal_user }
}
}
}
#[derive(Props, Clone, PartialEq)]
struct UserRowProps {
user: User,
}
fn UserRow(props: UserRowProps) -> Element {
#[component]
fn UserRow(user: User, modal_user: Signal<Option<User>>) -> Element {
rsx! {
tr {
class: "hover hover:cursor-pointer",
th { "{props.user.id}" }
td { "{props.user.email}" }
onclick: move |_| {
modal_user.set(Some(user.to_owned()))
},
th { "{user.id}" }
td { "{user.email}" }
}
}
}
#[component]
fn UserModal(user: Signal<Option<User>>) -> Element {
let mut loading = use_signal(|| false);
let mut user_admin = use_signal(|| false);
use_effect(move || {
if let Some(u) = user() {
user_admin.set(u.admin);
}
});
let submit = move |_| async move {
loading.set(true);
if let Some(u) = user() {
if let Ok(_res) = update_user(u.id, user_admin()).await {};
};
loading.set(false);
user.set(None)
};
rsx! {
dialog {
class: "modal modal-bottom sm:modal-middle z-50",
open: user().is_some(),
div {
class: "modal-box",
h3 { class: "text-lg font-bold", "Gebruiker bewerken" },
if let Some(u) = user() {
UserView { user: u, admin: user_admin }
} else {
"Geen gebruiker geselecteerd"
}
div {
class: "modal-action",
button {
class: "btn",
onclick: move |_| user.set(None),
disabled: loading(),
if loading() {
span { class: "loading loading-spinner" }
},
"Annuleren"
}
button {
class: "btn btn-primary",
onclick: submit,
disabled: loading(),
if loading() {
span { class: "loading loading-spinner" }
},
"Bewerken"
}
}
}
label {
class: "modal-backdrop bg-black/50",
onclick: move |_| user.set(None)
}
}
}
}
#[component]
fn UserView(user: User, admin: Signal<bool>) -> Element {
rsx! {
div {
div {
class: "grid gap-3",
label {
class: "form-control w-full",
div {
class: "label",
span { class: "label-text", "Id" }
}
b { class: "select-all", "{user.id}" },
}
label {
class: "form-control w-full",
div {
class: "label",
span { class: "label-text", "Email" }
}
b { class: "select-all", "{user.email}" },
}
}
div {
class: "mt-5",
label {
class: "form-control",
label {
class: "label cursor-pointer justify-start gap-2",
input {
r#type: "checkbox",
class: "toggle toggle-primary",
checked: admin(),
oninput: move |event| {
if event.value() == "true".to_string() {
admin.set(true);
} else {
admin.set(false);
}
}
},
span { class: "label-text", "Admin" },
}
}
}
}
}
}
#[server]
async fn fetch_users() -> Result<Vec<User>, ServerFnError> {
let user = Session::fetch_current_user().await?;
@ -63,3 +175,16 @@ async fn fetch_users() -> Result<Vec<User>, ServerFnError> {
Ok(users)
}
#[server]
async fn update_user(id: String, admin: bool) -> Result<(), ServerFnError> {
let user = Session::fetch_current_user().await?;
if !user.admin {
return Err(crate::Error::NoPermissions.into());
}
User::update_with_id(&id, admin).await?;
Ok(())
}

View File

@ -162,4 +162,16 @@ impl User {
Ok(())
}
pub async fn update_with_id(id: &str, admin: bool) -> Result<(), crate::Error> {
let res = DB
.query("UPDATE $user SET admin = $admin;")
.bind(("user", Thing::from(("user", id))))
.bind(("admin", admin))
.await?;
res.check()?;
Ok(())
}
}