Bluesky app fork with some witchin' additions 💫

ALF feed error screen (#9895)

authored by samuel.fm and committed by

GitHub a1cda126 ae115ca1

+25 -78
+25 -78
src/screens/Profile/ProfileFeed/index.tsx
··· 1 - import React, {useCallback, useMemo} from 'react' 2 - import {StyleSheet, View} from 'react-native' 3 import {useAnimatedRef} from 'react-native-reanimated' 4 import {AppBskyFeedDefs} from '@atproto/api' 5 - import {msg, Trans} from '@lingui/macro' 6 import {useLingui} from '@lingui/react' 7 - import {useIsFocused, useNavigation} from '@react-navigation/native' 8 import {type NativeStackScreenProps} from '@react-navigation/native-stack' 9 import {useQueryClient} from '@tanstack/react-query' 10 11 import {VIDEO_FEED_URIS} from '#/lib/constants' 12 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 13 - import {usePalette} from '#/lib/hooks/usePalette' 14 import {useSetTitle} from '#/lib/hooks/useSetTitle' 15 import {ComposeIcon2} from '#/lib/icons' 16 - import { 17 - type CommonNavigatorParams, 18 - type NavigationProp, 19 - } from '#/lib/routes/types' 20 import {makeRecordUri} from '#/lib/strings/url-helpers' 21 - import {s} from '#/lib/styles' 22 import {listenSoftReset} from '#/state/events' 23 import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback' 24 import { ··· 36 import {useSession} from '#/state/session' 37 import {PostFeed} from '#/view/com/posts/PostFeed' 38 import {EmptyState} from '#/view/com/util/EmptyState' 39 import {FAB} from '#/view/com/util/fab/FAB' 40 - import {Button} from '#/view/com/util/forms/Button' 41 import {type ListRef} from '#/view/com/util/List' 42 import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 43 import {PostFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 44 - import {Text} from '#/view/com/util/text/Text' 45 import { 46 ProfileFeedHeader, 47 ProfileFeedHeaderSkeleton, ··· 55 const {rkey, name: handleOrDid} = props.route.params 56 57 const feedParams: FeedParams | undefined = props.route.params.feedCacheKey 58 - ? { 59 - feedCacheKey: props.route.params.feedCacheKey, 60 - } 61 : undefined 62 - const pal = usePalette('default') 63 const {_} = useLingui() 64 - const navigation = useNavigation<NavigationProp>() 65 66 const uri = useMemo( 67 () => makeRecordUri(handleOrDid, 'app.bsky.feed.generator', rkey), 68 [rkey, handleOrDid], 69 ) 70 - const {error, data: resolvedUri} = useResolveUriQuery(uri) 71 - 72 - const onPressBack = React.useCallback(() => { 73 - if (navigation.canGoBack()) { 74 - navigation.goBack() 75 - } else { 76 - navigation.navigate('Home') 77 - } 78 - }, [navigation]) 79 80 - if (error) { 81 return ( 82 <Layout.Screen testID="profileFeedScreenError"> 83 - <Layout.Content> 84 - <View style={[pal.view, pal.border, styles.notFoundContainer]}> 85 - <Text type="title-lg" style={[pal.text, s.mb10]}> 86 - <Trans>Could not load feed</Trans> 87 - </Text> 88 - <Text type="md" style={[pal.text, s.mb20]}> 89 - {error.toString()} 90 - </Text> 91 - 92 - <View style={{flexDirection: 'row'}}> 93 - <Button 94 - type="default" 95 - accessibilityLabel={_(msg`Go back`)} 96 - accessibilityHint={_(msg`Returns to previous page`)} 97 - onPress={onPressBack} 98 - style={{flexShrink: 1}}> 99 - <Text type="button" style={pal.text}> 100 - <Trans>Go Back</Trans> 101 - </Text> 102 - </Button> 103 - </View> 104 - </View> 105 - </Layout.Content> 106 </Layout.Screen> 107 ) 108 } ··· 169 170 const feed = `feedgen|${feedInfo.uri}` as FeedDescriptor 171 172 - const [hasNew, setHasNew] = React.useState(false) 173 - const [isScrolledDown, setIsScrolledDown] = React.useState(false) 174 const queryClient = useQueryClient() 175 const feedFeedback = useFeedFeedback(feedInfo, hasSession) 176 const scrollElRef = useAnimatedRef() as ListRef ··· 180 animated: IS_NATIVE, 181 offset: 0, // -headerHeight, 182 }) 183 - truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) 184 setHasNew(false) 185 }, [scrollElRef, queryClient, feed, setHasNew]) 186 187 - React.useEffect(() => { 188 if (!isScreenFocused) { 189 return 190 } ··· 201 ) 202 }, [_]) 203 204 - const isVideoFeed = React.useMemo(() => { 205 const isBskyVideoFeed = VIDEO_FEED_URIS.includes(feedInfo.uri) 206 const feedIsVideoMode = 207 feedInfo.contentMode === AppBskyFeedDefs.CONTENTMODEVIDEO ··· 254 </> 255 ) 256 } 257 - 258 - const styles = StyleSheet.create({ 259 - btn: { 260 - flexDirection: 'row', 261 - alignItems: 'center', 262 - gap: 6, 263 - paddingVertical: 7, 264 - paddingHorizontal: 14, 265 - borderRadius: 50, 266 - marginLeft: 6, 267 - }, 268 - notFoundContainer: { 269 - margin: 10, 270 - paddingHorizontal: 18, 271 - paddingVertical: 14, 272 - borderRadius: 6, 273 - }, 274 - aboutSectionContainer: { 275 - paddingVertical: 4, 276 - paddingHorizontal: 16, 277 - gap: 12, 278 - }, 279 - })
··· 1 + import {useCallback, useEffect, useMemo, useState} from 'react' 2 import {useAnimatedRef} from 'react-native-reanimated' 3 import {AppBskyFeedDefs} from '@atproto/api' 4 + import {msg} from '@lingui/macro' 5 import {useLingui} from '@lingui/react' 6 + import {useIsFocused} from '@react-navigation/native' 7 import {type NativeStackScreenProps} from '@react-navigation/native-stack' 8 import {useQueryClient} from '@tanstack/react-query' 9 10 import {VIDEO_FEED_URIS} from '#/lib/constants' 11 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 12 import {useSetTitle} from '#/lib/hooks/useSetTitle' 13 import {ComposeIcon2} from '#/lib/icons' 14 + import {type CommonNavigatorParams} from '#/lib/routes/types' 15 + import {cleanError} from '#/lib/strings/errors' 16 import {makeRecordUri} from '#/lib/strings/url-helpers' 17 import {listenSoftReset} from '#/state/events' 18 import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback' 19 import { ··· 31 import {useSession} from '#/state/session' 32 import {PostFeed} from '#/view/com/posts/PostFeed' 33 import {EmptyState} from '#/view/com/util/EmptyState' 34 + import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' 35 import {FAB} from '#/view/com/util/fab/FAB' 36 import {type ListRef} from '#/view/com/util/List' 37 import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 38 import {PostFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 39 import { 40 ProfileFeedHeader, 41 ProfileFeedHeaderSkeleton, ··· 49 const {rkey, name: handleOrDid} = props.route.params 50 51 const feedParams: FeedParams | undefined = props.route.params.feedCacheKey 52 + ? {feedCacheKey: props.route.params.feedCacheKey} 53 : undefined 54 const {_} = useLingui() 55 56 const uri = useMemo( 57 () => makeRecordUri(handleOrDid, 'app.bsky.feed.generator', rkey), 58 [rkey, handleOrDid], 59 ) 60 + let { 61 + error, 62 + data: resolvedUri, 63 + refetch, 64 + isRefetching, 65 + } = useResolveUriQuery(uri) 66 67 + if (error && !isRefetching) { 68 return ( 69 <Layout.Screen testID="profileFeedScreenError"> 70 + <ErrorScreen 71 + showHeader 72 + title={_(msg`Could not load feed`)} 73 + message={cleanError(error)} 74 + onPressTryAgain={() => void refetch()} 75 + /> 76 </Layout.Screen> 77 ) 78 } ··· 139 140 const feed = `feedgen|${feedInfo.uri}` as FeedDescriptor 141 142 + const [hasNew, setHasNew] = useState(false) 143 + const [isScrolledDown, setIsScrolledDown] = useState(false) 144 const queryClient = useQueryClient() 145 const feedFeedback = useFeedFeedback(feedInfo, hasSession) 146 const scrollElRef = useAnimatedRef() as ListRef ··· 150 animated: IS_NATIVE, 151 offset: 0, // -headerHeight, 152 }) 153 + void truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) 154 setHasNew(false) 155 }, [scrollElRef, queryClient, feed, setHasNew]) 156 157 + useEffect(() => { 158 if (!isScreenFocused) { 159 return 160 } ··· 171 ) 172 }, [_]) 173 174 + const isVideoFeed = useMemo(() => { 175 const isBskyVideoFeed = VIDEO_FEED_URIS.includes(feedInfo.uri) 176 const feedIsVideoMode = 177 feedInfo.contentMode === AppBskyFeedDefs.CONTENTMODEVIDEO ··· 224 </> 225 ) 226 }