Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 117 lines 3.2 kB view raw
1import { ChatBubbleBottomCenterIcon } from "@heroicons/react/24/outline"; 2import { AccountFeedType } from "@hey/data/enums"; 3import { 4 type AnyPostFragment, 5 MainContentFocus, 6 PageSize, 7 type PostsRequest, 8 PostType, 9 usePostsQuery 10} from "@hey/indexer"; 11import { useCallback, useMemo } from "react"; 12import SinglePost from "@/components/Post/SinglePost"; 13import PostFeed from "@/components/Shared/Post/PostFeed"; 14 15interface AccountFeedProps { 16 username: string; 17 address: string; 18 type: 19 | AccountFeedType.Collects 20 | AccountFeedType.Feed 21 | AccountFeedType.Media 22 | AccountFeedType.Replies; 23} 24 25const EMPTY_MESSAGES: Record<AccountFeedType, string> = { 26 [AccountFeedType.Feed]: "has nothing in their feed yet!", 27 [AccountFeedType.Media]: "has no media yet!", 28 [AccountFeedType.Replies]: "hasn't replied yet!", 29 [AccountFeedType.Collects]: "hasn't collected anything yet!" 30}; 31 32const AccountFeed = ({ username, address, type }: AccountFeedProps) => { 33 const postTypes = useMemo(() => { 34 switch (type) { 35 case AccountFeedType.Feed: 36 return [PostType.Root, PostType.Repost, PostType.Quote]; 37 case AccountFeedType.Replies: 38 return [PostType.Comment]; 39 case AccountFeedType.Media: 40 return [PostType.Root, PostType.Quote]; 41 default: 42 return [ 43 PostType.Root, 44 PostType.Comment, 45 PostType.Repost, 46 PostType.Quote 47 ]; 48 } 49 }, [type]); 50 51 const getEmptyMessage = () => { 52 return EMPTY_MESSAGES[type] || ""; 53 }; 54 55 const request = useMemo<PostsRequest>( 56 () => ({ 57 filter: { 58 postTypes, 59 ...(type === AccountFeedType.Media && { 60 metadata: { 61 mainContentFocus: [ 62 MainContentFocus.Image, 63 MainContentFocus.Audio, 64 MainContentFocus.Video, 65 MainContentFocus.ShortVideo 66 ] 67 } 68 }), 69 ...(type === AccountFeedType.Collects 70 ? { collectedBy: { account: address } } 71 : { authors: [address] }) 72 }, 73 pageSize: PageSize.Fifty 74 }), 75 [address, postTypes, type] 76 ); 77 78 const { data, error, fetchMore, loading } = usePostsQuery({ 79 skip: !address, 80 variables: { request } 81 }); 82 83 const posts = data?.posts?.items; 84 const pageInfo = data?.posts?.pageInfo; 85 const hasMore = pageInfo?.next; 86 87 const safePosts = (posts ?? []) as AnyPostFragment[]; 88 89 const handleEndReached = useCallback(async () => { 90 if (hasMore) { 91 await fetchMore({ 92 variables: { request: { ...request, cursor: pageInfo?.next } } 93 }); 94 } 95 }, [fetchMore, hasMore, pageInfo?.next, request]); 96 97 return ( 98 <PostFeed 99 emptyIcon={<ChatBubbleBottomCenterIcon className="size-8" />} 100 emptyMessage={ 101 <div> 102 <b className="mr-1">{username}</b> 103 <span>{getEmptyMessage()}</span> 104 </div> 105 } 106 error={error} 107 errorTitle="Failed to load account feed" 108 handleEndReached={handleEndReached} 109 hasMore={hasMore} 110 items={safePosts} 111 loading={loading} 112 renderItem={(post) => <SinglePost key={post.id} post={post} />} 113 /> 114 ); 115}; 116 117export default AccountFeed;