aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Chen <ivan@thetaggid.com>2021-01-13 02:58:24 -0500
committerGitHub <noreply@github.com>2021-01-13 02:58:24 -0500
commit353c1ec685698bb86e0ff96a346d88205ee389cf (patch)
tree021f721cc8eb94ab007183c39d808e9eb3a468e8 /src
parent5664f30a218af4620be69c66f4aba93d5972f890 (diff)
[TMA-531] New Explore Page (#179)
* redux done * done * added refresh control * added profile navigation * minor spacing change
Diffstat (limited to 'src')
-rw-r--r--src/components/profile/ProfilePreview.tsx7
-rw-r--r--src/components/search/Explore.tsx35
-rw-r--r--src/components/search/ExploreSection.tsx26
-rw-r--r--src/components/search/ExploreSectionUser.tsx81
-rw-r--r--src/constants/api.ts1
-rw-r--r--src/constants/constants.ts11
-rw-r--r--src/screens/search/SearchScreen.tsx51
-rw-r--r--src/services/ExploreServices.ts34
-rw-r--r--src/store/actions/taggUsers.ts10
-rw-r--r--src/store/initialStates.ts15
-rw-r--r--src/store/reducers/taggUsersReducer.ts4
-rw-r--r--src/types/types.ts8
12 files changed, 209 insertions, 74 deletions
diff --git a/src/components/profile/ProfilePreview.tsx b/src/components/profile/ProfilePreview.tsx
index bd015811..6f008540 100644
--- a/src/components/profile/ProfilePreview.tsx
+++ b/src/components/profile/ProfilePreview.tsx
@@ -147,7 +147,8 @@ const ProfilePreview: React.FC<ProfilePreviewProps> = ({
screenType,
);
}
- const userXId = loggedInUser.username === user.username ? undefined : user.id;
+ const userXId =
+ loggedInUser.username === user.username ? undefined : user.id;
navigation.push('Profile', {
userXId,
screenType,
@@ -205,7 +206,6 @@ const ProfilePreview: React.FC<ProfilePreviewProps> = ({
usernameStyle = styles.searchResultUsername;
nameStyle = styles.searchResultName;
}
-
return (
<TouchableOpacity
onPress={addToRecentlyStoredAndNavigateToProfile}
@@ -257,9 +257,9 @@ const styles = StyleSheet.create({
discoverUsersContainer: {
alignItems: 'center',
textAlign: 'center',
- margin: '0.5%',
width: '32%',
marginVertical: 10,
+ borderWidth: 1,
},
searchResultAvatar: {
height: 60,
@@ -290,6 +290,7 @@ const styles = StyleSheet.create({
discoverUsersNameContainer: {
justifyContent: 'space-evenly',
alignSelf: 'stretch',
+ marginTop: 5,
},
searchResultUsername: {
fontSize: 18,
diff --git a/src/components/search/Explore.tsx b/src/components/search/Explore.tsx
index a02205a4..c07c66b8 100644
--- a/src/components/search/Explore.tsx
+++ b/src/components/search/Explore.tsx
@@ -1,27 +1,18 @@
import React from 'react';
-import {View, StyleSheet} from 'react-native';
+import {StyleSheet, Text, View} from 'react-native';
+import {useSelector} from 'react-redux';
+import {EXPLORE_SECTION_TITLES} from '../../constants';
+import {RootState} from '../../store/rootReducer';
+import {ExploreSectionType} from '../../types';
import ExploreSection from './ExploreSection';
const Explore: React.FC = () => {
- const sections: Array<string> = [
- 'People you follow',
- 'People you may know',
- 'Trending in sports',
- 'Trending on Tagg',
- 'Trending in music',
- ];
- const users: Array<string> = [
- 'Sam Davis',
- 'Becca Smith',
- 'Ann Taylor',
- 'Clara Johnson',
- 'Sarah Jung',
- 'Lila Hernandez',
- ];
+ const {explores} = useSelector((state: RootState) => state.taggUsers);
return (
<View style={styles.container}>
- {sections.map((title) => (
- <ExploreSection key={title} title={title} users={users} />
+ <Text style={styles.header}>Search Profiles</Text>
+ {EXPLORE_SECTION_TITLES.map((title: ExploreSectionType) => (
+ <ExploreSection key={title} title={title} users={explores[title]} />
))}
</View>
);
@@ -30,6 +21,14 @@ const Explore: React.FC = () => {
const styles = StyleSheet.create({
container: {
zIndex: 0,
+ // margin: '5%',
+ },
+ header: {
+ fontWeight: '700',
+ fontSize: 22,
+ color: '#fff',
+ marginBottom: '2%',
+ margin: '5%',
},
});
export default Explore;
diff --git a/src/components/search/ExploreSection.tsx b/src/components/search/ExploreSection.tsx
index 8e826bd9..8e8b4988 100644
--- a/src/components/search/ExploreSection.tsx
+++ b/src/components/search/ExploreSection.tsx
@@ -1,5 +1,6 @@
-import React from 'react';
-import {View, Text, ScrollView, StyleSheet} from 'react-native';
+import React, {Fragment} from 'react';
+import {ScrollView, StyleSheet, Text, View} from 'react-native';
+import {ProfilePreviewType} from '../../types';
import ExploreSectionUser from './ExploreSectionUser';
/**
@@ -9,33 +10,40 @@ import ExploreSectionUser from './ExploreSectionUser';
interface ExploreSectionProps {
title: string;
- users: Array<string>;
+ users: ProfilePreviewType[];
}
const ExploreSection: React.FC<ExploreSectionProps> = ({title, users}) => {
- return (
+ return users.length !== 0 ? (
<View style={styles.container}>
<Text style={styles.header}>{title}</Text>
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
- {users.map((name, key) => (
- <ExploreSectionUser {...{name, key}} style={styles.user} />
+ <View style={styles.padding} />
+ {users.map((user) => (
+ <ExploreSectionUser key={user.id} user={user} style={styles.user} />
))}
</ScrollView>
</View>
+ ) : (
+ <Fragment />
);
};
const styles = StyleSheet.create({
container: {
- marginBottom: 30,
+ marginVertical: '5%',
},
header: {
fontWeight: '600',
fontSize: 20,
color: '#fff',
- marginBottom: 20,
+ marginLeft: '5%',
+ marginBottom: '5%',
},
user: {
- marginHorizontal: 15,
+ marginHorizontal: 5,
+ },
+ padding: {
+ width: 10,
},
});
diff --git a/src/components/search/ExploreSectionUser.tsx b/src/components/search/ExploreSectionUser.tsx
index a9fce063..0bf68a20 100644
--- a/src/components/search/ExploreSectionUser.tsx
+++ b/src/components/search/ExploreSectionUser.tsx
@@ -1,12 +1,18 @@
-import React from 'react';
+import {useNavigation} from '@react-navigation/native';
+import React, {useEffect, useState} from 'react';
import {
+ Image,
StyleSheet,
Text,
- ViewProps,
- Image,
TouchableOpacity,
+ ViewProps,
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
+import {useDispatch, useSelector, useStore} from 'react-redux';
+import {loadAvatar} from '../../services';
+import {RootState} from '../../store/rootReducer';
+import {ProfilePreviewType, ScreenType} from '../../types';
+import {fetchUserX, userXInStore} from '../../utils';
/**
* Search Screen for user recommendations and a search
@@ -14,14 +20,52 @@ import LinearGradient from 'react-native-linear-gradient';
*/
interface ExploreSectionUserProps extends ViewProps {
- name: string;
+ user: ProfilePreviewType;
}
const ExploreSectionUser: React.FC<ExploreSectionUserProps> = ({
- name,
+ user,
style,
}) => {
+ const {id, username, first_name, last_name} = user;
+ const [avatar, setAvatar] = useState<string | null>(null);
+ const navigation = useNavigation();
+ const {user: loggedInUser} = useSelector((state: RootState) => state.user);
+ const state: RootState = useStore().getState();
+ const screenType = ScreenType.Search;
+
+ const dispatch = useDispatch();
+
+ useEffect(() => {
+ let mounted = true;
+ const loadAvatarImage = async () => {
+ const response = await loadAvatar(id, true);
+ if (mounted) {
+ setAvatar(response);
+ }
+ };
+ loadAvatarImage();
+ return () => {
+ mounted = false;
+ };
+ }, [user]);
+
+ const handlePress = async () => {
+ if (!userXInStore(state, screenType, user.id)) {
+ await fetchUserX(
+ dispatch,
+ {userId: user.id, username: user.username},
+ screenType,
+ );
+ }
+ const userXId = loggedInUser.username === user.username ? undefined : id;
+ navigation.push('Profile', {
+ userXId,
+ screenType,
+ });
+ };
+
return (
- <TouchableOpacity style={[styles.container, style]}>
+ <TouchableOpacity style={[styles.container, style]} onPress={handlePress}>
<LinearGradient
colors={['#9F00FF', '#27EAE9']}
useAngle
@@ -29,12 +73,18 @@ const ExploreSectionUser: React.FC<ExploreSectionUserProps> = ({
angleCenter={{x: 0.5, y: 0.5}}
style={styles.gradient}>
<Image
- source={require('../../assets/images/avatar-placeholder.png')}
+ source={
+ avatar
+ ? {uri: avatar}
+ : require('../../assets/images/avatar-placeholder.png')
+ }
style={styles.profile}
/>
</LinearGradient>
- <Text style={styles.name}>{name}</Text>
- <Text style={styles.username}>{`@${name.split(' ').join('')}`}</Text>
+ <Text style={styles.name} numberOfLines={2}>
+ {first_name} {last_name}
+ </Text>
+ <Text style={styles.username} numberOfLines={1}>{`@${username}`}</Text>
</TouchableOpacity>
);
};
@@ -42,27 +92,30 @@ const ExploreSectionUser: React.FC<ExploreSectionUserProps> = ({
const styles = StyleSheet.create({
container: {
alignItems: 'center',
+ width: 100,
},
gradient: {
- height: 80,
- width: 80,
+ height: 60,
+ aspectRatio: 1,
borderRadius: 40,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 10,
},
profile: {
- height: 76,
- width: 76,
+ height: 55,
+ aspectRatio: 1,
borderRadius: 38,
},
name: {
fontWeight: '600',
+ flexWrap: 'wrap',
fontSize: 16,
color: '#fff',
+ textAlign: 'center',
},
username: {
- fontWeight: '600',
+ fontWeight: '400',
fontSize: 14,
color: '#fff',
},
diff --git a/src/constants/api.ts b/src/constants/api.ts
index 639bc8f8..de43b94d 100644
--- a/src/constants/api.ts
+++ b/src/constants/api.ts
@@ -27,6 +27,7 @@ export const BLOCK_USER_ENDPOINT: string = API_URL + 'block/';
export const PASSWORD_RESET_ENDPOINT: string = API_URL + 'password-reset/';
export const MOMENT_CATEGORY_ENDPOINT: string = API_URL + 'moment-category/';
export const NOTIFICATIONS_ENDPOINT: string = API_URL + 'notifications/';
+export const DISCOVER_ENDPOINT: string = API_URL + 'discover/';
export const WAITLIST_USER_ENDPOINT: string = API_URL + 'waitlist-user/';
// Register as FCM device
diff --git a/src/constants/constants.ts b/src/constants/constants.ts
index 90d70724..b96d9438 100644
--- a/src/constants/constants.ts
+++ b/src/constants/constants.ts
@@ -1,5 +1,5 @@
import {ReactText} from 'react';
-import {BackgroundGradientType} from './../types/';
+import {BackgroundGradientType, ExploreSectionType} from './../types/';
import {SCREEN_WIDTH, SCREEN_HEIGHT} from '../utils';
export const CHIN_HEIGHT = 34;
@@ -160,3 +160,12 @@ export const MOMENT_CATEGORY_BG_COLORS: string[] = [
'#365F6A',
'#4E7175',
];
+
+export const EXPLORE_SECTION_TITLES: ExploreSectionType[] = [
+ 'New to Tagg',
+ 'People You May Know',
+ 'Trending on Tagg',
+ "Brown '21",
+ "Brown '22",
+ "Brown '23",
+];
diff --git a/src/screens/search/SearchScreen.tsx b/src/screens/search/SearchScreen.tsx
index 78c0c5cc..4505163c 100644
--- a/src/screens/search/SearchScreen.tsx
+++ b/src/screens/search/SearchScreen.tsx
@@ -1,9 +1,17 @@
import AsyncStorage from '@react-native-community/async-storage';
-import React, {useEffect, useState} from 'react';
-import {Keyboard, ScrollView, StatusBar, StyleSheet} from 'react-native';
+import {useFocusEffect} from '@react-navigation/native';
+import React, {useCallback, useEffect, useState} from 'react';
+import {
+ Keyboard,
+ RefreshControl,
+ ScrollView,
+ StatusBar,
+ StyleSheet,
+} from 'react-native';
import Animated, {Easing, timing} from 'react-native-reanimated';
+import {useDispatch, useSelector} from 'react-redux';
import {
- DiscoverUsers,
+ Explore,
RecentSearches,
SearchBackground,
SearchBar,
@@ -13,6 +21,8 @@ import {
TabsGradient,
} from '../../components';
import {SEARCH_ENDPOINT, TAGG_TEXT_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';
const NO_USER: UserType = {
@@ -20,18 +30,13 @@ const NO_USER: UserType = {
username: '',
};
-import {RootState} from '../../store/rootReducer';
-import {useSelector, useDispatch} from 'react-redux';
-import {resetScreenType} from '../../store/actions';
-import {useFocusEffect} from '@react-navigation/native';
-
/**
* Search Screen for user recommendations and a search
* tool to allow user to find other users
*/
const SearchScreen: React.FC = () => {
- const {recentSearches, taggUsers} = useSelector(
+ const {recentSearches, explores} = useSelector(
(state: RootState) => state.taggUsers,
);
const [query, setQuery] = useState<string>('');
@@ -42,6 +47,19 @@ const SearchScreen: React.FC = () => {
const [searching, setSearching] = useState(false);
const top = Animated.useValue(-SCREEN_HEIGHT);
const [user, setUser] = useState<UserType>(NO_USER);
+ const [refreshing, setRefreshing] = useState<boolean>(false);
+
+ const dispatch = useDispatch();
+
+ const onRefresh = useCallback(() => {
+ const refrestState = async () => {
+ dispatch(loadRecentlySearched());
+ };
+ setRefreshing(true);
+ refrestState().then(() => {
+ setRefreshing(false);
+ });
+ }, []);
useEffect(() => {
if (query.length < 3) {
@@ -76,8 +94,6 @@ const SearchScreen: React.FC = () => {
loadResults(query);
}, [query]);
- const dispatch = useDispatch();
-
/**
* Code under useFocusEffect gets executed every time the screen comes under focus / is being viewed by the user.
* This is done to reset the users stored in our store for the Search screen.
@@ -135,7 +151,10 @@ const SearchScreen: React.FC = () => {
keyboardShouldPersistTaps={'always'}
stickyHeaderIndices={[4]}
contentContainerStyle={styles.contentContainer}
- showsVerticalScrollIndicator={false}>
+ showsVerticalScrollIndicator={false}
+ refreshControl={
+ <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
+ }>
<SearchHeader style={styles.header} {...{top}} />
<SearchBar
style={styles.searchBar}
@@ -146,13 +165,7 @@ const SearchScreen: React.FC = () => {
value={query}
{...{top, searching}}
/>
- {/* Removed for Alpha for now */}
- {/* <Explore /> */}
- <DiscoverUsers
- sectionTitle="Discover Users"
- users={taggUsers}
- screenType={ScreenType.Search}
- />
+ <Explore />
<SearchResultsBackground {...{top}}>
{results.length === 0 && recents.length !== 0 ? (
<RecentSearches
diff --git a/src/services/ExploreServices.ts b/src/services/ExploreServices.ts
index 2181ea7d..ca4f1b69 100644
--- a/src/services/ExploreServices.ts
+++ b/src/services/ExploreServices.ts
@@ -1,4 +1,8 @@
-import {ALL_USERS_ENDPOINT} from '../constants';
+import AsyncStorage from '@react-native-community/async-storage';
+import {getDeviceToken} from 'react-native-device-info';
+import {ALL_USERS_ENDPOINT, DISCOVER_ENDPOINT} from '../constants';
+import {EMPTY_EXPLORE_SECTIONS} from '../store/initialStates';
+import {ExploreSectionType, ProfilePreviewType} from '../types';
export const getAllTaggUsers = async (token: string) => {
try {
@@ -26,3 +30,31 @@ export const getAllTaggUsers = async (token: string) => {
);
}
};
+
+export const getAllExploreSections = async () => {
+ try {
+ const token = await AsyncStorage.getItem('token');
+ const response = await fetch(DISCOVER_ENDPOINT, {
+ method: 'GET',
+ headers: {
+ Authorization: 'Token ' + token,
+ },
+ });
+ if (response.status !== 200) {
+ return EMPTY_EXPLORE_SECTIONS;
+ }
+ const data = await response.json();
+ const exploreSections: Record<ExploreSectionType, ProfilePreviewType[]> = {
+ 'New to Tagg': data.categories.new_to_tagg,
+ 'People You May Know': data.categories.people_you_may_know,
+ 'Trending on Tagg': data.categories.trending_on_tagg,
+ "Brown '21": data.categories.brown_21,
+ "Brown '22": data.categories.brown_22,
+ "Brown '23": data.categories.brown_23,
+ };
+
+ return exploreSections;
+ } catch (error) {
+ console.log('Unable to fetch explore data');
+ }
+};
diff --git a/src/store/actions/taggUsers.ts b/src/store/actions/taggUsers.ts
index 7f841c51..7b6d4d5e 100644
--- a/src/store/actions/taggUsers.ts
+++ b/src/store/actions/taggUsers.ts
@@ -1,8 +1,7 @@
-import {RootState} from '../rootReducer';
-import {loadRecentlySearchedUsers, getAllTaggUsers} from '../../services';
import {Action, ThunkAction} from '@reduxjs/toolkit';
+import {getAllExploreSections, loadRecentlySearchedUsers} from '../../services';
import {taggUsersFetched} from '../reducers';
-import {getTokenOrLogout} from '../../utils';
+import {RootState} from '../rootReducer';
export const loadRecentlySearched = (): ThunkAction<
Promise<void>,
@@ -11,12 +10,11 @@ export const loadRecentlySearched = (): ThunkAction<
Action<string>
> => async (dispatch) => {
try {
- const token = await getTokenOrLogout(dispatch);
const recentSearches = await loadRecentlySearchedUsers();
- const taggUsers = await getAllTaggUsers(token);
+ const exploreSections = await getAllExploreSections();
dispatch({
type: taggUsersFetched.type,
- payload: {recentSearches, taggUsers},
+ payload: {recentSearches, explores: exploreSections},
});
} catch (error) {
console.log(error);
diff --git a/src/store/initialStates.ts b/src/store/initialStates.ts
index de97b129..87e1ce22 100644
--- a/src/store/initialStates.ts
+++ b/src/store/initialStates.ts
@@ -1,4 +1,5 @@
import {
+ ExploreSectionType,
MomentType,
NotificationType,
ProfilePreviewType,
@@ -58,9 +59,21 @@ export const NO_SOCIAL_ACCOUNTS: Record<string, SocialAccountType> = {
Twitter: {posts: []},
};
+export const EMPTY_EXPLORE_SECTIONS: Record<
+ ExploreSectionType,
+ ProfilePreviewType[]
+> = {
+ 'People You May Know': EMPTY_PROFILE_PREVIEW_LIST,
+ 'New to Tagg': EMPTY_PROFILE_PREVIEW_LIST,
+ 'Trending on Tagg': EMPTY_PROFILE_PREVIEW_LIST,
+ "Brown '21": EMPTY_PROFILE_PREVIEW_LIST,
+ "Brown '22": EMPTY_PROFILE_PREVIEW_LIST,
+ "Brown '23": EMPTY_PROFILE_PREVIEW_LIST,
+};
+
export const NO_TAGG_USERS = {
recentSearches: EMPTY_PROFILE_PREVIEW_LIST,
- taggUsers: EMPTY_PROFILE_PREVIEW_LIST,
+ explores: EMPTY_EXPLORE_SECTIONS,
};
export const NO_SOCIALS = {
diff --git a/src/store/reducers/taggUsersReducer.ts b/src/store/reducers/taggUsersReducer.ts
index ff30f7a0..33e2e18d 100644
--- a/src/store/reducers/taggUsersReducer.ts
+++ b/src/store/reducers/taggUsersReducer.ts
@@ -6,8 +6,8 @@ const taggUsersSlice = createSlice({
initialState: NO_TAGG_USERS,
reducers: {
taggUsersFetched: (state, action) => {
- state.recentSearches = action.payload.taggUsers;
- state.taggUsers = action.payload.taggUsers;
+ state.recentSearches = action.payload.recentSearches;
+ state.explores = action.payload.explores;
},
},
});
diff --git a/src/types/types.ts b/src/types/types.ts
index 10e5de9a..093adbe4 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -103,6 +103,14 @@ export enum ScreenType {
Notifications,
}
+export type ExploreSectionType =
+ | 'People You May Know'
+ | 'New to Tagg'
+ | 'Trending on Tagg'
+ | "Brown '21"
+ | "Brown '22"
+ | "Brown '23";
+
/**
* Redux store to have a Record of ScreenType (Search, Profile, Home etc) mapped to
* A Record of userIXd mapped to UserXType