diff options
Diffstat (limited to 'src/components')
-rw-r--r-- | src/components/common/GradientBorderButton.tsx | 2 | ||||
-rw-r--r-- | src/components/common/TabsGradient.tsx | 2 | ||||
-rw-r--r-- | src/components/profile/PublicProfile.tsx | 2 | ||||
-rw-r--r-- | src/components/search/RecentSearches.tsx | 31 | ||||
-rw-r--r-- | src/components/search/SearchBar.tsx | 37 | ||||
-rw-r--r-- | src/components/search/SearchCategories.tsx | 68 | ||||
-rw-r--r-- | src/components/search/SearchResultList.tsx | 85 | ||||
-rw-r--r-- | src/components/search/SearchResults.tsx | 14 | ||||
-rw-r--r-- | src/components/search/SearchResultsBackground.tsx | 69 |
9 files changed, 155 insertions, 155 deletions
diff --git a/src/components/common/GradientBorderButton.tsx b/src/components/common/GradientBorderButton.tsx index 32ac5c52..a5dbde9d 100644 --- a/src/components/common/GradientBorderButton.tsx +++ b/src/components/common/GradientBorderButton.tsx @@ -42,7 +42,7 @@ const GradientBorderButton: React.FC<GradientBorderButtonProps> = ({ }; const styles = StyleSheet.create({ container: { - marginVertical: 15, + marginVertical: 10, }, gradientContainer: { width: SCREEN_WIDTH / 2 - 40, diff --git a/src/components/common/TabsGradient.tsx b/src/components/common/TabsGradient.tsx index a95e8bc3..07c55042 100644 --- a/src/components/common/TabsGradient.tsx +++ b/src/components/common/TabsGradient.tsx @@ -14,7 +14,7 @@ const TabsGradient: React.FC = () => { }; const styles = StyleSheet.create({ gradient: { - position: 'absolute', + ...StyleSheet.absoluteFillObject, top: (SCREEN_HEIGHT / 10) * 9, height: SCREEN_HEIGHT / 10, width: SCREEN_WIDTH, diff --git a/src/components/profile/PublicProfile.tsx b/src/components/profile/PublicProfile.tsx index 88e0ecd1..5f9b0b99 100644 --- a/src/components/profile/PublicProfile.tsx +++ b/src/components/profile/PublicProfile.tsx @@ -99,7 +99,7 @@ const PublicProfile: React.FC<ContentProps> = ({ scrollViewRef.current ) { setScrollEnabled(false); - scrollViewRef.current.getNode().scrollTo({y: 0}); + scrollViewRef.current.scrollTo({y: 0}); navigation.navigate('MomentUploadPrompt', { screenType, momentCategory: momentCategories[0], diff --git a/src/components/search/RecentSearches.tsx b/src/components/search/RecentSearches.tsx index 84d35cac..6cea9338 100644 --- a/src/components/search/RecentSearches.tsx +++ b/src/components/search/RecentSearches.tsx @@ -6,6 +6,7 @@ import { StyleSheet, TouchableOpacityProps, ScrollView, + Keyboard, } from 'react-native'; import { PreviewType, @@ -15,7 +16,7 @@ import { } from '../../types'; import {TAGG_LIGHT_BLUE} from '../../constants'; import SearchResults from './SearchResults'; -import {SCREEN_HEIGHT} from '../../utils'; +import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs'; interface RecentSearchesProps extends TouchableOpacityProps { sectionTitle: PreviewType; @@ -25,35 +26,25 @@ interface RecentSearchesProps extends TouchableOpacityProps { } const RecentSearches: React.FC<RecentSearchesProps> = (props) => { - const {sectionTitle, recents, recentCategories, screenType} = props; + const {recents, recentCategories} = props; return ( - <ScrollView - style={styles.mainContainer} - contentContainerStyle={styles.contentContainer}> + <> <View style={styles.header}> - <Text style={styles.title}>{sectionTitle}</Text> + <Text style={styles.title}>Recent</Text> <TouchableOpacity {...props}> <Text style={styles.clear}>Clear all</Text> </TouchableOpacity> </View> - <SearchResults - results={recents} - categories={recentCategories} - previewType={sectionTitle} - screenType={screenType} - /> - </ScrollView> + <ScrollView + onScrollBeginDrag={Keyboard.dismiss} + contentContainerStyle={{paddingBottom: useBottomTabBarHeight()}}> + <SearchResults results={recents} categories={recentCategories} /> + </ScrollView> + </> ); }; const styles = StyleSheet.create({ - mainContainer: { - flex: 1, - }, - contentContainer: { - paddingBottom: SCREEN_HEIGHT * 0.1, - flex: 1, - }, header: { paddingHorizontal: 25, paddingVertical: 5, diff --git a/src/components/search/SearchBar.tsx b/src/components/search/SearchBar.tsx index 7b833406..d441b07b 100644 --- a/src/components/search/SearchBar.tsx +++ b/src/components/search/SearchBar.tsx @@ -9,20 +9,23 @@ import { TextInputSubmitEditingEventData, TouchableOpacity, View, + ViewStyle, + LayoutChangeEvent, } from 'react-native'; import {normalize} from 'react-native-elements'; -import Animated, {interpolate} from 'react-native-reanimated'; +import Animated, {useAnimatedStyle} from 'react-native-reanimated'; import Icon from 'react-native-vector-icons/Feather'; import {useSelector} from 'react-redux'; import {RootState} from '../../store/rootReducer'; -import {getSearchSuggestions, SCREEN_HEIGHT} from '../../utils'; +import {getSearchSuggestions} from '../../utils'; const AnimatedIcon = Animated.createAnimatedComponent(Icon); interface SearchBarProps extends TextInputProps { onCancel: () => void; - top: Animated.Value<number>; + animationProgress: Animated.SharedValue<number>; searching: boolean; + onLayout: (e: LayoutChangeEvent) => void; } const SearchBar: React.FC<SearchBarProps> = ({ onFocus, @@ -31,7 +34,8 @@ const SearchBar: React.FC<SearchBarProps> = ({ value, onCancel, searching, - top, + animationProgress, + onLayout, }) => { const handleSubmit = ( e: NativeSyntheticEvent<TextInputSubmitEditingEventData>, @@ -107,23 +111,15 @@ const SearchBar: React.FC<SearchBarProps> = ({ }, [searching]); /* - * Animated nodes used in search bar activation animation. + * On-search marginRight style ("cancel" button slides and fades in). */ - // TODO: (Leon) use reanimated v2 - const marginRight = 0; - // const marginRight: Animated.Node<number> = interpolate(top, { - // inputRange: [-SCREEN_HEIGHT, 0], - // outputRange: [0, 58], - // }); - // TODO: (Leon) use reanimated v2 - const opacity = 0; - // const opacity: Animated.Node<number> = interpolate(top, { - // inputRange: [-SCREEN_HEIGHT, 0], - // outputRange: [0, 1], - // }); + const animatedStyles = useAnimatedStyle<ViewStyle>(() => ({ + marginRight: animationProgress.value * 58, + opacity: animationProgress.value, + })); return ( - <View style={styles.container}> + <View style={styles.container} onLayout={onLayout}> <Animated.View style={styles.inputContainer}> <AnimatedIcon name="search" @@ -135,13 +131,13 @@ const SearchBar: React.FC<SearchBarProps> = ({ style={[styles.input]} placeholderTextColor={'#828282'} onSubmitEditing={handleSubmit} - clearButtonMode="while-editing" + clearButtonMode="always" autoCapitalize="none" autoCorrect={false} {...{placeholder, value, onChangeText, onFocus, onBlur}} /> </Animated.View> - <Animated.View style={{marginRight, opacity}}> + <Animated.View style={animatedStyles}> <TouchableOpacity style={styles.cancelButton} onPress={onCancel}> <Text style={styles.cancelText}>Cancel</Text> </TouchableOpacity> @@ -155,6 +151,7 @@ const styles = StyleSheet.create({ height: 40, paddingHorizontal: 20, flexDirection: 'row', + zIndex: 2, }, inputContainer: { flexGrow: 1, diff --git a/src/components/search/SearchCategories.tsx b/src/components/search/SearchCategories.tsx index c747b34f..3d142981 100644 --- a/src/components/search/SearchCategories.tsx +++ b/src/components/search/SearchCategories.tsx @@ -3,29 +3,40 @@ import React, {useEffect, useState} from 'react'; import {StyleSheet, View} from 'react-native'; import {getSuggestedSearchBubbleSuggestions} from '../../services/ExploreService'; import {SearchCategoryType} from '../../types'; -import {SCREEN_WIDTH} from '../../utils'; import GradientBorderButton from '../common/GradientBorderButton'; +import {useSelector} from 'react-redux'; +import {RootState} from 'src/store/rootReducer'; interface SearchCategoriesProps { darkStyle?: boolean; - defaultButtons?: SearchCategoryType[]; + useSuggestions: boolean; } const SearchCategories: React.FC<SearchCategoriesProps> = ({ darkStyle = false, - defaultButtons, + useSuggestions, }) => { const navigation = useNavigation(); - const mtSearchCategory: (key: number) => SearchCategoryType = (key) => ({ + const { + profile: {university = ''}, + } = useSelector((state: RootState) => state.user); + const defaultButtons: SearchCategoryType[] = [21, 22, 23, 24].map( + (year, index) => ({ + id: index * -1, + name: `${university.split(' ')[0]} '${year}`, + category: university, + }), + ); + const createloadingCategory: (key: number) => SearchCategoryType = (key) => ({ id: key, name: '...', category: '...', }); const [buttons, setButtons] = useState<SearchCategoryType[]>([ - mtSearchCategory(-1), - mtSearchCategory(-2), - mtSearchCategory(-3), - mtSearchCategory(-4), + createloadingCategory(1), + createloadingCategory(2), + createloadingCategory(3), + createloadingCategory(4), ]); useEffect(() => { @@ -36,7 +47,7 @@ const SearchCategories: React.FC<SearchCategoriesProps> = ({ setButtons(localButtons); } }; - if (!defaultButtons) { + if (useSuggestions) { loadButtons(); } else { setButtons(defaultButtons); @@ -45,33 +56,34 @@ const SearchCategories: React.FC<SearchCategoriesProps> = ({ return ( <View style={styles.container}> - {buttons.map((searchCategory) => ( - <GradientBorderButton - key={searchCategory.id} - text={searchCategory.name} - darkStyle={darkStyle} - onPress={() => { - if (searchCategory.name !== '...') { - navigation.push('DiscoverUsers', { - searchCategory, - }); - } - }} - /> - ))} + <View style={styles.categoryContainer}> + {buttons.map((searchCategory, index) => ( + <GradientBorderButton + key={index} + text={searchCategory.name} + darkStyle={darkStyle} + onPress={() => { + if (searchCategory.name !== '...') { + navigation.push('DiscoverUsers', { + searchCategory, + }); + } + }} + /> + ))} + </View> </View> ); }; const styles = StyleSheet.create({ container: { - zIndex: 0, - top: '3%', - alignSelf: 'center', + paddingVertical: 20, + }, + categoryContainer: { flexDirection: 'row', - width: SCREEN_WIDTH * 0.9, - flexWrap: 'wrap', justifyContent: 'space-evenly', + flexWrap: 'wrap', }, }); export default SearchCategories; diff --git a/src/components/search/SearchResultList.tsx b/src/components/search/SearchResultList.tsx index 687b2285..a32760e1 100644 --- a/src/components/search/SearchResultList.tsx +++ b/src/components/search/SearchResultList.tsx @@ -1,15 +1,23 @@ import React, {useEffect, useState} from 'react'; -import {SectionList, StyleSheet, Text, View} from 'react-native'; +import { + SectionList, + StyleSheet, + Text, + View, + Keyboard, + SectionListData, +} from 'react-native'; import {useSelector} from 'react-redux'; import {RootState} from '../../store/rootreducer'; import {NO_RESULTS_FOUND} from '../../constants/strings'; import {PreviewType, ScreenType} from '../../types'; -import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; +import {normalize, SCREEN_WIDTH} from '../../utils'; import SearchResultsCell from './SearchResultCell'; +import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs'; interface SearchResultsProps { - results: Array<any> | undefined; - keyboardVisible: boolean; + // TODO: make sure results come in as same type, regardless of profile, category, badges + results: SectionListData<any>[]; previewType: PreviewType; screenType: ScreenType; } @@ -21,11 +29,8 @@ const sectionHeader: React.FC<Boolean> = (showBorder: Boolean) => { return null; }; -const SearchResultList: React.FC<SearchResultsProps> = ({ - results, - keyboardVisible, -}) => { - const [showEmptyView, setshowEmptyView] = useState(false); +const SearchResultList: React.FC<SearchResultsProps> = ({results}) => { + const [showEmptyView, setshowEmptyView] = useState<boolean>(false); const {user: loggedInUser} = useSelector((state: RootState) => state.user); useEffect(() => { @@ -38,57 +43,41 @@ const SearchResultList: React.FC<SearchResultsProps> = ({ } }, [results]); - return ( - <View style={styles.container}> - {showEmptyView && ( - <View style={styles.noResultsTextContainer}> - <Text style={styles.noResultsTextStyle}>{NO_RESULTS_FOUND}</Text> - </View> - )} - {!showEmptyView && ( - <SectionList - style={[ - {width: SCREEN_WIDTH}, - keyboardVisible ? styles.keyboardOpen : {}, - ]} - contentContainerStyle={styles.sectionListContentContainer} - sections={results} - keyExtractor={(item, index) => item.id + index} - renderItem={({section, item}) => { - return ( - <SearchResultsCell - profileData={item} - loggedInUser={loggedInUser} - /> - ); - }} - renderSectionHeader={({section: {data}}) => - sectionHeader(data.length !== 0) - } - /> - )} + return showEmptyView ? ( + <View style={styles.container} onTouchStart={Keyboard.dismiss}> + <Text style={styles.noResultsTextStyle}>{NO_RESULTS_FOUND}</Text> </View> + ) : ( + <SectionList + onScrollBeginDrag={Keyboard.dismiss} + contentContainerStyle={[{paddingBottom: useBottomTabBarHeight()}]} + sections={results} + keyExtractor={(item, index) => item.id + index} + renderItem={({item}) => { + return ( + <SearchResultsCell profileData={item} loggedInUser={loggedInUser} /> + ); + }} + renderSectionHeader={({section: {data}}) => + sectionHeader(data.length !== 0) + } + stickySectionHeadersEnabled={false} + /> ); }; const styles = StyleSheet.create({ container: { - height: SCREEN_HEIGHT, - paddingBottom: SCREEN_HEIGHT * 0.1, - }, - sectionListContentContainer: { - paddingBottom: SCREEN_HEIGHT * 0.15, - width: SCREEN_WIDTH, + flex: 1, + marginTop: 30, + alignItems: 'center', }, sectionHeaderStyle: { width: '100%', height: 0.5, - marginBottom: normalize(24), + marginVertical: 5, backgroundColor: '#C4C4C4', }, - keyboardOpen: { - marginBottom: SCREEN_HEIGHT * 0.35, - }, noResultsTextContainer: { justifyContent: 'center', flexDirection: 'row', diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index ef518d8b..a73d0b40 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -1,18 +1,10 @@ import React from 'react'; -import { - ProfilePreviewType, - PreviewType, - ScreenType, - CategoryPreviewType, -} from '../../types'; -import {View} from 'react-native'; +import {ProfilePreviewType, CategoryPreviewType} from '../../types'; import SearchResultsCell from './SearchResultCell'; import {useSelector} from 'react-redux'; import {RootState} from '../../store/rootReducer'; interface SearchResultsProps { results: ProfilePreviewType[]; - previewType: PreviewType; - screenType: ScreenType; categories: CategoryPreviewType[]; } const SearchResults: React.FC<SearchResultsProps> = ({results, categories}) => { @@ -22,7 +14,7 @@ const SearchResults: React.FC<SearchResultsProps> = ({results, categories}) => { */ const {user: loggedInUser} = useSelector((state: RootState) => state.user); return ( - <View> + <> {categories .slice(0) .reverse() @@ -43,7 +35,7 @@ const SearchResults: React.FC<SearchResultsProps> = ({results, categories}) => { {...{loggedInUser}} /> ))} - </View> + </> ); }; diff --git a/src/components/search/SearchResultsBackground.tsx b/src/components/search/SearchResultsBackground.tsx index 3d7fab4e..e5236295 100644 --- a/src/components/search/SearchResultsBackground.tsx +++ b/src/components/search/SearchResultsBackground.tsx @@ -1,32 +1,55 @@ import React from 'react'; -import {StyleSheet} from 'react-native'; -import Animated, {interpolate} from 'react-native-reanimated'; -import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; +import {StyleSheet, ViewStyle} from 'react-native'; +import Animated, { + useAnimatedStyle, + useDerivedValue, + interpolate, + Extrapolate, +} from 'react-native-reanimated'; +import {useSafeAreaInsets} from 'react-native-safe-area-context'; interface SearchResultsBackgroundProps { - top: Animated.Value<number>; + animationProgress: Animated.SharedValue<number>; + searchBarHeight: number; + searching: boolean; } const SearchResultsBackground: React.FC<SearchResultsBackgroundProps> = ({ - top, + animationProgress, + searchBarHeight, + searching, children, }) => { - // TODO: (Leon) use reanimated v2 - const opacityBackground = 0; - // const opacityBackground: Animated.Node<number> = interpolate(top, { - // inputRange: [-SCREEN_HEIGHT, 0], - // outputRange: [0, 1], - // }); - // TODO: (Leon) use reanimated v2 - const opacityContent = 0; - // const opacityContent: Animated.Node<number> = interpolate(top, { - // inputRange: [-SCREEN_HEIGHT / 40, 0], - // outputRange: [0, 1], - // }); + const {top: topInset} = useSafeAreaInsets(); + /* + * On-search container style (opacity fade-in). + */ + const backgroundAnimatedStyles = useAnimatedStyle<ViewStyle>(() => ({ + opacity: animationProgress.value, + })); + /* + * Derived animation value for contentAnimatedStyles. + */ + const contentAnimationProgress = useDerivedValue<number>(() => + interpolate(animationProgress.value, [0.9, 1], [0, 1], Extrapolate.CLAMP), + ); + /* + * On-search content style (delayed opacity fade-in). + */ + const contentAnimatedStyles = useAnimatedStyle<ViewStyle>(() => ({ + opacity: contentAnimationProgress.value, + })); return ( <Animated.View - style={[styles.container, {opacity: opacityBackground, top}]}> - <Animated.View - style={[styles.contentContainer, {opacity: opacityContent}]}> + style={[ + styles.container, + backgroundAnimatedStyles, + { + // absolute: inset + search screen paddingTop + searchBar + padding + paddingTop: topInset + 15 + searchBarHeight + 10, + }, + ]} + pointerEvents={searching ? 'auto' : 'none'}> + <Animated.View style={[styles.contentContainer, contentAnimatedStyles]}> {children} </Animated.View> </Animated.View> @@ -34,15 +57,11 @@ const SearchResultsBackground: React.FC<SearchResultsBackgroundProps> = ({ }; const styles = StyleSheet.create({ container: { - height: SCREEN_HEIGHT, - width: SCREEN_WIDTH, - position: 'absolute', + ...StyleSheet.absoluteFillObject, backgroundColor: 'white', }, contentContainer: { flex: 1, - paddingVertical: 10, - paddingBottom: SCREEN_HEIGHT / 15, }, }); export default SearchResultsBackground; |