Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 203 lines 5.3 kB view raw
1import type { PostFragment } from "@hey/indexer"; 2import { AnimateNumber } from "motion-plus-react"; 3import plur from "plur"; 4import { memo, useCallback, useState } from "react"; 5import { Link } from "react-router"; 6import Likes from "@/components/Shared/Modal/Likes"; 7import PostExecutors from "@/components/Shared/Modal/PostExecutors"; 8import Reposts from "@/components/Shared/Modal/Reposts"; 9import { Modal } from "@/components/Shared/UI"; 10 11const AnimatedNumber = ({ 12 key, 13 name, 14 value 15}: { 16 key: string; 17 name: string; 18 value: number; 19}) => { 20 return ( 21 <span className="flex items-center gap-x-1"> 22 <AnimateNumber 23 className="font-bold text-black dark:text-white" 24 format={{ notation: "compact" }} 25 key={key} 26 transition={{ type: "tween" }} 27 > 28 {value} 29 </AnimateNumber> 30 {plur(name, value)} 31 </span> 32 ); 33}; 34 35type PostExecutorsType = "Tippers" | "Collectors"; 36 37interface PostStatsProps { 38 post: PostFragment; 39} 40 41const PostStats = ({ post }: PostStatsProps) => { 42 const [showLikesModal, setShowLikesModal] = useState(false); 43 const [showRepostsModal, setShowRepostsModal] = useState(false); 44 const [showPostExecutorsModal, setShowPostExecutorsModal] = 45 useState<PostExecutorsType | null>(null); 46 47 const handleOpenRepostsModal = useCallback(() => { 48 setShowRepostsModal(true); 49 }, []); 50 51 const handleOpenLikesModal = useCallback(() => { 52 setShowLikesModal(true); 53 }, []); 54 55 const handleOpenTippersModal = useCallback(() => { 56 setShowPostExecutorsModal("Tippers"); 57 }, []); 58 59 const handleOpenCollectorsModal = useCallback(() => { 60 setShowPostExecutorsModal("Collectors"); 61 }, []); 62 63 const handleCloseLikesModal = useCallback(() => { 64 setShowLikesModal(false); 65 }, []); 66 67 const handleCloseRepostsModal = useCallback(() => { 68 setShowRepostsModal(false); 69 }, []); 70 71 const handleClosePostExecutorsModal = useCallback(() => { 72 setShowPostExecutorsModal(null); 73 }, []); 74 75 const { bookmarks, comments, reposts, quotes, reactions, collects, tips } = 76 post.stats; 77 78 const showStats = 79 comments > 0 || 80 reactions > 0 || 81 reposts > 0 || 82 quotes > 0 || 83 bookmarks > 0 || 84 collects > 0 || 85 tips > 0; 86 87 if (!showStats) { 88 return null; 89 } 90 91 return ( 92 <> 93 <div className="divider" /> 94 <div className="flex flex-wrap items-center gap-x-6 gap-y-3 py-3 text-gray-500 text-sm dark:text-gray-200"> 95 {comments > 0 ? ( 96 <AnimatedNumber 97 key={`comment-count-${post.id}`} 98 name="Comment" 99 value={comments} 100 /> 101 ) : null} 102 {reposts > 0 ? ( 103 <button 104 className="outline-offset-2" 105 onClick={handleOpenRepostsModal} 106 type="button" 107 > 108 <AnimatedNumber 109 key={`repost-count-${post.id}`} 110 name="Repost" 111 value={reposts} 112 /> 113 </button> 114 ) : null} 115 {quotes > 0 ? ( 116 <Link className="outline-offset-2" to={`/posts/${post.slug}/quotes`}> 117 <AnimatedNumber 118 key={`quote-count-${post.id}`} 119 name="Quote" 120 value={quotes} 121 /> 122 </Link> 123 ) : null} 124 {reactions > 0 ? ( 125 <button 126 className="outline-offset-2" 127 onClick={handleOpenLikesModal} 128 type="button" 129 > 130 <AnimatedNumber 131 key={`like-count-${post.id}`} 132 name="Like" 133 value={reactions} 134 /> 135 </button> 136 ) : null} 137 {tips > 0 ? ( 138 <button 139 className="outline-offset-2" 140 onClick={handleOpenTippersModal} 141 type="button" 142 > 143 <AnimatedNumber 144 key={`tip-count-${post.id}`} 145 name="Tip" 146 value={tips} 147 /> 148 </button> 149 ) : null} 150 {collects > 0 ? ( 151 <button 152 className="outline-offset-2" 153 onClick={handleOpenCollectorsModal} 154 type="button" 155 > 156 <AnimatedNumber 157 key={`collect-count-${post.id}`} 158 name="Collect" 159 value={collects} 160 /> 161 </button> 162 ) : null} 163 {bookmarks > 0 ? ( 164 <AnimatedNumber 165 key={`bookmark-count-${post.id}`} 166 name="Bookmark" 167 value={bookmarks} 168 /> 169 ) : null} 170 </div> 171 <Modal 172 onClose={handleCloseLikesModal} 173 show={showLikesModal} 174 title="Likes" 175 > 176 <Likes postId={post.id} /> 177 </Modal> 178 <Modal 179 onClose={handleCloseRepostsModal} 180 show={showRepostsModal} 181 title="Reposts" 182 > 183 <Reposts postId={post.id} /> 184 </Modal> 185 <Modal 186 onClose={handleClosePostExecutorsModal} 187 show={showPostExecutorsModal !== null} 188 title={showPostExecutorsModal === "Tippers" ? "Tippers" : "Collectors"} 189 > 190 <PostExecutors 191 filter={ 192 showPostExecutorsModal === "Tippers" 193 ? { tipping: true } 194 : { simpleCollect: true } 195 } 196 postId={post.id} 197 /> 198 </Modal> 199 </> 200 ); 201}; 202 203export default memo(PostStats);