aboutsummaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/common/GradientBorderButton.tsx2
-rw-r--r--src/components/common/TabsGradient.tsx2
-rw-r--r--src/components/profile/PublicProfile.tsx2
-rw-r--r--src/components/search/RecentSearches.tsx31
-rw-r--r--src/components/search/SearchBar.tsx37
-rw-r--r--src/components/search/SearchCategories.tsx68
-rw-r--r--src/components/search/SearchResultList.tsx85
-rw-r--r--src/components/search/SearchResults.tsx14
-rw-r--r--src/components/search/SearchResultsBackground.tsx69
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;