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