diff options
| author | Ivan Chen <ivan@thetaggid.com> | 2020-12-29 20:21:24 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-29 20:21:24 -0500 |
| commit | bd2f89805d0bb1c2f1d08fe8d91099aa4f109d35 (patch) | |
| tree | ac7219e034a0c4035096c6df8dbe6b92446b5111 /src/screens | |
| parent | ec478d4981c726856485b49b49ac33b0d9e6a903 (diff) | |
[TMA-461] Notifications Screen (#151)
* renamed ProfileStack to MainStack, created initial notifications data type
* cleaned up code
* added notifications to redux
* finished sectioned list
* updated types to make more sense
* finished sectioned notifications by date
* updated notification type and tested mock backend integration
* finished read or unread logic
* minor changes
* another minor fix
* finished integration
* moved stuff
* added ability to navigate to user profile
Co-authored-by: Husam Salhab <47015061+hsalhab@users.noreply.github.com>
Diffstat (limited to 'src/screens')
| -rw-r--r-- | src/screens/main/Notifications.tsx | 13 | ||||
| -rw-r--r-- | src/screens/main/NotificationsScreen.tsx | 167 | ||||
| -rw-r--r-- | src/screens/main/index.ts | 2 | ||||
| -rw-r--r-- | src/screens/profile/IndividualMoment.tsx | 2 | ||||
| -rw-r--r-- | src/screens/profile/MomentCommentsScreen.tsx | 2 |
5 files changed, 170 insertions, 16 deletions
diff --git a/src/screens/main/Notifications.tsx b/src/screens/main/Notifications.tsx deleted file mode 100644 index ca8c41c3..00000000 --- a/src/screens/main/Notifications.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import {ComingSoon} from '../../components'; - -/** - * Navigation Screen for displaying other users' - * actions on the logged in user's posts - */ - -const Notifications: React.FC = () => { - return <ComingSoon />; -}; - -export default Notifications; diff --git a/src/screens/main/NotificationsScreen.tsx b/src/screens/main/NotificationsScreen.tsx new file mode 100644 index 00000000..2343215f --- /dev/null +++ b/src/screens/main/NotificationsScreen.tsx @@ -0,0 +1,167 @@ +import AsyncStorage from '@react-native-community/async-storage'; +import moment from 'moment'; +import React, {useCallback, useEffect, useState} from 'react'; +import { + RefreshControl, + SectionList, + StyleSheet, + Text, + View, +} from 'react-native'; +import {SafeAreaView} from 'react-native-safe-area-context'; +import {useDispatch, useSelector} from 'react-redux'; +import {Notification} from '../../components/notifications'; +import {loadUserNotifications} from '../../store/actions'; +import {RootState} from '../../store/rootReducer'; +import {NotificationType, ScreenType} from '../../types'; +import {getDateAge, SCREEN_HEIGHT} from '../../utils'; + +const NotificationsScreen: React.FC = () => { + const [refreshing, setRefreshing] = useState(false); + // used for figuring out which ones are unread + const [lastViewed, setLastViewed] = useState<moment.Moment | undefined>( + undefined, + ); + const {notifications} = useSelector( + (state: RootState) => state.notifications, + ); + const [sectionedNotifications, setSectionedNotifications] = useState< + {title: 'Today' | 'Yesterday' | 'This Week'; data: NotificationType[]}[] + >([]); + + const dispatch = useDispatch(); + + const onRefresh = useCallback(() => { + const refrestState = async () => { + dispatch(loadUserNotifications()); + }; + setRefreshing(true); + refrestState().then(() => { + setRefreshing(false); + }); + }, [dispatch]); + + // handles storing and fetching the "previously viewed" information + useEffect(() => { + const getAndUpdateLastViewed = async () => { + const key = 'notificationLastViewed'; + const previousLastViewed = await AsyncStorage.getItem(key); + setLastViewed( + previousLastViewed == null + ? moment.unix(0) + : moment(previousLastViewed), + ); + await AsyncStorage.setItem(key, moment().toString()); + }; + getAndUpdateLastViewed(); + }, [notifications]); + + // handles sectioning notifications to "date age" + // mark notifications as read or unread + useEffect(() => { + const sortedNotifications = (notifications ?? []) + .slice() + .sort((a, b) => (a.timestamp < b.timestamp ? 1 : -1)); + let todays = []; + let yesterdays = []; + let thisWeeks = []; + for (const n of sortedNotifications) { + const notificationDate = moment(n.timestamp); + const dateAge = getDateAge(notificationDate); + if (dateAge === 'unknown') { + continue; + } + const unread = lastViewed ? lastViewed.diff(notificationDate) < 0 : false; + const newN = {...n, unread}; + switch (dateAge) { + case 'today': + todays.push(newN); + continue; + case 'yesterday': + yesterdays.push(newN); + continue; + case 'thisWeek': + thisWeeks.push(newN); + continue; + default: + continue; + } + } + setSectionedNotifications([ + { + title: 'Today', + data: todays, + }, + { + title: 'Yesterday', + data: yesterdays, + }, + { + title: 'This Week', + data: thisWeeks, + }, + ]); + }, [lastViewed, notifications]); + + const renderNotification = ({item}: {item: NotificationType}) => ( + <Notification item={item} screenType={ScreenType.Notifications} /> + ); + + const renderSectionHeader = ({section: {title}}) => ( + <View style={styles.sectionHeaderContainer}> + <Text style={styles.sectionHeader}>{title}</Text> + </View> + ); + + return ( + <SafeAreaView> + <View style={styles.header}> + <Text style={styles.headerText}>Notifications</Text> + <View style={styles.underline} /> + </View> + <SectionList + contentContainerStyle={styles.container} + sections={sectionedNotifications} + keyExtractor={(item, index) => index.toString()} + renderItem={renderNotification} + renderSectionHeader={renderSectionHeader} + refreshControl={ + <RefreshControl refreshing={refreshing} onRefresh={onRefresh} /> + } + /> + </SafeAreaView> + ); +}; + +const styles = StyleSheet.create({ + header: { + marginLeft: '5%', + marginTop: '5%', + alignSelf: 'flex-start', + flexDirection: 'column', + }, + headerText: { + fontWeight: 'bold', + fontSize: 16, + }, + underline: { + borderWidth: 2, + borderColor: '#8F01FF', + }, + container: { + paddingBottom: '20%', + minHeight: (SCREEN_HEIGHT * 8) / 10, + }, + sectionHeaderContainer: { + width: '100%', + backgroundColor: '#f3f2f2', + }, + sectionHeader: { + marginLeft: '5%', + marginTop: '5%', + marginBottom: '2%', + fontSize: 16, + }, +}); + +export default NotificationsScreen; diff --git a/src/screens/main/index.ts b/src/screens/main/index.ts index b15f76da..a5a723d7 100644 --- a/src/screens/main/index.ts +++ b/src/screens/main/index.ts @@ -1,3 +1,3 @@ export {default as Home} from './Home'; -export {default as Notifications} from './Notifications'; +export {default as NotificationsScreen} from './NotificationsScreen'; export {default as Upload} from './Upload'; diff --git a/src/screens/profile/IndividualMoment.tsx b/src/screens/profile/IndividualMoment.tsx index 469c648e..91742324 100644 --- a/src/screens/profile/IndividualMoment.tsx +++ b/src/screens/profile/IndividualMoment.tsx @@ -4,7 +4,7 @@ import {StackNavigationProp} from '@react-navigation/stack'; import React from 'react'; import {FlatList, StyleSheet, View} from 'react-native'; import {useSelector} from 'react-redux'; -import {ProfileStackParams} from 'src/routes/profile/ProfileStack'; +import {ProfileStackParams} from 'src/routes/main/ProfileStack'; import { IndividualMomentTitleBar, MomentPostContent, diff --git a/src/screens/profile/MomentCommentsScreen.tsx b/src/screens/profile/MomentCommentsScreen.tsx index 2cc809a3..ebe4da28 100644 --- a/src/screens/profile/MomentCommentsScreen.tsx +++ b/src/screens/profile/MomentCommentsScreen.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import {RouteProp, useNavigation} from '@react-navigation/native'; -import {ProfileStackParams} from '../../routes/profile'; +import {ProfileStackParams} from '../../routes/main'; import {CenteredView, CommentTile} from '../../components'; import {CommentType} from '../../types'; import {ScrollView, StyleSheet, Text, View} from 'react-native'; |
