diff options
Diffstat (limited to 'src/view/com/discover/SuggestedFollows.tsx')
-rw-r--r-- | src/view/com/discover/SuggestedFollows.tsx | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/view/com/discover/SuggestedFollows.tsx b/src/view/com/discover/SuggestedFollows.tsx new file mode 100644 index 000000000..e73d9a7db --- /dev/null +++ b/src/view/com/discover/SuggestedFollows.tsx @@ -0,0 +1,177 @@ +import React, {useMemo, useEffect} from 'react' +import { + ActivityIndicator, + FlatList, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native' +import LinearGradient from 'react-native-linear-gradient' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {observer} from 'mobx-react-lite' +import {ErrorScreen} from '../util/ErrorScreen' +import {UserAvatar} from '../util/UserAvatar' +import {useStores} from '../../../state' +import { + SuggestedActorsViewModel, + SuggestedActor, +} from '../../../state/models/suggested-actors-view' +import {s, colors, gradients} from '../../lib/styles' + +export const SuggestedFollows = observer( + ({onNoSuggestions}: {onNoSuggestions?: () => void}) => { + const store = useStores() + + const view = useMemo<SuggestedActorsViewModel>( + () => new SuggestedActorsViewModel(store), + [], + ) + + useEffect(() => { + console.log('Fetching suggested actors') + view + .setup() + .catch((err: any) => console.error('Failed to fetch suggestions', err)) + }, [view]) + + useEffect(() => { + if (!view.isLoading && !view.hasError && !view.hasContent) { + onNoSuggestions?.() + } + }, [view, view.isLoading, view.hasError, view.hasContent]) + + const onPressTryAgain = () => + view + .setup() + .catch((err: any) => console.error('Failed to fetch suggestions', err)) + + const renderItem = ({item}: {item: SuggestedActor}) => <User item={item} /> + return ( + <View style={styles.container}> + {view.isLoading ? ( + <View> + <ActivityIndicator /> + </View> + ) : view.hasError ? ( + <ErrorScreen + title="Failed to load suggestions" + message="There was an error while trying to load suggested follows." + details={view.error} + onPressTryAgain={onPressTryAgain} + /> + ) : ( + <View style={styles.suggestionsContainer}> + <FlatList + data={view.suggestions} + keyExtractor={item => item._reactKey} + renderItem={renderItem} + style={s.flex1} + /> + </View> + )} + </View> + ) + }, +) + +const User = ({item}: {item: SuggestedActor}) => { + return ( + <View style={styles.actor}> + <View style={styles.actorMeta}> + <View style={styles.actorAvi}> + <UserAvatar + size={40} + displayName={item.displayName} + handle={item.handle} + /> + </View> + <View style={styles.actorContent}> + <Text style={[s.f17, s.bold]} numberOfLines={1}> + {item.displayName} + </Text> + <Text style={[s.f14, s.gray5]} numberOfLines={1}> + @{item.handle} + </Text> + </View> + <View style={styles.actorBtn}> + <TouchableOpacity> + <LinearGradient + colors={[gradients.primary.start, gradients.primary.end]} + start={{x: 0, y: 0}} + end={{x: 1, y: 1}} + style={[styles.btn, styles.gradientBtn]}> + <FontAwesomeIcon icon="plus" style={[s.white, s.mr5]} size={15} /> + <Text style={[s.white, s.fw600, s.f15]}>Follow</Text> + </LinearGradient> + </TouchableOpacity> + </View> + </View> + {item.description ? ( + <View style={styles.actorDetails}> + <Text style={[s.f15]} numberOfLines={4}> + {item.description} + </Text> + </View> + ) : undefined} + </View> + ) +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + + suggestionsContainer: { + flex: 1, + backgroundColor: colors.gray1, + }, + + actor: { + backgroundColor: colors.white, + borderRadius: 6, + margin: 2, + marginBottom: 0, + }, + actorMeta: { + flexDirection: 'row', + }, + actorAvi: { + width: 60, + paddingLeft: 10, + paddingTop: 10, + paddingBottom: 10, + }, + actorContent: { + flex: 1, + paddingRight: 10, + paddingTop: 10, + }, + actorBtn: { + paddingRight: 10, + paddingTop: 10, + }, + actorDetails: { + paddingLeft: 60, + paddingRight: 10, + paddingBottom: 10, + }, + + gradientBtn: { + paddingHorizontal: 24, + paddingVertical: 6, + }, + secondaryBtn: { + paddingHorizontal: 14, + }, + btn: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + paddingVertical: 7, + borderRadius: 50, + backgroundColor: colors.gray1, + marginLeft: 6, + }, +}) |