diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-04-05 18:56:02 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-05 18:56:02 -0500 |
commit | ea04c2bd330dc5b46d6f9df0d7d4619bbd8f56d0 (patch) | |
tree | 870c7d3dbffe1f382cba30b858eaa2b76b31af36 /src/view/shell/Drawer.tsx | |
parent | 8e28d3c6be8e063b6d563b0068cb4fc907ff5df0 (diff) | |
download | voidsky-ea04c2bd330dc5b46d6f9df0d7d4619bbd8f56d0.tar.zst |
Add user invite codes (#393)
* Add mobile UIs for invite codes * Update invite code UIs for web * Finish implementing invite code behaviors (including notifications of invited users) * Bump deps * Update web right nav to use real data; also fix lint
Diffstat (limited to 'src/view/shell/Drawer.tsx')
-rw-r--r-- | src/view/shell/Drawer.tsx | 209 |
1 files changed, 132 insertions, 77 deletions
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', |