diff options
author | Ivan Chen <ivan@tagg.id> | 2021-03-08 19:54:42 -0500 |
---|---|---|
committer | Ivan Chen <ivan@tagg.id> | 2021-03-08 19:54:42 -0500 |
commit | f899dc058f90813c5ae71e55407a11e6ca13e1ed (patch) | |
tree | 84c93e869fab6d434d6709dc1d471c6e588c4e4e | |
parent | 8837ea74dbff9cf455cd7cb092767e51de3900f8 (diff) | |
parent | d77f43663fbe409b011b5509bcbff3d07f8ded55 (diff) |
Merge branch 'master' into tma684-search-for-badges
# Conflicts:
# src/components/search/SearchResultCell.tsx
# src/components/search/SearchResultList.tsx
-rw-r--r-- | src/components/search/RecentSearches.tsx | 51 | ||||
-rw-r--r-- | src/components/search/SearchResultCell.tsx | 35 | ||||
-rw-r--r-- | src/components/search/SearchResultList.tsx | 3 | ||||
-rw-r--r-- | src/components/search/SearchResults.tsx | 52 | ||||
-rw-r--r-- | src/components/search/SearchResultsBackground.tsx | 13 | ||||
-rw-r--r-- | src/screens/search/SearchScreen.tsx | 55 | ||||
-rw-r--r-- | src/services/ExploreService.ts | 1 | ||||
-rw-r--r-- | src/services/SocialLinkingService.ts | 1 | ||||
-rw-r--r-- | src/services/SuggestedPeopleService.ts | 2 | ||||
-rw-r--r-- | src/services/UserFriendsService.ts | 1 | ||||
-rw-r--r-- | src/types/types.ts | 5 | ||||
-rw-r--r-- | src/utils/users.ts | 36 |
12 files changed, 179 insertions, 76 deletions
diff --git a/src/components/search/RecentSearches.tsx b/src/components/search/RecentSearches.tsx index 6fb9fca9..b4cc5483 100644 --- a/src/components/search/RecentSearches.tsx +++ b/src/components/search/RecentSearches.tsx @@ -7,37 +7,45 @@ import { TouchableOpacityProps, ScrollView, } from 'react-native'; -import {PreviewType, ProfilePreviewType, ScreenType} from '../../types'; +import { + PreviewType, + ProfilePreviewType, + ScreenType, + CategoryPreviewType, +} from '../../types'; import {TAGG_LIGHT_BLUE} from '../../constants'; import SearchResults from './SearchResults'; import {SCREEN_HEIGHT} from '../../utils'; interface RecentSearchesProps extends TouchableOpacityProps { sectionTitle: PreviewType; - sectionButtonTitle: string; recents: Array<ProfilePreviewType>; + recentCategories: CategoryPreviewType[]; screenType: ScreenType; } -/** - * An image component that returns the <Image> of the icon for a specific social media platform. - */ + const RecentSearches: React.FC<RecentSearchesProps> = (props) => { + const { + sectionTitle, + recents, + recentCategories, + screenType, + } = props; return ( <ScrollView style={styles.mainContainer} - contentContainerStyle={{paddingBottom: SCREEN_HEIGHT * 0.1}}> - <View style={styles.container}> - <Text style={styles.title}>{props.sectionTitle}</Text> - {props.sectionButtonTitle && ( - <TouchableOpacity {...props}> - <Text style={styles.clear}>Clear all</Text> - </TouchableOpacity> - )} + contentContainerStyle={styles.contentContainer}> + <View style={styles.header}> + <Text style={styles.title}>{sectionTitle}</Text> + <TouchableOpacity {...props}> + <Text style={styles.clear}>Clear all</Text> + </TouchableOpacity> </View> <SearchResults - results={props.recents} - previewType={props.sectionTitle} - screenType={props.screenType} + results={recents} + categories={recentCategories} + previewType={sectionTitle} + screenType={screenType} /> </ScrollView> ); @@ -45,17 +53,20 @@ const RecentSearches: React.FC<RecentSearchesProps> = (props) => { const styles = StyleSheet.create({ mainContainer: { - marginLeft: '3%', - padding: 20, + flexGrow: 1, + }, + contentContainer: { + paddingBottom: SCREEN_HEIGHT * 0.1, }, - container: { + header: { + paddingHorizontal: 25, + paddingVertical: 5, flexDirection: 'row', }, title: { fontSize: 18, fontWeight: '600', flexGrow: 1, - marginBottom: '5%', }, clear: { fontSize: 18, diff --git a/src/components/search/SearchResultCell.tsx b/src/components/search/SearchResultCell.tsx index b6ce55d0..5cba6d2f 100644 --- a/src/components/search/SearchResultCell.tsx +++ b/src/components/search/SearchResultCell.tsx @@ -6,7 +6,12 @@ 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 { + ProfilePreviewType, + ScreenType, + UserType, + CategoryPreviewType, +} from '../../types'; import {normalize, SCREEN_WIDTH} from '../../utils'; import { addUserToRecentlyViewed, @@ -14,6 +19,7 @@ import { defaultUserProfile, fetchUserX, userXInStore, + addCategoryToRecentlySearched, } from '../../utils/users'; interface SearchResults { @@ -68,7 +74,7 @@ const SearchResultsCell: React.FC<SearchResults> = ({ return; } - await addUserToRecentlyViewed({ + addUserToRecentlyViewed({ id, first_name, last_name, @@ -101,6 +107,18 @@ const SearchResultsCell: React.FC<SearchResults> = ({ } }; + /* + * Save selected category in recently-searched categories and navigate to its Discover screen. + */ + const onPressCategory = async () => { + const categoryObj: CategoryPreviewType = {name, category}; + addCategoryToRecentlySearched(categoryObj); + navigation.navigate('DiscoverUsers', { + type, + searchCategory: {id, name}, + }); + }; + const userCell = () => { return ( <TouchableOpacity @@ -131,14 +149,7 @@ const SearchResultsCell: React.FC<SearchResults> = ({ const categoryCell = () => { return ( - <TouchableOpacity - style={styles.cellContainer} - onPress={() => - navigation.navigate('DiscoverUsers', { - type, - searchCategory: {id, name}, - }) - }> + <TouchableOpacity style={styles.cellContainer} onPress={onPressCategory}> <View style={[styles.imageContainer, styles.categoryBackground]}> <Image resizeMode="contain" @@ -159,8 +170,8 @@ const SearchResultsCell: React.FC<SearchResults> = ({ const styles = StyleSheet.create({ cellContainer: { flexDirection: 'row', - marginHorizontal: SCREEN_WIDTH * 0.08, - marginBottom: SCREEN_WIDTH * 0.08, + paddingHorizontal: 25, + paddingVertical: 15, }, imageContainer: { width: SCREEN_WIDTH * 0.112, diff --git a/src/components/search/SearchResultList.tsx b/src/components/search/SearchResultList.tsx index fe32ef65..939bfa2b 100644 --- a/src/components/search/SearchResultList.tsx +++ b/src/components/search/SearchResultList.tsx @@ -74,8 +74,7 @@ const SearchResultList: React.FC<SearchResultsProps> = ({ const styles = StyleSheet.create({ container: { - marginTop: SCREEN_HEIGHT * 0.02, - height: SCREEN_HEIGHT * 0.9, + height: SCREEN_HEIGHT, }, sectionHeaderStyle: { width: '100%', diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index bf355220..798d3251 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -1,22 +1,33 @@ import React from 'react'; -import {ProfilePreviewType, PreviewType, ScreenType} from '../../types'; +import { + ProfilePreviewType, + PreviewType, + ScreenType, + CategoryPreviewType, +} from '../../types'; import ProfilePreview from '../profile/ProfilePreview'; import {StyleSheet, View} from 'react-native'; +import SearchResultsCell from './SearchResultCell'; +import {useSelector} from 'react-redux'; +import {RootState} from 'src/store/rootReducer'; interface SearchResultsProps { - results: Array<ProfilePreviewType>; + results: ProfilePreviewType[]; previewType: PreviewType; screenType: ScreenType; + categories: CategoryPreviewType[]; } const SearchResults: React.FC<SearchResultsProps> = ({ results, previewType, screenType, + categories, }) => { /** * Added the following swicth case to make Results on Search and Recents screen a list * Flex is love */ - var containerStyle; + const {user: loggedInUser} = useSelector((state: RootState) => state.user); + let containerStyle; switch (previewType) { case 'Search': containerStyle = styles.containerSearch; @@ -29,25 +40,32 @@ const SearchResults: React.FC<SearchResultsProps> = ({ } return ( <View style={containerStyle}> - {results && - results.map((profilePreview) => ( - <ProfilePreview - style={styles.result} - key={profilePreview.id} - {...{profilePreview}} - previewType={previewType} - screenType={screenType} - /> - ))} + {categories.map((category: CategoryPreviewType) => ( + <SearchResultsCell + key={category.name} + profileData={category} + {...{loggedInUser}} + /> + ))} + {results.map((profile: ProfilePreviewType) => ( + <SearchResultsCell + key={profile.id} + profileData={profile} + {...{loggedInUser}} + /> + ))} </View> ); }; const styles = StyleSheet.create({ - containerSearch: {flexDirection: 'column', flexWrap: 'wrap'}, - container: {flexDirection: 'row', flexWrap: 'wrap'}, - result: { - marginVertical: 10, + containerSearch: { + flexDirection: 'column', + flexWrap: 'wrap', + }, + container: { + flexDirection: 'row', + flexWrap: 'wrap', }, }); diff --git a/src/components/search/SearchResultsBackground.tsx b/src/components/search/SearchResultsBackground.tsx index f6f40f52..25dcf781 100644 --- a/src/components/search/SearchResultsBackground.tsx +++ b/src/components/search/SearchResultsBackground.tsx @@ -21,7 +21,7 @@ const SearchResultsBackground: React.FC<SearchResultsBackgroundProps> = ({ return ( <Animated.View style={[styles.container, {opacity: opacityBackground, top}]}> - <Animated.View style={[styles.results, {opacity: opacityContent}]}> + <Animated.View style={{opacity: opacityContent}}> {children} </Animated.View> </Animated.View> @@ -33,15 +33,10 @@ const styles = StyleSheet.create({ height: SCREEN_HEIGHT, width: SCREEN_WIDTH, position: 'absolute', - backgroundColor: '#fff', + backgroundColor: 'white', + paddingTop: 60, + paddingBottom: 10, zIndex: 0, }, - contentContainer: { - flexGrow: 1, - paddingBottom: SCREEN_HEIGHT / 15, - }, - results: { - marginTop: StatusBarHeight, - }, }); export default SearchResultsBackground; diff --git a/src/screens/search/SearchScreen.tsx b/src/screens/search/SearchScreen.tsx index 82a4c1ae..e80e09aa 100644 --- a/src/screens/search/SearchScreen.tsx +++ b/src/screens/search/SearchScreen.tsx @@ -17,7 +17,7 @@ import {SEARCH_ENDPOINT, TAGG_LIGHT_BLUE} from '../../constants'; import {loadSearchResults} from '../../services'; import {resetScreenType} from '../../store/actions'; import {RootState} from '../../store/rootReducer'; -import {ProfilePreviewType, ScreenType} from '../../types'; +import {ProfilePreviewType, ScreenType, CategoryPreviewType} from '../../types'; import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; /** @@ -32,6 +32,9 @@ const SearchScreen: React.FC = () => { const [recents, setRecents] = useState<Array<ProfilePreviewType>>( recentSearches ?? [], ); + const [recentCategories, setRecentCategories] = useState< + CategoryPreviewType[] + >([]); const [searching, setSearching] = useState(false); const top = Animated.useValue(-SCREEN_HEIGHT); const [keyboardVisible, setKeyboardVisible] = React.useState( @@ -50,7 +53,18 @@ const SearchScreen: React.FC = () => { }, []); const dispatch = useDispatch(); + /* + * If user begins actively searching, refresh recently-searched list. + */ + useEffect(() => { + if (searching) loadRecentSearches(); + }, [searching]); + + /* + * Main handler for changes in query. + */ useEffect(() => { + if (!query.length) loadRecentSearches(); if (query.length < 3) { setResults(undefined); return; @@ -99,17 +113,17 @@ const SearchScreen: React.FC = () => { timing(top, topInConfig).start(); setSearching(true); }; - const handleBlur = () => { - setQuery(''); + const handleCancel = () => { Keyboard.dismiss(); const topOutConfig = { duration: 180, toValue: -SCREEN_HEIGHT, easing: Easing.inOut(Easing.ease), }; - timing(top, topOutConfig).start(); + timing(top, topOutConfig).start(() => setQuery('')); setSearching(false); }; + const loadRecentlySearchedUsers = async () => { try { const asyncCache = await AsyncStorage.getItem('@recently_searched_users'); @@ -118,17 +132,31 @@ const SearchScreen: React.FC = () => { console.log(e); } }; - const clearRecentlySearched = async () => { + const loadRecentlySearchedCategories = async () => { try { - await AsyncStorage.removeItem('@recently_searched_users'); - loadRecentlySearchedUsers(); + const recentCategoriesJSON = await AsyncStorage.getItem( + '@recently_searched_categories', + ); + setRecentCategories( + recentCategoriesJSON ? JSON.parse(recentCategoriesJSON) : [], + ); } catch (e) { console.log(e); } }; - const handleUpdate = async (val: string) => { - setQuery(val); + const loadRecentSearches = () => { loadRecentlySearchedUsers(); + loadRecentlySearchedCategories(); + }; + const clearRecentlySearched = async () => { + try { + AsyncStorage.removeItem('@recently_searched_users'); + AsyncStorage.removeItem('@recently_searched_categories'); + loadRecentlySearchedUsers(); + loadRecentlySearchedCategories(); + } catch (e) { + console.log(e); + } }; return ( @@ -143,8 +171,8 @@ const SearchScreen: React.FC = () => { showsVerticalScrollIndicator={false}> <SearchBar style={styles.searchBar} - onCancel={handleBlur} - onChangeText={handleUpdate} + onCancel={handleCancel} + onChangeText={setQuery} onBlur={Keyboard.dismiss} onFocus={handleFocus} value={query} @@ -152,13 +180,14 @@ const SearchScreen: React.FC = () => { /> <SearchCategories /> <SearchResultsBackground {...{top}}> - {results === undefined && recents.length !== 0 ? ( + {results === undefined && + recents.length + recentCategories.length !== 0 ? ( <RecentSearches sectionTitle="Recent" sectionButtonTitle="Clear all" onPress={clearRecentlySearched} - recents={recents} screenType={ScreenType.Search} + {...{recents, recentCategories}} /> ) : ( <SearchResultList diff --git a/src/services/ExploreService.ts b/src/services/ExploreService.ts index 4f7875dc..9b0b4f71 100644 --- a/src/services/ExploreService.ts +++ b/src/services/ExploreService.ts @@ -51,6 +51,7 @@ export const getAllExploreSections = async () => { return EMPTY_PROFILE_PREVIEW_LIST; } const data = await response.json(); + // TODO (if we return to original explore format): get keys from backend API const exploreSections: Record<ExploreSectionType, ProfilePreviewType[]> = { 'New to Tagg': data.categories.new_to_tagg, 'People You May Know': data.categories.people_you_may_know, diff --git a/src/services/SocialLinkingService.ts b/src/services/SocialLinkingService.ts index d1c5c2ff..90b26c96 100644 --- a/src/services/SocialLinkingService.ts +++ b/src/services/SocialLinkingService.ts @@ -13,7 +13,6 @@ import { LINK_TWITTER_OAUTH, } from '../constants'; import {COMING_SOON_MSG, ERROR_LINK, SUCCESS_LINK} from '../constants/strings'; -import {CategorySelection} from '../screens'; // A list of endpoint strings for all the integrated socials export const integratedEndpoints: {[social: string]: [string, string]} = { diff --git a/src/services/SuggestedPeopleService.ts b/src/services/SuggestedPeopleService.ts index c57de59d..d0032458 100644 --- a/src/services/SuggestedPeopleService.ts +++ b/src/services/SuggestedPeopleService.ts @@ -99,7 +99,7 @@ export const getSuggestedPeopleProfile = async (userId: string) => { } }; -export const getMutualBadgeHolders = async (badgeId: string) => { +export const getMutualBadgeHolders = async () => { try { const token = await AsyncStorage.getItem('token'); const response = await fetch(SP_MUTUAL_BADGE_HOLDERS_ENDPOINT, { diff --git a/src/services/UserFriendsService.ts b/src/services/UserFriendsService.ts index a0bf7ac7..dbec1974 100644 --- a/src/services/UserFriendsService.ts +++ b/src/services/UserFriendsService.ts @@ -25,7 +25,6 @@ export const loadFriends = async (userId: string, token: string) => { }; export const friendOrUnfriendUser = async ( - user: string, friend: string, token: string, friendship_status: FriendshipStatusType, diff --git a/src/types/types.ts b/src/types/types.ts index 186cb4d5..7839e3f5 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -14,6 +14,11 @@ export interface ProfilePreviewType { thumbnail_url: string; } +export interface CategoryPreviewType { + name: string; + category: string; +} + export type FriendshipStatusType = 'friends' | 'requested' | 'no_record'; export interface ProfileType { diff --git a/src/utils/users.ts b/src/utils/users.ts index 653c941e..15107c99 100644 --- a/src/utils/users.ts +++ b/src/utils/users.ts @@ -19,6 +19,7 @@ import {AppDispatch} from './../store/configureStore'; import {RootState} from './../store/rootReducer'; import { ProfilePreviewType, + CategoryPreviewType, ProfileType, ScreenType, UserType, @@ -196,3 +197,38 @@ export const addUserToRecentlyViewed = async (user: ProfilePreviewType) => { console.log(e); } }; + +/* + * Stores `category` in AsyncStorage as a recently searched category. + */ +export const addCategoryToRecentlySearched = async ( + category: CategoryPreviewType, +) => { + const recentlySearchedCategoriesKey = '@recently_searched_categories'; + let categories: CategoryPreviewType[]; + // retrieve recently-searched categories and set new list + try { + const categoriesJSON = await AsyncStorage.getItem( + recentlySearchedCategoriesKey, + ); + if (categoriesJSON) { + categories = JSON.parse(categoriesJSON); + // TODO: make this more efficient by comparing shorter key + if (categories.find((c) => c.name === category.name)) return; + categories.push(category); + } else { + categories = [category]; + } + // store updated list of recently-searched categories + try { + AsyncStorage.setItem( + recentlySearchedCategoriesKey, + JSON.stringify(categories), + ); + } catch (e) { + console.log(e); + } + } catch (e) { + console.log(e); + } +}; |