Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
6.0 kB · 232 lines
TSX
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233import { AppBskyGraphFollow } from "@atproto/api";import { useEffect, useState } from "react";import { useStreamplaceStore } from "./streamplace-store";import { usePDSAgent } from "./xrpc";
export function useCreateFollowRecord() { let agent = usePDSAgent(); const [isLoading, setIsLoading] = useState(false);
const createFollow = async (subjectDID: string) => { if (!agent) { throw new Error("No PDS agent found"); }
if (!agent.did) { throw new Error("No user DID found, assuming not logged in"); }
setIsLoading(true); try { const record: AppBskyGraphFollow.Record = { $type: "app.bsky.graph.follow", subject: subjectDID, createdAt: new Date().toISOString(), }; const result = await agent.com.atproto.repo.createRecord({ repo: agent.did, collection: "app.bsky.graph.follow", record, }); return result; } finally { setIsLoading(false); } };
return { createFollow, isLoading };}
export function useDeleteFollowRecord() { let agent = usePDSAgent(); const [isLoading, setIsLoading] = useState(false);
const deleteFollow = async (followRecordUri: string) => { if (!agent) { throw new Error("No PDS agent found"); }
if (!agent.did) { throw new Error("No user DID found, assuming not logged in"); }
setIsLoading(true); try { const result = await agent.com.atproto.repo.deleteRecord({ repo: agent.did, collection: "app.bsky.graph.follow", rkey: followRecordUri.split("/").pop()!, }); return result; } finally { setIsLoading(false); } };
return { deleteFollow, isLoading };}
interface GraphManagerState { isFollowing: boolean | null; followUri: string | null; isLoading: boolean; error: string | null;}
interface GraphManagerActions { follow: () => Promise<void>; unfollow: () => Promise<void>; refresh: () => Promise<void>;}
export function useGraphManager( subjectDID: string | null | undefined,): GraphManagerState & GraphManagerActions { const agent = usePDSAgent(); const [isFollowing, setIsFollowing] = useState<boolean | null>(null); const [followUri, setFollowUri] = useState<string | null>(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState<string | null>(null);
const userDID = agent?.did;
const streamplaceUrl = useStreamplaceStore((state) => state.url);
const fetchFollowStatus = async () => { if (!userDID || !subjectDID || !streamplaceUrl) { setIsFollowing(null); setFollowUri(null); return; }
setIsLoading(true); setError(null); try { const res = await fetch( `${streamplaceUrl}/xrpc/place.stream.graph.getFollowingUser?subjectDID=${encodeURIComponent(subjectDID)}&userDID=${encodeURIComponent(userDID)}`, { credentials: "include", }, );
if (!res.ok) { const errorText = await res.text(); throw new Error(`Failed to fetch follow status: ${errorText}`); }
const data = await res.json();
if (data.follow) { setIsFollowing(true); setFollowUri(data.follow.uri); } else { setIsFollowing(false); setFollowUri(null); } } catch (err) { setError( `Could not determine follow state: ${err instanceof Error ? err.message : `Unknown error: ${err}`}`, ); setIsFollowing(null); } finally { setIsLoading(false); } };
useEffect(() => { if (!userDID || !subjectDID) { setIsFollowing(null); setFollowUri(null); setError(null); return; }
fetchFollowStatus(); }, [userDID, subjectDID, streamplaceUrl]);
const follow = async () => { if (!agent || !subjectDID) { throw new Error("Cannot follow: not logged in or no subject DID"); }
if (!agent.did) { throw new Error("No user DID found, assuming not logged in"); }
setIsLoading(true); setError(null); const previousState = isFollowing; setIsFollowing(true); // Optimistic
try { const record: AppBskyGraphFollow.Record = { $type: "app.bsky.graph.follow", subject: subjectDID, createdAt: new Date().toISOString(), }; const result = await agent.com.atproto.repo.createRecord({ repo: agent.did, collection: "app.bsky.graph.follow", record, }); setFollowUri(result.data.uri); setIsFollowing(true); } catch (err) { setIsFollowing(previousState); const errorMsg = `Failed to follow: ${err instanceof Error ? err.message : "Unknown error"}`; setError(errorMsg); throw new Error(errorMsg); } finally { setIsLoading(false); } };
const unfollow = async () => { if (!agent || !subjectDID) { throw new Error("Cannot unfollow: not logged in or no subject DID"); }
if (!agent.did) { throw new Error("No user DID found, assuming not logged in"); }
if (!followUri) { throw new Error("Cannot unfollow: no follow URI found"); }
setIsLoading(true); setError(null); const previousState = isFollowing; const previousUri = followUri; setIsFollowing(false); // Optimistic setFollowUri(null);
try { await agent.com.atproto.repo.deleteRecord({ repo: agent.did, collection: "app.bsky.graph.follow", rkey: followUri.split("/").pop()!, }); setIsFollowing(false); setFollowUri(null); } catch (err) { setIsFollowing(previousState); setFollowUri(previousUri); const errorMsg = `Failed to unfollow: ${err instanceof Error ? err.message : "Unknown error"}`; setError(errorMsg); throw new Error(errorMsg); } finally { setIsLoading(false); } };
return { isFollowing, followUri, isLoading, error, follow, unfollow, refresh: fetchFollowStatus, };}