Bluesky app fork with some witchin' additions 馃挮
witchsky.app
bluesky
fork
client
1import {useCallback, useMemo, useState} from 'react'
2import {type AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
3import {msg} from '@lingui/core/macro'
4import {useLingui} from '@lingui/react'
5
6import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
7import {cleanError} from '#/lib/strings/errors'
8import {logger} from '#/logger'
9import {useLikedByQuery} from '#/state/queries/post-liked-by'
10import {useResolveUriQuery} from '#/state/queries/resolve-uri'
11import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard'
12import {List} from '#/view/com/util/List'
13import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
14
15function renderItem({item, index}: {item: GetLikes.Like; index: number}) {
16 return (
17 <ProfileCardWithFollowBtn
18 key={item.actor.did}
19 profile={item.actor}
20 noBorder={index === 0}
21 />
22 )
23}
24
25function keyExtractor(item: GetLikes.Like) {
26 return item.actor.did
27}
28
29export function PostLikedBy({uri}: {uri: string}) {
30 const {_} = useLingui()
31 const initialNumToRender = useInitialNumToRender()
32
33 const [isPTRing, setIsPTRing] = useState(false)
34
35 const {
36 data: resolvedUri,
37 error: resolveError,
38 isLoading: isLoadingUri,
39 } = useResolveUriQuery(uri)
40 const {
41 data,
42 isLoading: isLoadingLikes,
43 isFetchingNextPage,
44 hasNextPage,
45 fetchNextPage,
46 error,
47 refetch,
48 } = useLikedByQuery(resolvedUri?.uri)
49
50 const isError = Boolean(resolveError || error)
51
52 const likes = useMemo(() => {
53 if (data?.pages) {
54 return data.pages.flatMap(page => page.likes)
55 }
56 return []
57 }, [data])
58
59 const onRefresh = useCallback(async () => {
60 setIsPTRing(true)
61 try {
62 await refetch()
63 } catch (err) {
64 logger.error('Failed to refresh likes', {message: err})
65 }
66 setIsPTRing(false)
67 }, [refetch, setIsPTRing])
68
69 const onEndReached = useCallback(async () => {
70 if (isFetchingNextPage || !hasNextPage || isError) return
71 try {
72 await fetchNextPage()
73 } catch (err) {
74 logger.error('Failed to load more likes', {message: err})
75 }
76 }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage])
77
78 if (likes.length < 1) {
79 return (
80 <ListMaybePlaceholder
81 isLoading={isLoadingUri || isLoadingLikes}
82 isError={isError}
83 emptyType="results"
84 emptyTitle={_(msg`No likes yet`)}
85 emptyMessage={_(
86 msg`Nobody has liked this yet. Maybe you should be the first!`,
87 )}
88 errorMessage={cleanError(resolveError || error)}
89 sideBorders={false}
90 topBorder={false}
91 />
92 )
93 }
94
95 return (
96 <List
97 data={likes}
98 renderItem={renderItem}
99 keyExtractor={keyExtractor}
100 refreshing={isPTRing}
101 onRefresh={onRefresh}
102 onEndReached={onEndReached}
103 onEndReachedThreshold={4}
104 ListFooterComponent={
105 <ListFooter
106 isFetchingNextPage={isFetchingNextPage}
107 error={cleanError(error)}
108 onRetry={fetchNextPage}
109 />
110 }
111 desktopFixedHeight
112 initialNumToRender={initialNumToRender}
113 windowSize={11}
114 sideBorders={false}
115 />
116 )
117}