diff options
author | Brian Kim <brian@tagg.id> | 2021-06-09 09:24:00 +0900 |
---|---|---|
committer | Brian Kim <brian@tagg.id> | 2021-06-09 09:24:00 +0900 |
commit | 2ddd29120980ebced560dac09bbe270dc4aee0d1 (patch) | |
tree | 9a0676d47e548e1f3c25e5c166cbd8941c5a80f9 /src | |
parent | 2f66fec878e9bba15ac7f2397820bb48d3f167bb (diff) |
Create separate pill component
Diffstat (limited to 'src')
-rw-r--r-- | src/components/notifications/NotificationPill.tsx | 202 | ||||
-rw-r--r-- | src/components/notifications/index.ts | 1 | ||||
-rw-r--r-- | src/routes/tabs/NavigationBar.tsx | 221 | ||||
-rw-r--r-- | src/utils/common.ts | 1 |
4 files changed, 211 insertions, 214 deletions
diff --git a/src/components/notifications/NotificationPill.tsx b/src/components/notifications/NotificationPill.tsx new file mode 100644 index 00000000..7017d2e7 --- /dev/null +++ b/src/components/notifications/NotificationPill.tsx @@ -0,0 +1,202 @@ +import React, {useEffect, useState, useRef} from 'react'; +import {Image, StyleSheet, Text, View} from 'react-native'; +import LinearGradient from 'react-native-linear-gradient'; +import {SCREEN_WIDTH, isIPhoneX, numberWithCommas} from '../../utils'; +import { + NOTIFICATION_ICON_GRADIENT, + CHIN_HEIGHT, + NAV_BAR_HEIGHT, +} from '../../constants'; +import {getNotificationsUnreadCount} from '../../services'; +import {normalize} from 'react-native-elements'; +import PillIcon4 from '../../assets/images/Group 479.svg'; + +interface NotificationPillProps { + showIcon: boolean; +} + +export const NotificationPill: React.FC<NotificationPillProps> = ({ + showIcon, +}) => { + const [iconStart, setIconStart] = useState<number[]>([0, -100]); + const [tipStart, setTipStart] = useState<number[]>([0, -100]); + const [notificationSets, setNotificationSets] = useState({}); + const [timeCount, setTimeCount] = useState<boolean>(false); + const [timeOut, setTimeOut] = useState<boolean>(false); + const iconRef = useRef(null); + const tipRef = useRef(null); + const pillTip = require('../../assets/images/purple-tip.png'); + + const navBarPos = 20; + + // If there are notifications, determines the size of the pill + // and sets points for correct placement + useEffect(() => { + setTimeout(() => { + if (iconRef.current) { + iconRef.current.measure( + ( + _fx: number, + _fy: number, + width: number, + height: number, + _px: number, + _py: number, + ) => { + if (tipRef.current) { + tipRef.current.measure( + ( + __fx: number, + __fy: number, + width2: number, + __height: number, + __px: number, + __py: number, + ) => { + const x = SCREEN_WIDTH / 2 - width / 2; + const y = isIPhoneX() + ? CHIN_HEIGHT + NAV_BAR_HEIGHT + navBarPos + : NAV_BAR_HEIGHT + navBarPos; + setIconStart([x, y]); + setTipStart([width / 2 - width2 / 2, height - 1]); + setTimeCount(true); + }, + ); + } + }, + ); + } else { + } + }, 100); + }, [notificationSets, iconRef, tipRef]); + + // Used so that pill disappears after 5 seconds + useEffect(() => { + if (timeCount) { + setTimeout(() => { + setTimeOut(true); + }, 5000); + } + }, [timeCount]); + + // Gets data from backend to check for unreads + useEffect(() => { + const getCount = async () => { + const data = await getNotificationsUnreadCount(); + setTimeout(() => { + setNotificationSets(data); + }, 100); + }; + + getCount(); + }, []); + + return ( + <> + {notificationSets && + Object.keys(notificationSets).length !== 0 && + showIcon && + !timeOut && ( + <View + style={[ + styles.purpleContainer, + {bottom: iconStart[1], left: iconStart[0]}, + ]} + ref={iconRef}> + <LinearGradient + colors={NOTIFICATION_ICON_GRADIENT} + style={styles.iconPurple}> + {notificationSets.CMT && ( + <> + <Image + source={require('../../assets/images/pill-icon-1.png')} + style={styles.indicationIcon} + /> + <Text style={styles.text}> + {numberWithCommas(notificationSets.CMT)} + </Text> + </> + )} + {notificationSets.FR_REQ && ( + <> + <Image + source={require('../../assets/images/pill-icon-2.png')} + style={styles.indicationIcon} + /> + <Text style={styles.text}> + {numberWithCommas(notificationSets.FR_REQ)} + </Text> + </> + )} + {notificationSets.P_VIEW && ( + <> + <Image + source={require('../../assets/images/pill-icon-3.png')} + style={styles.indicationIcon} + /> + <Text style={styles.text}> + {numberWithCommas(notificationSets.P_VIEW)} + </Text> + </> + )} + {notificationSets.MOM_TAG && ( + <> + <PillIcon4 style={styles.indicationIcon} /> + <Text style={styles.text}> + {numberWithCommas(notificationSets.MOM_TAG)} + </Text> + </> + )} + </LinearGradient> + <Image + style={[styles.tip, {top: tipStart[1], left: tipStart[0]}]} + source={pillTip} + ref={tipRef} + /> + </View> + )} + </> + ); +}; + +const styles = StyleSheet.create({ + purpleContainer: { + flex: 1, + justifyContent: 'center', + position: 'absolute', + zIndex: 999, + }, + iconPurple: { + padding: 5, + borderRadius: 15, + flex: 1, + flexDirection: 'row', + alignItems: 'center', + }, + text: { + margin: 2, + color: 'white', + fontSize: normalize(10), + justifyContent: 'center', + alignItems: 'center', + marginRight: 5, + }, + tip: { + position: 'absolute', + zIndex: 999, + height: 12, + flex: 1, + resizeMode: 'contain', + }, + indicationIcon: { + height: 14, + width: 14, + margin: 2, + marginLeft: 5, + }, + svgIndicationIcon: { + height: 14, + width: 14, + margin: 3, + }, +}); diff --git a/src/components/notifications/index.ts b/src/components/notifications/index.ts index 733b56f1..077c26a4 100644 --- a/src/components/notifications/index.ts +++ b/src/components/notifications/index.ts @@ -1,2 +1,3 @@ export {default as Notification} from './Notification'; export {InviteFriendsPrompt} from './NotificationPrompts'; +export {NotificationPill} from './NotificationPill'; diff --git a/src/routes/tabs/NavigationBar.tsx b/src/routes/tabs/NavigationBar.tsx index e962c8da..c3a42739 100644 --- a/src/routes/tabs/NavigationBar.tsx +++ b/src/routes/tabs/NavigationBar.tsx @@ -1,26 +1,14 @@ import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'; -import React, {Fragment, useEffect, useState, useRef} from 'react'; -import {Image, StyleSheet, Text, View} from 'react-native'; -import LinearGradient from 'react-native-linear-gradient'; +import React, {Fragment, useEffect, useState} from 'react'; import {useSelector} from 'react-redux'; import {NavigationIcon} from '../../components'; import {NO_NOTIFICATIONS} from '../../store/initialStates'; import {RootState} from '../../store/rootReducer'; -import { - getNotificationsUnreadCount, - setNotificationsReadDate, -} from '../../services'; +import {setNotificationsReadDate} from '../../services'; import {ScreenType} from '../../types'; -import {haveUnreadNotifications, SCREEN_WIDTH, isIPhoneX} from '../../utils'; +import {haveUnreadNotifications} from '../../utils'; import MainStackScreen from '../main/MainStackScreen'; -import { - NOTIFICATION_ICON_GRADIENT, - CHIN_HEIGHT, - NAV_BAR_HEIGHT, -} from '../../constants'; -import {normalize} from 'react-native-elements'; -import {numberWithCommas} from '../../utils'; -import PillIcon4 from '../../assets/images/Group 479.svg'; +import {NotificationPill} from '../../components/notifications'; const Tabs = createBottomTabNavigator(); @@ -32,17 +20,8 @@ const NavigationBar: React.FC = () => { const {notifications: {notifications} = NO_NOTIFICATIONS} = useSelector( (state: RootState) => state, ); + // Triggered if user clicks on Notifications page to close the pill const [showIcon, setShowIcon] = useState<boolean>(true); - const [iconStart, setIconStart] = useState<number[]>([0, -100]); - const [tipStart, setTipStart] = useState<number[]>([0, -100]); - const [notificationSets, setNotificationSets] = useState({}); - const [timeCount, setTimeCount] = useState<boolean>(false); - const [timeOut, setTimeOut] = useState<boolean>(false); - const iconRef = useRef(null); - const tipRef = useRef(null); - const pillTip = require('../../assets/images/purple-tip.png'); - - const navBarPos = 20; const [unreadNotificationsPresent, setUnreadNotificationsPresent] = useState<boolean>(false); @@ -58,132 +37,9 @@ const NavigationBar: React.FC = () => { determine(); }, [notifications]); - // If there are notifications, determines the size of the pill - // and sets points for correct placement - useEffect(() => { - setTimeout(() => { - if (iconRef.current) { - iconRef.current.measure( - ( - _fx: number, - _fy: number, - width: number, - height: number, - _px: number, - _py: number, - ) => { - if (tipRef.current) { - tipRef.current.measure( - ( - __fx: number, - __fy: number, - width2: number, - __height: number, - __px: number, - __py: number, - ) => { - const x = SCREEN_WIDTH / 2 - width / 2; - const y = isIPhoneX() - ? CHIN_HEIGHT + NAV_BAR_HEIGHT + navBarPos - : NAV_BAR_HEIGHT + navBarPos; - setIconStart([x, y]); - setTipStart([width / 2 - width2 / 2, height - 1]); - setTimeCount(true); - }, - ); - } - }, - ); - } else { - } - }, 100); - }, [notificationSets, iconRef, tipRef]); - - // Used so that pill disappears after 5 seconds - useEffect(() => { - if (timeCount) { - setTimeout(() => { - setTimeOut(true); - }, 5000); - } - }, [timeCount]); - - // Gets data from backend to check for unreads - useEffect(() => { - const getCount = async () => { - const data = await getNotificationsUnreadCount(); - setTimeout(() => { - setNotificationSets(data); - }, 100); - }; - - getCount(); - }, []); - return ( <> - {notificationSets && - Object.keys(notificationSets).length !== 0 && - showIcon && - !timeOut && ( - <View - style={[ - styles.purpleContainer, - {bottom: iconStart[1], left: iconStart[0]}, - ]} - ref={iconRef}> - <LinearGradient - colors={NOTIFICATION_ICON_GRADIENT} - style={styles.iconPurple}> - {notificationSets.CMT && ( - <> - <Image - source={require('../../assets/images/pill-icon-1.png')} - style={styles.indicationIcon} - /> - <Text style={styles.text}> - {numberWithCommas(notificationSets.CMT)} - </Text> - </> - )} - {notificationSets.FR_REQ && ( - <> - <Image - source={require('../../assets/images/pill-icon-2.png')} - style={styles.indicationIcon} - /> - <Text style={styles.text}> - {numberWithCommas(notificationSets.FR_REQ)} - </Text> - </> - )} - {notificationSets.P_VIEW && ( - <> - <Image - source={require('../../assets/images/pill-icon-3.png')} - style={styles.indicationIcon} - /> - <Text style={styles.text}> - {numberWithCommas(notificationSets.P_VIEW)} - </Text> - </> - )} - {notificationSets.MOM_TAG && ( - <> - <PillIcon4 style={styles.indicationIcon} /> - <Text style={styles.text}> - {numberWithCommas(notificationSets.MOM_TAG)} - </Text> - </> - )} - </LinearGradient> - <Image - style={[styles.tip, {top: tipStart[1], left: tipStart[0]}]} - source={pillTip} - ref={tipRef} - /> - </View> - )} + <NotificationPill showIcon={showIcon} /> <Tabs.Navigator screenOptions={({route}) => ({ tabBarIcon: ({focused}) => { @@ -233,23 +89,11 @@ const NavigationBar: React.FC = () => { name="SuggestedPeople" component={MainStackScreen} initialParams={{screenType: ScreenType.SuggestedPeople}} - // Added these to as a way to close pill when on - // notification page - listeners={{ - tabPress: (_) => { - setShowIcon(true); - }, - }} /> <Tabs.Screen name="Search" component={MainStackScreen} initialParams={{screenType: ScreenType.Search}} - listeners={{ - tabPress: (_) => { - setShowIcon(true); - }, - }} /> <Tabs.Screen name="Notifications" @@ -257,6 +101,7 @@ const NavigationBar: React.FC = () => { initialParams={{screenType: ScreenType.Notifications}} listeners={{ tabPress: (_) => { + // Closes the pill once this screen has been opened setShowIcon(false); // Updates backend's date of reading notifications setNotificationsReadDate(); @@ -267,67 +112,15 @@ const NavigationBar: React.FC = () => { name="Chat" component={MainStackScreen} initialParams={{screenType: ScreenType.Chat}} - listeners={{ - tabPress: (_) => { - setShowIcon(true); - }, - }} /> <Tabs.Screen name="Profile" component={MainStackScreen} initialParams={{screenType: ScreenType.Profile}} - listeners={{ - tabPress: (_) => { - setShowIcon(true); - }, - }} /> </Tabs.Navigator> </> ); }; -const styles = StyleSheet.create({ - purpleContainer: { - flex: 1, - justifyContent: 'center', - position: 'absolute', - zIndex: 999, - }, - iconPurple: { - padding: 5, - borderRadius: 15, - flex: 1, - flexDirection: 'row', - alignItems: 'center', - }, - text: { - margin: 2, - color: 'white', - fontSize: normalize(10), - justifyContent: 'center', - alignItems: 'center', - marginRight: 5, - }, - tip: { - position: 'absolute', - zIndex: 999, - height: 12, - flex: 1, - resizeMode: 'contain', - }, - indicationIcon: { - height: 14, - width: 14, - margin: 2, - marginLeft: 5, - }, - svgIndicationIcon: { - height: 14, - width: 14, - margin: 3, - }, -}); - export default NavigationBar; diff --git a/src/utils/common.ts b/src/utils/common.ts index 049dae90..cb0bd62d 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -198,6 +198,7 @@ export const validateImageLink = async (url: string | undefined) => { }); }; +// Documentation: https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript export const numberWithCommas = (digits: number) => { return digits.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); }; |