aboutsummaryrefslogtreecommitdiff
path: root/src/components/profile
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/profile')
-rw-r--r--src/components/profile/CaptionScreenHeader.tsx37
-rw-r--r--src/components/profile/Content.tsx5
-rw-r--r--src/components/profile/Moment.tsx126
-rw-r--r--src/components/profile/MomentTile.tsx33
-rw-r--r--src/components/profile/ProfilePreview.tsx216
-rw-r--r--src/components/profile/index.ts3
6 files changed, 219 insertions, 201 deletions
diff --git a/src/components/profile/CaptionScreenHeader.tsx b/src/components/profile/CaptionScreenHeader.tsx
deleted file mode 100644
index 4715b4ef..00000000
--- a/src/components/profile/CaptionScreenHeader.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import {Text, View, StyleSheet, ViewProps} from 'react-native';
-interface CaptionScreenHeaderProps extends ViewProps {
- title: string;
-}
-const CaptionScreenHeader: React.FC<CaptionScreenHeaderProps> = ({
- title,
- style,
-}) => {
- return (
- <View style={[styles.container, style]}>
- <View style={styles.headerContainer}>
- <Text style={styles.header}>{title}</Text>
- </View>
- </View>
- );
-};
-
-const styles = StyleSheet.create({
- container: {
- flexDirection: 'row',
- justifyContent: 'center',
- height: 30,
- },
- headerContainer: {
- position: 'absolute',
- left: '50%',
- },
- header: {
- position: 'relative',
- right: '50%',
- fontSize: 20,
- fontWeight: 'bold',
- color: 'white',
- },
-});
-export default CaptionScreenHeader;
diff --git a/src/components/profile/Content.tsx b/src/components/profile/Content.tsx
index 0bf66dc7..8f20cd8d 100644
--- a/src/components/profile/Content.tsx
+++ b/src/components/profile/Content.tsx
@@ -7,7 +7,7 @@ import {MomentType} from 'src/types';
import {defaultMoments, MOMENTS_ENDPOINT} from '../../constants';
import {SCREEN_HEIGHT} from '../../utils';
import TaggsBar from '../taggs/TaggsBar';
-import Moment from './Moment';
+import {Moment} from '../moments';
import ProfileBody from './ProfileBody';
import ProfileCutout from './ProfileCutout';
import ProfileHeader from './ProfileHeader';
@@ -45,7 +45,6 @@ const Content: React.FC<ContentProps> = ({y, isProfileView}) => {
});
setImagesMap(map);
- console.log(map);
}, [imagesList]);
useEffect(() => {
@@ -56,7 +55,7 @@ const Content: React.FC<ContentProps> = ({y, isProfileView}) => {
const retrieveMoments = async () => {
try {
const token = await AsyncStorage.getItem('token');
- const response = await fetch(MOMENTS_ENDPOINT + `${userId}/`, {
+ const response = await fetch(MOMENTS_ENDPOINT + '?user_id=' + userId, {
method: 'GET',
headers: {
Authorization: 'Token ' + token,
diff --git a/src/components/profile/Moment.tsx b/src/components/profile/Moment.tsx
deleted file mode 100644
index 1ec5511e..00000000
--- a/src/components/profile/Moment.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import {useNavigation} from '@react-navigation/native';
-import React from 'react';
-import {Alert, StyleSheet, View} from 'react-native';
-import {Text} from 'react-native-animatable';
-import {ScrollView, TouchableOpacity} from 'react-native-gesture-handler';
-import LinearGradient from 'react-native-linear-gradient';
-import PlusIcon from '../../assets/icons/plus_icon-01.svg';
-import BigPlusIcon from '../../assets/icons/plus_icon-02.svg';
-import {MOMENTS_TITLE_COLOR} from '../../constants';
-import {SCREEN_WIDTH} from '../../utils';
-import ImagePicker from 'react-native-image-crop-picker';
-import MomentTile from './MomentTile';
-import {MomentType} from 'src/types';
-
-interface MomentProps {
- title: string;
- images: MomentType[] | undefined;
- isProfileView: boolean;
-}
-
-const Moment: React.FC<MomentProps> = ({title, images, isProfileView}) => {
- const navigation = useNavigation();
-
- const navigateToImagePicker = () => {
- ImagePicker.openPicker({
- width: 580,
- height: 580,
- cropping: true,
- cropperToolbarTitle: 'Upload a moment',
- mediaType: 'photo',
- })
- .then((picture) => {
- if ('path' in picture) {
- navigation.navigate('CaptionScreen', {
- title: title,
- image: picture,
- });
- }
- })
- .catch((err) => {
- Alert.alert('Unable to upload moment!');
- });
- };
- return (
- <View style={styles.container}>
- <View style={styles.header}>
- <Text style={styles.titleText}>{title}</Text>
- {!isProfileView ? (
- <PlusIcon
- width={21}
- height={21}
- onPress={() => navigateToImagePicker()}
- />
- ) : (
- <React.Fragment />
- )}
- </View>
- <ScrollView
- horizontal
- showsHorizontalScrollIndicator={false}
- style={styles.scrollContainer}>
- {images &&
- images.map((imageObj: MomentType) => (
- <MomentTile key={imageObj.moment_id} moment={imageObj} />
- ))}
- {(images === undefined || images.length === 0) && !isProfileView && (
- <TouchableOpacity onPress={() => navigateToImagePicker()}>
- <LinearGradient
- colors={['rgba(105, 141, 211, 1)', 'rgba(105, 141, 211, 0.3)']}>
- <View style={styles.defaultImage}>
- <BigPlusIcon width={50} height={50} />
- <Text style={styles.defaultImageText}>
- Add a moment of your {title.toLowerCase()}!
- </Text>
- </View>
- </LinearGradient>
- </TouchableOpacity>
- )}
- </ScrollView>
- </View>
- );
-};
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- flexDirection: 'column',
- backgroundColor: '#eee',
- },
- header: {
- flex: 1,
- paddingHorizontal: 10,
- padding: 5,
- paddingTop: 20,
- backgroundColor: 'white',
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'center',
- },
- titleText: {
- fontSize: 16,
- fontWeight: 'bold',
- color: MOMENTS_TITLE_COLOR,
- },
- scrollContainer: {
- height: SCREEN_WIDTH / 2,
- backgroundColor: '#eee',
- },
- defaultImage: {
- aspectRatio: 1,
- height: '100%',
- alignItems: 'center',
- justifyContent: 'center',
- flexDirection: 'column',
- },
- defaultImageText: {
- fontSize: 20,
- paddingTop: 20,
- color: 'white',
- fontWeight: 'bold',
- width: '75%',
- textAlign: 'center',
- },
-});
-
-export default Moment;
diff --git a/src/components/profile/MomentTile.tsx b/src/components/profile/MomentTile.tsx
deleted file mode 100644
index 70b20d40..00000000
--- a/src/components/profile/MomentTile.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import {useNavigation} from '@react-navigation/native';
-import React from 'react';
-import {StyleSheet, View, Image, TouchableOpacity} from 'react-native';
-import {MomentType} from 'src/types';
-
-interface MomentTileProps {
- moment: MomentType;
-}
-const MomentTile: React.FC<MomentTileProps> = ({moment}) => {
- const navigation = useNavigation();
- const {path_hash} = moment;
- return (
- <TouchableOpacity
- onPress={() => {
- navigation.navigate('IndividualMoment', {moment});
- }}>
- <View style={styles.image}>
- <Image style={styles.image} source={{uri: path_hash}} />
- </View>
- </TouchableOpacity>
- );
-};
-
-const styles = StyleSheet.create({
- image: {
- aspectRatio: 1,
- height: '100%',
- alignItems: 'center',
- justifyContent: 'center',
- flexDirection: 'column',
- },
-});
-export default MomentTile;
diff --git a/src/components/profile/ProfilePreview.tsx b/src/components/profile/ProfilePreview.tsx
new file mode 100644
index 00000000..c527746a
--- /dev/null
+++ b/src/components/profile/ProfilePreview.tsx
@@ -0,0 +1,216 @@
+import React, {useEffect, useState, useContext} from 'react';
+import {ProfilePreviewType} from '../../types';
+import {
+ View,
+ Text,
+ Image,
+ StyleSheet,
+ ViewProps,
+ TouchableOpacity,
+} from 'react-native';
+import {useNavigation} from '@react-navigation/native';
+import RNFetchBlob from 'rn-fetch-blob';
+import AsyncStorage from '@react-native-community/async-storage';
+import {AVATAR_PHOTO_ENDPOINT} from '../../constants';
+import {UserType} from '../../types';
+import {ProfileContext} from '../../routes/viewProfile';
+const NO_USER: UserType = {
+ userId: '',
+ username: '',
+};
+
+/**
+ * This component returns user's profile picture followed by username as a touchable component.
+ * What happens when someone clicks on this component is partly decided by the prop isComment.
+ * If isComment is true then it means that we are not displaying this tile as a part of search results.
+ * And hence we do not cache the search results.
+ * On the other hand, if isComment is false, then we should update the search cache. (This cache needs to be revamped to clear outdated results.)
+ * In either case, we load the ProfileContext with data and set the getNewMoments flag to true (Which ensures that everything that needs to be displayed on a user's profile is set).
+ * Finally, We navigate to Profile if we are on the Search Stack. Else we navigate to ProfileView.
+ */
+
+interface ProfilePreviewProps extends ViewProps {
+ profilePreview: ProfilePreviewType;
+ isComment: boolean;
+}
+const ProfilePreview: React.FC<ProfilePreviewProps> = ({
+ profilePreview: {username, first_name, last_name, id},
+ isComment,
+ style,
+}) => {
+ const navigation = useNavigation();
+ const {loadProfile, updateMoments} = useContext(ProfileContext);
+ const [avatarURI, setAvatarURI] = useState<string | null>(null);
+ const [user, setUser] = useState<UserType>(NO_USER);
+ useEffect(() => {
+ let mounted = true;
+ const loadAvatar = async () => {
+ try {
+ const token = await AsyncStorage.getItem('token');
+ if (!token) {
+ setUser(NO_USER);
+ return;
+ }
+ const response = await RNFetchBlob.config({
+ fileCache: true,
+ appendExt: 'jpg',
+ }).fetch('GET', AVATAR_PHOTO_ENDPOINT + `${id}/`, {
+ Authorization: 'Token ' + token,
+ });
+ const status = response.info().status;
+ if (status === 200) {
+ if (mounted) {
+ setAvatarURI(response.path());
+ }
+ return;
+ }
+ if (mounted) {
+ setAvatarURI('');
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ };
+ loadAvatar();
+ return () => {
+ mounted = false;
+ };
+ }, [id]);
+
+ /**
+ * Adds a searched user to the recently searched cache if they're tapped on.
+ * Cache maintains 10 recently searched users, popping off the oldest one if
+ * needed to make space.
+ */
+ const addToRecentlyStoredAndNavigateToProfile = async () => {
+ let user: ProfilePreviewType = {
+ id,
+ username,
+ first_name,
+ last_name,
+ };
+ try {
+ if (!isComment) {
+ 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);
+ }
+ }
+
+ //Load user profile and set new moments to true, navigate to Profile
+ //Load user profile makes sure that we actually load profile of the user the logged in user want to view
+ //Set new moments to true makes sure that we download the moment for the user being viewed again.
+ loadProfile(user.id, user.username);
+ updateMoments(true);
+ if (!isComment) {
+ navigation.navigate('Profile', {
+ isProfileView: true,
+ });
+ } else {
+ navigation.navigate('ProfileView', {
+ isProfileView: true,
+ });
+ }
+ } catch (e) {
+ console.log(e);
+ }
+ };
+
+ //With @ sign if on search screen.
+ const usernameToDisplay = !isComment ? `@` + username : username;
+ const usernameStyle = isComment
+ ? styles.commentUsername
+ : styles.searchUsername;
+
+ const avatarStyle = !isComment ? styles.searchAvatar : styles.commentAvatar;
+
+ return (
+ <TouchableOpacity
+ onPress={addToRecentlyStoredAndNavigateToProfile}
+ style={[styles.container, style]}>
+ <Image
+ style={avatarStyle}
+ source={
+ avatarURI
+ ? {uri: avatarURI}
+ : require('../../assets/images/avatar-placeholder.png')
+ }
+ />
+ <View style={styles.nameContainer}>
+ <Text style={usernameStyle}>{usernameToDisplay}</Text>
+ {first_name ? (
+ <Text style={styles.name}>{first_name.concat(' ', last_name)}</Text>
+ ) : (
+ React.Fragment
+ )}
+ </View>
+ </TouchableOpacity>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ searchAvatar: {
+ height: 60,
+ width: 60,
+ borderRadius: 30,
+ marginRight: 15,
+ },
+ commentAvatar: {
+ height: 40,
+ width: 40,
+ borderRadius: 20,
+ marginRight: 15,
+ marginTop: '2%',
+ },
+ nameContainer: {
+ justifyContent: 'space-evenly',
+ alignSelf: 'stretch',
+ },
+ searchUsername: {
+ fontSize: 18,
+ fontWeight: '500',
+ },
+ commentUsername: {
+ fontSize: 16,
+ fontWeight: '500',
+ },
+ name: {
+ fontSize: 16,
+ color: '#333',
+ },
+});
+
+export default ProfilePreview;
diff --git a/src/components/profile/index.ts b/src/components/profile/index.ts
index e2063e26..eb65d509 100644
--- a/src/components/profile/index.ts
+++ b/src/components/profile/index.ts
@@ -1,7 +1,6 @@
export {default as Cover} from './Cover';
export {default as Content} from './Content';
-export {default as Moment} from './Moment';
export {default as ProfileCutout} from './ProfileCutout';
export {default as ProfileBody} from './ProfileBody';
export {default as ProfileHeader} from './ProfileHeader';
-export {default as CaptionScreenHeader} from './CaptionScreenHeader';
+export {default as ProfilePreview} from '../profile/ProfilePreview';