use crate::{ components::avatar_event_bus::{AvatarEventBus, Response}, infra::common_component::{CommonComponent, CommonComponentParts}, }; use anyhow::{bail, Result}; use graphql_client::GraphQLQuery; use serde::{Deserialize, Serialize}; use yew::prelude::*; use yew_agent::{Bridge, Bridged}; #[derive(GraphQLQuery)] #[graphql( schema_path = "../schema.graphql", query_path = "queries/get_user_avatar.graphql", response_derives = "Debug", custom_scalars_module = "crate::infra::graphql" )] pub struct GetUserAvatar; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct AvatarData(String); impl AvatarData { pub fn new(data: String) -> Self { AvatarData(data) } } pub struct Avatar { common: CommonComponentParts, avatar: Option, _producer: Box>, } /// 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. UserAvatarResponse(Result), Update(Response), } #[derive(yew::Properties, Clone, PartialEq, Eq)] pub struct Props { pub username: String, pub width: i32, pub height: i32, } impl CommonComponent for Avatar { fn handle_msg( &mut self, ctx: &Context, msg: ::Message, ) -> Result { match msg { Msg::UserAvatarResponse(response) => match response { Ok(user) => self.avatar = user.user.avatar.map(AvatarData::new), Err(e) => { self.avatar = None; bail!("Error getting user avatar: {}", e); } }, Msg::Update(Response::Update((username, avatar))) => { if username == ctx.props().username { self.avatar = avatar; return Ok(true); } return Ok(false); } } Ok(true) } fn mut_common(&mut self) -> &mut CommonComponentParts { &mut self.common } } impl Avatar { fn get_user_avatar(&mut self, ctx: &Context) { self.common.call_graphql::( ctx, get_user_avatar::Variables { id: ctx.props().username.clone(), }, Msg::UserAvatarResponse, "Error trying to fetch user avatar", ) } } impl Component for Avatar { type Message = Msg; type Properties = Props; fn create(ctx: &Context) -> Self { let mut avatar = Self { common: CommonComponentParts::::create(), avatar: None, _producer: AvatarEventBus::bridge(ctx.link().callback(Msg::Update)), }; avatar.get_user_avatar(ctx); avatar } fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { CommonComponentParts::::update(self, ctx, msg) } fn view(&self, ctx: &Context) -> Html { match &self.avatar { Some(avatar) => html! { Avatar }, None => html! { }, } } }