Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
119
fork

Configure Feed

Select the types of activity you want to include in your feed.

at a876aae44ea07494ebea9727350aa060b81f317b 117 lines 3.2 kB view raw
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}