aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShravya Ramesh <37447613+shravyaramesh@users.noreply.github.com>2021-03-05 20:33:51 -0800
committerGitHub <noreply@github.com>2021-03-05 20:33:51 -0800
commit27925a267e9d279e29a1a1852891e392fdc4b3af (patch)
treef77ab55bf3f5cbd6190177058353ef01ad767711
parent8e4d9135f0645b56665ad23d6de5dd0afa1ef444 (diff)
parent59bc015a22a0c50d6c64ecf7501c269dae59bfbd (diff)
Merge branch 'master' into badges-people-screen
-rw-r--r--src/assets/images/badges/alpha_chi_omega.pngbin0 -> 1039 bytes
-rw-r--r--src/assets/images/badges/alpha_phi_alpha.pngbin0 -> 1107 bytes
-rw-r--r--src/assets/images/badges/baseball.pngbin0 -> 1305 bytes
-rw-r--r--src/assets/images/badges/basketball.pngbin0 -> 1484 bytes
-rw-r--r--src/assets/images/badges/beta_omega_chi.pngbin0 -> 1187 bytes
-rw-r--r--src/assets/images/badges/brown_badge.pngbin0 -> 843 bytes
-rw-r--r--src/assets/images/badges/delta_gamma.pngbin0 -> 643 bytes
-rw-r--r--src/assets/images/badges/delta_phi.pngbin0 -> 857 bytes
-rw-r--r--src/assets/images/badges/field_hockey.pngbin0 -> 970 bytes
-rw-r--r--src/assets/images/badges/football.pngbin0 -> 5374 bytes
-rw-r--r--src/assets/images/badges/gymnastics.pngbin0 -> 1643 bytes
-rw-r--r--src/assets/images/badges/hockey.pngbin0 -> 1077 bytes
-rw-r--r--src/assets/images/badges/kappa_alpha_psi.pngbin0 -> 1018 bytes
-rw-r--r--src/assets/images/badges/kappa_delta.pngbin0 -> 758 bytes
-rw-r--r--src/assets/images/badges/lax.pngbin0 -> 1091 bytes
-rw-r--r--src/assets/images/badges/sigma.pngbin0 -> 685 bytes
-rw-r--r--src/assets/images/badges/theta_alpha.pngbin0 -> 852 bytes
-rw-r--r--src/assets/images/badges/track.pngbin0 -> 1162 bytes
-rw-r--r--src/assets/images/badges/volleyball.pngbin0 -> 1674 bytes
-rw-r--r--src/assets/images/bwbadges.pngbin0 -> 528 bytes
-rw-r--r--src/assets/images/bwbadges@2x.pngbin0 -> 991 bytes
-rw-r--r--src/assets/images/bwbadges@3x.pngbin0 -> 1438 bytes
-rw-r--r--src/assets/images/search.pngbin0 -> 354 bytes
-rw-r--r--src/assets/images/search@2x.pngbin0 -> 643 bytes
-rw-r--r--src/assets/images/search@3x.pngbin0 -> 901 bytes
-rw-r--r--src/components/common/TaggPrompt.tsx62
-rw-r--r--src/components/index.ts1
-rw-r--r--src/components/profile/ProfilePreview.tsx35
-rw-r--r--src/components/search/ExploreSection.tsx2
-rw-r--r--src/components/search/RecentSearches.tsx9
-rw-r--r--src/components/search/SearchResultCell.tsx187
-rw-r--r--src/components/search/SearchResultList.tsx93
-rw-r--r--src/components/search/SearchResultsBackground.tsx9
-rw-r--r--src/components/search/index.ts1
-rw-r--r--src/components/taggs/SocialMediaInfo.tsx2
-rw-r--r--src/constants/api.ts5
-rw-r--r--src/constants/constants.ts8
-rw-r--r--src/constants/strings.ts13
-rw-r--r--src/routes/Routes.tsx6
-rw-r--r--src/routes/main/MainStackScreen.tsx1
-rw-r--r--src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackNavigator.tsx1
-rw-r--r--src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen.tsx8
-rw-r--r--src/routes/tabs/NavigationBar.tsx7
-rw-r--r--src/screens/badge/BadgeItem.tsx84
-rw-r--r--src/screens/badge/BadgeList.tsx57
-rw-r--r--src/screens/badge/BadgeListHeader.tsx33
-rw-r--r--src/screens/badge/BadgeScreenHeader.tsx42
-rw-r--r--src/screens/badge/BadgeSelection.tsx266
-rw-r--r--src/screens/badge/index.ts5
-rw-r--r--src/screens/index.ts1
-rw-r--r--src/screens/main/NotificationsScreen.tsx116
-rw-r--r--src/screens/profile/SocialMediaTaggs.tsx7
-rw-r--r--src/screens/search/SearchScreen.tsx72
-rw-r--r--src/screens/search/mock.ts118
-rw-r--r--src/screens/suggestedPeopleOnboarding/SuggestedPeopleUploadPictureScreen.tsx1
-rw-r--r--src/services/CommonService.ts2
-rw-r--r--src/services/FCMService.ts2
-rw-r--r--src/services/ReportingService.ts5
-rw-r--r--src/services/SearchService.ts22
-rw-r--r--src/services/index.ts1
-rw-r--r--src/store/actions/user.ts12
-rw-r--r--src/store/reducers/userBlockReducer.ts5
-rw-r--r--src/utils/common.ts4
-rw-r--r--src/utils/users.ts37
64 files changed, 1189 insertions, 153 deletions
diff --git a/src/assets/images/badges/alpha_chi_omega.png b/src/assets/images/badges/alpha_chi_omega.png
new file mode 100644
index 00000000..473894cc
--- /dev/null
+++ b/src/assets/images/badges/alpha_chi_omega.png
Binary files differ
diff --git a/src/assets/images/badges/alpha_phi_alpha.png b/src/assets/images/badges/alpha_phi_alpha.png
new file mode 100644
index 00000000..275e0eb3
--- /dev/null
+++ b/src/assets/images/badges/alpha_phi_alpha.png
Binary files differ
diff --git a/src/assets/images/badges/baseball.png b/src/assets/images/badges/baseball.png
new file mode 100644
index 00000000..7b470dbe
--- /dev/null
+++ b/src/assets/images/badges/baseball.png
Binary files differ
diff --git a/src/assets/images/badges/basketball.png b/src/assets/images/badges/basketball.png
new file mode 100644
index 00000000..45d1139b
--- /dev/null
+++ b/src/assets/images/badges/basketball.png
Binary files differ
diff --git a/src/assets/images/badges/beta_omega_chi.png b/src/assets/images/badges/beta_omega_chi.png
new file mode 100644
index 00000000..f2a85996
--- /dev/null
+++ b/src/assets/images/badges/beta_omega_chi.png
Binary files differ
diff --git a/src/assets/images/badges/brown_badge.png b/src/assets/images/badges/brown_badge.png
new file mode 100644
index 00000000..bcffb6e3
--- /dev/null
+++ b/src/assets/images/badges/brown_badge.png
Binary files differ
diff --git a/src/assets/images/badges/delta_gamma.png b/src/assets/images/badges/delta_gamma.png
new file mode 100644
index 00000000..84182eca
--- /dev/null
+++ b/src/assets/images/badges/delta_gamma.png
Binary files differ
diff --git a/src/assets/images/badges/delta_phi.png b/src/assets/images/badges/delta_phi.png
new file mode 100644
index 00000000..074317d1
--- /dev/null
+++ b/src/assets/images/badges/delta_phi.png
Binary files differ
diff --git a/src/assets/images/badges/field_hockey.png b/src/assets/images/badges/field_hockey.png
new file mode 100644
index 00000000..766f0f60
--- /dev/null
+++ b/src/assets/images/badges/field_hockey.png
Binary files differ
diff --git a/src/assets/images/badges/football.png b/src/assets/images/badges/football.png
new file mode 100644
index 00000000..2e8214b7
--- /dev/null
+++ b/src/assets/images/badges/football.png
Binary files differ
diff --git a/src/assets/images/badges/gymnastics.png b/src/assets/images/badges/gymnastics.png
new file mode 100644
index 00000000..5d500f26
--- /dev/null
+++ b/src/assets/images/badges/gymnastics.png
Binary files differ
diff --git a/src/assets/images/badges/hockey.png b/src/assets/images/badges/hockey.png
new file mode 100644
index 00000000..7e269665
--- /dev/null
+++ b/src/assets/images/badges/hockey.png
Binary files differ
diff --git a/src/assets/images/badges/kappa_alpha_psi.png b/src/assets/images/badges/kappa_alpha_psi.png
new file mode 100644
index 00000000..1b7d7aff
--- /dev/null
+++ b/src/assets/images/badges/kappa_alpha_psi.png
Binary files differ
diff --git a/src/assets/images/badges/kappa_delta.png b/src/assets/images/badges/kappa_delta.png
new file mode 100644
index 00000000..642ddb5b
--- /dev/null
+++ b/src/assets/images/badges/kappa_delta.png
Binary files differ
diff --git a/src/assets/images/badges/lax.png b/src/assets/images/badges/lax.png
new file mode 100644
index 00000000..3810589b
--- /dev/null
+++ b/src/assets/images/badges/lax.png
Binary files differ
diff --git a/src/assets/images/badges/sigma.png b/src/assets/images/badges/sigma.png
new file mode 100644
index 00000000..7e6c9d22
--- /dev/null
+++ b/src/assets/images/badges/sigma.png
Binary files differ
diff --git a/src/assets/images/badges/theta_alpha.png b/src/assets/images/badges/theta_alpha.png
new file mode 100644
index 00000000..607720f5
--- /dev/null
+++ b/src/assets/images/badges/theta_alpha.png
Binary files differ
diff --git a/src/assets/images/badges/track.png b/src/assets/images/badges/track.png
new file mode 100644
index 00000000..a531f641
--- /dev/null
+++ b/src/assets/images/badges/track.png
Binary files differ
diff --git a/src/assets/images/badges/volleyball.png b/src/assets/images/badges/volleyball.png
new file mode 100644
index 00000000..a9bb9c88
--- /dev/null
+++ b/src/assets/images/badges/volleyball.png
Binary files differ
diff --git a/src/assets/images/bwbadges.png b/src/assets/images/bwbadges.png
new file mode 100644
index 00000000..3a337775
--- /dev/null
+++ b/src/assets/images/bwbadges.png
Binary files differ
diff --git a/src/assets/images/bwbadges@2x.png b/src/assets/images/bwbadges@2x.png
new file mode 100644
index 00000000..60c2f995
--- /dev/null
+++ b/src/assets/images/bwbadges@2x.png
Binary files differ
diff --git a/src/assets/images/bwbadges@3x.png b/src/assets/images/bwbadges@3x.png
new file mode 100644
index 00000000..874c0c4d
--- /dev/null
+++ b/src/assets/images/bwbadges@3x.png
Binary files differ
diff --git a/src/assets/images/search.png b/src/assets/images/search.png
new file mode 100644
index 00000000..ba9906ba
--- /dev/null
+++ b/src/assets/images/search.png
Binary files differ
diff --git a/src/assets/images/search@2x.png b/src/assets/images/search@2x.png
new file mode 100644
index 00000000..fa133ae1
--- /dev/null
+++ b/src/assets/images/search@2x.png
Binary files differ
diff --git a/src/assets/images/search@3x.png b/src/assets/images/search@3x.png
new file mode 100644
index 00000000..3ea4ce15
--- /dev/null
+++ b/src/assets/images/search@3x.png
Binary files differ
diff --git a/src/components/common/TaggPrompt.tsx b/src/components/common/TaggPrompt.tsx
index 5cd3ac3f..75f3009b 100644
--- a/src/components/common/TaggPrompt.tsx
+++ b/src/components/common/TaggPrompt.tsx
@@ -1,13 +1,15 @@
import * as React from 'react';
-import {Platform, Text, StyleSheet, TouchableOpacity} from 'react-native';
+import {StyleSheet, Text, TouchableOpacity} from 'react-native';
import {Image, View} from 'react-native-animatable';
-import {SCREEN_HEIGHT} from '../../utils';
import CloseIcon from '../../assets/ionicons/close-outline.svg';
+import {normalize, SCREEN_HEIGHT} from '../../utils';
type TaggPromptProps = {
messageHeader: string;
- messageBody: string;
- logoType: string;
+ messageBody: string | Element;
+ logoType: 'plus' | 'tagg';
+ hideCloseButton?: boolean;
+ noPadding?: boolean;
onClose: () => void;
};
@@ -15,27 +17,43 @@ const TaggPrompt: React.FC<TaggPromptProps> = ({
messageHeader,
messageBody,
logoType,
+ hideCloseButton,
+ noPadding,
onClose,
}) => {
/**
* Generic prompt for Tagg
*/
+ const logo = () => {
+ switch (logoType) {
+ case 'plus':
+ return require('../../assets/icons/plus-logo.png');
+ case 'tagg':
+ default:
+ return require('../../assets/images/logo-purple.png');
+ }
+ };
+
return (
- <View style={styles.container}>
- <Image
- style={styles.icon}
- source={require('../../assets/icons/plus-logo.png')}
- />
+ <View
+ style={[
+ styles.container,
+ {paddingTop: noPadding ? 0 : SCREEN_HEIGHT / 10},
+ {paddingBottom: noPadding ? 0 : SCREEN_HEIGHT / 50},
+ ]}>
+ <Image style={styles.icon} source={logo()} />
<Text style={styles.header}>{messageHeader}</Text>
<Text style={styles.subtext}>{messageBody}</Text>
- <TouchableOpacity
- style={styles.closeButton}
- onPress={() => {
- onClose();
- }}>
- <CloseIcon height={'50%'} width={'50%'} color="gray" />
- </TouchableOpacity>
+ {!hideCloseButton && (
+ <TouchableOpacity
+ style={styles.closeButton}
+ onPress={() => {
+ onClose();
+ }}>
+ <CloseIcon height={'50%'} width={'50%'} color="gray" />
+ </TouchableOpacity>
+ )}
</View>
);
};
@@ -47,8 +65,6 @@ const styles = StyleSheet.create({
alignItems: 'center',
backgroundColor: 'white',
height: SCREEN_HEIGHT / 4.5,
- paddingTop: SCREEN_HEIGHT / 10,
- paddingBottom: SCREEN_HEIGHT / 50,
},
closeButton: {
position: 'relative',
@@ -58,22 +74,24 @@ const styles = StyleSheet.create({
alignSelf: 'flex-end',
},
icon: {
- width: 40,
- height: 40,
+ width: normalize(40),
+ height: normalize(40),
},
header: {
color: 'black',
- fontSize: 16,
+ fontSize: normalize(16),
fontWeight: '600',
textAlign: 'center',
marginTop: '2%',
},
subtext: {
color: 'gray',
- fontSize: 12,
+ fontSize: normalize(12),
fontWeight: '500',
+ lineHeight: normalize(20),
textAlign: 'center',
marginTop: '2%',
+ width: '95%',
},
});
export default TaggPrompt;
diff --git a/src/components/index.ts b/src/components/index.ts
index 0a7c189b..d5649323 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -6,4 +6,3 @@ export * from './taggs';
export * from './comments';
export * from './moments';
export * from './suggestedPeople';
-
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/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';
diff --git a/src/components/taggs/SocialMediaInfo.tsx b/src/components/taggs/SocialMediaInfo.tsx
index 8f5f38c1..5497226c 100644
--- a/src/components/taggs/SocialMediaInfo.tsx
+++ b/src/components/taggs/SocialMediaInfo.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
-import { ScreenType } from '../../types';
+import {ScreenType} from '../../types';
import {SocialIcon} from '../common';
import {handleOpenSocialUrlOnBrowser} from '../../utils';
diff --git a/src/constants/api.ts b/src/constants/api.ts
index 9eaf60ee..ab1ace74 100644
--- a/src/constants/api.ts
+++ b/src/constants/api.ts
@@ -4,7 +4,7 @@ const BASE_URL: string = 'http://127.0.0.1:8000/'; // local server
const API_URL: string = BASE_URL + 'api/';
export const LOGIN_ENDPOINT: string = API_URL + 'login/';
-export const VERSION_ENDPOINT: string = API_URL + 'version/';
+export const VERSION_ENDPOINT: string = API_URL + 'version/v2/';
export const REGISTER_ENDPOINT: string = API_URL + 'register/';
export const EDIT_PROFILE_ENDPOINT: string = API_URL + 'edit-profile/';
export const SEND_OTP_ENDPOINT: string = API_URL + 'send-otp/';
@@ -17,7 +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_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/';
@@ -32,6 +32,7 @@ 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/';
export const COMMENT_THREAD_ENDPOINT: string = API_URL + 'reply/';
+export const ADD_USER_BADGES: string = API_URL + 'suggested_people/add_badges/';
// Suggested People
export const SP_USERS_ENDPOINT: string = API_URL + 'suggested_people/';
diff --git a/src/constants/constants.ts b/src/constants/constants.ts
index 14bff6a7..72eb1b57 100644
--- a/src/constants/constants.ts
+++ b/src/constants/constants.ts
@@ -79,6 +79,14 @@ export const NOTIFICATION_GRADIENT = [
'rgba(247, 248, 248, 1)',
'rgba(247, 248, 248, 0)',
];
+export const BADGE_GRADIENT_FIRST = [
+ 'rgba(86, 63, 51, 1)',
+ 'rgba(236, 32, 39, 1)',
+];
+export const BADGE_GRADIENT_REST = [
+ 'rgba(78, 54, 41, 1)',
+ 'rgba(236, 32, 39, 1)',
+];
export const SOCIAL_FONT_COLORS = {
INSTAGRAM: INSTAGRAM_FONT_COLOR,
diff --git a/src/constants/strings.ts b/src/constants/strings.ts
index 104cc198..93da6e59 100644
--- a/src/constants/strings.ts
+++ b/src/constants/strings.ts
@@ -14,7 +14,6 @@ export const ERROR_DELETED_OBJECT = 'Oh sad! Looks like the comment / moment was
export const ERROR_DOUBLE_CHECK_CONNECTION = 'Please double-check your network connection and retry';
export const ERROR_DUP_OLD_PWD = 'You may not use a previously used password';
export const ERROR_EMAIL_IN_USE = 'Email already in use, please try another one';
-export const ERROR_PHONE_IN_USE = 'Phone already in use, please try another one';
export const ERROR_FAILED_LOGIN_INFO = 'Login failed, please try re-entering your login information';
export const ERROR_FAILED_TO_COMMENT = 'Unable to post comment, refresh and try again!';
export const ERROR_FAILED_TO_DELETE_COMMENT = 'Unable to delete comment, refresh and try again!';
@@ -28,20 +27,24 @@ export const ERROR_LINK = (str: string) => `Unable to link with ${str}, Please c
export const ERROR_LOGIN = 'There was a problem logging you in, please refresh and try again';
export const ERROR_LOGIN_FAILED = 'Login failed. Check your username and password, and try again';
export const ERROR_NEXT_PAGE = 'There was a problem while loading the next page 😓, try again in a couple minutes';
+export const ERROR_NOT_ONBOARDED = 'You are now on waitlist, please enter your invitation code if you have one';
+export const ERROR_PHONE_IN_USE = 'Phone already in use, please try another one';
export const ERROR_PROFILE_CREATION_SHORT = 'Profile creation failed 😓';
export const ERROR_PWD_ACCOUNT = (str: string) => `Please make sure that the email / username entered is registered with us. You may contact our customer support at ${str}`;
export const ERROR_REGISTRATION = (str: string) => `Registration failed 😔, ${str}`;
-export const ERROR_SELECT_CLASS_YEAR = 'Please select your Class Year';
export const ERROR_SELECT_BIRTHDAY = 'Please select your birthday';
+export const ERROR_SELECT_CLASS_YEAR = 'Please select your Class Year';
export const ERROR_SELECT_GENDER = 'Please select your gender';
export const ERROR_SERVER_DOWN = 'mhm, looks like our servers are down, please refresh and try again in a few mins';
-export const ERROR_TWILIO_SERVER_ERROR = 'mhm, looks like that is an invalid phone number or our servers are down, please try again in a few mins';
export const ERROR_SOMETHING_WENT_WRONG = 'Oh dear, don’t worry someone will be held responsible for this error, In the meantime refresh the app';
export const ERROR_SOMETHING_WENT_WRONG_REFRESH = "Ha, looks like this one's on us, please refresh and try again";
export const ERROR_SOMETHING_WENT_WRONG_RELOAD = "You broke it, Just kidding! we don't know what happened... Please reload the app and try again";
+export const ERROR_TWILIO_SERVER_ERROR = 'mhm, looks like that is an invalid phone number or our servers are down, please try again in a few mins';
export const ERROR_UNABLE_TO_FIND_PROFILE = 'We were unable to find this profile. Please check username and try again';
export const ERROR_UNABLE_TO_VIEW_PROFILE = 'Unable to view this profile';
export const ERROR_UPLOAD = 'An error occurred while uploading. Please try again!';
+export const ERROR_UPLOAD_BADGES = 'Unable to upload your badges. Please retry';
+export const ERROR_BADGES_EXCEED_LIMIT = 'You can\'t have more than 5 badges!';
export const ERROR_UPLOAD_LARGE_PROFILE_PIC = "Can't have the first image seen on the profile be blank, please upload a large picture";
export const ERROR_UPLOAD_MOMENT = 'Unable to upload moment. Please retry';
export const ERROR_UPLOAD_SMALL_PROFILE_PIC = "Can't have a profile without a pic to represent you, please upload a small profile picture";
@@ -49,13 +52,13 @@ 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_INVITATION_CODE = 'Perfect! You entered a valid invitation code, you are now able to login and explore Tagg!';
export const SUCCESS_LINK = (str: string) => `Successfully linked ${str} 🎉`;
export const SUCCESS_PIC_UPLOAD = 'Beautiful, the picture was uploaded successfully!';
export const SUCCESS_PWD_RESET = 'Your password was reset successfully!';
export const SUCCESS_VERIFICATION_CODE_SENT = 'New verification code sent! Check your phone messages for your code';
-export const SUCCESS_INVITATION_CODE = 'Perfect! You entered a valid invitation code, you are now able to login and explore Tagg!';
-export const ERROR_NOT_ONBOARDED = 'You are now on waitlist, please enter your invitation code if you have one';
export const UP_TO_DATE = 'Up-to-Date!';
export const UPLOAD_MOMENT_PROMPT_ONE_MESSAGE = 'Post your first moment to\n continue building your digital\nidentity!';
export const UPLOAD_MOMENT_PROMPT_THREE_HEADER = 'Continue to build your profile';
diff --git a/src/routes/Routes.tsx b/src/routes/Routes.tsx
index 1cbc9bc5..c7b9aeee 100644
--- a/src/routes/Routes.tsx
+++ b/src/routes/Routes.tsx
@@ -3,7 +3,7 @@ import React, {useEffect, useState} from 'react';
import DeviceInfo from 'react-native-device-info';
import SplashScreen from 'react-native-splash-screen';
import {useDispatch, useSelector} from 'react-redux';
-import {fcmService, getLiveVersion} from '../services';
+import {fcmService, getCurrentLiveVersions} from '../services';
import {
updateNewNotificationReceived,
updateNewVersionAvailable,
@@ -54,8 +54,8 @@ const Routes: React.FC = () => {
useEffect(() => {
const checkVersion = async () => {
- const liveVersion = await getLiveVersion();
- if (liveVersion && liveVersion !== DeviceInfo.getVersion()) {
+ const liveVersions = await getCurrentLiveVersions();
+ if (liveVersions && !liveVersions.includes(DeviceInfo.getVersion())) {
setNewVersionAvailable(true);
dispatch(updateNewVersionAvailable(true));
}
diff --git a/src/routes/main/MainStackScreen.tsx b/src/routes/main/MainStackScreen.tsx
index 66cce109..50802d06 100644
--- a/src/routes/main/MainStackScreen.tsx
+++ b/src/routes/main/MainStackScreen.tsx
@@ -8,6 +8,7 @@ import MutualBadgeHolders from '../../screens/suggestedPeople/MutualBadgeHolders
import BackIcon from '../../assets/icons/back-arrow.svg';
import {
AnimatedTutorial,
+ BadgeSelection,
CaptionScreen,
CategorySelection,
CreateCustomCategory,
diff --git a/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackNavigator.tsx b/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackNavigator.tsx
index 85249034..737c503c 100644
--- a/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackNavigator.tsx
+++ b/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackNavigator.tsx
@@ -5,6 +5,7 @@ export type SuggestedPeopleOnboardingStackParams = {
UploadPicture: {
goTo: string;
};
+ BadgeSelection: undefined;
};
export const SuggestedPeopleOnboardingStack = createStackNavigator<SuggestedPeopleOnboardingStackParams>();
diff --git a/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen.tsx b/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen.tsx
index 61cc694c..d1a6e5e1 100644
--- a/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen.tsx
+++ b/src/routes/suggestedPeopleOnboarding/SuggestedPeopleOnboardingStackScreen.tsx
@@ -3,6 +3,7 @@ import {SuggestedPeopleOnboardingStack} from './SuggestedPeopleOnboardingStackNa
import {
SuggestedPeopleWelcomeScreen,
SuggestedPeopleUploadPictureScreen,
+ BadgeSelection,
} from '../../screens';
import {SCREEN_WIDTH} from '../../utils';
import {headerBarOptions} from '../main';
@@ -30,6 +31,13 @@ const SuggestedPeopleOnboardingStackScreen: React.FC = () => {
...headerBarOptions('white', ''),
}}
/>
+ <SuggestedPeopleOnboardingStack.Screen
+ name="BadgeSelection"
+ component={BadgeSelection}
+ options={{
+ ...headerBarOptions('white', ''),
+ }}
+ />
</SuggestedPeopleOnboardingStack.Navigator>
);
};
diff --git a/src/routes/tabs/NavigationBar.tsx b/src/routes/tabs/NavigationBar.tsx
index 49713d66..5d4f7cf2 100644
--- a/src/routes/tabs/NavigationBar.tsx
+++ b/src/routes/tabs/NavigationBar.tsx
@@ -19,9 +19,10 @@ const NavigationBar: React.FC = () => {
(state: RootState) => state,
);
- const [unreadNotificationsPresent, setUnreadNotificationsPresent] = useState<
- boolean
- >(false);
+ const [
+ unreadNotificationsPresent,
+ setUnreadNotificationsPresent,
+ ] = useState<boolean>(false);
useEffect(() => {
const determine = async () => {
diff --git a/src/screens/badge/BadgeItem.tsx b/src/screens/badge/BadgeItem.tsx
new file mode 100644
index 00000000..d7c0b74a
--- /dev/null
+++ b/src/screens/badge/BadgeItem.tsx
@@ -0,0 +1,84 @@
+import React from 'react';
+import {View, Text, StyleSheet, Image, ImageSourcePropType} from 'react-native';
+import {SCREEN_WIDTH, normalize} from '../../utils';
+import LinearGradient from 'react-native-linear-gradient';
+import {BADGE_GRADIENT_FIRST, BADGE_GRADIENT_REST} from '../../constants';
+import {TouchableOpacity} from 'react-native-gesture-handler';
+
+interface BadgeItemProps {
+ title: string;
+ resourcePath: ImageSourcePropType;
+ index: Number;
+ selected: boolean;
+ onSelection: (ikey: string) => void;
+}
+
+const BadgeItem: React.FC<BadgeItemProps> = ({
+ title,
+ resourcePath,
+ selected,
+ index,
+ onSelection,
+}) => {
+ return (
+ <TouchableOpacity onPress={() => onSelection(title)}>
+ <LinearGradient
+ colors={index === 0 ? BADGE_GRADIENT_FIRST : BADGE_GRADIENT_REST}
+ useAngle={true}
+ angle={136.69}
+ style={styles.item}>
+ <View
+ style={
+ selected ? styles.selectedDetailContainer : styles.detailContainer
+ }>
+ <Image source={resourcePath} style={styles.imageStyles} />
+ <View style={styles.textContainer}>
+ <Text style={styles.title}>{title}</Text>
+ </View>
+ </View>
+ </LinearGradient>
+ </TouchableOpacity>
+ );
+};
+
+const styles = StyleSheet.create({
+ item: {
+ width: SCREEN_WIDTH / 3 - 20,
+ height: SCREEN_WIDTH / 3 - 20,
+ marginLeft: 15,
+ marginBottom: 12,
+ borderRadius: 8,
+ },
+ detailContainer: {
+ flexGrow: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ borderWidth: 3,
+ borderRadius: 8,
+ borderColor: 'transparent',
+ },
+ selectedDetailContainer: {
+ flexGrow: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ borderWidth: 3,
+ borderColor: 'white',
+ borderRadius: 8,
+ },
+ imageStyles: {
+ width: '31%',
+ height: '31%',
+ marginTop: '11%',
+ },
+ textContainer: {marginTop: '16%'},
+ title: {
+ fontSize: normalize(15),
+ fontWeight: '500',
+ lineHeight: normalize(17.9),
+ textAlign: 'center',
+ color: 'white',
+ marginHorizontal: '2%',
+ },
+});
+
+export default BadgeItem;
diff --git a/src/screens/badge/BadgeList.tsx b/src/screens/badge/BadgeList.tsx
new file mode 100644
index 00000000..f3e96d60
--- /dev/null
+++ b/src/screens/badge/BadgeList.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import {SectionList, StyleSheet} from 'react-native';
+import {SCREEN_HEIGHT} from '../../utils';
+import BadgeItem from './BadgeItem';
+import BadgeHeader from './BadgeListHeader';
+
+interface BadgeListProps {
+ data: any[];
+ selectedBadges: any[];
+ selectKey: (ikey: string) => void;
+}
+
+const BadgeList: React.FC<BadgeListProps> = ({
+ data,
+ selectedBadges,
+ selectKey,
+}) => {
+ return (
+ <SectionList
+ stickySectionHeadersEnabled={false}
+ style={{height: SCREEN_HEIGHT * 0.8}}
+ contentContainerStyle={styles.listContainer}
+ sections={data}
+ keyExtractor={(item, index) => item + index}
+ extraData={selectedBadges}
+ renderItem={({item: {badgeName, badgeImage}, index}) => {
+ return (
+ <BadgeItem
+ selected={selectedBadges.includes(badgeName)}
+ onSelection={selectKey}
+ title={badgeName}
+ resourcePath={badgeImage}
+ index={index}
+ />
+ );
+ }}
+ renderSectionHeader={({section: {title}}) => (
+ <BadgeHeader title={title} />
+ )}
+ />
+ );
+};
+
+const styles = StyleSheet.create({
+ listContainer: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ alignItems: 'center',
+ flexGrow: 1,
+ paddingBottom: SCREEN_HEIGHT * 0.1,
+ },
+ scrollViewStyles: {
+ paddingBottom: SCREEN_HEIGHT * 0.5,
+ },
+});
+
+export default BadgeList;
diff --git a/src/screens/badge/BadgeListHeader.tsx b/src/screens/badge/BadgeListHeader.tsx
new file mode 100644
index 00000000..27335dfb
--- /dev/null
+++ b/src/screens/badge/BadgeListHeader.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import {View, Text, StyleSheet} from 'react-native';
+import {SCREEN_WIDTH, normalize} from '../../utils';
+
+interface BadgeHeaderProps {
+ title: String;
+}
+
+const BadgeListHeader: React.FC<BadgeHeaderProps> = ({title}) => {
+ return (
+ <View style={styles.headerContainer}>
+ <Text style={styles.header}>{title}</Text>
+ </View>
+ );
+};
+
+const styles = StyleSheet.create({
+ headerContainer: {
+ width: SCREEN_WIDTH * 0.75,
+ marginHorizontal: SCREEN_WIDTH * 0.125,
+ marginBottom: '2%',
+ marginTop: '4%',
+ },
+ header: {
+ fontSize: normalize(20),
+ fontWeight: '700',
+ lineHeight: normalize(23.87),
+ color: '#fff',
+ textAlign: 'center',
+ },
+});
+
+export default BadgeListHeader;
diff --git a/src/screens/badge/BadgeScreenHeader.tsx b/src/screens/badge/BadgeScreenHeader.tsx
new file mode 100644
index 00000000..fd250585
--- /dev/null
+++ b/src/screens/badge/BadgeScreenHeader.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import {Image, StyleSheet, Text, View} from 'react-native';
+import {normalize} from '../../utils';
+
+const BadgeScreenHeader: React.FC = () => {
+ return (
+ <View style={styles.container}>
+ <Image source={require('../../assets/images/badges/brown_badge.png')} />
+ <View style={styles.universityTextContainer}>
+ <Text style={styles.universityText}>Brown University Badges</Text>
+ </View>
+ <View style={styles.searchTextContainer}>
+ <Text style={styles.searchText}>
+ Search for organizations you are a part of!
+ </Text>
+ </View>
+ </View>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ marginBottom: '1%',
+ },
+ universityTextContainer: {marginTop: 12},
+ universityText: {
+ fontSize: normalize(20),
+ fontWeight: '700',
+ lineHeight: normalize(23.87),
+ color: 'white',
+ },
+ searchTextContainer: {marginTop: 6},
+ searchText: {
+ fontSize: normalize(15),
+ fontWeight: '500',
+ lineHeight: normalize(17.9),
+ color: 'white',
+ },
+});
+
+export default BadgeScreenHeader;
diff --git a/src/screens/badge/BadgeSelection.tsx b/src/screens/badge/BadgeSelection.tsx
new file mode 100644
index 00000000..4754960b
--- /dev/null
+++ b/src/screens/badge/BadgeSelection.tsx
@@ -0,0 +1,266 @@
+import AsyncStorage from '@react-native-community/async-storage';
+import {StackNavigationProp} from '@react-navigation/stack';
+import React, {useEffect, useState} from 'react';
+import {Alert, SafeAreaView, StatusBar, StyleSheet, View} from 'react-native';
+import {Text} from 'react-native-animatable';
+import {TouchableOpacity} from 'react-native-gesture-handler';
+import LinearGradient from 'react-native-linear-gradient';
+import {useDispatch} from 'react-redux';
+import {ADD_USER_BADGES, BACKGROUND_GRADIENT_MAP} from '../../constants';
+import {
+ ERROR_BADGES_EXCEED_LIMIT,
+ ERROR_UPLOAD_BADGES,
+} from '../../constants/strings';
+import {suggestedPeopleBadgesFinished} from '../../store/actions';
+import {BackgroundGradientType} from '../../types';
+import {SCREEN_HEIGHT, StatusBarHeight} from '../../utils';
+import BadgeList from './BadgeList';
+import BadgeScreenHeader from './BadgeScreenHeader';
+
+/**
+ * Home Screen for displaying Tagg Badge Selections
+ **/
+
+const BadgeImages = {
+ football: require('../../assets/images/badges/football.png'),
+ track: require('../../assets/images/badges/track.png'),
+ volleyball: require('../../assets/images/badges/volleyball.png'),
+ lax: require('../../assets/images/badges/brown_badge.png'),
+ fieldHockey: require('../../assets/images/badges/field_hockey.png'),
+ gymnastics: require('../../assets/images/badges/gymnastics.png'),
+ hockey: require('../../assets/images/badges/hockey.png'),
+ baseball: require('../../assets/images/badges/baseball.png'),
+ basketball: require('../../assets/images/badges/basketball.png'),
+ kappadelta: require('../../assets/images/badges/kappa_delta.png'),
+ alphachiomega: require('../../assets/images/badges/alpha_chi_omega.png'),
+ deltagamma: require('../../assets/images/badges/delta_gamma.png'),
+ sigma: require('../../assets/images/badges/sigma.png'),
+ thetaalpha: require('../../assets/images/badges/theta_alpha.png'),
+ deltaphi: require('../../assets/images/badges/delta_phi.png'),
+ kappaalphapsi: require('../../assets/images/badges/kappa_alpha_psi.png'),
+ alphaphialpha: require('../../assets/images/badges/alpha_phi_alpha.png'),
+ betaomegachi: require('../../assets/images/badges/beta_omega_chi.png'),
+};
+
+const DATA = [
+ {
+ title: 'Athletics',
+ data: [
+ {
+ badgeName: 'Brown Football',
+ badgeImage: BadgeImages.football,
+ },
+ {
+ badgeName: 'Brown Track',
+ badgeImage: BadgeImages.track,
+ },
+ {
+ badgeName: 'Brown Volleyball',
+ badgeImage: BadgeImages.volleyball,
+ },
+ {
+ badgeName: 'Brown LAX',
+ badgeImage: BadgeImages.lax,
+ },
+ {
+ badgeName: 'Brown Field Hockey',
+ badgeImage: BadgeImages.fieldHockey,
+ },
+ {
+ badgeName: 'Brown Gymnastics',
+ badgeImage: BadgeImages.gymnastics,
+ },
+ {
+ badgeName: 'Brown Hockey',
+ badgeImage: BadgeImages.hockey,
+ },
+ {
+ badgeName: 'Brown Baseball',
+ badgeImage: BadgeImages.baseball,
+ },
+ {
+ badgeName: 'Brown Basketball',
+ badgeImage: BadgeImages.basketball,
+ },
+ ],
+ },
+
+ {
+ title: 'Sorority',
+ data: [
+ {
+ badgeName: 'Kappa Delta',
+ badgeImage: BadgeImages.kappadelta,
+ },
+ {
+ badgeName: 'Alpha Chi Omega',
+ badgeImage: BadgeImages.alphachiomega,
+ },
+ {
+ badgeName: 'Delta Gamma',
+ badgeImage: BadgeImages.deltagamma,
+ },
+ ],
+ },
+
+ {
+ title: 'Fraternity',
+ data: [
+ {
+ badgeName: 'Sigma',
+ badgeImage: BadgeImages.sigma,
+ },
+ {
+ badgeName: 'Theta Alpha',
+ badgeImage: BadgeImages.thetaalpha,
+ },
+ {
+ badgeName: 'Delta Phi',
+ badgeImage: BadgeImages.deltaphi,
+ },
+ ],
+ },
+ {
+ title: 'Historically Black Fraternities',
+ data: [
+ {
+ badgeName: 'Kappa Alpha Psi',
+ badgeImage: BadgeImages.kappadelta,
+ },
+ {
+ badgeName: 'Alpha Phi Alpha',
+ badgeImage: BadgeImages.alphaphialpha,
+ },
+ {
+ badgeName: 'Beta Omega Chi',
+ badgeImage: BadgeImages.betaomegachi,
+ },
+ ],
+ },
+];
+
+type BadgeSelectionParamList = {
+ BadgeList: any[];
+};
+
+type BadgeSelectionScreenNavigationProp = StackNavigationProp<
+ BadgeSelectionParamList,
+ 'BadgeList'
+>;
+
+type BadgeSelectionProps = {
+ navigation: BadgeSelectionScreenNavigationProp;
+};
+
+const BadgeSelection: React.FC<BadgeSelectionProps> = ({navigation}) => {
+ const [canSubmit, setCanSubmit] = useState(false);
+ navigation.setOptions({
+ headerRight: () => (
+ <TouchableOpacity
+ style={styles.rightButtonContainer}
+ onPress={() => {
+ if (canSubmit) {
+ uploadUserSelection();
+ }
+ }}>
+ <Text style={styles.rightButton}>{canSubmit ? 'Done' : 'Skip'}</Text>
+ </TouchableOpacity>
+ ),
+ });
+
+ const [selectedBadges, setSelectedBadges] = useState<string[]>([]);
+ const selectKey = (key: string) => {
+ if (selectedBadges.includes(key)) {
+ const selectedBadgesArray = [...selectedBadges];
+ const itemIndex = selectedBadgesArray.indexOf(key);
+ if (itemIndex > -1) {
+ selectedBadgesArray.splice(itemIndex, 1);
+ }
+ setSelectedBadges(selectedBadgesArray);
+ } else {
+ const selectedBadgesArray = [...selectedBadges, key];
+ setSelectedBadges(selectedBadgesArray);
+ }
+ };
+ const dispatch = useDispatch();
+ useEffect(() => {
+ setCanSubmit(selectedBadges.length !== 0);
+ }, [selectedBadges]);
+
+ const uploadUserSelection = async () => {
+ try {
+ const token = await AsyncStorage.getItem('token');
+ const form = new FormData();
+ form.append('badges', JSON.stringify(selectedBadges));
+ const response = await fetch(ADD_USER_BADGES, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ Authorization: 'Token ' + token,
+ },
+ body: form,
+ });
+ if (response.status === 400) {
+ Alert.alert(ERROR_BADGES_EXCEED_LIMIT);
+ return;
+ }
+ dispatch(suggestedPeopleBadgesFinished());
+ } catch (error) {
+ console.log(error);
+ Alert.alert(ERROR_UPLOAD_BADGES);
+ }
+ };
+
+ return (
+ <LinearGradient
+ colors={BACKGROUND_GRADIENT_MAP[BackgroundGradientType.Dark]}
+ style={styles.container}>
+ <StatusBar barStyle={'light-content'} />
+ <SafeAreaView>
+ <View style={styles.listContainer}>
+ <BadgeScreenHeader />
+ {/* filter not working, comment out for now */}
+ {/* <SearchBar
+ style={styles.searchBarStyle}
+ onCancel={() => {}}
+ top={Animated.useValue(0)}
+ /> */}
+ <BadgeList
+ data={DATA}
+ selectedBadges={selectedBadges}
+ selectKey={selectKey}
+ />
+ </View>
+ </SafeAreaView>
+ </LinearGradient>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ searchBarStyle: {
+ width: '95%',
+ alignSelf: 'center',
+ marginTop: SCREEN_HEIGHT * 0.05,
+ },
+ viewContainer: {marginTop: StatusBarHeight},
+ listContainer: {marginTop: SCREEN_HEIGHT * 0.05},
+ rightButtonContainer: {marginRight: 24},
+ rightButton: {
+ color: '#FFFFFF',
+ fontWeight: 'bold',
+ fontSize: 15,
+ lineHeight: 18,
+ },
+ leftButtonContainer: {marginLeft: 24},
+ leftButton: {
+ color: '#FFFFFF',
+ fontWeight: '500',
+ fontSize: 15,
+ lineHeight: 18,
+ },
+});
+
+export default BadgeSelection;
diff --git a/src/screens/badge/index.ts b/src/screens/badge/index.ts
new file mode 100644
index 00000000..217aa7e8
--- /dev/null
+++ b/src/screens/badge/index.ts
@@ -0,0 +1,5 @@
+export {default as BadgeSelection} from './BadgeSelection';
+export {default as BadgeItem} from './BadgeItem';
+export {default as BadgeListHeader} from './BadgeListHeader';
+export {default as BadgeList} from './BadgeList';
+export {default as BadgeScreenHeader} from './BadgeScreenHeader';
diff --git a/src/screens/index.ts b/src/screens/index.ts
index faf3d0b7..50ada3d1 100644
--- a/src/screens/index.ts
+++ b/src/screens/index.ts
@@ -4,3 +4,4 @@ export * from './profile';
export * from './search';
export * from './suggestedPeople';
export * from './suggestedPeopleOnboarding';
+export * from './badge';
diff --git a/src/screens/main/NotificationsScreen.tsx b/src/screens/main/NotificationsScreen.tsx
index aa53c4a9..74bcf906 100644
--- a/src/screens/main/NotificationsScreen.tsx
+++ b/src/screens/main/NotificationsScreen.tsx
@@ -1,8 +1,15 @@
import AsyncStorage from '@react-native-community/async-storage';
import {useFocusEffect} from '@react-navigation/native';
import moment from 'moment';
-import React, {useCallback, useEffect, useState} from 'react';
+import React, {
+ Fragment,
+ ReactElement,
+ useCallback,
+ useEffect,
+ useState,
+} from 'react';
import {
+ Image,
RefreshControl,
SectionList,
StatusBar,
@@ -12,26 +19,22 @@ import {
} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import {useDispatch, useSelector} from 'react-redux';
+import {TabsGradient, TaggPrompt} from '../../components';
import {Notification} from '../../components/notifications';
-import EmptyNotificationView from './notification/EmptyNotificationView';
import {
loadUserNotifications,
updateNewNotificationReceived,
} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {NotificationType, ScreenType} from '../../types';
-import {getDateAge, SCREEN_HEIGHT} from '../../utils';
-import {normalize} from '../../utils';
+import {getDateAge, normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
+import EmptyNotificationView from './notification/EmptyNotificationView';
const NotificationsScreen: React.FC = () => {
- const {moments: loggedInUserMoments} = useSelector(
- (state: RootState) => state.moments,
- );
const {newNotificationReceived} = useSelector(
(state: RootState) => state.user,
);
const [refreshing, setRefreshing] = useState(false);
- const [noNotification, setNoNotification] = useState(false);
// used for figuring out which ones are unread
const [lastViewed, setLastViewed] = useState<moment.Moment | undefined>(
undefined,
@@ -39,13 +42,14 @@ const NotificationsScreen: React.FC = () => {
const {notifications} = useSelector(
(state: RootState) => state.notifications,
);
-
+ const {suggested_people_linked} = useSelector(
+ (state: RootState) => state.user.profile,
+ );
+ const [showSPNotifyPopUp, setShowSPNotifyPopUp] = useState(false);
const {user: loggedInUser} = useSelector((state: RootState) => state.user);
-
const [sectionedNotifications, setSectionedNotifications] = useState<
{title: 'Today' | 'Yesterday' | 'This Week'; data: NotificationType[]}[]
>([]);
-
const dispatch = useDispatch();
const refreshNotifications = () => {
@@ -62,6 +66,10 @@ const NotificationsScreen: React.FC = () => {
refreshNotifications();
}, [refreshNotifications]);
+ useEffect(() => {
+ setShowSPNotifyPopUp(suggested_people_linked !== 2);
+ }, [suggested_people_linked]);
+
useFocusEffect(
useCallback(() => {
const resetNewNotificationFlag = () => {
@@ -126,15 +134,20 @@ const NotificationsScreen: React.FC = () => {
continue;
}
}
- setSectionedNotifications([
- {title: 'Today', data: todays},
- {title: 'Yesterday', data: yesterdays},
- {title: 'This Week', data: thisWeeks},
- ]);
- setNoNotification(
- todays.length === 0 && yesterdays.length === 0 && thisWeeks.length === 0,
+ setSectionedNotifications(
+ todays.length === 0 && yesterdays.length === 0 && thisWeeks.length === 0
+ ? []
+ : [
+ {title: 'Today', data: todays},
+ {title: 'Yesterday', data: yesterdays},
+ {title: 'This Week', data: thisWeeks},
+ ],
);
- }, [lastViewed, notifications]);
+ }, [lastViewed, notifications, showSPNotifyPopUp]);
+
+ useEffect(() => {
+ console.log(sectionedNotifications);
+ }, [sectionedNotifications]);
const renderNotification = ({item}: {item: NotificationType}) => (
<Notification
@@ -151,35 +164,65 @@ const NotificationsScreen: React.FC = () => {
</View>
);
+ const SPPromptNotification: ReactElement = showSPNotifyPopUp ? (
+ <TaggPrompt
+ messageHeader={'New Suggested People Page!'}
+ messageBody={
+ <>
+ <Text>
+ A new page where you can discover new profiles. Just press the new{' '}
+ </Text>
+ <Image
+ style={styles.icon}
+ source={require('../../assets/navigationIcons/home.png')}
+ />
+ <Text> button on the tab bar to check it out!</Text>
+ </>
+ }
+ logoType={'tagg'}
+ hideCloseButton={true}
+ noPadding={true}
+ onClose={() => {}}
+ />
+ ) : (
+ <Fragment />
+ );
+
return (
- <SafeAreaView>
- <StatusBar barStyle="dark-content" />
- <View style={styles.header}>
- <Text style={styles.headerText}>Notifications</Text>
- </View>
- {noNotification && (
- <View style={styles.emptyViewContainer}>
- <EmptyNotificationView />
+ <View style={styles.background}>
+ <SafeAreaView>
+ <StatusBar barStyle="dark-content" />
+ <View style={styles.header}>
+ <Text style={styles.headerText}>Notifications</Text>
</View>
- )}
-
- {!noNotification && (
<SectionList
contentContainerStyle={styles.container}
sections={sectionedNotifications}
keyExtractor={(item, index) => index.toString()}
renderItem={renderNotification}
renderSectionHeader={renderSectionHeader}
+ ListHeaderComponent={SPPromptNotification}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
+ ListEmptyComponent={
+ <View style={styles.emptyViewContainer}>
+ <EmptyNotificationView />
+ </View>
+ }
/>
- )}
- </SafeAreaView>
+ </SafeAreaView>
+ <TabsGradient />
+ </View>
);
};
const styles = StyleSheet.create({
+ background: {
+ width: SCREEN_WIDTH,
+ height: SCREEN_HEIGHT,
+ backgroundColor: 'white',
+ },
header: {
marginLeft: '8%',
marginTop: '5%',
@@ -197,7 +240,6 @@ const styles = StyleSheet.create({
},
sectionHeaderContainer: {
width: '100%',
- backgroundColor: '#f3f2f2',
},
sectionHeader: {
marginLeft: '8%',
@@ -209,7 +251,13 @@ const styles = StyleSheet.create({
color: '#828282',
},
emptyViewContainer: {
- marginTop: '22%',
+ flex: 1,
+ justifyContent: 'center',
+ },
+ icon: {
+ width: 20,
+ height: 20,
+ tintColor: 'grey',
},
});
diff --git a/src/screens/profile/SocialMediaTaggs.tsx b/src/screens/profile/SocialMediaTaggs.tsx
index 45d417a6..466ba509 100644
--- a/src/screens/profile/SocialMediaTaggs.tsx
+++ b/src/screens/profile/SocialMediaTaggs.tsx
@@ -12,7 +12,12 @@ import {
} from '../../components';
import {AVATAR_GRADIENT} from '../../constants';
import {ProfileStackParams} from '../../routes';
-import {SimplePostType, TwitterPostType, SocialAccountType, ScreenType} from '../../types';
+import {
+ SimplePostType,
+ TwitterPostType,
+ SocialAccountType,
+ ScreenType,
+} from '../../types';
import {AvatarHeaderHeight, SCREEN_HEIGHT} from '../../utils';
import {useSelector} from 'react-redux';
import {RootState} from '../../store/rootReducer';
diff --git a/src/screens/search/SearchScreen.tsx b/src/screens/search/SearchScreen.tsx
index 84efa931..70733d7e 100644
--- a/src/screens/search/SearchScreen.tsx
+++ b/src/screens/search/SearchScreen.tsx
@@ -16,19 +16,16 @@ import {
SearchBackground,
SearchBar,
SearchHeader,
- SearchResults,
+ SearchResultList,
SearchResultsBackground,
TabsGradient,
} from '../../components';
import {SEARCH_ENDPOINT, TAGG_LIGHT_BLUE} from '../../constants';
+import {loadSearchResults} from '../../services';
import {loadRecentlySearched, resetScreenType} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
-import {ProfilePreviewType, ScreenType, UserType} from '../../types';
+import {ProfilePreviewType, ScreenType} from '../../types';
import {SCREEN_HEIGHT, SCREEN_WIDTH, StatusBarHeight} from '../../utils';
-const NO_USER: UserType = {
- userId: '',
- username: '',
-};
/**
* Search Screen for user recommendations and a search
@@ -38,14 +35,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<ProfilePreviewType>>([]);
+ 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,31 +70,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_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,
+ },
+ {
+ title: 'users',
+ data: users,
},
- });
- const status = response.status;
- if (status === 200) {
- let searchResults = await response.json();
- setResults(searchResults);
- return;
- }
- setResults([]);
- } catch (error) {
- console.log(error);
- setResults([]);
+ ];
+ setResults(sanitizedResult);
+ } else {
+ setResults(undefined);
}
- };
- loadResults(query);
+ })();
}, [query]);
/**
@@ -160,8 +170,9 @@ const SearchScreen: React.FC = () => {
{...{top, searching}}
/>
<Explore />
+
<SearchResultsBackground {...{top}}>
- {results.length === 0 && recents.length !== 0 ? (
+ {results === undefined && recents.length !== 0 ? (
<RecentSearches
sectionTitle="Recent"
sectionButtonTitle="Clear all"
@@ -170,8 +181,9 @@ const SearchScreen: React.FC = () => {
screenType={ScreenType.Search}
/>
) : (
- <SearchResults
+ <SearchResultList
{...{results}}
+ keyboardVisible={keyboardVisible === 'keyboardVisibleTrue'}
previewType={'Search'}
screenType={ScreenType.Search}
/>
diff --git a/src/screens/search/mock.ts b/src/screens/search/mock.ts
new file mode 100644
index 00000000..d9909b22
--- /dev/null
+++ b/src/screens/search/mock.ts
@@ -0,0 +1,118 @@
+const MockResults = () => {
+ return {
+ categories: [
+ {
+ id: 11,
+ name: "Brown '21",
+ category: 'Brown',
+ },
+ {
+ id: 12,
+ name: "Brown '22",
+ category: 'Brown',
+ },
+ {
+ id: 13,
+ name: "Brown '23",
+ category: null,
+ },
+ {
+ id: 14,
+ name: "Brown '24",
+ category: null,
+ },
+ ],
+ users: [
+ {
+ id: 'd5295557-59ce-49fc-aa8a-442874dbffc3',
+ username: 'foobar',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-d5295557-59ce-49fc-aa8a-442874dbffc3-thumbnail.jpg',
+ },
+ {
+ id: '31e93eb5-ccc9-4743-b053-eff368e23fa8',
+ username: 'foobar2',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-31e93eb5-ccc9-4743-b053-eff368e23fa8-thumbnail.jpg',
+ },
+ {
+ id: 'b1b68df9-97ac-48de-b00d-eab10a6a644a',
+ username: 'foobar3',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-b1b68df9-97ac-48de-b00d-eab10a6a644a-thumbnail.jpg',
+ },
+ {
+ id: 'b89c88b3-6b2f-4b6c-85d9-a03ff5396113',
+ username: 'foobar4',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-b89c88b3-6b2f-4b6c-85d9-a03ff5396113-thumbnail.jpg',
+ },
+ {
+ id: '73b4496a-0aa8-4115-98da-2070bf326134',
+ username: 'foobar5',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-73b4496a-0aa8-4115-98da-2070bf326134-thumbnail.jpg',
+ },
+ {
+ id: '329763b8-931e-4d4d-8a07-003374d38497',
+ username: 'foobar6',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-329763b8-931e-4d4d-8a07-003374d38497-thumbnail.jpg',
+ },
+ {
+ id: '9e82fea2-cddc-41e1-be05-6873f58138ca',
+ username: 'foobar7',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-9e82fea2-cddc-41e1-be05-6873f58138ca-thumbnail.jpg',
+ },
+ {
+ id: '6e5b8892-4384-45a1-bc0a-8f2c9d614fbc',
+ username: 'foobar8',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-6e5b8892-4384-45a1-bc0a-8f2c9d614fbc-thumbnail.jpg',
+ },
+ {
+ id: 'c49b01c6-9151-4654-8fae-834adfa15727',
+ username: 'foobar9',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-c49b01c6-9151-4654-8fae-834adfa15727-thumbnail.jpg',
+ },
+ {
+ id: '5b394d5b-62e3-405e-8ecd-7433517ef688',
+ username: 'foobar10',
+ first_name: 'Foo',
+ last_name: 'Bar',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-5b394d5b-62e3-405e-8ecd-7433517ef688-thumbnail.jpg',
+ },
+ {
+ id: '698e38f0-24ed-404c-9f0c-6a24e43af576',
+ username: 'fooo',
+ first_name: 'wefwef',
+ last_name: 'wefwef',
+ thumbnail_url:
+ 'https://tagg-dev.s3.us-east-2.amazonaws.com/thumbnails/smallProfilePicture/spp-698e38f0-24ed-404c-9f0c-6a24e43af576-thumbnail.jpg',
+ },
+ ],
+ };
+};
+
+export default MockResults;
diff --git a/src/screens/suggestedPeopleOnboarding/SuggestedPeopleUploadPictureScreen.tsx b/src/screens/suggestedPeopleOnboarding/SuggestedPeopleUploadPictureScreen.tsx
index c587e930..bb8aaccf 100644
--- a/src/screens/suggestedPeopleOnboarding/SuggestedPeopleUploadPictureScreen.tsx
+++ b/src/screens/suggestedPeopleOnboarding/SuggestedPeopleUploadPictureScreen.tsx
@@ -76,6 +76,7 @@ const SuggestedPeopleUploadPictureScreen: React.FC = ({route}) => {
const success = await sendSuggestedPeoplePhoto(image);
if (success) {
dispatch(uploadedSuggestedPeoplePhoto(image));
+ navigation.push('BadgeSelection');
} else {
Alert.alert(ERROR_UPLOAD);
}
diff --git a/src/services/CommonService.ts b/src/services/CommonService.ts
index 9fa7417f..5bc1174d 100644
--- a/src/services/CommonService.ts
+++ b/src/services/CommonService.ts
@@ -22,7 +22,7 @@ export const loadImageFromURL = async (url: string) => {
}
};
-export const getLiveVersion = async () => {
+export const getCurrentLiveVersions = async () => {
try {
const response = await fetch(VERSION_ENDPOINT, {method: 'GET'});
return response.status === 200 ? await response.json() : undefined;
diff --git a/src/services/FCMService.ts b/src/services/FCMService.ts
index b6cd18af..84f30f09 100644
--- a/src/services/FCMService.ts
+++ b/src/services/FCMService.ts
@@ -134,7 +134,7 @@ class FCMService {
// TODO: Get {name, params} of screen when user must be redirected to
// Redirected to Notification Screen for now
const redirectTo = 'Notifications';
- /* TODO: Check login status and redirect user/store screen to async as
+ /* TODO: Check login status and redirect user/store screen to async as
initialRoute for NavigationBar Stack */
RootNavigation.navigate(redirectTo);
}
diff --git a/src/services/ReportingService.ts b/src/services/ReportingService.ts
index 8c0a4bfb..76883e81 100644
--- a/src/services/ReportingService.ts
+++ b/src/services/ReportingService.ts
@@ -3,10 +3,7 @@
import {REPORT_ISSUE_ENDPOINT} from '../constants';
import {Alert} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
-import {
- ERROR_SOMETHING_WENT_WRONG,
- MARKED_AS_MSG,
-} from '../constants/strings';
+import {ERROR_SOMETHING_WENT_WRONG, MARKED_AS_MSG} from '../constants/strings';
export const sendReport = async (
moment_id: string,
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/store/actions/user.ts b/src/store/actions/user.ts
index a9f9d945..4f1da47c 100644
--- a/src/store/actions/user.ts
+++ b/src/store/actions/user.ts
@@ -174,6 +174,18 @@ export const uploadedSuggestedPeoplePhoto = (
type: setSuggestedPeopleImage.type,
payload: {suggestedPeopleImage: imageUri},
});
+ } catch (error) {
+ console.log(error);
+ }
+};
+
+export const suggestedPeopleBadgesFinished = (): ThunkAction<
+ Promise<void>,
+ RootState,
+ unknown,
+ Action<string>
+> => async (dispatch) => {
+ try {
dispatch({
type: setSuggestedPeopleLinked.type,
payload: {suggested_people_linked: 1},
diff --git a/src/store/reducers/userBlockReducer.ts b/src/store/reducers/userBlockReducer.ts
index 90e4a04a..64bdda30 100644
--- a/src/store/reducers/userBlockReducer.ts
+++ b/src/store/reducers/userBlockReducer.ts
@@ -11,8 +11,9 @@ const userBlockSlice = createSlice({
updateBlockedList: (state, action) => {
const {isBlocked, data} = action.payload;
- if (!isBlocked) state.blockedUsers.push(data);
- else {
+ if (!isBlocked) {
+ state.blockedUsers.push(data);
+ } else {
state.blockedUsers = state.blockedUsers.filter(
(user) => user.username != data.username,
);
diff --git a/src/utils/common.ts b/src/utils/common.ts
index 50f96493..30122e79 100644
--- a/src/utils/common.ts
+++ b/src/utils/common.ts
@@ -88,7 +88,9 @@ export const haveUnreadNotifications = async (
continue;
}
const unread = lastViewed ? lastViewed.diff(notificationDate) < 0 : false;
- if (unread) return true;
+ if (unread) {
+ return true;
+ }
}
return false;
};
diff --git a/src/utils/users.ts b/src/utils/users.ts
index ca917ae4..653c941e 100644
--- a/src/utils/users.ts
+++ b/src/utils/users.ts
@@ -159,3 +159,40 @@ export const checkIfUserIsBlocked = async (
}
return await isUserBlocked(userId, loggedInUser.userId, token);
};
+
+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);
+ }
+};