mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at push-notifications 113 lines 2.8 kB view raw
1import React, {useRef} from 'react' 2import {observer} from 'mobx-react-lite' 3import {ActivityIndicator, FlatList, View} from 'react-native' 4import { 5 PostThreadViewModel, 6 PostThreadViewPostModel, 7} from '../../../state/models/post-thread-view' 8import {PostThreadItem} from './PostThreadItem' 9import {ErrorMessage} from '../util/error/ErrorMessage' 10import {s} from '../../lib/styles' 11 12export const PostThread = observer(function PostThread({ 13 uri, 14 view, 15}: { 16 uri: string 17 view: PostThreadViewModel 18}) { 19 const ref = useRef<FlatList>(null) 20 const posts = view.thread ? Array.from(flattenThread(view.thread)) : [] 21 const onRefresh = () => { 22 view 23 ?.refresh() 24 .catch(err => 25 view.rootStore.log.error('Failed to refresh posts thread', err), 26 ) 27 } 28 const onLayout = () => { 29 const index = posts.findIndex(post => post._isHighlightedPost) 30 if (index !== -1) { 31 ref.current?.scrollToIndex({ 32 index, 33 animated: false, 34 viewOffset: 40, 35 }) 36 } 37 } 38 const onScrollToIndexFailed = (info: { 39 index: number 40 highestMeasuredFrameIndex: number 41 averageItemLength: number 42 }) => { 43 ref.current?.scrollToOffset({ 44 animated: false, 45 offset: info.averageItemLength * info.index, 46 }) 47 } 48 49 // loading 50 // = 51 if ((view.isLoading && !view.isRefreshing) || view.params.uri !== uri) { 52 return ( 53 <View> 54 <ActivityIndicator /> 55 </View> 56 ) 57 } 58 59 // error 60 // = 61 if (view.hasError) { 62 return ( 63 <View> 64 <ErrorMessage message={view.error} onPressTryAgain={onRefresh} /> 65 </View> 66 ) 67 } 68 69 // loaded 70 // = 71 const renderItem = ({item}: {item: PostThreadViewPostModel}) => ( 72 <PostThreadItem item={item} onPostReply={onRefresh} /> 73 ) 74 return ( 75 <FlatList 76 ref={ref} 77 data={posts} 78 keyExtractor={item => item._reactKey} 79 renderItem={renderItem} 80 refreshing={view.isRefreshing} 81 onRefresh={onRefresh} 82 onLayout={onLayout} 83 onScrollToIndexFailed={onScrollToIndexFailed} 84 style={s.h100pct} 85 contentContainerStyle={s.contentContainer} 86 /> 87 ) 88}) 89 90function* flattenThread( 91 post: PostThreadViewPostModel, 92 isAscending = false, 93): Generator<PostThreadViewPostModel, void> { 94 if (post.parent) { 95 if ('notFound' in post.parent && post.parent.notFound) { 96 // TODO render not found 97 } else { 98 yield* flattenThread(post.parent as PostThreadViewPostModel, true) 99 } 100 } 101 yield post 102 if (post.replies?.length) { 103 for (const reply of post.replies) { 104 if ('notFound' in reply && reply.notFound) { 105 // TODO render not found 106 } else { 107 yield* flattenThread(reply as PostThreadViewPostModel) 108 } 109 } 110 } else if (!isAscending && !post.parent && post.post.replyCount > 0) { 111 post._hasMore = true 112 } 113}