Review feedback plus avatar rounding

This commit is contained in:
Austin 2023-03-23 19:29:46 +00:00
parent d60d869eba
commit d509dc82a0
4 changed files with 59 additions and 21 deletions

View File

@ -1,9 +1,11 @@
use crate::{
components::avatar_event_bus::AvatarEventBus,
infra::common_component::{CommonComponent, CommonComponentParts}};
components::avatar_event_bus::{AvatarEventBus, Response},
infra::common_component::{CommonComponent, CommonComponentParts},
};
use anyhow::{bail, Result};
use graphql_client::GraphQLQuery;
use yew::{prelude::*};
use serde::{Deserialize, Serialize};
use yew::prelude::*;
use yew_agent::{Bridge, Bridged};
#[derive(GraphQLQuery)]
@ -15,11 +17,18 @@ use yew_agent::{Bridge, Bridged};
)]
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<Self>,
/// The user info. If none, the error is in `error`. If `error` is None, then we haven't
/// received the server response yet.
avatar: Option<String>,
avatar: Option<AvatarData>,
_producer: Box<dyn Bridge<AvatarEventBus>>,
}
@ -28,7 +37,7 @@ pub struct Avatar {
pub enum Msg {
/// Received the user details response, either the user data or an error.
UserAvatarResponse(Result<get_user_avatar::ResponseData>),
Update
Update(Response),
}
#[derive(yew::Properties, Clone, PartialEq, Eq)]
@ -39,16 +48,26 @@ pub struct Props {
}
impl CommonComponent<Avatar> for Avatar {
fn handle_msg(&mut self, ctx: &Context<Self>, msg: <Self as Component>::Message) -> Result<bool> {
fn handle_msg(
&mut self,
ctx: &Context<Self>,
msg: <Self as Component>::Message,
) -> Result<bool> {
match msg {
Msg::UserAvatarResponse(response) => match response {
Ok(user) => self.avatar = user.user.avatar,
Ok(user) => self.avatar = user.user.avatar.map(AvatarData::new),
Err(e) => {
self.avatar = None;
bail!("Error getting user avatar: {}", e);
}
},
Msg::Update => self.get_user_avatar(ctx),
Msg::Update(Response::Update((username, avatar))) => {
if username == ctx.props().username {
self.avatar = avatar;
return Ok(true);
}
return Ok(false);
}
}
Ok(true)
}
@ -79,7 +98,7 @@ impl Component for Avatar {
let mut avatar = Self {
common: CommonComponentParts::<Self>::create(),
avatar: None,
_producer: AvatarEventBus::bridge(ctx.link().callback(|_| Msg::Update)),
_producer: AvatarEventBus::bridge(ctx.link().callback(Msg::Update)),
};
avatar.get_user_avatar(ctx);
avatar
@ -93,8 +112,8 @@ impl Component for Avatar {
match &self.avatar {
Some(avatar) => html! {
<img
id="avatarDisplay"
src={format!("data:image/jpeg;base64, {}", avatar)}
class="avatar"
src={format!("data:image/jpeg;base64, {}", avatar.0)}
style={format!("max-height:{}px;max-width:{}px;height:auto;width:auto;", ctx.props().height,ctx.props().width)}
alt="Avatar" />
},

View File

@ -2,9 +2,16 @@ use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use yew_agent::{Agent, AgentLink, Context, HandlerId};
use super::avatar::AvatarData;
#[derive(Serialize, Deserialize, Debug)]
pub enum Request {
Update,
Update((String, Option<AvatarData>)),
}
#[derive(Serialize, Deserialize, Debug)]
pub enum Response {
Update((String, Option<AvatarData>)),
}
pub struct AvatarEventBus {
@ -16,7 +23,7 @@ impl Agent for AvatarEventBus {
type Reach = Context<Self>;
type Message = ();
type Input = Request;
type Output = ();
type Output = Response;
fn create(link: AgentLink<Self>) -> Self {
Self {
@ -29,9 +36,10 @@ impl Agent for AvatarEventBus {
fn handle_input(&mut self, msg: Self::Input, _id: HandlerId) {
match msg {
Request::Update => {
Request::Update((username, avatar)) => {
for sub in self.subscribers.iter() {
self.link.respond(*sub, ());
self.link
.respond(*sub, Response::Update((username.clone(), avatar.clone())));
}
}
}
@ -44,4 +52,4 @@ impl Agent for AvatarEventBus {
fn disconnected(&mut self, id: HandlerId) {
self.subscribers.remove(&id);
}
}
}

View File

@ -1,8 +1,9 @@
use std::str::FromStr;
use crate::{
components::user_details::User,
components::avatar::AvatarData,
components::avatar_event_bus::{AvatarEventBus, Request},
components::user_details::User,
infra::common_component::{CommonComponent, CommonComponentParts},
};
use anyhow::{bail, Error, Result};
@ -14,8 +15,8 @@ use graphql_client::GraphQLQuery;
use validator_derive::Validate;
use web_sys::{FileList, HtmlInputElement, InputEvent};
use yew::prelude::*;
use yew_form_derive::Model;
use yew_agent::{Dispatched, Dispatcher};
use yew_form_derive::Model;
#[derive(Default)]
struct JsFile {
@ -406,7 +407,13 @@ impl UserDetailsForm {
self.user.avatar = Some(avatar);
}
self.just_updated = true;
self.avatar_event_bus.send(Request::Update);
self.avatar_event_bus.send(Request::Update((
self.user.id.clone(),
self.user
.avatar
.as_ref()
.map(|data| AvatarData::new(data.clone())),
)));
Ok(true)
}

View File

@ -29,4 +29,8 @@ html.dark .nav-link {
.nav-link {
color: #212529
}
.avatar {
border-radius: 50%;
}