diff options
-rw-r--r-- | src/assets/images/heart-filled.png | bin | 0 -> 1208 bytes | |||
-rw-r--r-- | src/assets/images/heart-outlined.png | bin | 0 -> 1055 bytes | |||
-rw-r--r-- | src/components/comments/CommentTile.tsx | 133 | ||||
-rw-r--r-- | src/components/comments/CommentsContainer.tsx | 1 | ||||
-rw-r--r-- | src/components/common/LikeButton.tsx | 38 | ||||
-rw-r--r-- | src/components/common/index.ts | 1 | ||||
-rw-r--r-- | src/components/profile/Friends.tsx | 97 | ||||
-rw-r--r-- | src/constants/api.ts | 2 | ||||
-rw-r--r-- | src/routes/main/MainStackNavigator.tsx | 11 | ||||
-rw-r--r-- | src/routes/main/MainStackScreen.tsx | 8 | ||||
-rw-r--r-- | src/screens/profile/CommentReactionScreen.tsx | 69 | ||||
-rw-r--r-- | src/screens/profile/FriendsListScreen.tsx | 4 | ||||
-rw-r--r-- | src/screens/profile/MomentCommentsScreen.tsx | 2 | ||||
-rw-r--r-- | src/screens/profile/index.ts | 1 | ||||
-rw-r--r-- | src/services/CommentService.ts | 95 | ||||
-rw-r--r-- | src/types/types.ts | 11 |
16 files changed, 334 insertions, 139 deletions
diff --git a/src/assets/images/heart-filled.png b/src/assets/images/heart-filled.png Binary files differnew file mode 100644 index 00000000..59bf0ab1 --- /dev/null +++ b/src/assets/images/heart-filled.png diff --git a/src/assets/images/heart-outlined.png b/src/assets/images/heart-outlined.png Binary files differnew file mode 100644 index 00000000..aeb87a99 --- /dev/null +++ b/src/assets/images/heart-outlined.png diff --git a/src/components/comments/CommentTile.tsx b/src/components/comments/CommentTile.tsx index ecdb4c30..ee32f889 100644 --- a/src/components/comments/CommentTile.tsx +++ b/src/components/comments/CommentTile.tsx @@ -11,7 +11,11 @@ import Trash from '../../assets/ionicons/trash-outline.svg'; import {TAGG_LIGHT_BLUE} from '../../constants'; import {ERROR_FAILED_TO_DELETE_COMMENT} from '../../constants/strings'; import {CommentContext} from '../../screens/profile/MomentCommentsScreen'; -import {deleteComment, getCommentsCount} from '../../services'; +import { + deleteComment, + getCommentsCount, + handleLikeUnlikeComment, +} from '../../services'; import {RootState} from '../../store/rootReducer'; import { CommentThreadType, @@ -19,13 +23,9 @@ import { ScreenType, UserType, } from '../../types'; -import { - getTimePosted, - navigateToProfile, - normalize, - SCREEN_WIDTH, -} from '../../utils'; +import {getTimePosted, navigateToProfile, normalize} from '../../utils'; import {mentionPartTypes, renderTextWithMentions} from '../../utils/comments'; +import {LikeButton} from '../common'; import {ProfilePreview} from '../profile'; import CommentsContainer from './CommentsContainer'; @@ -55,6 +55,7 @@ const CommentTile: React.FC<CommentTileProps> = ({ const [showReplies, setShowReplies] = useState<boolean>(false); const [showKeyboard, setShowKeyboard] = useState<boolean>(false); const [shouldUpdateChild, setShouldUpdateChild] = useState(true); + const [liked, setLiked] = useState(commentObject.user_reaction !== null); const swipeRef = useRef<Swipeable>(null); const {replyPosted} = useSelector((state: RootState) => state.user); const state: RootState = useStore().getState(); @@ -100,7 +101,7 @@ const CommentTile: React.FC<CommentTileProps> = ({ showReplies ? 'Hide' : comment.replies_count > 0 - ? `Replies (${comment.replies_count})` + ? `Replies (${comment.replies_count}) ` : 'Replies'; const renderRightAction = (text: string, color: string) => { @@ -143,11 +144,19 @@ const CommentTile: React.FC<CommentTileProps> = ({ containerStyle={styles.swipableContainer}> <View style={[styles.container, isThread ? styles.moreMarginWithThread : {}]}> - <ProfilePreview - profilePreview={commentObject.commenter} - previewType={'Comment'} - screenType={screenType} - /> + <View style={styles.commentHeaderContainer}> + <ProfilePreview + profilePreview={commentObject.commenter} + previewType={'Comment'} + screenType={screenType} + /> + <LikeButton + liked={liked} + setLiked={setLiked} + onPress={() => handleLikeUnlikeComment(commentObject, liked)} + style={styles.likeButton} + /> + </View> <TouchableOpacity style={styles.body} onPress={toggleAddComment}> {renderTextWithMentions({ value: commentObject.comment, @@ -156,33 +165,53 @@ const CommentTile: React.FC<CommentTileProps> = ({ onPress: (user: UserType) => navigateToProfile(state, dispatch, navigation, screenType, user), })} - <View style={styles.clockIconAndTime}> - <ClockIcon style={styles.clockIcon} /> - <Text style={styles.date_time}>{' ' + timePosted}</Text> - <View style={styles.flexer} /> + <View style={styles.commentInfoContainer}> + <View style={styles.row}> + <ClockIcon style={styles.clockIcon} /> + <Text style={styles.date_time}>{' ' + timePosted}</Text> + </View> + <View style={styles.row}> + <TouchableOpacity + style={styles.row} + disabled={commentObject.reaction_count === 0} + onPress={() => { + navigation.navigate('CommentReactionScreen', { + comment: commentObject, + screenType: screenType, + }); + }}> + <Text style={[styles.date_time, styles.likeCount]}> + {commentObject.user_reaction !== null + ? commentObject.reaction_count + (liked ? 0 : -1) + : commentObject.reaction_count + (liked ? 1 : 0)} + </Text> + <Text style={styles.date_time}>Likes</Text> + </TouchableOpacity> + {/* Show replies text only if there are some replies present */} + {!isThread && (commentObject as CommentType).replies_count > 0 && ( + <TouchableOpacity + style={styles.repliesTextAndIconContainer} + onPress={toggleReplies}> + <Text style={styles.repliesText}> + {getRepliesText(commentObject as CommentType)} + </Text> + <Arrow + width={12} + height={11} + color={TAGG_LIGHT_BLUE} + style={ + !showReplies + ? styles.repliesDownArrow + : styles.repliesUpArrow + } + /> + </TouchableOpacity> + )} + </View> </View> </TouchableOpacity> - {/*** Show replies text only if there are some replies present */} - {!isThread && (commentObject as CommentType).replies_count > 0 && ( - <TouchableOpacity - style={styles.repliesTextAndIconContainer} - onPress={toggleReplies}> - <Text style={styles.repliesText}> - {getRepliesText(commentObject as CommentType)} - </Text> - <Arrow - width={12} - height={11} - color={TAGG_LIGHT_BLUE} - style={ - !showReplies ? styles.repliesDownArrow : styles.repliesUpArrow - } - /> - </TouchableOpacity> - )} </View> - - {/*** Show replies if toggle state is true */} + {/* Show replies if toggle state is true */} {showReplies && ( <View> <CommentsContainer @@ -206,8 +235,8 @@ const styles = StyleSheet.create({ flexDirection: 'column', flex: 1, paddingTop: '3%', - paddingBottom: '5%', - marginLeft: '7%', + marginLeft: '5%', + paddingBottom: '2%', }, swipeActions: { flexDirection: 'row', @@ -215,6 +244,14 @@ const styles = StyleSheet.create({ moreMarginWithThread: { marginLeft: '14%', }, + commentHeaderContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + }, + likeButton: { + marginRight: 10, + }, body: { marginLeft: 56, }, @@ -231,18 +268,23 @@ const styles = StyleSheet.create({ height: 12, alignSelf: 'center', }, - clockIconAndTime: { + commentInfoContainer: { flexDirection: 'row', marginTop: '3%', + justifyContent: 'space-between', + alignItems: 'center', }, - flexer: { - flex: 1, + likeCount: { + color: 'black', + marginRight: 5, + }, + row: { + flexDirection: 'row', }, repliesTextAndIconContainer: { flexDirection: 'row', alignItems: 'center', - marginTop: '5%', - marginLeft: 56, + paddingLeft: 10, }, repliesText: { color: TAGG_LIGHT_BLUE, @@ -250,9 +292,6 @@ const styles = StyleSheet.create({ fontSize: normalize(12), marginRight: '1%', }, - repliesBody: { - width: SCREEN_WIDTH, - }, repliesDownArrow: { transform: [{rotate: '270deg'}], marginTop: '1%', diff --git a/src/components/comments/CommentsContainer.tsx b/src/components/comments/CommentsContainer.tsx index 0bfd5ad6..595ec743 100644 --- a/src/components/comments/CommentsContainer.tsx +++ b/src/components/comments/CommentsContainer.tsx @@ -136,7 +136,6 @@ const CommentsContainer: React.FC<CommentsContainerProps> = ({ }; const styles = StyleSheet.create({ - scrollView: {}, scrollViewContent: { justifyContent: 'center', }, diff --git a/src/components/common/LikeButton.tsx b/src/components/common/LikeButton.tsx new file mode 100644 index 00000000..81383eca --- /dev/null +++ b/src/components/common/LikeButton.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import {Image, ImageStyle, StyleSheet, TouchableOpacity} from 'react-native'; +import {normalize} from '../../utils'; + +interface LikeButtonProps { + onPress: () => void; + style: ImageStyle; + liked: boolean; + setLiked: (liked: boolean) => void; +} +const LikeButton: React.FC<LikeButtonProps> = ({ + onPress, + style, + liked, + setLiked, +}) => { + const uri = liked + ? require('../../assets/images/heart-filled.png') + : require('../../assets/images/heart-outlined.png'); + return ( + <TouchableOpacity + onPress={() => { + setLiked(!liked); + onPress(); + }}> + <Image style={[styles.image, style]} source={uri} /> + </TouchableOpacity> + ); +}; + +const styles = StyleSheet.create({ + image: { + width: normalize(18), + height: normalize(15), + }, +}); + +export default LikeButton; diff --git a/src/components/common/index.ts b/src/components/common/index.ts index b38056c6..48abb8b8 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -26,3 +26,4 @@ export {default as BasicButton} from './BasicButton'; export {default as Avatar} from './Avatar'; export {default as TaggTypeahead} from './TaggTypeahead'; export {default as TaggUserRowCell} from './TaggUserRowCell'; +export {default as LikeButton} from './LikeButton'; diff --git a/src/components/profile/Friends.tsx b/src/components/profile/Friends.tsx index a7a06567..f800597b 100644 --- a/src/components/profile/Friends.tsx +++ b/src/components/profile/Friends.tsx @@ -1,98 +1,39 @@ -import React, {useEffect, useState} from 'react'; +import React from 'react'; import {ScrollView, StyleSheet, Text, View} from 'react-native'; -import {checkPermission} from 'react-native-contacts'; import {TouchableOpacity} from 'react-native-gesture-handler'; import {useDispatch, useStore} from 'react-redux'; import {TAGG_LIGHT_BLUE} from '../../constants'; -import {usersFromContactsService} from '../../services'; import {NO_USER} from '../../store/initialStates'; import {RootState} from '../../store/rootReducer'; import {ProfilePreviewType, ScreenType} from '../../types'; -import { - extractContacts, - normalize, - SCREEN_HEIGHT, - SCREEN_WIDTH, -} from '../../utils'; -import {handleAddFriend, handleUnfriend} from '../../utils/friends'; +import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; +import {handleUnfriend} from '../../utils/friends'; import {ProfilePreview} from '../profile'; interface FriendsProps { result: Array<ProfilePreviewType>; screenType: ScreenType; userId: string | undefined; + hideFriendsFeature?: boolean; } -const Friends: React.FC<FriendsProps> = ({result, screenType, userId}) => { +const Friends: React.FC<FriendsProps> = ({ + result, + screenType, + userId, + hideFriendsFeature, +}) => { const state: RootState = useStore().getState(); const dispatch = useDispatch(); const {user: loggedInUser = NO_USER} = state.user; - const [usersFromContacts, setUsersFromContacts] = useState< - ProfilePreviewType[] - >([]); - - useEffect(() => { - const handleFindFriends = () => { - extractContacts().then(async (contacts) => { - const permission = await checkPermission(); - if (permission === 'authorized') { - let response = await usersFromContactsService(contacts); - setUsersFromContacts(response.existing_tagg_users); - } else { - console.log('Authorize access to contacts'); - } - }); - }; - handleFindFriends(); - }, []); - - const UsersFromContacts = () => ( - <> - {usersFromContacts?.splice(0, 2).map((profilePreview) => ( - <View key={profilePreview.id} style={styles.container}> - <View style={styles.friend}> - <ProfilePreview - {...{profilePreview}} - previewType={'Friend'} - screenType={screenType} - /> - </View> - <TouchableOpacity - style={styles.addFriendButton} - onPress={() => { - handleAddFriend(screenType, profilePreview, dispatch, state).then( - (success) => { - if (success) { - let users = usersFromContacts; - setUsersFromContacts( - users.filter( - (user) => user.username !== profilePreview.username, - ), - ); - } - }, - ); - }}> - <Text style={styles.addFriendButtonTitle}>Add Friend</Text> - </TouchableOpacity> - </View> - ))} - </> - ); return ( <> - {loggedInUser.userId === userId && usersFromContacts.length !== 0 && ( - <View style={styles.subheader}> - <View style={styles.addFriendHeaderContainer}> - <Text style={[styles.subheaderText]}>Contacts on Tagg</Text> - </View> - <UsersFromContacts /> - </View> + {!hideFriendsFeature && ( + <Text style={[styles.subheaderText, styles.friendsSubheaderText]}> + Friends + </Text> )} - <Text style={[styles.subheaderText, styles.friendsSubheaderText]}> - Friends - </Text> <ScrollView keyboardShouldPersistTaps={'always'} style={styles.scrollView} @@ -129,7 +70,6 @@ const styles = StyleSheet.create({ alignSelf: 'center', width: SCREEN_WIDTH * 0.85, }, - firstScrollView: {}, scrollViewContent: { alignSelf: 'center', paddingBottom: SCREEN_HEIGHT / 7, @@ -142,7 +82,6 @@ const styles = StyleSheet.create({ marginBottom: '3%', marginTop: '2%', }, - header: {flexDirection: 'row'}, subheader: { alignSelf: 'center', width: SCREEN_WIDTH * 0.85, @@ -154,20 +93,12 @@ const styles = StyleSheet.create({ fontWeight: '600', lineHeight: normalize(14.32), }, - findFriendsButton: {flexDirection: 'row'}, friendsSubheaderText: { alignSelf: 'center', width: SCREEN_WIDTH * 0.85, marginVertical: '1%', marginBottom: '2%', }, - findFriendsSubheaderText: { - marginLeft: '5%', - color: '#08E2E2', - fontSize: normalize(12), - fontWeight: '600', - lineHeight: normalize(14.32), - }, container: { alignSelf: 'center', flexDirection: 'row', diff --git a/src/constants/api.ts b/src/constants/api.ts index e5ce9e77..9d3f70c9 100644 --- a/src/constants/api.ts +++ b/src/constants/api.ts @@ -33,6 +33,8 @@ 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/'; export const COMMENTS_ENDPOINT: string = API_URL + 'comments/'; +export const COMMENT_REACTIONS_ENDPOINT: string = API_URL + 'reaction-comment/'; +export const COMMENT_REACTIONS_REPLY_ENDPOINT: string = API_URL + 'reaction-reply/'; export const FRIENDS_ENDPOINT: string = API_URL + 'friends/'; export const ALL_USERS_ENDPOINT: string = API_URL + 'users/'; export const REPORT_ISSUE_ENDPOINT: string = API_URL + 'report/'; diff --git a/src/routes/main/MainStackNavigator.tsx b/src/routes/main/MainStackNavigator.tsx index 1f173569..3b183cc0 100644 --- a/src/routes/main/MainStackNavigator.tsx +++ b/src/routes/main/MainStackNavigator.tsx @@ -3,7 +3,12 @@ */ import {createStackNavigator} from '@react-navigation/stack'; import {Image} from 'react-native-image-crop-picker'; -import {MomentType, ScreenType, SearchCategoryType} from '../../types'; +import { + CommentBaseType, + MomentType, + ScreenType, + SearchCategoryType, +} from '../../types'; export type MainStackParams = { SuggestedPeople: { @@ -46,6 +51,10 @@ export type MainStackParams = { screenType: ScreenType; comment_id?: string; }; + CommentReactionScreen: { + comment: CommentBaseType; + screenType: ScreenType; + }; FriendsListScreen: { userXId: string | undefined; screenType: ScreenType; diff --git a/src/routes/main/MainStackScreen.tsx b/src/routes/main/MainStackScreen.tsx index f5100e58..d76f9137 100644 --- a/src/routes/main/MainStackScreen.tsx +++ b/src/routes/main/MainStackScreen.tsx @@ -12,6 +12,7 @@ import { CategorySelection, ChatListScreen, ChatScreen, + CommentReactionScreen, CreateCustomCategory, DiscoverUsers, EditProfile, @@ -217,6 +218,13 @@ const MainStackScreen: React.FC<MainStackProps> = ({route}) => { }} /> <MainStack.Screen + name="CommentReactionScreen" + component={CommentReactionScreen} + options={{ + ...headerBarOptions('black', 'Likes'), + }} + /> + <MainStack.Screen name="MomentUploadPrompt" component={MomentUploadPromptScreen} initialParams={{screenType}} diff --git a/src/screens/profile/CommentReactionScreen.tsx b/src/screens/profile/CommentReactionScreen.tsx new file mode 100644 index 00000000..0596a184 --- /dev/null +++ b/src/screens/profile/CommentReactionScreen.tsx @@ -0,0 +1,69 @@ +import {RouteProp, useNavigation} from '@react-navigation/native'; +import React, {useEffect, useState} from 'react'; +import {Alert, ScrollView, StyleSheet, View} from 'react-native'; +import {SafeAreaView} from 'react-native-safe-area-context'; +import {Friends} from '../../components'; +import {ERROR_SOMETHING_WENT_WRONG} from '../../constants/strings'; +import {MainStackParams} from '../../routes/main'; +import {getUsersReactedToAComment} from '../../services'; +import {ProfilePreviewType} from '../../types'; +import {HeaderHeight, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; + +type CommentReactionScreenRouteProps = RouteProp< + MainStackParams, + 'CommentReactionScreen' +>; + +interface CommentReactionScreenProps { + route: CommentReactionScreenRouteProps; +} + +const CommentReactionScreen: React.FC<CommentReactionScreenProps> = ({ + route, +}) => { + const navigation = useNavigation(); + const {comment, screenType} = route.params; + const [users, setUsers] = useState<ProfilePreviewType[]>([]); + + useEffect(() => { + const loadUsers = async () => { + const response = await getUsersReactedToAComment(comment); + if (response.length !== 0) { + setUsers(response); + } else { + Alert.alert(ERROR_SOMETHING_WENT_WRONG); + navigation.goBack(); + } + }; + loadUsers(); + }, []); + + return ( + <View style={styles.background}> + <SafeAreaView> + <ScrollView style={styles.container}> + <Friends + result={users} + screenType={screenType} + userId={undefined} + hideFriendsFeature + /> + </ScrollView> + </SafeAreaView> + </View> + ); +}; + +const styles = StyleSheet.create({ + background: { + backgroundColor: 'white', + width: SCREEN_WIDTH, + height: SCREEN_HEIGHT, + }, + container: { + marginTop: HeaderHeight, + height: SCREEN_HEIGHT - HeaderHeight, + }, +}); + +export default CommentReactionScreen; diff --git a/src/screens/profile/FriendsListScreen.tsx b/src/screens/profile/FriendsListScreen.tsx index 1d10bc86..73364f3b 100644 --- a/src/screens/profile/FriendsListScreen.tsx +++ b/src/screens/profile/FriendsListScreen.tsx @@ -36,10 +36,6 @@ const FriendsListScreen: React.FC<FriendsListScreenProps> = ({route}) => { }; const styles = StyleSheet.create({ - background: { - backgroundColor: 'white', - height: '100%', - }, backButton: { marginLeft: 10, }, diff --git a/src/screens/profile/MomentCommentsScreen.tsx b/src/screens/profile/MomentCommentsScreen.tsx index bf07ae30..4b332b56 100644 --- a/src/screens/profile/MomentCommentsScreen.tsx +++ b/src/screens/profile/MomentCommentsScreen.tsx @@ -102,7 +102,7 @@ const styles = StyleSheet.create({ }, body: { marginTop: HeaderHeight, - width: SCREEN_WIDTH * 0.9, + width: SCREEN_WIDTH * 0.95, height: SCREEN_HEIGHT * 0.8, paddingTop: '3%', }, diff --git a/src/screens/profile/index.ts b/src/screens/profile/index.ts index d5377494..ea0505a2 100644 --- a/src/screens/profile/index.ts +++ b/src/screens/profile/index.ts @@ -12,3 +12,4 @@ export {default as PrivacyScreen} from './PrivacyScreen'; export {default as AccountType} from './AccountType'; export {default as CategorySelection} from './CategorySelection'; export {default as CreateCustomCategory} from './CreateCustomCategory'; +export {default as CommentReactionScreen} from './CommentReactionScreen'; diff --git a/src/services/CommentService.ts b/src/services/CommentService.ts index 2faaa8db..6d71ce9c 100644 --- a/src/services/CommentService.ts +++ b/src/services/CommentService.ts @@ -1,8 +1,18 @@ import AsyncStorage from '@react-native-community/async-storage'; import {Alert} from 'react-native'; -import {COMMENTS_ENDPOINT, COMMENT_THREAD_ENDPOINT} from '../constants'; +import { + COMMENTS_ENDPOINT, + COMMENT_REACTIONS_ENDPOINT, + COMMENT_REACTIONS_REPLY_ENDPOINT, + COMMENT_THREAD_ENDPOINT, +} from '../constants'; import {ERROR_FAILED_TO_COMMENT} from '../constants/strings'; -import {CommentType} from '../types'; +import { + CommentThreadType, + CommentType, + ProfilePreviewType, + ReactionOptionsType, +} from '../types'; export const getComments = async ( objectId: string, @@ -116,3 +126,84 @@ export const deleteComment = async (id: string, isThread: boolean) => { return false; } }; + +/** + * If `user_reaction` is undefined, we like the comment, if `user_reaction` + * is defined, we unlike the comment. + * + * @param comment the comment object that contains `user_reaction` (or not) + * @returns + */ +export const handleLikeUnlikeComment = async ( + comment: CommentType | CommentThreadType, + liked: boolean, +) => { + try { + const isReply = 'parent_comment' in comment; + const token = await AsyncStorage.getItem('token'); + let url = isReply + ? COMMENT_REACTIONS_REPLY_ENDPOINT + : COMMENT_REACTIONS_ENDPOINT; + if (liked) { + // unlike a comment + url += `${comment.comment_id}/?reaction_type=LIKE`; + const response = await fetch(url, { + method: 'DELETE', + headers: { + Authorization: 'Token ' + token, + }, + }); + return response.status === 200; + } else { + // like a comment + const form = new FormData(); + form.append('comment_id', comment.comment_id); + form.append('reaction_type', ReactionOptionsType.Like); + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'multipart/form-data', + Authorization: 'Token ' + token, + }, + body: form, + }); + return response.status === 200; + } + } catch (error) { + console.log('Unable to like/unlike a comment'); + console.error(error); + } +}; + +export const getUsersReactedToAComment = async ( + comment: CommentType | CommentThreadType, +) => { + try { + const isReply = 'parent_comment' in comment; + const token = await AsyncStorage.getItem('token'); + let url = isReply + ? COMMENT_REACTIONS_REPLY_ENDPOINT + : COMMENT_REACTIONS_ENDPOINT; + url += `?comment_id=${comment.comment_id}`; + const response = await fetch(url, { + method: 'GET', + headers: { + Authorization: 'Token ' + token, + }, + }); + const typedResponse: { + reaction: ReactionOptionsType; + user_list: ProfilePreviewType[]; + }[] = await response.json(); + for (const obj of typedResponse) { + if (obj.reaction === ReactionOptionsType.Like) { + return obj.user_list; + } + } + return []; + } catch (error) { + console.log('Unable to fetch list of users whom reacted to a comment'); + console.error(error); + } + return []; +}; diff --git a/src/types/types.ts b/src/types/types.ts index 00501d49..e9975529 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -122,6 +122,8 @@ export interface CommentBaseType { comment: string; date_created: string; commenter: ProfilePreviewType; + user_reaction: ReactionType | null; + reaction_count: number; } export interface CommentType extends CommentBaseType { @@ -316,3 +318,12 @@ export type ChatContextType = { >; chatClient: StreamChat; }; + +export enum ReactionOptionsType { + Like = 'LIKE', +} + +export type ReactionType = { + id: string; + type: ReactionOptionsType; +}; |