use crate::{ components::{ add_group_member::{self, AddGroupMemberComponent}, remove_user_from_group::RemoveUserFromGroupComponent, router::{AppRoute, Link}, }, 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_group_details.graphql", response_derives = "Debug, Hash, PartialEq, Eq, Clone", custom_scalars_module = "crate::infra::graphql" )] pub struct GetGroupDetails; pub type Group = get_group_details::GetGroupDetailsGroup; pub type User = get_group_details::GetGroupDetailsGroupUsers; pub type AddGroupMemberUser = add_group_member::User; pub struct GroupDetails { common: CommonComponentParts, /// The group info. If none, the error is in `error`. If `error` is None, then we haven't /// received the server response yet. group: 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 group details response, either the group data or an error. GroupDetailsResponse(Result), OnError(Error), OnUserAddedToGroup(AddGroupMemberUser), OnUserRemovedFromGroup((String, i64)), } #[derive(yew::Properties, Clone, PartialEq)] pub struct Props { pub group_id: i64, } impl GroupDetails { fn get_group_details(&mut self) { self.common.call_graphql::( get_group_details::Variables { id: self.common.group_id, }, Msg::GroupDetailsResponse, "Error trying to fetch group details", ); } fn view_messages(&self, error: &Option) -> Html { if let Some(e) = error { html! {
{"Error: "}{e.to_string()}
} } else { html! {} } } fn view_user_list(&self, g: &Group) -> Html { let make_user_row = |user: &User| { let user_id = user.id.clone(); let display_name = user.display_name.clone(); html! { {user_id.clone()} {display_name} } }; html! { <>

{g.display_name.to_string()}

{"Members"}
{if g.users.is_empty() { html! { } } else { html! {<>{g.users.iter().map(make_user_row).collect::>()}} }}
{"User Id"} {"Display name"}
{"No members"}
} } fn view_add_user_button(&self, g: &Group) -> Html { let users: Vec<_> = g .users .iter() .map(|u| AddGroupMemberUser { id: u.id.clone(), display_name: u.display_name.clone(), }) .collect(); html! { } } } impl CommonComponent for GroupDetails { fn handle_msg(&mut self, msg: ::Message) -> Result { match msg { Msg::GroupDetailsResponse(response) => match response { Ok(group) => self.group = Some(group.group), Err(e) => { self.group = None; bail!("Error getting user details: {}", e); } }, Msg::OnError(e) => return Err(e), Msg::OnUserAddedToGroup(user) => { self.group.as_mut().unwrap().users.push(User { id: user.id, display_name: user.display_name, }); } Msg::OnUserRemovedFromGroup((user_id, _)) => { self.group .as_mut() .unwrap() .users .retain(|u| u.id != user_id); } } Ok(true) } fn mut_common(&mut self) -> &mut CommonComponentParts { &mut self.common } } impl Component for GroupDetails { type Message = Msg; type Properties = Props; fn create(props: Self::Properties, link: ComponentLink) -> Self { let mut table = Self { common: CommonComponentParts::::create(props, link), group: None, }; table.get_group_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.group, &self.common.error) { (None, None) => html! {{"Loading..."}}, (None, Some(e)) => html! {
{"Error: "}{e.to_string()}
}, (Some(u), error) => { html! {
{self.view_user_list(u)} {self.view_add_user_button(u)} {self.view_messages(error)}
} } } } }