Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { HeartIcon } from "@heroicons/react/24/outline";
2import {
3 PageSize,
4 type PostReactionsRequest,
5 usePostReactionsQuery
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 LikesProps {
19 postId: string;
20}
21
22const Likes = ({ postId }: LikesProps) => {
23 const { currentAccount } = useAccountStore();
24
25 const request: PostReactionsRequest = {
26 pageSize: PageSize.Fifty,
27 post: postId
28 };
29
30 const { data, error, fetchMore, loading } = usePostReactionsQuery({
31 skip: !postId,
32 variables: { request }
33 });
34
35 const accounts = data?.postReactions?.items;
36 const pageInfo = data?.postReactions?.pageInfo;
37 const hasMore = pageInfo?.next;
38
39 const handleEndReached = useCallback(async () => {
40 if (hasMore) {
41 await fetchMore({
42 variables: { request: { ...request, cursor: pageInfo?.next } }
43 });
44 }
45 }, [fetchMore, hasMore, pageInfo?.next, request]);
46
47 const loadMoreRef = useLoadMoreOnIntersect(handleEndReached);
48
49 if (loading) {
50 return <AccountListShimmer />;
51 }
52
53 if (!accounts?.length) {
54 return (
55 <div className="p-5">
56 <EmptyState
57 hideCard
58 icon={<HeartIcon className="size-8" />}
59 message="No likes."
60 />
61 </div>
62 );
63 }
64
65 if (error) {
66 return (
67 <ErrorMessage
68 className="m-5"
69 error={error}
70 title="Failed to load likes"
71 />
72 );
73 }
74
75 return (
76 <div className="max-h-[80vh] overflow-y-auto">
77 <Virtualizer>
78 {accounts.map((like, index) => (
79 <motion.div
80 animate="visible"
81 className={cn(
82 "divider p-5",
83 index === accounts.length - 1 && "border-b-0"
84 )}
85 initial="hidden"
86 key={like.account.address}
87 variants={accountsList}
88 >
89 <SingleAccount
90 account={like.account}
91 hideFollowButton={
92 currentAccount?.address === like.account.address
93 }
94 hideUnfollowButton={
95 currentAccount?.address === like.account.address
96 }
97 showBio
98 showUserPreview={false}
99 />
100 </motion.div>
101 ))}
102 {hasMore && <span ref={loadMoreRef} />}
103 </Virtualizer>
104 </div>
105 );
106};
107
108export default Likes;