aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorankit-thanekar007 <ankit.thanekar007@gmail.com>2021-03-04 16:06:21 -0800
committerankit-thanekar007 <ankit.thanekar007@gmail.com>2021-03-04 16:06:21 -0800
commit79396f899fe25f611d790d918e8ae4275a61e43c (patch)
treef5c9c003091d3d28ca32b31bb2b1bf8f67892acc
parent95bc850b9db986b9f462f19d7801218027307d58 (diff)
TMA-663-Changes for empty view
-rw-r--r--src/components/profile/ProfilePreview.tsx35
-rw-r--r--src/components/search/RecentSearches.tsx1
-rw-r--r--src/components/search/SearchResultCell.tsx87
-rw-r--r--src/components/search/SearchResultList.tsx82
-rw-r--r--src/constants/api.ts3
-rw-r--r--src/constants/strings.ts1
-rw-r--r--src/screens/search/SearchScreen.tsx114
-rw-r--r--src/services/SearchService.ts22
-rw-r--r--src/services/index.ts1
-rw-r--r--src/utils/users.ts32
10 files changed, 249 insertions, 129 deletions
diff --git a/src/components/profile/ProfilePreview.tsx b/src/components/profile/ProfilePreview.tsx
index 0021b1c6..f08335a1 100644
--- a/src/components/profile/ProfilePreview.tsx
+++ b/src/components/profile/ProfilePreview.tsx
@@ -16,6 +16,7 @@ import {loadImageFromURL} from '../../services';
import {RootState} from '../../store/rootreducer';
import {PreviewType, ProfilePreviewType, ScreenType} from '../../types';
import {
+ addUserToRecentlyViewed,
checkIfUserIsBlocked,
fetchUserX,
isIPhoneX,
@@ -89,39 +90,7 @@ const ProfilePreview: React.FC<ProfilePreviewProps> = ({
return;
}
if (previewType !== 'Comment') {
- const jsonValue = await AsyncStorage.getItem(
- '@recently_searched_users',
- );
- let recentlySearchedList =
- jsonValue != null ? JSON.parse(jsonValue) : null;
- if (recentlySearchedList) {
- if (recentlySearchedList.length > 0) {
- if (
- recentlySearchedList.some(
- (saved_user: ProfilePreviewType) => saved_user.id === id,
- )
- ) {
- console.log('User already in recently searched.');
- } else {
- if (recentlySearchedList.length >= 10) {
- recentlySearchedList.pop();
- }
- recentlySearchedList.unshift(user);
- }
- }
- } else {
- recentlySearchedList = [user];
- }
-
- try {
- let recentlySearchedListString = JSON.stringify(recentlySearchedList);
- await AsyncStorage.setItem(
- '@recently_searched_users',
- recentlySearchedListString,
- );
- } catch (e) {
- console.log(e);
- }
+ await addUserToRecentlyViewed(user)
}
const userXId =
diff --git a/src/components/search/RecentSearches.tsx b/src/components/search/RecentSearches.tsx
index 43a26514..3925d084 100644
--- a/src/components/search/RecentSearches.tsx
+++ b/src/components/search/RecentSearches.tsx
@@ -54,7 +54,6 @@ const styles = StyleSheet.create({
marginBottom: '5%',
},
clear: {
-
fontSize: 18,
fontWeight: 'bold',
color: TAGG_LIGHT_BLUE,
diff --git a/src/components/search/SearchResultCell.tsx b/src/components/search/SearchResultCell.tsx
index 084c6afe..705fb5c9 100644
--- a/src/components/search/SearchResultCell.tsx
+++ b/src/components/search/SearchResultCell.tsx
@@ -1,12 +1,24 @@
+import {useNavigation} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
-import {Image, StyleSheet, Text, View} from 'react-native';
+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 {ProfilePreviewType} from '../../types';
+import {RootState} from '../../store/rootReducer';
+import {ProfilePreviewType, ScreenType, UserType} from '../../types';
import {normalize, SCREEN_WIDTH} from '../../utils';
-import {defaultUserProfile} from '../../utils/users';
+import {
+ addUserToRecentlyViewed,
+ checkIfUserIsBlocked,
+ defaultUserProfile,
+ fetchUserX,
+ userXInStore,
+} from '../../utils/users';
interface SearchResults {
profileData: ProfilePreviewType;
+ loggedInUser: UserType;
}
const SearchResultsCell: React.FC<SearchResults> = ({
@@ -19,8 +31,9 @@ const SearchResultsCell: React.FC<SearchResults> = ({
thumbnail_url,
category,
},
+ loggedInUser,
}) => {
- const [avatar, setAvatar] = useState('');
+ const [avatar, setAvatar] = useState<string | undefined>(undefined);
useEffect(() => {
(async () => {
if (thumbnail_url !== undefined) {
@@ -37,9 +50,60 @@ const SearchResultsCell: React.FC<SearchResults> = ({
})();
}, [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 (
- <View style={styles.cellContainer}>
+ <TouchableOpacity
+ onPress={addToRecentlyStoredAndNavigateToProfile}
+ style={styles.cellContainer}>
<Image
defaultSource={defaultUserProfile()}
source={{uri: avatar}}
@@ -51,7 +115,7 @@ const SearchResultsCell: React.FC<SearchResults> = ({
{first_name + ' ' + last_name}
</Text>
</View>
- </View>
+ </TouchableOpacity>
);
};
@@ -65,7 +129,7 @@ const SearchResultsCell: React.FC<SearchResults> = ({
const categoryCell = () => {
return (
- <View style={styles.cellContainer}>
+ <TouchableOpacity style={styles.cellContainer}>
<View style={[styles.imageContainer, styles.categoryBackground]}>
<Image
resizeMode="contain"
@@ -76,16 +140,11 @@ const SearchResultsCell: React.FC<SearchResults> = ({
<View style={styles.initialTextContainer}>
<Text style={styles.initialTextStyle}>{name}</Text>
</View>
- </View>
+ </TouchableOpacity>
);
};
- return (
- <>
- {name !== undefined && categoryCell()}
- {name === undefined && userCell()}
- </>
- );
+ return name === undefined ? userCell() : categoryCell();
};
const styles = StyleSheet.create({
diff --git a/src/components/search/SearchResultList.tsx b/src/components/search/SearchResultList.tsx
index bf08e205..7f8073c4 100644
--- a/src/components/search/SearchResultList.tsx
+++ b/src/components/search/SearchResultList.tsx
@@ -1,16 +1,20 @@
-import React, { useState } from 'react';
+import React, {useEffect, useState} from 'react';
import {
+ Keyboard,
KeyboardAvoidingView,
SectionList,
StyleSheet,
- View
+ Text,
+ View,
} from 'react-native';
-import { PreviewType, ScreenType } from '../../types';
-import { normalize, SCREEN_HEIGHT } from '../../utils';
+import {useSelector} from 'react-redux';
+import {RootState} from 'src/store/rootreducer';
+import {PreviewType, ScreenType} from '../../types';
+import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
import SearchResultsCell from './SearchResultCell';
-
+import {NO_RESULTS_FOUND} from '../../constants/strings';
interface SearchResultsProps {
- results: [];
+ results: Array<any> | undefined;
previewType: PreviewType;
screenType: ScreenType;
}
@@ -24,34 +28,66 @@ const sectionHeader: React.FC<Boolean> = (showBorder: Boolean) => {
const SearchResultList: React.FC<SearchResultsProps> = ({results}) => {
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 (
- <KeyboardAvoidingView style={styles.container} behavior="padding">
- <SectionList
- style={styles.container}
- showsVerticalScrollIndicator={false}
- sections={results}
- keyExtractor={(item, index) => item + index}
- renderItem={({item}) => <SearchResultsCell profileData={item} />}
- renderSectionHeader={({section: {title, data}}) => {
- if (title === 'categories' && data.length === 0) {
- setShowSection(false);
- }
- return sectionHeader(title !== 'categories' && showSection);
- }}
- />
- <View style={{height: SCREEN_HEIGHT * 0.35}} />
- </KeyboardAvoidingView>
+ <View style={styles.container}>
+ {showEmptyView && (
+ <View style={styles.noResultsTextContainer}>
+ <Text style={styles.noResultsTextStyle}>{NO_RESULTS_FOUND}</Text>
+ </View>
+ )}
+ {!showEmptyView && (
+ <SectionList
+ style={{height: SCREEN_HEIGHT, width: SCREEN_WIDTH}}
+ showsVerticalScrollIndicator={false}
+ 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},
+ container: {
+ marginTop: SCREEN_HEIGHT * 0.04,
+ },
sectionHeaderStyle: {
width: '100%',
height: 0.5,
marginBottom: normalize(24),
backgroundColor: '#C4C4C4',
},
+ keyboardOpen: {marginBottom: SCREEN_HEIGHT * 0.3},
+ keyboardClose: {marginBottom: 20},
+ noResultsTextContainer: {
+ justifyContent: 'center',
+ flexDirection: 'row',
+ width: SCREEN_WIDTH,
+ },
+ noResultsTextStyle: {
+ fontWeight: '500',
+ fontSize: normalize(14),
+ },
});
export default SearchResultList;
diff --git a/src/constants/api.ts b/src/constants/api.ts
index 5e23ac7e..1463683f 100644
--- a/src/constants/api.ts
+++ b/src/constants/api.ts
@@ -17,8 +17,7 @@ export const PROFILE_PHOTO_THUMBNAIL_ENDPOINT: string =
export const GET_IG_POSTS_ENDPOINT: string = API_URL + 'posts-ig/';
export const GET_FB_POSTS_ENDPOINT: string = API_URL + 'posts-fb/';
export const GET_TWITTER_POSTS_ENDPOINT: string = API_URL + 'posts-twitter/';
-export const SEARCH_ENDPOINT: string = API_URL + 'search/';
-export const SEARCH_V2_ENDPOINT: string = API_URL + 'search/v2/';
+export const SEARCH_ENDPOINT: string = API_URL + 'search/v2/';
export const MOMENTS_ENDPOINT: string = API_URL + 'moments/';
export const MOMENT_THUMBNAIL_ENDPOINT: string = API_URL + 'moment-thumbnail/';
export const VERIFY_INVITATION_CODE_ENDPOUNT: string = API_URL + 'verify-code/';
diff --git a/src/constants/strings.ts b/src/constants/strings.ts
index 104cc198..7652fccd 100644
--- a/src/constants/strings.ts
+++ b/src/constants/strings.ts
@@ -49,6 +49,7 @@ export const ERROR_VERIFICATION_FAILED_SHORT = 'Verification failed 😓';
export const MARKED_AS_MSG = (str: string) => `Marked as ${str}`;
export const MOMENT_DELETED_MSG = 'Moment deleted....Some moments have to go, to create space for greater ones';
export const NO_NEW_NOTIFICATIONS = 'You have no new notifications';
+export const NO_RESULTS_FOUND = 'No Results Found!';
export const SUCCESS_CATEGORY_DELETE = 'Category successfully deleted, but its memory will live on';
export const SUCCESS_LINK = (str: string) => `Successfully linked ${str} 🎉`;
export const SUCCESS_PIC_UPLOAD = 'Beautiful, the picture was uploaded successfully!';
diff --git a/src/screens/search/SearchScreen.tsx b/src/screens/search/SearchScreen.tsx
index a66a2cbc..b6841480 100644
--- a/src/screens/search/SearchScreen.tsx
+++ b/src/screens/search/SearchScreen.tsx
@@ -3,10 +3,12 @@ import {useFocusEffect} from '@react-navigation/native';
import React, {useCallback, useEffect, useState} from 'react';
import {
Keyboard,
+ KeyboardAvoidingView,
RefreshControl,
ScrollView,
StatusBar,
StyleSheet,
+ SafeAreaView,
} from 'react-native';
import Animated, {Easing, timing} from 'react-native-reanimated';
import {useDispatch, useSelector} from 'react-redux';
@@ -20,11 +22,12 @@ import {
SearchResultsBackground,
TabsGradient,
} from '../../components';
-import {SEARCH_V2_ENDPOINT, TAGG_LIGHT_BLUE} from '../../constants';
+import {SEARCH_ENDPOINT, TAGG_LIGHT_BLUE} from '../../constants';
import {loadRecentlySearched, resetScreenType} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {ProfilePreviewType, ScreenType, UserType} from '../../types';
import {SCREEN_HEIGHT, SCREEN_WIDTH, StatusBarHeight} from '../../utils';
+import {loadSearchResults} from '../../services';
const NO_USER: UserType = {
userId: '',
username: '',
@@ -38,14 +41,27 @@ const NO_USER: UserType = {
const SearchScreen: React.FC = () => {
const {recentSearches} = useSelector((state: RootState) => state.taggUsers);
const [query, setQuery] = useState<string>('');
- const [results, setResults] = useState(Array<any>());
+ const [results, setResults] = useState<Array<any> | undefined>(undefined);
const [recents, setRecents] = useState<Array<ProfilePreviewType>>(
recentSearches ?? [],
);
const [searching, setSearching] = useState(false);
const top = Animated.useValue(-SCREEN_HEIGHT);
const [refreshing, setRefreshing] = useState<boolean>(false);
+ const [keyboardVisible, setKeyboardVisible] = React.useState(
+ 'keyboardVisible',
+ );
+ useEffect(() => {
+ const showKeyboard = () => setKeyboardVisible('keyboardVisibleTrue');
+ Keyboard.addListener('keyboardWillShow', showKeyboard);
+ return () => Keyboard.removeListener('keyboardWillShow', showKeyboard);
+ }, []);
+ useEffect(() => {
+ const hideKeyboard = () => setKeyboardVisible('keyboardVisibleFalse');
+ Keyboard.addListener('keyboardWillHide', hideKeyboard);
+ return () => Keyboard.removeListener('keyboardWillHide', hideKeyboard);
+ }, []);
const dispatch = useDispatch();
const onRefresh = useCallback(() => {
@@ -60,48 +76,31 @@ const SearchScreen: React.FC = () => {
useEffect(() => {
if (query.length < 3) {
- setResults([]);
+ setResults(undefined);
return;
}
- const loadResults = async (q: string) => {
- try {
- const token = await AsyncStorage.getItem('token');
- const response = await fetch(`${SEARCH_V2_ENDPOINT}?query=${q}`, {
- method: 'GET',
- headers: {
- Authorization: 'Token ' + token,
+ (async () => {
+ const searchResults = await loadSearchResults(
+ `${SEARCH_ENDPOINT}?query=${query}`,
+ );
+ if (query.length > 2) {
+ const categories = searchResults?.categories;
+ const users = searchResults?.users;
+ const sanitizedResult = [
+ {
+ title: 'categories',
+ data: categories,
},
- });
- const {status} = response;
- if (status === 200) {
- const searchResults = await response.json();
- const sanitizedResult = [
- {
- title: 'categories',
- data: searchResults.categories,
- },
- {
- title: 'users',
- data: searchResults.users,
- },
- ];
-
- if (
- searchResults.categories.length !== 0 ||
- searchResults.users.length !== 0
- ) {
- if (query.length > 3) {
- setResults(sanitizedResult);
- return;
- }
- }
- }
- } catch (error) {
- console.log(error);
+ {
+ title: 'users',
+ data: users,
+ },
+ ];
+ setResults(sanitizedResult);
+ } else {
+ setResults(undefined);
}
- setResults([]);
- };
- loadResults(query);
+ })();
}, [query]);
/**
@@ -179,24 +178,27 @@ const SearchScreen: React.FC = () => {
<Explore />
<SearchResultsBackground {...{top}}>
- {results && results.length === 0 ? (
- <RecentSearches
- sectionTitle="Recent"
- sectionButtonTitle="Clear all"
- onPress={clearRecentlySearched}
- recents={recents}
- screenType={ScreenType.Search}
- />
- ) : (
- <SearchResultList
- {...{results}}
- previewType={'Search'}
- screenType={ScreenType.Search}
- />
- )}
+ <KeyboardAvoidingView
+ behavior={'padding'}
+ keyboardVerticalOffset={SCREEN_HEIGHT * 0.1}>
+ {results === undefined && recents.length !== 0 ? (
+ <RecentSearches
+ sectionTitle="Recent"
+ sectionButtonTitle="Clear all"
+ onPress={clearRecentlySearched}
+ recents={recents}
+ screenType={ScreenType.Search}
+ />
+ ) : (
+ <SearchResultList
+ {...{results}}
+ previewType={'Search'}
+ screenType={ScreenType.Search}
+ />
+ )}
+ </KeyboardAvoidingView>
</SearchResultsBackground>
</ScrollView>
-
<TabsGradient />
</SearchBackground>
);
diff --git a/src/services/SearchService.ts b/src/services/SearchService.ts
new file mode 100644
index 00000000..7b97f9a7
--- /dev/null
+++ b/src/services/SearchService.ts
@@ -0,0 +1,22 @@
+import AsyncStorage from '@react-native-community/async-storage';
+
+export const loadSearchResults = async (url: string) => {
+ try {
+ const token = await AsyncStorage.getItem('token');
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ Authorization: 'Token ' + token,
+ },
+ });
+ const {status} = response;
+ if (status === 200) {
+ const searchResults = await response.json();
+ return searchResults;
+ }
+ } catch (error) {
+ console.log(error);
+ throw error;
+ }
+ return {};
+};
diff --git a/src/services/index.ts b/src/services/index.ts
index ef71233a..28e03e0e 100644
--- a/src/services/index.ts
+++ b/src/services/index.ts
@@ -12,3 +12,4 @@ export * from './WaitlistUserService';
export * from './CommonService';
export * from './CommentService';
export * from './SuggestedPeopleService';
+export * from './SearchService';
diff --git a/src/utils/users.ts b/src/utils/users.ts
index b8faf206..653c941e 100644
--- a/src/utils/users.ts
+++ b/src/utils/users.ts
@@ -164,3 +164,35 @@ export const defaultUserProfile = () => {
const defaultImage = require('../assets/images/avatar-placeholder.png');
return defaultImage;
};
+
+export const addUserToRecentlyViewed = async (user: ProfilePreviewType) => {
+ const jsonValue = await AsyncStorage.getItem('@recently_searched_users');
+ let recentlySearchedList = jsonValue != null ? JSON.parse(jsonValue) : null;
+ if (recentlySearchedList) {
+ if (recentlySearchedList.length > 0) {
+ if (
+ recentlySearchedList.some(
+ (saved_user: ProfilePreviewType) => saved_user.id === user.id,
+ )
+ ) {
+ console.log('User already in recently searched.');
+ } else {
+ if (recentlySearchedList.length >= 10) {
+ recentlySearchedList.pop();
+ }
+ recentlySearchedList.unshift(user);
+ }
+ }
+ } else {
+ recentlySearchedList = [user];
+ }
+ try {
+ let recentlySearchedListString = JSON.stringify(recentlySearchedList);
+ await AsyncStorage.setItem(
+ '@recently_searched_users',
+ recentlySearchedListString,
+ );
+ } catch (e) {
+ console.log(e);
+ }
+};