aboutsummaryrefslogtreecommitdiff
path: root/src/components/notifications/Notification.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/notifications/Notification.tsx')
-rw-r--r--src/components/notifications/Notification.tsx188
1 files changed, 144 insertions, 44 deletions
diff --git a/src/components/notifications/Notification.tsx b/src/components/notifications/Notification.tsx
index e648b554..951a5bf6 100644
--- a/src/components/notifications/Notification.tsx
+++ b/src/components/notifications/Notification.tsx
@@ -1,18 +1,31 @@
import {useNavigation} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
-import {Image, StyleSheet, Text, View} from 'react-native';
+import {Alert, Image, StyleSheet, Text, View} from 'react-native';
import {TouchableWithoutFeedback} from 'react-native-gesture-handler';
+import LinearGradient from 'react-native-linear-gradient';
import {useDispatch, useStore} from 'react-redux';
-import {loadImageFromURL, loadMomentThumbnail} from '../../services';
+import {BACKGROUND_GRADIENT_MAP} from '../../constants';
+import {ERROR_DELETED_OBJECT} from '../../constants/strings';
+import {
+ loadImageFromURL,
+ loadMoments,
+ loadMomentThumbnail,
+} from '../../services';
import {
acceptFriendRequest,
declineFriendRequest,
loadUserNotifications,
+ updateReplyPosted,
updateUserXFriends,
} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {MomentType, NotificationType, ScreenType} from '../../types';
-import {fetchUserX, SCREEN_HEIGHT, userXInStore} from '../../utils';
+import {
+ fetchUserX,
+ getTokenOrLogout,
+ SCREEN_HEIGHT,
+ userXInStore,
+} from '../../utils';
import AcceptDeclineButtons from '../common/AcceptDeclineButtons';
interface NotificationProps {
@@ -40,27 +53,51 @@ const Notification: React.FC<NotificationProps> = (props) => {
const [avatar, setAvatar] = useState<string | undefined>(undefined);
const [momentURI, setMomentURI] = useState<string | undefined>(undefined);
- const backgroundColor = unread ? '#DCF1F1' : 'rgba(0,0,0,0)';
+ const [onTapLoadProfile, setOnTapLoadProfile] = useState<boolean>(false);
useEffect(() => {
(async () => {
const response = await loadImageFromURL(thumbnail_url);
if (response) {
setAvatar(response);
+ } else {
+ setAvatar(undefined);
}
})();
}, []);
useEffect(() => {
+ if (onTapLoadProfile) {
+ fetchUserX(dispatch, {userId: id, username: username}, screenType);
+ }
+ return () => {
+ setOnTapLoadProfile(false);
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [onTapLoadProfile]);
+
+ useEffect(() => {
let mounted = true;
const loadMomentImage = async (moment_id: string) => {
const response = await loadMomentThumbnail(moment_id);
if (mounted && response) {
setMomentURI(response);
+ } else {
+ // if not set to empty, it will re-use the previous notification's state
+ setMomentURI(undefined);
}
};
- if (notification_type === 'CMT' && notification_object) {
- loadMomentImage(notification_object.moment_id);
+ if (
+ (notification_type === 'CMT' ||
+ notification_type === 'MOM_3+' ||
+ notification_type === 'MOM_FRIEND') &&
+ notification_object
+ ) {
+ loadMomentImage(
+ notification_object.moment_id
+ ? notification_object.moment_id
+ : notification_object.parent_comment.moment_id,
+ );
return () => {
mounted = false;
};
@@ -84,31 +121,85 @@ const Notification: React.FC<NotificationProps> = (props) => {
});
break;
case 'CMT':
- // find the moment we need to display
- const moment = loggedInUserMoments?.find(
- (m) => m.moment_id === notification_object?.moment_id,
+ //Notification object is set to null if the comment / comment_thread / moment gets deleted
+ if (!notification_object) {
+ Alert.alert(ERROR_DELETED_OBJECT);
+ break;
+ }
+ let {moment_id} = notification_object;
+ let {comment_id} = notification_object;
+
+ //If this is a thread, get comment_id and moment_id from parent_comment
+ if (!notification_object?.moment_id) {
+ moment_id = notification_object?.parent_comment?.moment_id;
+ comment_id = notification_object?.parent_comment?.comment_id;
+ }
+
+ // Now find the moment we need to display
+ let moment: MomentType | undefined = loggedInUserMoments?.find(
+ (m) => m.moment_id === moment_id,
);
+ let userXId;
+
+ // If moment does not belong to the logged in user, then the comment was probably a reply to logged in user's comment
+ // on userX's moment
+ // Load moments for userX
+ if (!moment) {
+ let moments: MomentType[] = [];
+ try {
+ //Populate local state in the mean time
+ setOnTapLoadProfile(true);
+ const token = await getTokenOrLogout(dispatch);
+ moments = await loadMoments(id, token);
+ } catch (err) {
+ console.log(err);
+ }
+ moment = moments?.find((m) => m.moment_id === moment_id);
+ userXId = id;
+ }
+
+ //Now if moment was found, navigate to the respective moment
if (moment) {
+ if (notification_object?.parent_comment) {
+ dispatch(updateReplyPosted(notification_object));
+ }
navigation.push('IndividualMoment', {
moment,
- userXId: undefined, // we're only viewing our own moment here
+ userXId: userXId, // we're only viewing our own moment here
screenType,
});
setTimeout(() => {
navigation.push('MomentCommentsScreen', {
- moment_id: moment.moment_id,
+ moment_id: moment_id,
screenType,
+ comment_id: comment_id,
});
}, 500);
}
break;
+ case 'MOM_3+':
+ case 'MOM_FRIEND':
+ const object = notification_object as MomentType;
+ await fetchUserX(
+ dispatch,
+ {userId: id, username: username},
+ screenType,
+ );
+ navigation.push('IndividualMoment', {
+ moment: object,
+ userXId: id,
+ screenType,
+ });
+ break;
default:
break;
}
};
const handleAcceptRequest = async () => {
- await dispatch(acceptFriendRequest({id, username, first_name, last_name}));
+ await dispatch(
+ acceptFriendRequest({id, username, first_name, last_name, thumbnail_url}),
+ );
await dispatch(updateUserXFriends(id, state));
dispatch(loadUserNotifications());
};
@@ -118,48 +209,57 @@ const Notification: React.FC<NotificationProps> = (props) => {
dispatch(loadUserNotifications());
};
- return (
- <>
- <TouchableWithoutFeedback
- style={[styles.container, {backgroundColor}]}
- onPress={onNotificationTap}>
- <View style={styles.avatarContainer}>
- <Image
- style={styles.avatar}
- source={
- avatar
- ? {uri: avatar, cache: 'only-if-cached'}
- : require('../../assets/images/avatar-placeholder.png')
- }
+ const renderContent = () => (
+ <TouchableWithoutFeedback
+ style={styles.container}
+ onPress={onNotificationTap}>
+ <View style={styles.avatarContainer}>
+ <Image
+ style={styles.avatar}
+ source={
+ avatar
+ ? {uri: avatar}
+ : require('../../assets/images/avatar-placeholder.png')
+ }
+ />
+ </View>
+ <View style={styles.contentContainer}>
+ <Text style={styles.actorName}>
+ {first_name} {last_name}
+ </Text>
+ <Text>{verbage}</Text>
+ </View>
+ {notification_type === 'FRD_REQ' && (
+ <View style={styles.buttonsContainer}>
+ <AcceptDeclineButtons
+ requester={{id, username, first_name, last_name}}
+ onAccept={handleAcceptRequest}
+ onReject={handleDeclineFriendRequest}
/>
</View>
- <View style={styles.contentContainer}>
- <Text style={styles.actorName}>
- {first_name} {last_name}
- </Text>
- <Text>{verbage}</Text>
- </View>
- {notification_type === 'FRD_REQ' && (
- <View style={styles.buttonsContainer}>
- <AcceptDeclineButtons
- requester={{id, username, first_name, last_name}}
- onAccept={handleAcceptRequest}
- onReject={handleDeclineFriendRequest}
- />
- </View>
- )}
- {notification_type === 'CMT' && notification_object && (
+ )}
+ {(notification_type === 'CMT' ||
+ notification_type === 'MOM_3+' ||
+ notification_type === 'MOM_FRIEND') &&
+ notification_object && (
<Image style={styles.moment} source={{uri: momentURI}} />
)}
- </TouchableWithoutFeedback>
- </>
+ </TouchableWithoutFeedback>
+ );
+
+ return unread ? (
+ <LinearGradient colors={BACKGROUND_GRADIENT_MAP[2]} useAngle angle={90}>
+ {renderContent()}
+ </LinearGradient>
+ ) : (
+ renderContent()
);
};
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
- height: SCREEN_HEIGHT / 10,
+ height: Math.round(SCREEN_HEIGHT / 10),
flex: 1,
alignItems: 'center',
},