Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { ShoppingBagIcon } from "@heroicons/react/24/outline";
2import {
3 type PostActionFilter,
4 useWhoExecutedActionOnPostQuery,
5 type WhoExecutedActionOnPostRequest
6} from "@hey/indexer";
7import { motion } from "motion/react";
8import { useCallback } from "react";
9import { Virtualizer } from "virtua";
10import SingleAccount from "@/components/Shared/Account/SingleAccount";
11import AccountListShimmer from "@/components/Shared/Shimmer/AccountListShimmer";
12import { EmptyState, ErrorMessage } from "@/components/Shared/UI";
13import cn from "@/helpers/cn";
14import useLoadMoreOnIntersect from "@/hooks/useLoadMoreOnIntersect";
15import { useAccountStore } from "@/store/persisted/useAccountStore";
16import { accountsList } from "@/variants";
17
18interface PostExecutorsProps {
19 postId: string;
20 filter: PostActionFilter;
21}
22
23const PostExecutors = ({ postId, filter }: PostExecutorsProps) => {
24 const { currentAccount } = useAccountStore();
25
26 const request: WhoExecutedActionOnPostRequest = {
27 filter: { anyOf: [filter] },
28 post: postId
29 };
30
31 const { data, error, fetchMore, loading } = useWhoExecutedActionOnPostQuery({
32 skip: !postId,
33 variables: { request }
34 });
35
36 const accounts = data?.whoExecutedActionOnPost?.items;
37 const pageInfo = data?.whoExecutedActionOnPost?.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 (!accounts?.length) {
55 return (
56 <div className="p-5">
57 <EmptyState
58 hideCard
59 icon={<ShoppingBagIcon className="size-8" />}
60 message="No actions."
61 />
62 </div>
63 );
64 }
65
66 if (error) {
67 return (
68 <ErrorMessage
69 className="m-5"
70 error={error}
71 title="Failed to load actions"
72 />
73 );
74 }
75
76 return (
77 <div className="max-h-[80vh] overflow-y-auto">
78 <Virtualizer>
79 {accounts.map((action, index) => (
80 <motion.div
81 animate="visible"
82 className={cn(
83 "divider p-5",
84 index === accounts.length - 1 && "border-b-0"
85 )}
86 initial="hidden"
87 key={action.account.address}
88 variants={accountsList}
89 >
90 <SingleAccount
91 account={action.account}
92 hideFollowButton={
93 currentAccount?.address === action.account.address
94 }
95 hideUnfollowButton={
96 currentAccount?.address === action.account.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 PostExecutors;