diff options
Diffstat (limited to 'src/view/shell')
-rw-r--r-- | src/view/shell/BottomBar.tsx | 4 | ||||
-rw-r--r-- | src/view/shell/Drawer.tsx | 209 | ||||
-rw-r--r-- | src/view/shell/desktop/LeftNav.tsx | 4 | ||||
-rw-r--r-- | src/view/shell/desktop/RightNav.tsx | 46 |
4 files changed, 183 insertions, 80 deletions
diff --git a/src/view/shell/BottomBar.tsx b/src/view/shell/BottomBar.tsx index e46eeb991..b01366b2b 100644 --- a/src/view/shell/BottomBar.tsx +++ b/src/view/shell/BottomBar.tsx @@ -167,7 +167,9 @@ export const BottomBar = observer(({navigation}: BottomTabBarProps) => { ) } onPress={onPressNotifications} - notificationCount={store.me.notifications.unreadCount} + notificationCount={ + store.me.notifications.unreadCount + store.invitedUsers.numNotifs + } /> <Btn testID="bottomBarProfileBtn" diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx index ccf64c0e6..ebadb2126 100644 --- a/src/view/shell/Drawer.tsx +++ b/src/view/shell/Drawer.tsx @@ -103,63 +103,19 @@ export const DrawerContent = observer(() => { store.shell.closeDrawer() }, [navigation, track, store.shell]) - const onPressFeedback = () => { + const onPressFeedback = React.useCallback(() => { track('Menu:FeedbackClicked') Linking.openURL(FEEDBACK_FORM_URL) - } + }, [track]) + + const onDarkmodePress = React.useCallback(() => { + track('Menu:ItemClicked', {url: '#darkmode'}) + store.shell.setDarkMode(!store.shell.darkMode) + }, [track, store]) // rendering // = - const MenuItem = ({ - icon, - label, - count, - bold, - onPress, - }: { - icon: JSX.Element - label: string - count?: number - bold?: boolean - onPress: () => void - }) => ( - <TouchableOpacity - testID={`menuItemButton-${label}`} - style={styles.menuItem} - onPress={onPress}> - <View style={[styles.menuItemIconWrapper]}> - {icon} - {count ? ( - <View - style={[ - styles.menuItemCount, - count > 99 - ? styles.menuItemCountHundreds - : count > 9 - ? styles.menuItemCountTens - : undefined, - ]}> - <Text style={styles.menuItemCountLabel} numberOfLines={1}> - {count > 999 ? `${Math.round(count / 1000)}k` : count} - </Text> - </View> - ) : undefined} - </View> - <Text - type={bold ? '2xl-bold' : '2xl'} - style={[pal.text, s.flex1]} - numberOfLines={1}> - {label} - </Text> - </TouchableOpacity> - ) - - const onDarkmodePress = () => { - track('Menu:ItemClicked', {url: '/darkmode'}) - store.shell.setDarkMode(!store.shell.darkMode) - } - return ( <View testID="drawer" @@ -168,29 +124,34 @@ export const DrawerContent = observer(() => { theme.colorScheme === 'light' ? pal.view : styles.viewDarkMode, ]}> <SafeAreaView style={s.flex1}> - <TouchableOpacity testID="profileCardButton" onPress={onPressProfile}> - <UserAvatar size={80} avatar={store.me.avatar} /> - <Text - type="title-lg" - style={[pal.text, s.bold, styles.profileCardDisplayName]}> - {store.me.displayName || store.me.handle} - </Text> - <Text type="2xl" style={[pal.textLight, styles.profileCardHandle]}> - @{store.me.handle} - </Text> - <Text type="xl" style={[pal.textLight, styles.profileCardFollowers]}> - <Text type="xl-medium" style={pal.text}> - {store.me.followersCount || 0} - </Text>{' '} - {pluralize(store.me.followersCount || 0, 'follower')} ·{' '} - <Text type="xl-medium" style={pal.text}> - {store.me.followsCount || 0} - </Text>{' '} - following - </Text> - </TouchableOpacity> + <View style={styles.main}> + <TouchableOpacity testID="profileCardButton" onPress={onPressProfile}> + <UserAvatar size={80} avatar={store.me.avatar} /> + <Text + type="title-lg" + style={[pal.text, s.bold, styles.profileCardDisplayName]}> + {store.me.displayName || store.me.handle} + </Text> + <Text type="2xl" style={[pal.textLight, styles.profileCardHandle]}> + @{store.me.handle} + </Text> + <Text + type="xl" + style={[pal.textLight, styles.profileCardFollowers]}> + <Text type="xl-medium" style={pal.text}> + {store.me.followersCount || 0} + </Text>{' '} + {pluralize(store.me.followersCount || 0, 'follower')} ·{' '} + <Text type="xl-medium" style={pal.text}> + {store.me.followsCount || 0} + </Text>{' '} + following + </Text> + </TouchableOpacity> + </View> + <InviteCodes /> <View style={s.flex1} /> - <View> + <View style={styles.main}> <MenuItem icon={ isAtSearch ? ( @@ -248,7 +209,9 @@ export const DrawerContent = observer(() => { ) } label="Notifications" - count={store.me.notifications.unreadCount} + count={ + store.me.notifications.unreadCount + store.invitedUsers.numNotifs + } bold={isAtNotifications} onPress={onPressNotifications} /> @@ -315,16 +278,97 @@ export const DrawerContent = observer(() => { ) }) +function MenuItem({ + icon, + label, + count, + bold, + onPress, +}: { + icon: JSX.Element + label: string + count?: number + bold?: boolean + onPress: () => void +}) { + const pal = usePalette('default') + return ( + <TouchableOpacity + testID={`menuItemButton-${label}`} + style={styles.menuItem} + onPress={onPress}> + <View style={[styles.menuItemIconWrapper]}> + {icon} + {count ? ( + <View + style={[ + styles.menuItemCount, + count > 99 + ? styles.menuItemCountHundreds + : count > 9 + ? styles.menuItemCountTens + : undefined, + ]}> + <Text style={styles.menuItemCountLabel} numberOfLines={1}> + {count > 999 ? `${Math.round(count / 1000)}k` : count} + </Text> + </View> + ) : undefined} + </View> + <Text + type={bold ? '2xl-bold' : '2xl'} + style={[pal.text, s.flex1]} + numberOfLines={1}> + {label} + </Text> + </TouchableOpacity> + ) +} + +const InviteCodes = observer(() => { + const {track} = useAnalytics() + const store = useStores() + const pal = usePalette('default') + const onPress = React.useCallback(() => { + track('Menu:ItemClicked', {url: '#invite-codes'}) + store.shell.closeDrawer() + store.shell.openModal({name: 'invite-codes'}) + }, [store, track]) + return ( + <TouchableOpacity + testID="menuItemInviteCodes" + style={[styles.inviteCodes]} + onPress={onPress}> + <FontAwesomeIcon + icon="ticket" + style={[ + styles.inviteCodesIcon, + store.me.invitesAvailable > 0 ? pal.link : pal.textLight, + ]} + size={18} + /> + <Text + type="lg-medium" + style={store.me.invitesAvailable > 0 ? pal.link : pal.textLight}> + {store.me.invitesAvailable} invite{' '} + {pluralize(store.me.invitesAvailable, 'code')} + </Text> + </TouchableOpacity> + ) +}) + const styles = StyleSheet.create({ view: { flex: 1, paddingTop: 20, paddingBottom: 50, - paddingLeft: 20, }, viewDarkMode: { backgroundColor: '#1B1919', }, + main: { + paddingLeft: 20, + }, profileCardDisplayName: { marginTop: 20, @@ -336,7 +380,7 @@ const styles = StyleSheet.create({ }, profileCardFollowers: { marginTop: 16, - paddingRight: 30, + paddingRight: 10, }, menuItem: { @@ -376,11 +420,22 @@ const styles = StyleSheet.create({ color: colors.white, }, + inviteCodes: { + paddingLeft: 22, + paddingVertical: 8, + flexDirection: 'row', + alignItems: 'center', + }, + inviteCodesIcon: { + marginRight: 6, + }, + footer: { flexDirection: 'row', justifyContent: 'space-between', paddingRight: 30, - paddingTop: 80, + paddingTop: 20, + paddingLeft: 20, }, footerBtn: { flexDirection: 'row', diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx index 2c1cb6678..45dd6579f 100644 --- a/src/view/shell/desktop/LeftNav.tsx +++ b/src/view/shell/desktop/LeftNav.tsx @@ -157,7 +157,9 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() { /> <NavItem href="/notifications" - count={store.me.notifications.unreadCount} + count={ + store.me.notifications.unreadCount + store.invitedUsers.numNotifs + } icon={<BellIcon strokeWidth={2} size={24} style={pal.text} />} iconFilled={ <BellIconSolid strokeWidth={1.5} size={24} style={pal.text} /> diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx index 3f196cb70..a344f0fc0 100644 --- a/src/view/shell/desktop/RightNav.tsx +++ b/src/view/shell/desktop/RightNav.tsx @@ -1,6 +1,7 @@ import React from 'react' import {observer} from 'mobx-react-lite' -import {StyleSheet, View} from 'react-native' +import {StyleSheet, TouchableOpacity, View} from 'react-native' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {usePalette} from 'lib/hooks/usePalette' import {DesktopSearch} from './Search' import {Text} from 'view/com/util/text/Text' @@ -8,6 +9,7 @@ import {TextLink} from 'view/com/util/Link' import {FEEDBACK_FORM_URL} from 'lib/constants' import {s} from 'lib/styles' import {useStores} from 'state/index' +import {pluralize} from 'lib/strings/helpers' export const DesktopRightNav = observer(function DesktopRightNav() { const store = useStores() @@ -38,10 +40,40 @@ export const DesktopRightNav = observer(function DesktopRightNav() { /> </View> </View> + <InviteCodes /> </View> ) }) +function InviteCodes() { + const store = useStores() + const pal = usePalette('default') + + const onPress = React.useCallback(() => { + store.shell.openModal({name: 'invite-codes'}) + }, [store]) + return ( + <TouchableOpacity + style={[styles.inviteCodes, pal.border]} + onPress={onPress}> + <FontAwesomeIcon + icon="ticket" + style={[ + styles.inviteCodesIcon, + store.me.invitesAvailable > 0 ? pal.link : pal.textLight, + ]} + size={16} + /> + <Text + type="md-medium" + style={store.me.invitesAvailable > 0 ? pal.link : pal.textLight}> + {store.me.invitesAvailable} invite{' '} + {pluralize(store.me.invitesAvailable, 'code')} available + </Text> + </TouchableOpacity> + ) +} + const styles = StyleSheet.create({ rightNav: { position: 'absolute', @@ -57,4 +89,16 @@ const styles = StyleSheet.create({ messageLine: { marginBottom: 10, }, + + inviteCodes: { + marginTop: 12, + borderTopWidth: 1, + paddingHorizontal: 16, + paddingVertical: 12, + flexDirection: 'row', + alignItems: 'center', + }, + inviteCodesIcon: { + marginRight: 6, + }, }) |