Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 109 lines 3.0 kB view raw
1import { UsersIcon } from "@heroicons/react/24/outline"; 2import type { FollowersRequest } from "@hey/indexer"; 3import { PageSize, useFollowersQuery } from "@hey/indexer"; 4import { motion } from "motion/react"; 5import { useCallback } from "react"; 6import { Virtualizer } from "virtua"; 7import SingleAccount from "@/components/Shared/Account/SingleAccount"; 8import AccountListShimmer from "@/components/Shared/Shimmer/AccountListShimmer"; 9import { EmptyState, ErrorMessage } from "@/components/Shared/UI"; 10import cn from "@/helpers/cn"; 11import useLoadMoreOnIntersect from "@/hooks/useLoadMoreOnIntersect"; 12import { useAccountStore } from "@/store/persisted/useAccountStore"; 13import { accountsList } from "@/variants"; 14 15interface FollowersProps { 16 username: string; 17 address: string; 18} 19 20const Followers = ({ username, address }: FollowersProps) => { 21 const { currentAccount } = useAccountStore(); 22 23 const request: FollowersRequest = { 24 account: address, 25 pageSize: PageSize.Fifty 26 }; 27 28 const { data, error, fetchMore, loading } = useFollowersQuery({ 29 skip: !address, 30 variables: { request } 31 }); 32 33 const followers = data?.followers?.items; 34 const pageInfo = data?.followers?.pageInfo; 35 const hasMore = pageInfo?.next; 36 37 const handleEndReached = useCallback(async () => { 38 if (hasMore) { 39 await fetchMore({ 40 variables: { request: { ...request, cursor: pageInfo?.next } } 41 }); 42 } 43 }, [fetchMore, hasMore, pageInfo?.next, request]); 44 45 const loadMoreRef = useLoadMoreOnIntersect(handleEndReached); 46 47 if (loading) { 48 return <AccountListShimmer />; 49 } 50 51 if (!followers?.length) { 52 return ( 53 <EmptyState 54 hideCard 55 icon={<UsersIcon className="size-8" />} 56 message={ 57 <div> 58 <span className="mr-1 font-bold">@{username}</span> 59 <span>doesn't have any followers yet.</span> 60 </div> 61 } 62 /> 63 ); 64 } 65 66 if (error) { 67 return ( 68 <ErrorMessage 69 className="m-5" 70 error={error} 71 title="Failed to load followers" 72 /> 73 ); 74 } 75 76 return ( 77 <div className="!h-[80vh] overflow-y-auto"> 78 <Virtualizer> 79 {followers.map((follower, index) => ( 80 <motion.div 81 animate="visible" 82 className={cn( 83 "divider p-5", 84 index === followers.length - 1 && "border-b-0" 85 )} 86 initial="hidden" 87 key={follower.follower.address} 88 variants={accountsList} 89 > 90 <SingleAccount 91 account={follower.follower} 92 hideFollowButton={ 93 currentAccount?.address === follower.follower.address 94 } 95 hideUnfollowButton={ 96 currentAccount?.address === follower.follower.address 97 } 98 showBio 99 showUserPreview={false} 100 /> 101 </motion.div> 102 ))} 103 {hasMore && <span ref={loadMoreRef} />} 104 </Virtualizer> 105 </div> 106 ); 107}; 108 109export default Followers;