Added the ability to edit user
This commit is contained in:
parent
45c5eb0020
commit
5c30804553
@ -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;
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user