a tool for shared writing and social publishing

use bluesky api for profile data

+29 -34
+5 -6
app/(home-pages)/p/[didOrHandle]/ProfileHeader.tsx
··· 8 import { PubIcon } from "components/ActionBar/Publications"; 9 import { Json } from "supabase/database.types"; 10 import { BlueskyTiny } from "components/Icons/BlueskyTiny"; 11 12 export const ProfileHeader = (props: { 13 - profile: ProfileData; 14 publications: { record: Json; uri: string }[]; 15 }) => { 16 - let profileRecord = props.profile.record as AppBskyActorProfile.Record; 17 18 return ( 19 <div className="flex flex-col relative" id="profile-header"> 20 <Avatar 21 - src={ 22 - profileRecord.avatar?.ref && 23 - blobRefToSrc(profileRecord.avatar?.ref, props.profile.did) 24 - } 25 displayName={profileRecord.displayName} 26 className="mx-auto mt-3 sm:mt-4" 27 giant
··· 8 import { PubIcon } from "components/ActionBar/Publications"; 9 import { Json } from "supabase/database.types"; 10 import { BlueskyTiny } from "components/Icons/BlueskyTiny"; 11 + import { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs"; 12 13 export const ProfileHeader = (props: { 14 + profile: ProfileViewDetailed; 15 publications: { record: Json; uri: string }[]; 16 }) => { 17 + console.log(props.profile); 18 + let profileRecord = props.profile; 19 20 return ( 21 <div className="flex flex-col relative" id="profile-header"> 22 <Avatar 23 + src={profileRecord.avatar} 24 displayName={profileRecord.displayName} 25 className="mx-auto mt-3 sm:mt-4" 26 giant
+12 -6
app/(home-pages)/p/[didOrHandle]/layout.tsx
··· 6 import { ProfileTabs } from "./ProfileTabs"; 7 import { DashboardLayout } from "components/PageLayouts/DashboardLayout"; 8 import { ProfileLayout } from "./ProfileLayout"; 9 10 export default async function ProfilePageLayout(props: { 11 params: Promise<{ didOrHandle: string }>; ··· 33 did = resolved; 34 } 35 36 - let { data: profile } = await supabaseServerClient 37 - .from("bsky_profiles") 38 - .select(`*`) 39 - .eq("did", did) 40 - .single(); 41 - let { data: publications } = await supabaseServerClient 42 .from("publications") 43 .select("*") 44 .eq("identity_did", did); 45 46 if (!profile) return null; 47
··· 6 import { ProfileTabs } from "./ProfileTabs"; 7 import { DashboardLayout } from "components/PageLayouts/DashboardLayout"; 8 import { ProfileLayout } from "./ProfileLayout"; 9 + import { Agent } from "@atproto/api"; 10 11 export default async function ProfilePageLayout(props: { 12 params: Promise<{ didOrHandle: string }>; ··· 34 did = resolved; 35 } 36 37 + let agent = new Agent({ 38 + service: "https://public.api.bsky.app", 39 + }); 40 + let profileReq = agent.app.bsky.actor.getProfile({ actor: did }); 41 + 42 + let publicationsReq = supabaseServerClient 43 .from("publications") 44 .select("*") 45 .eq("identity_did", did); 46 + 47 + let [{ data: profile }, { data: publications }] = await Promise.all([ 48 + profileReq, 49 + publicationsReq, 50 + ]); 51 52 if (!profile) return null; 53
+11 -21
app/api/rpc/[command]/get_profile_data.ts
··· 2 import { makeRoute } from "../lib"; 3 import type { Env } from "./route"; 4 import { idResolver } from "app/(home-pages)/reader/idResolver"; 5 6 export type GetProfileDataReturnType = Awaited< 7 ReturnType<(typeof get_profile_data)["handler"]> ··· 24 did = resolved; 25 } 26 27 - // Fetch profile 28 - const { data: profile, error: profileError } = await supabase 29 - .from("bsky_profiles") 30 - .select("*") 31 - .eq("did", did) 32 - .single(); 33 - 34 - if (profileError) { 35 - throw new Error(`Failed to fetch profile: ${profileError.message}`); 36 - } 37 - 38 - if (!profile) { 39 - throw new Error("Profile not found"); 40 - } 41 42 - // Fetch publications for the DID 43 - const { data: publications, error: publicationsError } = await supabase 44 .from("publications") 45 .select("*") 46 .eq("identity_did", did); 47 48 - if (publicationsError) { 49 - throw new Error( 50 - `Failed to fetch publications: ${publicationsError.message}`, 51 - ); 52 - } 53 54 return { 55 result: {
··· 2 import { makeRoute } from "../lib"; 3 import type { Env } from "./route"; 4 import { idResolver } from "app/(home-pages)/reader/idResolver"; 5 + import { supabaseServerClient } from "supabase/serverClient"; 6 + import { Agent } from "@atproto/api"; 7 8 export type GetProfileDataReturnType = Awaited< 9 ReturnType<(typeof get_profile_data)["handler"]> ··· 26 did = resolved; 27 } 28 29 + let agent = new Agent({ 30 + service: "https://public.api.bsky.app", 31 + }); 32 + let profileReq = agent.app.bsky.actor.getProfile({ actor: did }); 33 34 + let publicationsReq = supabaseServerClient 35 .from("publications") 36 .select("*") 37 .eq("identity_did", did); 38 39 + let [{ data: profile }, { data: publications }] = await Promise.all([ 40 + profileReq, 41 + publicationsReq, 42 + ]); 43 44 return { 45 result: {
+1 -1
components/ProfilePopover.tsx
··· 1 "use client"; 2 - import { ProfileHeader } from "app/p/[didOrHandle]/(profile)/ProfileHeader"; 3 import { Popover } from "./Popover"; 4 import useSWR from "swr"; 5 import { callRPC } from "app/api/rpc/client"; 6 import { useState } from "react"; 7 8 export const ProfilePopover = (props: { 9 trigger: React.ReactNode;
··· 1 "use client"; 2 import { Popover } from "./Popover"; 3 import useSWR from "swr"; 4 import { callRPC } from "app/api/rpc/client"; 5 import { useState } from "react"; 6 + import { ProfileHeader } from "app/(home-pages)/p/[didOrHandle]/ProfileHeader"; 7 8 export const ProfilePopover = (props: { 9 trigger: React.ReactNode;