frontend client for gemstone. decentralised workplace app
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: profile provider

serenity c09b0f3c 6c233fc2

+68 -39
+5 -13
src/app/(protected)/index.tsx
··· 2 2 import { Loading } from "@/components/Loading"; 3 3 import { useChannelRecords } from "@/providers/authed/ChannelsProvider"; 4 4 import { useSessions } from "@/providers/authed/SessionsProvider"; 5 - import { useOAuthSession } from "@/providers/OAuthProvider"; 6 - import { Redirect } from "expo-router"; 7 5 import { View } from "react-native"; 8 6 9 7 export default function Index() { 10 - const oAuthSession = useOAuthSession(); 11 8 const { channels } = useChannelRecords(); 12 9 const { isInitialising } = useSessions(); 13 10 ··· 20 17 alignItems: "center", 21 18 }} 22 19 > 23 - {oAuthSession ? ( 24 - isAppReady ? ( 25 - <ChatComponentProfiled 26 - did={oAuthSession.did} 27 - channelAtUri={channels[0].channelAtUri} 28 - /> 29 - ) : ( 30 - <Loading /> 31 - ) 20 + {isAppReady ? ( 21 + <ChatComponentProfiled 22 + channelAtUri={channels[0].channelAtUri} 23 + /> 32 24 ) : ( 33 - <Redirect href="/login" /> 25 + <Loading /> 34 26 )} 35 27 </View> 36 28 );
+6 -25
src/components/ChatComponentProfiled.tsx
··· 2 2 import { Message } from "@/components/Message"; 3 3 import { useChannel } from "@/lib/hooks/useChannel"; 4 4 import type { AtUri, DidPlc, DidWeb } from "@/lib/types/atproto"; 5 - import { getBskyProfile } from "@/queries/get-profile"; 6 - import { useQuery } from "@tanstack/react-query"; 5 + import { useProfile } from "@/providers/authed/ProfileProvider"; 7 6 import { useState } from "react"; 8 7 import { 9 8 View, ··· 16 15 } from "react-native"; 17 16 18 17 export default function ChatComponentProfiled({ 19 - did, 20 18 channelAtUri, 21 19 }: { 22 - did: DidPlc | DidWeb; 23 - channelAtUri: AtUri 20 + channelAtUri: AtUri; 24 21 }) { 25 22 const [inputText, setInputText] = useState(""); 26 - const { messages, sendMessageToChannel, isConnected } = useChannel( 27 - channelAtUri, 28 - ); 23 + const { messages, sendMessageToChannel, isConnected } = 24 + useChannel(channelAtUri); 29 25 30 26 const handleSend = () => { 31 27 if (inputText.trim()) { ··· 34 30 } 35 31 }; 36 32 37 - const { 38 - data: profile, 39 - isPending, 40 - isError, 41 - error, 42 - } = useQuery({ 43 - queryKey: [did], 44 - queryFn: async () => { 45 - return await getBskyProfile(did); 46 - }, 47 - }); 33 + const { profile, isLoading } = useProfile(); 48 34 49 - return isPending ? ( 35 + return isLoading ? ( 50 36 <Loading /> 51 - ) : isError ? ( 52 - <View> 53 - <Text>Something went wrong :(</Text> 54 - <Text>{error.message}</Text> 55 - </View> 56 37 ) : ( 57 38 <View style={styles.container}> 58 39 {profile && (
+53
src/providers/authed/ProfileProvider.tsx
··· 1 + import type { Did } from "@/lib/types/atproto"; 2 + import { useOAuthSessionGuaranteed } from "@/providers/OAuthProvider"; 3 + import { getBskyProfile } from "@/queries/get-profile"; 4 + import { useQuery } from "@tanstack/react-query"; 5 + import type { ReactNode } from "react"; 6 + import { createContext, useContext } from "react"; 7 + 8 + interface ProfileContextValue { 9 + did: Did; 10 + profile: 11 + | { 12 + avatar?: `${string}:${string}`; 13 + displayName?: string; 14 + handle: string; 15 + } 16 + | undefined; 17 + isLoading: boolean; 18 + } 19 + 20 + const ProfileContext = createContext<ProfileContextValue | null>(null); 21 + 22 + export const useProfile = () => { 23 + const value = useContext(ProfileContext); 24 + if (!value) 25 + throw new Error( 26 + "Profile context was null. Did you try to access this outside of the authed providers? ProfileProvider must be below OAuthProvider.", 27 + ); 28 + return value; 29 + }; 30 + 31 + export const ProfileProvider = ({ children }: { children: ReactNode }) => { 32 + const oAuthSession = useOAuthSessionGuaranteed(); 33 + const { did } = oAuthSession; 34 + 35 + const { data: profile, isLoading } = useQuery({ 36 + queryKey: [did], 37 + queryFn: async () => { 38 + return await getBskyProfile(did); 39 + }, 40 + }); 41 + 42 + const value: ProfileContextValue = { 43 + did, 44 + profile: { 45 + avatar: profile?.avatar, 46 + displayName: profile?.displayName, 47 + handle: profile?.handle ?? "", 48 + }, 49 + isLoading, 50 + }; 51 + 52 + return <ProfileContext value={value}>{children}</ProfileContext>; 53 + };
+4 -1
src/providers/authed/index.tsx
··· 1 1 import { HandshakesProvider } from "@/providers/authed/HandshakesProvider"; 2 + import { ProfileProvider } from "@/providers/authed/ProfileProvider"; 2 3 import { SessionsProvider } from "@/providers/authed/SessionsProvider"; 3 4 import type { ReactNode } from "react"; 4 5 5 6 export const AuthedProviders = ({ children }: { children: ReactNode }) => { 6 7 return ( 7 8 <HandshakesProvider> 8 - <SessionsProvider>{children}</SessionsProvider> 9 + <SessionsProvider> 10 + <ProfileProvider>{children}</ProfileProvider> 11 + </SessionsProvider> 9 12 </HandshakesProvider> 10 13 ); 11 14 };