diff options
| author | Shravya Ramesh <37447613+shravyaramesh@users.noreply.github.com> | 2021-03-05 20:33:51 -0800 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-05 20:33:51 -0800 | 
| commit | 27925a267e9d279e29a1a1852891e392fdc4b3af (patch) | |
| tree | f77ab55bf3f5cbd6190177058353ef01ad767711 /src/components/search | |
| parent | 8e4d9135f0645b56665ad23d6de5dd0afa1ef444 (diff) | |
| parent | 59bc015a22a0c50d6c64ecf7501c269dae59bfbd (diff) | |
Merge branch 'master' into badges-people-screen
Diffstat (limited to 'src/components/search')
| -rw-r--r-- | src/components/search/ExploreSection.tsx | 2 | ||||
| -rw-r--r-- | src/components/search/RecentSearches.tsx | 9 | ||||
| -rw-r--r-- | src/components/search/SearchResultCell.tsx | 187 | ||||
| -rw-r--r-- | src/components/search/SearchResultList.tsx | 93 | ||||
| -rw-r--r-- | src/components/search/SearchResultsBackground.tsx | 9 | ||||
| -rw-r--r-- | src/components/search/index.ts | 1 | 
6 files changed, 292 insertions, 9 deletions
diff --git a/src/components/search/ExploreSection.tsx b/src/components/search/ExploreSection.tsx index 784e089c..1af815db 100644 --- a/src/components/search/ExploreSection.tsx +++ b/src/components/search/ExploreSection.tsx @@ -14,7 +14,7 @@ interface ExploreSectionProps {    users: ProfilePreviewType[];  }  const ExploreSection: React.FC<ExploreSectionProps> = ({title, users}) => { -  return users?.length !== 0 ? ( +  return users && users.length !== 0 ? (      <View style={styles.container}>        <Text style={styles.header}>{title}</Text>        <FlatList diff --git a/src/components/search/RecentSearches.tsx b/src/components/search/RecentSearches.tsx index bebf6bcf..6fb9fca9 100644 --- a/src/components/search/RecentSearches.tsx +++ b/src/components/search/RecentSearches.tsx @@ -5,10 +5,12 @@ import {    TouchableOpacity,    StyleSheet,    TouchableOpacityProps, +  ScrollView,  } from 'react-native';  import {PreviewType, ProfilePreviewType, ScreenType} from '../../types';  import {TAGG_LIGHT_BLUE} from '../../constants';  import SearchResults from './SearchResults'; +import {SCREEN_HEIGHT} from '../../utils';  interface RecentSearchesProps extends TouchableOpacityProps {    sectionTitle: PreviewType; @@ -21,7 +23,9 @@ interface RecentSearchesProps extends TouchableOpacityProps {   */  const RecentSearches: React.FC<RecentSearchesProps> = (props) => {    return ( -    <View style={styles.mainContainer}> +    <ScrollView +      style={styles.mainContainer} +      contentContainerStyle={{paddingBottom: SCREEN_HEIGHT * 0.1}}>        <View style={styles.container}>          <Text style={styles.title}>{props.sectionTitle}</Text>          {props.sectionButtonTitle && ( @@ -35,13 +39,14 @@ const RecentSearches: React.FC<RecentSearchesProps> = (props) => {          previewType={props.sectionTitle}          screenType={props.screenType}        /> -    </View> +    </ScrollView>    );  };  const styles = StyleSheet.create({    mainContainer: {      marginLeft: '3%', +    padding: 20,    },    container: {      flexDirection: 'row', diff --git a/src/components/search/SearchResultCell.tsx b/src/components/search/SearchResultCell.tsx new file mode 100644 index 00000000..705fb5c9 --- /dev/null +++ b/src/components/search/SearchResultCell.tsx @@ -0,0 +1,187 @@ +import {useNavigation} from '@react-navigation/native'; +import React, {useEffect, useState} from 'react'; +import {Alert, Image, StyleSheet, Text, View} from 'react-native'; +import {TouchableOpacity} from 'react-native-gesture-handler'; +import {useDispatch, useStore} from 'react-redux'; +import {ERROR_UNABLE_TO_VIEW_PROFILE} from '../../constants/strings'; +import {loadImageFromURL} from '../../services'; +import {RootState} from '../../store/rootReducer'; +import {ProfilePreviewType, ScreenType, UserType} from '../../types'; +import {normalize, SCREEN_WIDTH} from '../../utils'; +import { +  addUserToRecentlyViewed, +  checkIfUserIsBlocked, +  defaultUserProfile, +  fetchUserX, +  userXInStore, +} from '../../utils/users'; + +interface SearchResults { +  profileData: ProfilePreviewType; +  loggedInUser: UserType; +} + +const SearchResultsCell: React.FC<SearchResults> = ({ +  profileData: { +    id, +    name, +    username, +    first_name, +    last_name, +    thumbnail_url, +    category, +  }, +  loggedInUser, +}) => { +  const [avatar, setAvatar] = useState<string | undefined>(undefined); +  useEffect(() => { +    (async () => { +      if (thumbnail_url !== undefined) { +        try { +          const response = await loadImageFromURL(thumbnail_url); +          if (response) { +            setAvatar(response); +          } +        } catch (error) { +          console.log('Error while downloading ', error); +          throw error; +        } +      } +    })(); +  }, [thumbnail_url]); + +  const dispatch = useDispatch(); +  const state: RootState = useStore().getState(); +  const navigation = useNavigation(); +  const addToRecentlyStoredAndNavigateToProfile = async () => { +    try { +      //If the logged in user is blocked by the user being viewed, do not proceed. +      const isUserBlocked = await checkIfUserIsBlocked( +        id, +        dispatch, +        loggedInUser, +      ); +      if (isUserBlocked) { +        Alert.alert(ERROR_UNABLE_TO_VIEW_PROFILE); +        return; +      } + +      await addUserToRecentlyViewed({ +        id, +        first_name, +        last_name, +        thumbnail_url, +        username, +      }); + +      const userXId = loggedInUser.username === username ? undefined : id; + +      /** +       * Dispatch an event to Fetch the user details only if we're navigating to +       * a userX's profile. +       * If the user is already present in store, do not fetch again. +       * Finally, Navigate to profile of the user selected. +       */ +      if (userXId && !userXInStore(state, ScreenType.Search, id)) { +        await fetchUserX( +          dispatch, +          {userId: id, username: username}, +          ScreenType.Search, +        ); +      } + +      navigation.navigate('Profile', { +        userXId, +        screenType: ScreenType.Search, +      }); +    } catch (e) { +      console.log(e); +    } +  }; + +  const userCell = () => { +    return ( +      <TouchableOpacity +        onPress={addToRecentlyStoredAndNavigateToProfile} +        style={styles.cellContainer}> +        <Image +          defaultSource={defaultUserProfile()} +          source={{uri: avatar}} +          style={styles.imageContainer} +        /> +        <View style={[styles.initialTextContainer, styles.multiText]}> +          <Text style={styles.initialTextStyle}>{`@${username}`}</Text> +          <Text style={styles.secondaryTextStyle}> +            {first_name + ' ' + last_name} +          </Text> +        </View> +      </TouchableOpacity> +    ); +  }; + +  const searchIcon = () => { +    return require('../../assets/images/search.png'); +  }; + +  const universityIcon = () => { +    return require('../../assets/images/bwbadges.png'); +  }; + +  const categoryCell = () => { +    return ( +      <TouchableOpacity style={styles.cellContainer}> +        <View style={[styles.imageContainer, styles.categoryBackground]}> +          <Image +            resizeMode="contain" +            source={category === 'Brown' ? universityIcon() : searchIcon()} +            style={styles.categoryImage} +          /> +        </View> +        <View style={styles.initialTextContainer}> +          <Text style={styles.initialTextStyle}>{name}</Text> +        </View> +      </TouchableOpacity> +    ); +  }; + +  return name === undefined ? userCell() : categoryCell(); +}; + +const styles = StyleSheet.create({ +  cellContainer: { +    flexDirection: 'row', +    marginHorizontal: SCREEN_WIDTH * 0.08, +    marginBottom: SCREEN_WIDTH * 0.08, +  }, +  imageContainer: { +    width: SCREEN_WIDTH * 0.112, +    height: SCREEN_WIDTH * 0.112, +    borderRadius: (SCREEN_WIDTH * 0.112) / 2, +  }, +  categoryBackground: { +    backgroundColor: 'rgba(196, 196, 196, 0.45)', +    justifyContent: 'center', +    alignItems: 'center', +  }, +  categoryImage: { +    width: '40%', +    height: '40%', +  }, +  initialTextContainer: { +    marginLeft: SCREEN_WIDTH * 0.08, +    flexDirection: 'column', +    justifyContent: 'center', +  }, +  initialTextStyle: { +    fontWeight: '500', +    fontSize: normalize(14), +  }, +  secondaryTextStyle: { +    fontWeight: '500', +    fontSize: normalize(12), +    color: '#828282', +  }, +  multiText: {justifyContent: 'space-between'}, +}); + +export default SearchResultsCell; diff --git a/src/components/search/SearchResultList.tsx b/src/components/search/SearchResultList.tsx new file mode 100644 index 00000000..a3d9c8c5 --- /dev/null +++ b/src/components/search/SearchResultList.tsx @@ -0,0 +1,93 @@ +import React, {useEffect, useState} from 'react'; +import {SectionList, StyleSheet, Text, View} from 'react-native'; +import {useSelector} from 'react-redux'; +import {RootState} from 'src/store/rootreducer'; +import {NO_RESULTS_FOUND} from '../../constants/strings'; +import {PreviewType, ScreenType} from '../../types'; +import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; +import SearchResultsCell from './SearchResultCell'; + +interface SearchResultsProps { +  results: Array<any> | undefined; +  keyboardVisible: boolean; +  previewType: PreviewType; +  screenType: ScreenType; +} + +const sectionHeader: React.FC<Boolean> = (showBorder: Boolean) => { +  if (showBorder) { +    return <View style={styles.sectionHeaderStyle} />; +  } +  return null; +}; + +const SearchResultList: React.FC<SearchResultsProps> = ({ +  results, +  keyboardVisible, +}) => { +  const [showSection, setShowSection] = useState(true); +  const [showEmptyView, setshowEmptyView] = useState(false); +  const {user: loggedInUser} = useSelector((state: RootState) => state.user); + +  useEffect(() => { +    if (results && results.length > 0) { +      setshowEmptyView( +        results[0].data.length === 0 && results[1].data.length === 0, +      ); +    } +  }, [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={{paddingBottom: SCREEN_HEIGHT * 0.1}} +          sections={results} +          keyExtractor={(item, index) => item.id + index} +          renderItem={({item}) => ( +            <SearchResultsCell profileData={item} loggedInUser={loggedInUser} /> +          )} +          renderSectionHeader={({section: {title, data}}) => { +            if (title === 'categories' && data.length === 0) { +              setShowSection(false); +            } +            return sectionHeader(title !== 'categories' && showSection); +          }} +        /> +      )} +    </View> +  ); +}; + +const styles = StyleSheet.create({ +  container: { +    marginTop: SCREEN_HEIGHT * 0.02, +  }, +  sectionHeaderStyle: { +    width: '100%', +    height: 0.5, +    marginBottom: normalize(24), +    backgroundColor: '#C4C4C4', +  }, +  keyboardOpen: {marginBottom: SCREEN_HEIGHT * 0.3}, +  noResultsTextContainer: { +    justifyContent: 'center', +    flexDirection: 'row', +    width: SCREEN_WIDTH, +  }, +  noResultsTextStyle: { +    fontWeight: '500', +    fontSize: normalize(14), +  }, +}); + +export default SearchResultList; diff --git a/src/components/search/SearchResultsBackground.tsx b/src/components/search/SearchResultsBackground.tsx index 77b1821d..c5fcc6fb 100644 --- a/src/components/search/SearchResultsBackground.tsx +++ b/src/components/search/SearchResultsBackground.tsx @@ -1,6 +1,6 @@  import React from 'react'; -import Animated, {interpolate} from 'react-native-reanimated';  import {StyleSheet} from 'react-native'; +import Animated, {interpolate} from 'react-native-reanimated';  import {SCREEN_HEIGHT, SCREEN_WIDTH, StatusBarHeight} from '../../utils';  interface SearchResultsBackgroundProps { @@ -21,11 +21,9 @@ const SearchResultsBackground: React.FC<SearchResultsBackgroundProps> = ({    return (      <Animated.View        style={[styles.container, {opacity: opacityBackground, top}]}> -      <Animated.ScrollView -        contentContainerStyle={styles.contentContainer} -        style={[styles.results, {opacity: opacityContent}]}> +      <Animated.View style={[styles.results, {opacity: opacityContent}]}>          {children} -      </Animated.ScrollView> +      </Animated.View>      </Animated.View>    );  }; @@ -34,7 +32,6 @@ const styles = StyleSheet.create({      flex: 1,      height: SCREEN_HEIGHT,      width: SCREEN_WIDTH, -    padding: 20,      position: 'absolute',      backgroundColor: '#fff',      zIndex: 0, diff --git a/src/components/search/index.ts b/src/components/search/index.ts index 08052f77..7418f0ba 100644 --- a/src/components/search/index.ts +++ b/src/components/search/index.ts @@ -3,5 +3,6 @@ export {default as SearchHeader} from './SearchHeader';  export {default as SearchBar} from './SearchBar';  export {default as Explore} from './Explore';  export {default as SearchResultsBackground} from './SearchResultsBackground'; +export {default as SearchResultList} from './SearchResultList';  export {default as SearchResults} from './SearchResults';  export {default as DiscoverUsers} from './DiscoverUsers';  | 
