its for when you want to get like notifications for your reposts
1import { Did, Handle } from "@atcute/lexicons"; 2import { Client, ok, simpleFetchHandler } from "@atcute/client"; 3import type {} from "@atcute/bluesky"; 4import type {} from "@atcute/atproto"; 5import { isDid, parseCanonicalResourceUri } from "@atcute/lexicons/syntax"; 6import { Component, createSignal, createEffect } from "solid-js"; 7import { ATProtoActivity } from "./types.js"; 8 9const profileCache = new Map<string, ActorData>(); 10const handler = simpleFetchHandler({ 11 service: "https://public.api.bsky.app", 12}); 13const rpc = new Client({ handler }); 14 15interface ActivityItemProps { 16 data: ATProtoActivity; 17} 18 19interface ActorData { 20 did: Did; 21 handle: Handle; 22 displayName?: string; 23} 24 25export const ActivityItem: Component<ActivityItemProps> = (props) => { 26 const [actorData, setActorData] = createSignal<ActorData | null>(null); 27 const [error, setError] = createSignal<string | null>(null); 28 const [postUrl, setPostUrl] = createSignal<string | null>(null); 29 30 const fetchProfile = async (did: string) => { 31 if (!isDid(did)) { 32 setError("user DID invalid"); 33 return; 34 } 35 const resp = ok( 36 await rpc.get("app.bsky.actor.getProfile", { 37 params: { actor: did }, 38 }), 39 ); 40 const data: ActorData = { 41 did, 42 handle: resp.handle, 43 displayName: resp.displayName, 44 }; 45 setActorData(data); 46 profileCache.set(data.did, data); 47 }; 48 49 createEffect(() => { 50 const actorData = profileCache.get(props.data.did); 51 if (actorData) { 52 setActorData(actorData); 53 } else { 54 fetchProfile(props.data.did); 55 } 56 57 const postUri = parseCanonicalResourceUri(props.data.post_uri); 58 if (postUri.ok) { 59 setPostUrl( 60 `https://bsky.app/profile/${postUri.value.repo}/post/${postUri.value.rkey}`, 61 ); 62 } 63 }); 64 65 return ( 66 <div 67 class={`flex flex-wrap items-center border py-1 px-2 ${ 68 props.data.liked 69 ? "bg-green-50 border-green-200" 70 : "bg-red-50 border-red-200" 71 }`} 72 > 73 <p text-wrap> 74 <span text-lg>{props.data.liked ? "❤️" : "💔"}</span>{" "} 75 {(actorData() && ( 76 <span font-medium text="sm gray-700"> 77 {actorData()!.displayName ?? actorData()!.handle}{" "} 78 {actorData()!.displayName && ( 79 <span font-normal text-gray-500> 80 (@{actorData()!.handle}) 81 </span> 82 )} 83 </span> 84 )) || 85 (error() && ( 86 <span italic text="xs red-500"> 87 !{error()}! 88 </span> 89 )) || ( 90 <span font-medium text="sm gray-700"> 91 {props.data.did} 92 </span> 93 )}{" "} 94 <span text-gray-800>{props.data.liked ? "liked" : "unliked"}</span>{" "} 95 <a 96 text-blue-800 97 hover="underline text-blue-400" 98 href={postUrl() ?? props.data.post_uri} 99 > 100 this post 101 </a>{" "} 102 </p> 103 <div grow /> 104 <div text="xs gray-500 end">{new Date().toLocaleTimeString()}</div> 105 </div> 106 ); 107};