aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Kim <brian@tagg.id>2021-06-09 09:24:00 +0900
committerBrian Kim <brian@tagg.id>2021-06-09 09:24:00 +0900
commit2ddd29120980ebced560dac09bbe270dc4aee0d1 (patch)
tree9a0676d47e548e1f3c25e5c166cbd8941c5a80f9
parent2f66fec878e9bba15ac7f2397820bb48d3f167bb (diff)
Create separate pill component
-rw-r--r--src/components/notifications/NotificationPill.tsx202
-rw-r--r--src/components/notifications/index.ts1
-rw-r--r--src/routes/tabs/NavigationBar.tsx221
-rw-r--r--src/utils/common.ts1
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, ',');
};