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