Bluesky app fork with some witchin' additions 馃挮
witchsky.app
bluesky
fork
client
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}