use crate::{ components::{ add_user_to_group::AddUserToGroupComponent, remove_user_from_group::RemoveUserFromGroupComponent, router::{AppRoute, Link, NavButton}, user_details_form::UserDetailsForm, }, infra::common_component::{CommonComponent, CommonComponentParts}, }; use anyhow::{bail, Error, Result}; use graphql_client::GraphQLQuery; use yew::prelude::*; #[derive(GraphQLQuery)] #[graphql( schema_path = "../schema.graphql", query_path = "queries/get_user_details.graphql", response_derives = "Debug, Hash, PartialEq, Eq, Clone", custom_scalars_module = "crate::infra::graphql" )] pub struct GetUserDetails; pub type User = get_user_details::GetUserDetailsUser; pub type Group = get_user_details::GetUserDetailsUserGroups; pub struct UserDetails { common: CommonComponentParts, /// The user info. If none, the error is in `error`. If `error` is None, then we haven't /// received the server response yet. user: Option, } /// State machine describing the possible transitions of the component state. /// It starts out by fetching the user's details from the backend when loading. pub enum Msg { /// Received the user details response, either the user data or an error. UserDetailsResponse(Result), OnError(Error), OnUserAddedToGroup(Group), OnUserRemovedFromGroup((String, i64)), } #[derive(yew::Properties, Clone, PartialEq)] pub struct Props { pub username: String, pub is_admin: bool, } impl CommonComponent for UserDetails { fn handle_msg(&mut self, msg: ::Message) -> Result { match msg { Msg::UserDetailsResponse(response) => match response { Ok(user) => self.user = Some(user.user), Err(e) => { self.user = None; bail!("Error getting user details: {}", e); } }, Msg::OnError(e) => return Err(e), Msg::OnUserAddedToGroup(group) => { self.user.as_mut().unwrap().groups.push(group); } Msg::OnUserRemovedFromGroup((_, group_id)) => { self.user .as_mut() .unwrap() .groups .retain(|g| g.id != group_id); } } Ok(true) } fn mut_common(&mut self) -> &mut CommonComponentParts { &mut self.common } } impl UserDetails { fn get_user_details(&mut self) { self.common.call_graphql::( get_user_details::Variables { id: self.common.username.clone(), }, Msg::UserDetailsResponse, "Error trying to fetch user details", ); } fn view_messages(&self, error: &Option) -> Html { if let Some(e) = error { html! {
{"Error: "}{e.to_string()}
} } else { html! {} } } fn view_group_memberships(&self, u: &User) -> Html { let make_group_row = |group: &Group| { let display_name = group.display_name.clone(); html! { {if self.common.is_admin { html! { <> {&group.display_name} } } else { html! { {&group.display_name} } } } } }; html! { <>
{"Group memberships"}
{ if self.common.is_admin { html!{ }} else { html!{} }} {if u.groups.is_empty() { html! { } } else { html! {<>{u.groups.iter().map(make_group_row).collect::>()}} }}
{"Group"}
{"Not member of any group"}
} } fn view_add_group_button(&self, u: &User) -> Html { if self.common.is_admin { html! { } } else { html! {} } } } impl Component for UserDetails { type Message = Msg; type Properties = Props; fn create(props: Self::Properties, link: ComponentLink) -> Self { let mut table = Self { common: CommonComponentParts::::create(props, link), user: None, }; table.get_user_details(); table } fn update(&mut self, msg: Self::Message) -> ShouldRender { CommonComponentParts::::update(self, msg) } fn change(&mut self, _: Self::Properties) -> ShouldRender { false } fn view(&self) -> Html { match (&self.user, &self.common.error) { (None, None) => html! {{"Loading..."}}, (None, Some(e)) => html! {
{"Error: "}{e.to_string()}
}, (Some(u), error) => { html! { <>

{u.id.to_string()}

{"Change password"}
{self.view_group_memberships(u)} {self.view_add_group_button(u)} {self.view_messages(error)} } } } } }