ProfileFollows and ProfileFollowers cleanup (#3219)
* cleanup PostThread rm some more unnecessary code cleanup some more pieces fix `isLoading` logic few fixes organize refactor `PostThread` allow chaining of `postThreadQuery` Update `Hashtag` screen with the component changes Make some changes to the List components adjust height and padding of bottom loader to account for bottom bar * rm unnecessary chaining logic * maxReplies logic * adjust error logic * use `<` instead of `<=` * add back warning comment * remove unused prop * adjust order * implement list improvements for followers/follows * update prop name * small adjustments fix flex add window size adjust isLoading * remove log * don't show retry for no results * don't show error if `isLoading`
This commit is contained in:
		
							parent
							
								
									addd66b37f
								
							
						
					
					
						commit
						b9474a5d55
					
				
					 4 changed files with 133 additions and 118 deletions
				
			
		|  | @ -1,39 +1,66 @@ | |||
| import React from 'react' | ||||
| import {ActivityIndicator, StyleSheet, View} from 'react-native' | ||||
| import {AppBskyActorDefs as ActorDefs} from '@atproto/api' | ||||
| import {CenteredView} from '../util/Views' | ||||
| import {LoadingScreen} from '../util/LoadingScreen' | ||||
| import {List} from '../util/List' | ||||
| import {ErrorMessage} from '../util/error/ErrorMessage' | ||||
| import {ProfileCardWithFollowBtn} from './ProfileCard' | ||||
| import {useProfileFollowersQuery} from '#/state/queries/profile-followers' | ||||
| import {useResolveDidQuery} from '#/state/queries/resolve-uri' | ||||
| import {logger} from '#/logger' | ||||
| import {cleanError} from '#/lib/strings/errors' | ||||
| import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' | ||||
| import { | ||||
|   ListFooter, | ||||
|   ListHeaderDesktop, | ||||
|   ListMaybePlaceholder, | ||||
| } from '#/components/Lists' | ||||
| import {msg} from '@lingui/macro' | ||||
| import {useLingui} from '@lingui/react' | ||||
| import {useSession} from 'state/session' | ||||
| import {View} from 'react-native' | ||||
| 
 | ||||
| function renderItem({item}: {item: ActorDefs.ProfileViewBasic}) { | ||||
|   return <ProfileCardWithFollowBtn key={item.did} profile={item} /> | ||||
| } | ||||
| 
 | ||||
| function keyExtractor(item: ActorDefs.ProfileViewBasic) { | ||||
|   return item.did | ||||
| } | ||||
| 
 | ||||
| export function ProfileFollowers({name}: {name: string}) { | ||||
|   const {_} = useLingui() | ||||
|   const initialNumToRender = useInitialNumToRender() | ||||
|   const {currentAccount} = useSession() | ||||
| 
 | ||||
|   const [isPTRing, setIsPTRing] = React.useState(false) | ||||
|   const { | ||||
|     data: resolvedDid, | ||||
|     isLoading: isDidLoading, | ||||
|     error: resolveError, | ||||
|     isFetching: isFetchingDid, | ||||
|   } = useResolveDidQuery(name) | ||||
|   const { | ||||
|     data, | ||||
|     isLoading: isFollowersLoading, | ||||
|     isFetching, | ||||
|     isFetched, | ||||
|     isFetchingNextPage, | ||||
|     hasNextPage, | ||||
|     fetchNextPage, | ||||
|     isError, | ||||
|     error, | ||||
|     refetch, | ||||
|   } = useProfileFollowersQuery(resolvedDid) | ||||
| 
 | ||||
|   const isError = React.useMemo( | ||||
|     () => !!resolveError || !!error, | ||||
|     [resolveError, error], | ||||
|   ) | ||||
| 
 | ||||
|   const isMe = React.useMemo(() => { | ||||
|     return resolvedDid === currentAccount?.did | ||||
|   }, [resolvedDid, currentAccount?.did]) | ||||
| 
 | ||||
|   const followers = React.useMemo(() => { | ||||
|     if (data?.pages) { | ||||
|       return data.pages.flatMap(page => page.followers) | ||||
|     } | ||||
|     return [] | ||||
|   }, [data]) | ||||
| 
 | ||||
|   const onRefresh = React.useCallback(async () => { | ||||
|  | @ -47,7 +74,7 @@ export function ProfileFollowers({name}: {name: string}) { | |||
|   }, [refetch, setIsPTRing]) | ||||
| 
 | ||||
|   const onEndReached = async () => { | ||||
|     if (isFetching || !hasNextPage || isError) return | ||||
|     if (isFetching || !hasNextPage || !!error) return | ||||
|     try { | ||||
|       await fetchNextPage() | ||||
|     } catch (err) { | ||||
|  | @ -55,57 +82,38 @@ export function ProfileFollowers({name}: {name: string}) { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const renderItem = React.useCallback( | ||||
|     ({item}: {item: ActorDefs.ProfileViewBasic}) => ( | ||||
|       <ProfileCardWithFollowBtn key={item.did} profile={item} /> | ||||
|     ), | ||||
|     [], | ||||
|   ) | ||||
| 
 | ||||
|   if (isFetchingDid || !isFetched) { | ||||
|     return <LoadingScreen /> | ||||
|   } | ||||
| 
 | ||||
|   // error
 | ||||
|   // =
 | ||||
|   if (resolveError || isError) { | ||||
|     return ( | ||||
|       <CenteredView> | ||||
|         <ErrorMessage | ||||
|           message={cleanError(resolveError || error)} | ||||
|           onPressTryAgain={onRefresh} | ||||
|         /> | ||||
|       </CenteredView> | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   // loaded
 | ||||
|   // =
 | ||||
|   return ( | ||||
|     <List | ||||
|       data={followers} | ||||
|       keyExtractor={item => item.did} | ||||
|       refreshing={isPTRing} | ||||
|       onRefresh={onRefresh} | ||||
|       onEndReached={onEndReached} | ||||
|       renderItem={renderItem} | ||||
|       initialNumToRender={15} | ||||
|       // FIXME(dan)
 | ||||
|       // eslint-disable-next-line react/no-unstable-nested-components
 | ||||
|       ListFooterComponent={() => ( | ||||
|         <View style={styles.footer}> | ||||
|           {(isFetching || isFetchingNextPage) && <ActivityIndicator />} | ||||
|         </View> | ||||
|     <View style={{flex: 1}}> | ||||
|       <ListMaybePlaceholder | ||||
|         isLoading={isDidLoading || isFollowersLoading} | ||||
|         isEmpty={followers.length < 1} | ||||
|         isError={isError} | ||||
|         emptyType="results" | ||||
|         emptyMessage={ | ||||
|           isMe | ||||
|             ? _(msg`You do not have any followers.`) | ||||
|             : _(msg`This user doesn't have any followers.`) | ||||
|         } | ||||
|         errorMessage={cleanError(resolveError || error)} | ||||
|         onRetry={isError ? refetch : undefined} | ||||
|       /> | ||||
|       {followers.length > 0 && ( | ||||
|         <List | ||||
|           data={followers} | ||||
|           renderItem={renderItem} | ||||
|           keyExtractor={keyExtractor} | ||||
|           refreshing={isPTRing} | ||||
|           onRefresh={onRefresh} | ||||
|           onEndReached={onEndReached} | ||||
|           onEndReachedThreshold={4} | ||||
|           ListHeaderComponent={<ListHeaderDesktop title={_(msg`Followers`)} />} | ||||
|           ListFooterComponent={<ListFooter isFetching={isFetchingNextPage} />} | ||||
|           // @ts-ignore our .web version only -prf
 | ||||
|           desktopFixedHeight | ||||
|           initialNumToRender={initialNumToRender} | ||||
|           windowSize={11} | ||||
|         /> | ||||
|       )} | ||||
|       // @ts-ignore our .web version only -prf
 | ||||
|       desktopFixedHeight | ||||
|     /> | ||||
|     </View> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| const styles = StyleSheet.create({ | ||||
|   footer: { | ||||
|     height: 200, | ||||
|     paddingTop: 20, | ||||
|   }, | ||||
| }) | ||||
|  |  | |||
|  | @ -1,39 +1,65 @@ | |||
| import React from 'react' | ||||
| import {ActivityIndicator, StyleSheet, View} from 'react-native' | ||||
| import {AppBskyActorDefs as ActorDefs} from '@atproto/api' | ||||
| import {CenteredView} from '../util/Views' | ||||
| import {LoadingScreen} from '../util/LoadingScreen' | ||||
| import {List} from '../util/List' | ||||
| import {ErrorMessage} from '../util/error/ErrorMessage' | ||||
| import {ProfileCardWithFollowBtn} from './ProfileCard' | ||||
| import {useProfileFollowsQuery} from '#/state/queries/profile-follows' | ||||
| import {useResolveDidQuery} from '#/state/queries/resolve-uri' | ||||
| import {logger} from '#/logger' | ||||
| import {cleanError} from '#/lib/strings/errors' | ||||
| import { | ||||
|   ListFooter, | ||||
|   ListHeaderDesktop, | ||||
|   ListMaybePlaceholder, | ||||
| } from '#/components/Lists' | ||||
| import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' | ||||
| import {useSession} from 'state/session' | ||||
| import {msg} from '@lingui/macro' | ||||
| import {useLingui} from '@lingui/react' | ||||
| 
 | ||||
| function renderItem({item}: {item: ActorDefs.ProfileViewBasic}) { | ||||
|   return <ProfileCardWithFollowBtn key={item.did} profile={item} /> | ||||
| } | ||||
| 
 | ||||
| function keyExtractor(item: ActorDefs.ProfileViewBasic) { | ||||
|   return item.did | ||||
| } | ||||
| 
 | ||||
| export function ProfileFollows({name}: {name: string}) { | ||||
|   const {_} = useLingui() | ||||
|   const initialNumToRender = useInitialNumToRender() | ||||
|   const {currentAccount} = useSession() | ||||
| 
 | ||||
|   const [isPTRing, setIsPTRing] = React.useState(false) | ||||
|   const { | ||||
|     data: resolvedDid, | ||||
|     isLoading: isDidLoading, | ||||
|     error: resolveError, | ||||
|     isFetching: isFetchingDid, | ||||
|   } = useResolveDidQuery(name) | ||||
|   const { | ||||
|     data, | ||||
|     isLoading: isFollowsLoading, | ||||
|     isFetching, | ||||
|     isFetched, | ||||
|     isFetchingNextPage, | ||||
|     hasNextPage, | ||||
|     fetchNextPage, | ||||
|     isError, | ||||
|     error, | ||||
|     refetch, | ||||
|   } = useProfileFollowsQuery(resolvedDid) | ||||
| 
 | ||||
|   const isError = React.useMemo( | ||||
|     () => !!resolveError || !!error, | ||||
|     [resolveError, error], | ||||
|   ) | ||||
| 
 | ||||
|   const isMe = React.useMemo(() => { | ||||
|     return resolvedDid === currentAccount?.did | ||||
|   }, [resolvedDid, currentAccount?.did]) | ||||
| 
 | ||||
|   const follows = React.useMemo(() => { | ||||
|     if (data?.pages) { | ||||
|       return data.pages.flatMap(page => page.follows) | ||||
|     } | ||||
|     return [] | ||||
|   }, [data]) | ||||
| 
 | ||||
|   const onRefresh = React.useCallback(async () => { | ||||
|  | @ -47,7 +73,7 @@ export function ProfileFollows({name}: {name: string}) { | |||
|   }, [refetch, setIsPTRing]) | ||||
| 
 | ||||
|   const onEndReached = async () => { | ||||
|     if (isFetching || !hasNextPage || isError) return | ||||
|     if (isFetching || !hasNextPage || !!error) return | ||||
|     try { | ||||
|       await fetchNextPage() | ||||
|     } catch (err) { | ||||
|  | @ -55,57 +81,38 @@ export function ProfileFollows({name}: {name: string}) { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const renderItem = React.useCallback( | ||||
|     ({item}: {item: ActorDefs.ProfileViewBasic}) => ( | ||||
|       <ProfileCardWithFollowBtn key={item.did} profile={item} /> | ||||
|     ), | ||||
|     [], | ||||
|   ) | ||||
| 
 | ||||
|   if (isFetchingDid || !isFetched) { | ||||
|     return <LoadingScreen /> | ||||
|   } | ||||
| 
 | ||||
|   // error
 | ||||
|   // =
 | ||||
|   if (resolveError || isError) { | ||||
|     return ( | ||||
|       <CenteredView> | ||||
|         <ErrorMessage | ||||
|           message={cleanError(resolveError || error)} | ||||
|           onPressTryAgain={onRefresh} | ||||
|         /> | ||||
|       </CenteredView> | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   // loaded
 | ||||
|   // =
 | ||||
|   return ( | ||||
|     <List | ||||
|       data={follows} | ||||
|       keyExtractor={item => item.did} | ||||
|       refreshing={isPTRing} | ||||
|       onRefresh={onRefresh} | ||||
|       onEndReached={onEndReached} | ||||
|       renderItem={renderItem} | ||||
|       initialNumToRender={15} | ||||
|       // FIXME(dan)
 | ||||
|       // eslint-disable-next-line react/no-unstable-nested-components
 | ||||
|       ListFooterComponent={() => ( | ||||
|         <View style={styles.footer}> | ||||
|           {(isFetching || isFetchingNextPage) && <ActivityIndicator />} | ||||
|         </View> | ||||
|     <> | ||||
|       <ListMaybePlaceholder | ||||
|         isLoading={isDidLoading || isFollowsLoading} | ||||
|         isEmpty={follows.length < 1} | ||||
|         isError={isError} | ||||
|         emptyType="results" | ||||
|         emptyMessage={ | ||||
|           isMe | ||||
|             ? _(msg`You are not following anyone.`) | ||||
|             : _(msg`This user isn't following anyone.`) | ||||
|         } | ||||
|         errorMessage={cleanError(resolveError || error)} | ||||
|         onRetry={isError ? refetch : undefined} | ||||
|       /> | ||||
|       {follows.length > 0 && ( | ||||
|         <List | ||||
|           data={follows} | ||||
|           renderItem={renderItem} | ||||
|           keyExtractor={keyExtractor} | ||||
|           refreshing={isPTRing} | ||||
|           onRefresh={onRefresh} | ||||
|           onEndReached={onEndReached} | ||||
|           onEndReachedThreshold={4} | ||||
|           ListHeaderComponent={<ListHeaderDesktop title={_(msg`Following`)} />} | ||||
|           ListFooterComponent={<ListFooter isFetching={isFetchingNextPage} />} | ||||
|           // @ts-ignore our .web version only -prf
 | ||||
|           desktopFixedHeight | ||||
|           initialNumToRender={initialNumToRender} | ||||
|           windowSize={11} | ||||
|         /> | ||||
|       )} | ||||
|       // @ts-ignore our .web version only -prf
 | ||||
|       desktopFixedHeight | ||||
|     /> | ||||
|     </> | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| const styles = StyleSheet.create({ | ||||
|   footer: { | ||||
|     height: 200, | ||||
|     paddingTop: 20, | ||||
|   }, | ||||
| }) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue