Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { XMarkIcon } from "@heroicons/react/24/outline";
2import {
3 type AccountFragment,
4 PageSize,
5 useAccountRecommendationsQuery
6} from "@hey/indexer";
7import { memo, useState } from "react";
8import Suggested from "@/components/Home/Suggested";
9import DismissRecommendedAccount from "@/components/Shared/Account/DismissRecommendedAccount";
10import SingleAccount from "@/components/Shared/Account/SingleAccount";
11import SingleAccountShimmer from "@/components/Shared/Shimmer/SingleAccountShimmer";
12import Skeleton from "@/components/Shared/Skeleton";
13import { Card, ErrorMessage, H5, Modal } from "@/components/Shared/UI";
14import { useAccountStore } from "@/store/persisted/useAccountStore";
15
16const Title = memo(() => <H5>Who to Follow</H5>);
17
18const WhoToFollow = () => {
19 const { currentAccount } = useAccountStore();
20 const [showMore, setShowMore] = useState(false);
21
22 const { data, error, loading } = useAccountRecommendationsQuery({
23 variables: {
24 request: {
25 account: currentAccount?.address,
26 pageSize: PageSize.Fifty,
27 shuffle: true
28 }
29 }
30 });
31
32 if (loading) {
33 return (
34 <Card className="space-y-4 p-5">
35 <Title />
36 {Array.from({ length: 5 }, (_, index) => `placeholder-${index}`).map(
37 (id) => (
38 <div className="flex items-center gap-x-3" key={id}>
39 <div className="w-full">
40 <SingleAccountShimmer showFollowUnfollowButton />
41 </div>
42 <XMarkIcon className="size-4 text-gray-500" />
43 </div>
44 )
45 )}
46 <div className="pt-2 pb-1">
47 <Skeleton className="h-3 w-5/12 rounded-full" />
48 </div>
49 </Card>
50 );
51 }
52
53 if (!data?.mlAccountRecommendations.items.length) {
54 return null;
55 }
56
57 const recommendedAccounts = data?.mlAccountRecommendations.items.filter(
58 (account) =>
59 !account.operations?.isBlockedByMe &&
60 !account.operations?.isFollowedByMe &&
61 !account.operations?.hasBlockedMe
62 ) as AccountFragment[];
63
64 if (!recommendedAccounts?.length) {
65 return null;
66 }
67
68 return (
69 <>
70 <Card className="space-y-4 p-5">
71 <Title />
72 <ErrorMessage error={error} title="Failed to load recommendations" />
73 {recommendedAccounts?.slice(0, 5).map((account) => (
74 <div
75 className="flex items-center gap-x-3 truncate"
76 key={account?.address}
77 >
78 <div className="w-full">
79 <SingleAccount
80 account={account}
81 hideFollowButton={currentAccount?.address === account.address}
82 hideUnfollowButton={currentAccount?.address === account.address}
83 />
84 </div>
85 <DismissRecommendedAccount account={account} />
86 </div>
87 ))}
88 {recommendedAccounts.length > 5 && (
89 <button
90 className="font-bold text-gray-500 dark:text-gray-200"
91 onClick={() => setShowMore(true)}
92 type="button"
93 >
94 Show more
95 </button>
96 )}
97 </Card>
98 <Modal
99 onClose={() => setShowMore(false)}
100 show={showMore}
101 title="Suggested for you"
102 >
103 <Suggested accounts={recommendedAccounts} />
104 </Modal>
105 </>
106 );
107};
108
109export default memo(WhoToFollow);