mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React, {useMemo, useCallback} from 'react'
2import {ActivityIndicator, FlatList, View} from 'react-native'
3import {msg, Trans} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
6
7import {useResolveUriQuery} from '#/state/queries/resolve-uri'
8import {useLikedByQuery} from '#/state/queries/post-liked-by'
9import {cleanError} from '#/lib/strings/errors'
10import {logger} from '#/logger'
11
12import {atoms as a, useTheme} from '#/alf'
13import {Text} from '#/components/Typography'
14import * as Dialog from '#/components/Dialog'
15import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
16import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard'
17import {Loader} from '#/components/Loader'
18
19interface LikesDialogProps {
20 control: Dialog.DialogOuterProps['control']
21 uri: string
22}
23
24export function LikesDialog(props: LikesDialogProps) {
25 return (
26 <Dialog.Outer control={props.control}>
27 <Dialog.Handle />
28
29 <LikesDialogInner {...props} />
30 </Dialog.Outer>
31 )
32}
33
34export function LikesDialogInner({control, uri}: LikesDialogProps) {
35 const {_} = useLingui()
36 const t = useTheme()
37
38 const {
39 data: resolvedUri,
40 error: resolveError,
41 isFetched: hasFetchedResolvedUri,
42 } = useResolveUriQuery(uri)
43 const {
44 data,
45 isFetching: isFetchingLikedBy,
46 isFetched: hasFetchedLikedBy,
47 isFetchingNextPage,
48 hasNextPage,
49 fetchNextPage,
50 isError,
51 error: likedByError,
52 } = useLikedByQuery(resolvedUri?.uri)
53
54 const isLoading = !hasFetchedResolvedUri || !hasFetchedLikedBy
55 const likes = useMemo(() => {
56 if (data?.pages) {
57 return data.pages.flatMap(page => page.likes)
58 }
59 return []
60 }, [data])
61
62 const onEndReached = useCallback(async () => {
63 if (isFetchingLikedBy || !hasNextPage || isError) return
64 try {
65 await fetchNextPage()
66 } catch (err) {
67 logger.error('Failed to load more likes', {message: err})
68 }
69 }, [isFetchingLikedBy, hasNextPage, isError, fetchNextPage])
70
71 const renderItem = useCallback(
72 ({item}: {item: GetLikes.Like}) => {
73 return (
74 <ProfileCardWithFollowBtn
75 key={item.actor.did}
76 profile={item.actor}
77 onPress={() => control.close()}
78 />
79 )
80 },
81 [control],
82 )
83
84 return (
85 <Dialog.Inner label={_(msg`Users that have liked this content or profile`)}>
86 <Text style={[a.text_2xl, a.font_bold, a.leading_tight, a.pb_lg]}>
87 <Trans>Liked by</Trans>
88 </Text>
89
90 {isLoading ? (
91 <View style={{minHeight: 300}}>
92 <Loader size="xl" />
93 </View>
94 ) : resolveError || likedByError || !data ? (
95 <ErrorMessage message={cleanError(resolveError || likedByError)} />
96 ) : likes.length === 0 ? (
97 <View style={[t.atoms.bg_contrast_50, a.px_md, a.py_xl, a.rounded_md]}>
98 <Text style={[a.text_center]}>
99 <Trans>
100 Nobody has liked this yet. Maybe you should be the first!
101 </Trans>
102 </Text>
103 </View>
104 ) : (
105 <FlatList
106 data={likes}
107 keyExtractor={item => item.actor.did}
108 onEndReached={onEndReached}
109 renderItem={renderItem}
110 initialNumToRender={15}
111 ListFooterComponent={
112 <ListFooterComponent isFetching={isFetchingNextPage} />
113 }
114 />
115 )}
116
117 <Dialog.Close />
118 </Dialog.Inner>
119 )
120}
121
122function ListFooterComponent({isFetching}: {isFetching: boolean}) {
123 if (isFetching) {
124 return (
125 <View style={a.pt_lg}>
126 <ActivityIndicator />
127 </View>
128 )
129 }
130 return null
131}