use leptos::*; use leptos_router::*; use crate::{getters::Getter, prelude::*, DEFAULT_AVATAR_URL}; use apb::{field::OptionalString, ActivityMut, Actor, Base, Object, ObjectMut}; #[component] pub fn ActorHeader() -> impl IntoView { let params = use_params::(); let auth = use_context::().expect("missing auth context"); let actor = create_local_resource( move || params.get().ok().and_then(|x| x.id).unwrap_or_default(), move |id| { async move { match cache::OBJECTS.get(&Uri::full(U::Actor, &id)) { Some(x) => Ok::<_, String>(x.clone()), None => { let user : serde_json::Value = Http::fetch(&Uri::api(U::Actor, &id, true), auth) .await .map_err(|e| e.to_string())?; let user = std::sync::Arc::new(user); let uid = Uri::full(U::Actor, &id); cache::OBJECTS.store(&uid, user.clone()); if let Some(url) = user.url().id().str() { cache::WEBFINGER.store(&url, uid); } Ok(user) }, } } } ); move || match actor.get() { None => view! { }.into_view(), Some(Err(e)) => view! { "could not resolve user: "{e} }.into_view(), Some(Ok(actor)) => { let avatar_url = actor.icon().get().map(|x| x.url().id().str().unwrap_or(DEFAULT_AVATAR_URL.into())).unwrap_or(DEFAULT_AVATAR_URL.into()); let background_url = actor.image().get().map(|x| x.url().id().str().unwrap_or(DEFAULT_AVATAR_URL.into())).unwrap_or(DEFAULT_AVATAR_URL.into()); let username = actor.preferred_username().unwrap_or_default().to_string(); let name = actor.name().str().unwrap_or(username.clone()); let created = actor.published().ok(); let following_me = actor.following_me().unwrap_or(false); let followed_by_me = actor.followed_by_me().unwrap_or(false); let domain = actor.id().unwrap_or_default().replace("https://", "").split('/').next().unwrap_or_default().to_string(); let actor_type = actor.actor_type().unwrap_or(apb::ActorType::Person); let actor_type_tag = if actor_type == apb::ActorType::Person { None } else { Some(view! { "["{actor_type.as_ref().to_lowercase()}"]" } ) }; let uid = actor.id().unwrap_or_default().to_string(); let web_path = Uri::web(U::Actor, &uid); let _uid = uid.clone(); view! {
{name}{actor_type_tag} {actor.statuses_count().want()}" ""\u{1f582}"
{username.clone()}@{domain} {actor.following_count().want()}" ""👥"
{actor.followers_count().want()}" ""📢"
{if following_me { Some(view! { follows you }) } else { None }} {if followed_by_me { view! { "following" }.into_view() } else { view! { }.into_view() }}

}.into_view() }, } } #[allow(unused)] async fn send_follow_response(kind: apb::ActivityType, target: String, to: String, auth: Auth) { let payload = apb::new() .set_activity_type(Some(kind)) .set_object(apb::Node::link(target)) .set_to(apb::Node::links(vec![to])); if let Err(e) = Http::post(&auth.outbox(), &payload, auth).await { tracing::error!("failed posting follow response: {e}"); } } fn send_follow_request(target: String) { let auth = use_context::().expect("missing auth context"); spawn_local(async move { let payload = apb::new() .set_activity_type(Some(apb::ActivityType::Follow)) .set_object(apb::Node::link(target.clone())) .set_to(apb::Node::links(vec![target])); if let Err(e) = Http::post(&auth.outbox(), &payload, auth).await { tracing::error!("failed sending follow request: {e}"); } }) } fn unfollow(target: String) { let auth = use_context::().expect("missing auth context"); spawn_local(async move { let payload = apb::new() .set_activity_type(Some(apb::ActivityType::Undo)) .set_to(apb::Node::links(vec![target.clone()])) .set_object(apb::Node::object( apb::new() .set_activity_type(Some(apb::ActivityType::Follow)) .set_object(apb::Node::link(target)) )); if let Err(e) = Http::post(&auth.outbox(), &payload, auth).await { tracing::error!("failed sending follow request: {e}"); } }) }