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;
|
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 {
|
.toggle:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
|
@ -4,6 +4,7 @@ use crate::util::model::{session::Session, user::User};
|
|||||||
|
|
||||||
pub fn Users() -> Element {
|
pub fn Users() -> Element {
|
||||||
let users = use_resource(fetch_users);
|
let users = use_resource(fetch_users);
|
||||||
|
let modal_user: Signal<Option<User>> = use_signal(|| None);
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
@ -23,7 +24,7 @@ pub fn Users() -> Element {
|
|||||||
}
|
}
|
||||||
tbody {
|
tbody {
|
||||||
for user in res {
|
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" } },
|
Some(Err(_)) => rsx! { div { "Error while loading users" } },
|
||||||
None => rsx! { div { "Loading..." } },
|
None => rsx! { div { "Loading..." } },
|
||||||
}
|
}
|
||||||
|
UserModal { user: modal_user }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Props, Clone, PartialEq)]
|
#[component]
|
||||||
struct UserRowProps {
|
fn UserRow(user: User, modal_user: Signal<Option<User>>) -> Element {
|
||||||
user: User,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn UserRow(props: UserRowProps) -> Element {
|
|
||||||
rsx! {
|
rsx! {
|
||||||
tr {
|
tr {
|
||||||
class: "hover hover:cursor-pointer",
|
class: "hover hover:cursor-pointer",
|
||||||
th { "{props.user.id}" }
|
onclick: move |_| {
|
||||||
td { "{props.user.email}" }
|
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]
|
#[server]
|
||||||
async fn fetch_users() -> Result<Vec<User>, ServerFnError> {
|
async fn fetch_users() -> Result<Vec<User>, ServerFnError> {
|
||||||
let user = Session::fetch_current_user().await?;
|
let user = Session::fetch_current_user().await?;
|
||||||
@ -63,3 +175,16 @@ async fn fetch_users() -> Result<Vec<User>, ServerFnError> {
|
|||||||
|
|
||||||
Ok(users)
|
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(())
|
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