use crate::{ components::{ add_user_to_group::AddUserToGroupComponent, remove_user_from_group::RemoveUserFromGroupComponent, router::{AppRoute, Link}, 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, Eq)] pub struct Props { pub username: String, pub is_admin: bool, } impl CommonComponent for UserDetails { fn handle_msg(&mut self, _: &Context, 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, ctx: &Context) { self.common.call_graphql::( ctx, get_user_details::Variables { id: ctx.props().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, ctx: &Context, u: &User) -> Html { let link = &ctx.link(); let make_group_row = |group: &Group| { let display_name = group.display_name.clone(); html! { {if ctx.props().is_admin { html! { <> {&group.display_name} } } else { html! { {&group.display_name} } } } } }; html! { <>
{"Group memberships"}
{ if ctx.props().is_admin { html!{ }} else { html!{} }} {if u.groups.is_empty() { html! { } } else { html! {<>{u.groups.iter().map(make_group_row).collect::>()}} }}
{"Group"}
{"This user is not a member of any groups."}
} } fn view_add_group_button(&self, ctx: &Context, u: &User) -> Html { let link = &ctx.link(); if ctx.props().is_admin { html! { } } else { html! {} } } } impl Component for UserDetails { type Message = Msg; type Properties = Props; fn create(ctx: &Context) -> Self { let mut table = Self { common: CommonComponentParts::::create(), user: None, }; table.get_user_details(ctx); table } fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { CommonComponentParts::::update(self, ctx, msg) } fn view(&self, ctx: &Context) -> 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()}

{"Modify password"}
{"User details"}
{self.view_group_memberships(ctx, u)} {self.view_add_group_button(ctx, u)} {self.view_messages(error)} } } } } }