Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
at main 125 lines 3.3 kB view raw
1import {useCallback, useMemo, useState} from 'react' 2import {type AppBskyActorDefs as ActorDefs} 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 {usePostRepostedByQuery} from '#/state/queries/post-reposted-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({ 16 item, 17 index, 18}: { 19 item: ActorDefs.ProfileView 20 index: number 21}) { 22 return ( 23 <ProfileCardWithFollowBtn 24 key={item.did} 25 profile={item} 26 noBorder={index === 0} 27 /> 28 ) 29} 30 31function keyExtractor(item: ActorDefs.ProfileViewBasic) { 32 return item.did 33} 34 35export function PostRepostedBy({uri}: {uri: string}) { 36 const {_} = useLingui() 37 const initialNumToRender = useInitialNumToRender() 38 39 const [isPTRing, setIsPTRing] = useState(false) 40 41 const { 42 data: resolvedUri, 43 error: resolveError, 44 isLoading: isLoadingUri, 45 } = useResolveUriQuery(uri) 46 const { 47 data, 48 isLoading: isLoadingRepostedBy, 49 isFetchingNextPage, 50 hasNextPage, 51 fetchNextPage, 52 error, 53 refetch, 54 } = usePostRepostedByQuery(resolvedUri?.uri) 55 56 const isError = Boolean(resolveError || error) 57 58 const repostedBy = useMemo(() => { 59 if (data?.pages) { 60 return data.pages.flatMap(page => page.repostedBy) 61 } 62 return [] 63 }, [data]) 64 65 const onRefresh = useCallback(async () => { 66 setIsPTRing(true) 67 try { 68 await refetch() 69 } catch (err) { 70 logger.error('Failed to refresh reposts', {message: err}) 71 } 72 setIsPTRing(false) 73 }, [refetch, setIsPTRing]) 74 75 const onEndReached = useCallback(async () => { 76 if (isFetchingNextPage || !hasNextPage || isError) return 77 try { 78 await fetchNextPage() 79 } catch (err) { 80 logger.error('Failed to load more reposts', {message: err}) 81 } 82 }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage]) 83 84 if (repostedBy.length < 1) { 85 return ( 86 <ListMaybePlaceholder 87 isLoading={isLoadingUri || isLoadingRepostedBy} 88 isError={isError} 89 emptyType="results" 90 emptyTitle={_(msg`No reposts yet`)} 91 emptyMessage={_( 92 msg`Nobody has reposted this yet. Maybe you should be the first!`, 93 )} 94 errorMessage={cleanError(resolveError || error)} 95 sideBorders={false} 96 /> 97 ) 98 } 99 100 // loaded 101 // = 102 return ( 103 <List 104 data={repostedBy} 105 renderItem={renderItem} 106 keyExtractor={keyExtractor} 107 refreshing={isPTRing} 108 onRefresh={onRefresh} 109 onEndReached={onEndReached} 110 onEndReachedThreshold={4} 111 ListFooterComponent={ 112 <ListFooter 113 isFetchingNextPage={isFetchingNextPage} 114 error={cleanError(error)} 115 onRetry={fetchNextPage} 116 /> 117 } 118 // @ts-ignore our .web version only -prf 119 desktopFixedHeight 120 initialNumToRender={initialNumToRender} 121 windowSize={11} 122 sideBorders={false} 123 /> 124 ) 125}