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/main/NotificationsScreen.tsx | |
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/main/NotificationsScreen.tsx')
-rw-r--r-- | src/screens/main/NotificationsScreen.tsx | 167 |
1 files changed, 167 insertions, 0 deletions
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; |