aboutsummaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
authorAshm Walia <40498934+ashmgarv@users.noreply.github.com>2020-10-22 15:34:21 -0700
committerGitHub <noreply@github.com>2020-10-22 18:34:21 -0400
commitd0237cbb61e5c4d77c7b0cefc50891639646ee91 (patch)
tree5b0c1e33c1043887ad45c06a30173dc469d28228 /src/components
parent5db451725d6165de16ee11cda608a05e96e481f9 (diff)
[TMA 236] Comments PR (#64)
* Added comments count and retrieve comments * Working draft * The one before cleanup * Finally * Added time icon and major refactoring * Small fix for social media taggs * Addressed review comments
Diffstat (limited to 'src/components')
-rw-r--r--src/components/comments/AddComment.tsx103
-rw-r--r--src/components/comments/CommentTile.tsx71
-rw-r--r--src/components/comments/CommentsCount.tsx57
-rw-r--r--src/components/comments/index.ts3
-rw-r--r--src/components/index.ts2
-rw-r--r--src/components/moments/CaptionScreenHeader.tsx (renamed from src/components/profile/CaptionScreenHeader.tsx)0
-rw-r--r--src/components/moments/Moment.tsx (renamed from src/components/profile/Moment.tsx)0
-rw-r--r--src/components/moments/MomentTile.tsx (renamed from src/components/profile/MomentTile.tsx)0
-rw-r--r--src/components/moments/index.ts2
-rw-r--r--src/components/profile/Content.tsx5
-rw-r--r--src/components/profile/ProfilePreview.tsx (renamed from src/components/search/SearchResult.tsx)120
-rw-r--r--src/components/profile/index.ts3
-rw-r--r--src/components/search/SearchResults.tsx5
13 files changed, 326 insertions, 45 deletions
diff --git a/src/components/comments/AddComment.tsx b/src/components/comments/AddComment.tsx
new file mode 100644
index 00000000..65c0b066
--- /dev/null
+++ b/src/components/comments/AddComment.tsx
@@ -0,0 +1,103 @@
+import * as React from 'react';
+import {Image, StyleSheet, TextInput, View} from 'react-native';
+import AsyncStorage from '@react-native-community/async-storage';
+import {AuthContext} from '../../routes';
+import {TaggBigInput} from '../onboarding';
+import {postMomentComment} from '../../services';
+
+/**
+ * This file provides the add comment view for a user.
+ * Displays the logged in user's profile picture to the left and then provides space to add a comment.
+ * Comment is posted when enter is pressed as requested by product team.
+ */
+
+export interface AddCommentProps {
+ setNewCommentsAvailable: Function;
+ moment_id: string;
+}
+
+const AddComment: React.FC<AddCommentProps> = ({
+ setNewCommentsAvailable,
+ moment_id,
+}) => {
+ const [comment, setComment] = React.useState('');
+ const {
+ avatar,
+ user: {userId, username},
+ logout,
+ } = React.useContext(AuthContext);
+
+ const handleCommentUpdate = (comment: string) => {
+ setComment(comment);
+ };
+
+ const postComment = async () => {
+ try {
+ const token = await AsyncStorage.getItem('token');
+ if (!token) {
+ logout();
+ return;
+ }
+ const postedComment = await postMomentComment(
+ userId,
+ comment,
+ moment_id,
+ token,
+ );
+
+ if (postedComment) {
+ //Set the current comment to en empty string if the comment was posted successfully.
+ handleCommentUpdate('');
+
+ //Indicate the MomentCommentsScreen that it needs to download the new comments again
+ setNewCommentsAvailable(true);
+ }
+ } catch (err) {
+ console.log('Error while posting comment!');
+ }
+ };
+
+ return (
+ <View style={styles.container}>
+ <Image
+ style={styles.avatar}
+ source={
+ avatar
+ ? {uri: avatar}
+ : require('../../assets/images/avatar-placeholder.png')
+ }
+ />
+ <TaggBigInput
+ style={styles.text}
+ multiline
+ placeholder="Add a comment....."
+ placeholderTextColor="gray"
+ onChangeText={handleCommentUpdate}
+ onSubmitEditing={postComment}
+ value={comment}
+ />
+ </View>
+ );
+};
+const styles = StyleSheet.create({
+ container: {flexDirection: 'row'},
+ text: {
+ position: 'relative',
+ right: '18%',
+ backgroundColor: 'white',
+ width: '70%',
+ paddingLeft: '2%',
+ paddingRight: '2%',
+ paddingBottom: '1%',
+ paddingTop: '1%',
+ height: 60,
+ },
+ avatar: {
+ height: 40,
+ width: 40,
+ borderRadius: 30,
+ marginRight: 15,
+ },
+});
+
+export default AddComment;
diff --git a/src/components/comments/CommentTile.tsx b/src/components/comments/CommentTile.tsx
new file mode 100644
index 00000000..02840d47
--- /dev/null
+++ b/src/components/comments/CommentTile.tsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import {Text, View} from 'react-native-animatable';
+import {ProfilePreview} from '../profile';
+import {CommentType} from '../../types';
+import {StyleSheet} from 'react-native';
+import {getTimePosted} from '../../utils';
+import ClockIcon from '../../assets/icons/clock-icon-01.svg';
+
+/**
+ * Displays users's profile picture, comment posted by them and the time difference between now and when a comment was posted.
+ */
+
+interface CommentTileProps {
+ comment_object: CommentType;
+}
+
+const CommentTile: React.FC<CommentTileProps> = ({comment_object}) => {
+ const timePosted = getTimePosted(comment_object.date_time);
+ return (
+ <View style={styles.container}>
+ <ProfilePreview
+ profilePreview={{
+ id: comment_object.commenter__id,
+ username: comment_object.commenter__username,
+ first_name: '',
+ last_name: '',
+ }}
+ isComment={true}
+ />
+ <View style={styles.body}>
+ <Text style={styles.comment}>{comment_object.comment}</Text>
+ <View style={styles.clockIconAndTime}>
+ <ClockIcon style={styles.clockIcon} />
+ <Text style={styles.date_time}>{' ' + timePosted}</Text>
+ </View>
+ </View>
+ </View>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ marginLeft: '3%',
+ marginRight: '3%',
+ borderBottomWidth: 1,
+ borderColor: 'lightgray',
+ marginBottom: '3%',
+ },
+ body: {
+ marginLeft: 56,
+ },
+ comment: {
+ position: 'relative',
+ top: -5,
+ marginBottom: '2%',
+ },
+ date_time: {
+ color: 'gray',
+ },
+ clockIcon: {
+ width: 12,
+ height: 12,
+ alignSelf: 'center',
+ },
+ clockIconAndTime: {
+ flexDirection: 'row',
+ marginBottom: '3%',
+ },
+});
+
+export default CommentTile;
diff --git a/src/components/comments/CommentsCount.tsx b/src/components/comments/CommentsCount.tsx
new file mode 100644
index 00000000..74b4194c
--- /dev/null
+++ b/src/components/comments/CommentsCount.tsx
@@ -0,0 +1,57 @@
+import * as React from 'react';
+import {Text} from 'react-native-animatable';
+import {StyleSheet, TouchableOpacity} from 'react-native';
+import CommentIcon from '../../assets/icons/moment-comment-icon.svg';
+import {useNavigation} from '@react-navigation/native';
+
+/**
+ * Provides a view for the comment icon and the comment count.
+ * When the user clicks on this view, a new screen opens to display all the comments.
+ */
+
+type CommentsCountProps = {
+ comments_count: string;
+ isProfileView: boolean;
+ moment_id: string;
+};
+
+const CommentsCount: React.FC<CommentsCountProps> = ({
+ comments_count,
+ isProfileView,
+ moment_id,
+}) => {
+ const navigation = useNavigation();
+ const navigateToCommentsScreen = async () => {
+ navigation.navigate('MomentCommentsScreen', {
+ isProfileView: isProfileView,
+ moment_id: moment_id,
+ });
+ };
+ return (
+ <>
+ <TouchableOpacity onPress={() => navigateToCommentsScreen()}>
+ <CommentIcon style={styles.image} />
+ <Text style={styles.count}>
+ {comments_count !== '0' ? comments_count : ''}
+ </Text>
+ </TouchableOpacity>
+ </>
+ );
+};
+
+const styles = StyleSheet.create({
+ image: {
+ position: 'relative',
+ width: 21,
+ height: 21,
+ },
+
+ count: {
+ position: 'relative',
+ fontWeight: 'bold',
+ color: 'white',
+ paddingTop: '2%',
+ },
+});
+
+export default CommentsCount;
diff --git a/src/components/comments/index.ts b/src/components/comments/index.ts
new file mode 100644
index 00000000..6293f799
--- /dev/null
+++ b/src/components/comments/index.ts
@@ -0,0 +1,3 @@
+export {default as CommentsCount} from '../comments/CommentsCount';
+export {default as CommentTile} from './CommentTile';
+export {default as AddComment} from './AddComment';
diff --git a/src/components/index.ts b/src/components/index.ts
index 1b726051..46a7773f 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -3,3 +3,5 @@ export * from './onboarding';
export * from './profile';
export * from './search';
export * from './taggs';
+export * from './comments';
+export * from './moments';
diff --git a/src/components/profile/CaptionScreenHeader.tsx b/src/components/moments/CaptionScreenHeader.tsx
index 4715b4ef..4715b4ef 100644
--- a/src/components/profile/CaptionScreenHeader.tsx
+++ b/src/components/moments/CaptionScreenHeader.tsx
diff --git a/src/components/profile/Moment.tsx b/src/components/moments/Moment.tsx
index 1ec5511e..1ec5511e 100644
--- a/src/components/profile/Moment.tsx
+++ b/src/components/moments/Moment.tsx
diff --git a/src/components/profile/MomentTile.tsx b/src/components/moments/MomentTile.tsx
index 70b20d40..70b20d40 100644
--- a/src/components/profile/MomentTile.tsx
+++ b/src/components/moments/MomentTile.tsx
diff --git a/src/components/moments/index.ts b/src/components/moments/index.ts
new file mode 100644
index 00000000..339e0e19
--- /dev/null
+++ b/src/components/moments/index.ts
@@ -0,0 +1,2 @@
+export {default as CaptionScreenHeader} from '../moments/CaptionScreenHeader';
+export {default as Moment} from './Moment';
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/search/SearchResult.tsx b/src/components/profile/ProfilePreview.tsx
index 04624004..c527746a 100644
--- a/src/components/search/SearchResult.tsx
+++ b/src/components/profile/ProfilePreview.tsx
@@ -19,11 +19,23 @@ const NO_USER: UserType = {
username: '',
};
-interface SearchResultProps extends ViewProps {
+/**
+ * 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 SearchResult: React.FC<SearchResultProps> = ({
+const ProfilePreview: React.FC<ProfilePreviewProps> = ({
profilePreview: {username, first_name, last_name, id},
+ isComment,
style,
}) => {
const navigation = useNavigation();
@@ -78,58 +90,75 @@ const SearchResult: React.FC<SearchResultProps> = ({
last_name,
};
try {
- 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();
+ 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);
}
- recentlySearchedList.unshift(user);
}
+ } else {
+ recentlySearchedList = [user];
+ }
+
+ try {
+ let recentlySearchedListString = JSON.stringify(recentlySearchedList);
+ await AsyncStorage.setItem(
+ '@recently_searched_users',
+ recentlySearchedListString,
+ );
+ } catch (e) {
+ console.log(e);
}
- } else {
- recentlySearchedList = [user];
}
//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.
- //Not sure if we should make this call before caching the search results ??
loadProfile(user.id, user.username);
updateMoments(true);
- navigation.navigate('Profile', {
- isProfileView: true,
- });
-
- try {
- let recentlySearchedListString = JSON.stringify(recentlySearchedList);
- await AsyncStorage.setItem(
- '@recently_searched_users',
- recentlySearchedListString,
- );
- } catch (e) {
- console.log(e);
+ 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={styles.avatar}
+ style={avatarStyle}
source={
avatarURI
? {uri: avatarURI}
@@ -137,8 +166,12 @@ const SearchResult: React.FC<SearchResultProps> = ({
}
/>
<View style={styles.nameContainer}>
- <Text style={styles.username}>@{username}</Text>
- <Text style={styles.name}>{first_name.concat(' ', last_name)}</Text>
+ <Text style={usernameStyle}>{usernameToDisplay}</Text>
+ {first_name ? (
+ <Text style={styles.name}>{first_name.concat(' ', last_name)}</Text>
+ ) : (
+ React.Fragment
+ )}
</View>
</TouchableOpacity>
);
@@ -149,24 +182,35 @@ const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
},
- avatar: {
+ 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',
},
- username: {
+ searchUsername: {
fontSize: 18,
fontWeight: '500',
},
+ commentUsername: {
+ fontSize: 16,
+ fontWeight: '500',
+ },
name: {
fontSize: 16,
color: '#333',
},
});
-export default SearchResult;
+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';
diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx
index 16bff818..57db4167 100644
--- a/src/components/search/SearchResults.tsx
+++ b/src/components/search/SearchResults.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import {ProfilePreviewType} from '../../types';
-import SearchResult from './SearchResult';
+import ProfilePreview from '../profile/ProfilePreview';
import {StyleSheet, View} from 'react-native';
interface SearchResultsProps {
results: Array<ProfilePreviewType>;
@@ -9,10 +9,11 @@ const SearchResults: React.FC<SearchResultsProps> = ({results}) => {
return (
<View>
{results.map((profilePreview) => (
- <SearchResult
+ <ProfilePreview
style={styles.result}
key={profilePreview.id}
{...{profilePreview}}
+ isComment={false}
/>
))}
</View>