|
1 | 1 | import { Ionicons } from '@expo/vector-icons'; |
2 | 2 | import { Screen } from '@/src/common/components/layout'; |
3 | 3 | import { Fab } from '@/src/common/components'; |
4 | | -import { FeedViewer, type FeedType } from '@/src/features/post'; |
| 4 | +import { Text } from '@/src/common/components/primitives'; |
| 5 | +import { FeedViewer } from '@/src/features/post'; |
5 | 6 | import { ComposerInput } from '@/src/features/composer'; |
6 | 7 | import { useFollowingFeed } from './hooks/useFollowingFeed'; |
7 | 8 | import { openCompose } from '@/src/common/constants'; |
8 | 9 | import { isWeb } from '@/src/common/util/platform'; |
| 10 | +import { Atoms, useTheme } from '@/src/common/theme'; |
| 11 | +import { ActivityIndicator, RefreshControl, View } from 'react-native'; |
| 12 | + |
| 13 | +const ListHeader = () => ( |
| 14 | + <> |
| 15 | + {!isWeb ? <Screen.Topbar /> : null} |
| 16 | + <ComposerInput /> |
| 17 | + </> |
| 18 | +); |
9 | 19 |
|
10 | 20 | export default function FeedScreen() { |
| 21 | + const { theme } = useTheme(); |
11 | 22 | const showComposeFab = !isWeb; |
12 | 23 |
|
13 | | - const feed = useFollowingFeed({ |
14 | | - enabled: true, |
15 | | - }); |
| 24 | + const feed = useFollowingFeed({ enabled: true }); |
16 | 25 |
|
17 | | - const handleFabPress = () => { |
18 | | - openCompose(); |
19 | | - }; |
| 26 | + if (feed.error) { |
| 27 | + return ( |
| 28 | + <Screen> |
| 29 | + <Screen.PrimaryColumn> |
| 30 | + <View |
| 31 | + style={[ |
| 32 | + Atoms.flex_1, |
| 33 | + Atoms.items_center, |
| 34 | + Atoms.justify_center, |
| 35 | + Atoms.p_lg, |
| 36 | + ]} |
| 37 | + > |
| 38 | + <Text color="neutral_500">Failed to load feed</Text> |
| 39 | + </View> |
| 40 | + </Screen.PrimaryColumn> |
| 41 | + </Screen> |
| 42 | + ); |
| 43 | + } |
20 | 44 |
|
21 | 45 | return ( |
22 | 46 | <Screen> |
23 | 47 | <Screen.PrimaryColumn> |
24 | | - <ComposerInput /> |
25 | 48 | <FeedViewer |
26 | | - items={feed.items} |
27 | | - isLoading={feed.isLoading} |
28 | | - error={feed.error} |
29 | | - onRefresh={feed.refresh} |
30 | | - onEndReached={feed.loadMore} |
31 | | - hasMore={feed.hasMore} |
32 | | - bottomPadding={0} |
| 49 | + data={feed.items} |
| 50 | + ListHeaderComponent={ListHeader} |
| 51 | + ListEmptyComponent={ |
| 52 | + !feed.isLoading ? ( |
| 53 | + <View |
| 54 | + style={[ |
| 55 | + Atoms.flex_1, |
| 56 | + Atoms.items_center, |
| 57 | + Atoms.justify_center, |
| 58 | + Atoms.p_lg, |
| 59 | + ]} |
| 60 | + > |
| 61 | + <Text color="neutral_500">No posts yet</Text> |
| 62 | + </View> |
| 63 | + ) : null |
| 64 | + } |
| 65 | + ListFooterComponent={ |
| 66 | + feed.hasMore && feed.items.length > 0 ? ( |
| 67 | + <View style={[Atoms.items_center, Atoms.p_lg]}> |
| 68 | + <ActivityIndicator |
| 69 | + size="small" |
| 70 | + color={theme.palette.neutral_500} |
| 71 | + accessibilityLabel="Loading more posts" |
| 72 | + /> |
| 73 | + </View> |
| 74 | + ) : null |
| 75 | + } |
| 76 | + onEndReached={feed.hasMore ? feed.loadMore : undefined} |
| 77 | + onEndReachedThreshold={0.5} |
| 78 | + refreshControl={ |
| 79 | + !isWeb ? ( |
| 80 | + <RefreshControl |
| 81 | + refreshing={feed.isLoading} |
| 82 | + onRefresh={feed.refresh} |
| 83 | + /> |
| 84 | + ) : undefined |
| 85 | + } |
| 86 | + showsVerticalScrollIndicator={false} |
33 | 87 | /> |
34 | 88 | {showComposeFab ? ( |
35 | 89 | <Fab |
36 | 90 | title="New Post" |
37 | | - onPress={handleFabPress} |
| 91 | + onPress={openCompose} |
38 | 92 | icon={() => <Ionicons name="add-circle" size={22} color="white" />} |
39 | 93 | /> |
40 | 94 | ) : null} |
|
0 commit comments