forked from
jollywhoppers.com/witchsky.app
fork
Configure Feed
Select the types of activity you want to include in your feed.
Bluesky app fork with some witchin' additions 馃挮
fork
Configure Feed
Select the types of activity you want to include in your feed.
1import {useCallback, useState} from 'react'
2import {
3 type AppBskyFeedDefs,
4 AppBskyFeedPost,
5 moderatePost,
6 type ModerationDecision,
7} from '@atproto/api'
8import {msg} from '@lingui/core/macro'
9import {useLingui} from '@lingui/react'
10
11import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
12import {usePostViewTracking} from '#/lib/hooks/usePostViewTracking'
13import {cleanError} from '#/lib/strings/errors'
14import {logger} from '#/logger'
15import {useModerationOpts} from '#/state/preferences/moderation-opts'
16import {usePostQuotesQuery} from '#/state/queries/post-quotes'
17import {useResolveUriQuery} from '#/state/queries/resolve-uri'
18import {Post} from '#/view/com/post/Post'
19import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
20import {List} from '../util/List'
21
22function renderItem({
23 item,
24 index,
25}: {
26 item: {
27 post: AppBskyFeedDefs.PostView
28 moderation: ModerationDecision
29 record: AppBskyFeedPost.Record
30 }
31 index: number
32}) {
33 return <Post post={item.post} hideTopBorder={index === 0} />
34}
35
36function keyExtractor(item: {
37 post: AppBskyFeedDefs.PostView
38 moderation: ModerationDecision
39 record: AppBskyFeedPost.Record
40}) {
41 return item.post.uri
42}
43
44export function PostQuotes({uri}: {uri: string}) {
45 const {_} = useLingui()
46 const initialNumToRender = useInitialNumToRender()
47 const [isPTRing, setIsPTRing] = useState(false)
48 const trackPostView = usePostViewTracking('PostQuotes')
49
50 const {
51 data: resolvedUri,
52 error: resolveError,
53 isLoading: isLoadingUri,
54 } = useResolveUriQuery(uri)
55 const {
56 data,
57 isLoading: isLoadingQuotes,
58 isFetchingNextPage,
59 hasNextPage,
60 fetchNextPage,
61 error,
62 refetch,
63 } = usePostQuotesQuery(resolvedUri?.uri)
64
65 const moderationOpts = useModerationOpts()
66
67 const isError = Boolean(resolveError || error)
68
69 const quotes =
70 data?.pages
71 .flatMap(page =>
72 page.posts.map(post => {
73 if (!AppBskyFeedPost.isRecord(post.record) || !moderationOpts) {
74 return null
75 }
76 const moderation = moderatePost(post, moderationOpts)
77 return {post, record: post.record, moderation}
78 }),
79 )
80 .filter(item => item !== null) ?? []
81
82 const onRefresh = useCallback(async () => {
83 setIsPTRing(true)
84 try {
85 await refetch()
86 } catch (err) {
87 logger.error('Failed to refresh quotes', {message: err})
88 }
89 setIsPTRing(false)
90 }, [refetch, setIsPTRing])
91
92 const onEndReached = useCallback(async () => {
93 if (isFetchingNextPage || !hasNextPage || isError) return
94 try {
95 await fetchNextPage()
96 } catch (err) {
97 logger.error('Failed to load more quotes', {message: err})
98 }
99 }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage])
100
101 if (quotes.length < 1) {
102 return (
103 <ListMaybePlaceholder
104 isLoading={isLoadingUri || isLoadingQuotes}
105 isError={isError}
106 emptyType="results"
107 emptyTitle={_(msg`No quotes yet`)}
108 emptyMessage={_(
109 msg`Nobody has quoted this yet. Maybe you should be the first!`,
110 )}
111 errorMessage={cleanError(resolveError || error)}
112 sideBorders={false}
113 />
114 )
115 }
116
117 // loaded
118 // =
119 return (
120 <List
121 data={quotes}
122 renderItem={renderItem}
123 keyExtractor={keyExtractor}
124 refreshing={isPTRing}
125 onRefresh={onRefresh}
126 onEndReached={onEndReached}
127 onEndReachedThreshold={4}
128 onItemSeen={item => trackPostView(item.post)}
129 ListFooterComponent={
130 <ListFooter
131 isFetchingNextPage={isFetchingNextPage}
132 error={cleanError(error)}
133 onRetry={fetchNextPage}
134 showEndMessage
135 endMessageText={_(msg`That's all, folks!`)}
136 />
137 }
138 // @ts-ignore our .web version only -prf
139 desktopFixedHeight
140 initialNumToRender={initialNumToRender}
141 windowSize={11}
142 sideBorders={false}
143 />
144 )
145}