about summary refs log tree commit diff
path: root/src/view/shell/bottom-bar
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/shell/bottom-bar')
-rw-r--r--src/view/shell/bottom-bar/BottomBar.tsx186
-rw-r--r--src/view/shell/bottom-bar/BottomBarStyles.tsx3
-rw-r--r--src/view/shell/bottom-bar/BottomBarWeb.tsx77
3 files changed, 149 insertions, 117 deletions
diff --git a/src/view/shell/bottom-bar/BottomBar.tsx b/src/view/shell/bottom-bar/BottomBar.tsx
index d360ceead..746b4d123 100644
--- a/src/view/shell/bottom-bar/BottomBar.tsx
+++ b/src/view/shell/bottom-bar/BottomBar.tsx
@@ -1,12 +1,11 @@
 import React, {ComponentProps} from 'react'
 import {GestureResponderEvent, TouchableOpacity, View} from 'react-native'
 import Animated from 'react-native-reanimated'
+import {useQueryClient} from '@tanstack/react-query'
 import {StackActions} from '@react-navigation/native'
 import {BottomTabBarProps} from '@react-navigation/bottom-tabs'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
-import {observer} from 'mobx-react-lite'
 import {Text} from 'view/com/util/text/Text'
-import {useStores} from 'state/index'
 import {useAnalytics} from 'lib/analytics/analytics'
 import {clamp} from 'lib/numbers'
 import {
@@ -24,21 +23,33 @@ import {styles} from './BottomBarStyles'
 import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
 import {useNavigationTabState} from 'lib/hooks/useNavigationTabState'
 import {UserAvatar} from 'view/com/util/UserAvatar'
+import {useLingui} from '@lingui/react'
+import {msg} from '@lingui/macro'
+import {useModalControls} from '#/state/modals'
+import {useShellLayout} from '#/state/shell/shell-layout'
+import {useUnreadNotifications} from '#/state/queries/notifications/unread'
+import {emitSoftReset} from '#/state/events'
+import {useSession} from '#/state/session'
+import {useProfileQuery} from '#/state/queries/profile'
+import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
+import {truncateAndInvalidate} from '#/state/queries/util'
 
 type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds'
 
-export const BottomBar = observer(function BottomBarImpl({
-  navigation,
-}: BottomTabBarProps) {
-  const store = useStores()
+export function BottomBar({navigation}: BottomTabBarProps) {
+  const {openModal} = useModalControls()
+  const {hasSession, currentAccount} = useSession()
   const pal = usePalette('default')
+  const {_} = useLingui()
+  const queryClient = useQueryClient()
   const safeAreaInsets = useSafeAreaInsets()
   const {track} = useAnalytics()
+  const {footerHeight} = useShellLayout()
   const {isAtHome, isAtSearch, isAtFeeds, isAtNotifications, isAtMyProfile} =
     useNavigationTabState()
-
-  const {minimalShellMode, footerMinimalShellTransform} = useMinimalShellMode()
-  const {notifications} = store.me
+  const numUnreadNotifications = useUnreadNotifications()
+  const {footerMinimalShellTransform} = useMinimalShellMode()
+  const {data: profile} = useProfileQuery({did: currentAccount?.did})
 
   const onPressTab = React.useCallback(
     (tab: TabOptions) => {
@@ -46,14 +57,18 @@ export const BottomBar = observer(function BottomBarImpl({
       const state = navigation.getState()
       const tabState = getTabState(state, tab)
       if (tabState === TabState.InsideAtRoot) {
-        store.emitScreenSoftReset()
+        emitSoftReset()
       } else if (tabState === TabState.Inside) {
         navigation.dispatch(StackActions.popToTop())
       } else {
+        if (tab === 'Notifications') {
+          // fetch new notifs on view
+          truncateAndInvalidate(queryClient, NOTIFS_RQKEY())
+        }
         navigation.navigate(`${tab}Tab`)
       }
     },
-    [store, track, navigation],
+    [track, navigation, queryClient],
   )
   const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])
   const onPressSearch = React.useCallback(
@@ -72,8 +87,8 @@ export const BottomBar = observer(function BottomBarImpl({
     onPressTab('MyProfile')
   }, [onPressTab])
   const onLongPressProfile = React.useCallback(() => {
-    store.shell.openModal({name: 'switch-account'})
-  }, [store])
+    openModal({name: 'switch-account'})
+  }, [openModal])
 
   return (
     <Animated.View
@@ -83,8 +98,10 @@ export const BottomBar = observer(function BottomBarImpl({
         pal.border,
         {paddingBottom: clamp(safeAreaInsets.bottom, 15, 30)},
         footerMinimalShellTransform,
-        minimalShellMode && styles.disabled,
-      ]}>
+      ]}
+      onLayout={e => {
+        footerHeight.value = e.nativeEvent.layout.height
+      }}>
       <Btn
         testID="bottomBarHomeBtn"
         icon={
@@ -104,7 +121,7 @@ export const BottomBar = observer(function BottomBarImpl({
         }
         onPress={onPressHome}
         accessibilityRole="tab"
-        accessibilityLabel="Home"
+        accessibilityLabel={_(msg`Home`)}
         accessibilityHint=""
       />
       <Btn
@@ -126,7 +143,7 @@ export const BottomBar = observer(function BottomBarImpl({
         }
         onPress={onPressSearch}
         accessibilityRole="search"
-        accessibilityLabel="Search"
+        accessibilityLabel={_(msg`Search`)}
         accessibilityHint=""
       />
       <Btn
@@ -148,78 +165,83 @@ export const BottomBar = observer(function BottomBarImpl({
         }
         onPress={onPressFeeds}
         accessibilityRole="tab"
-        accessibilityLabel="Feeds"
+        accessibilityLabel={_(msg`Feeds`)}
         accessibilityHint=""
       />
-      <Btn
-        testID="bottomBarNotificationsBtn"
-        icon={
-          isAtNotifications ? (
-            <BellIconSolid
-              size={24}
-              strokeWidth={1.9}
-              style={[styles.ctrlIcon, pal.text, styles.bellIcon]}
-            />
-          ) : (
-            <BellIcon
-              size={24}
-              strokeWidth={1.9}
-              style={[styles.ctrlIcon, pal.text, styles.bellIcon]}
-            />
-          )
-        }
-        onPress={onPressNotifications}
-        notificationCount={notifications.unreadCountLabel}
-        accessible={true}
-        accessibilityRole="tab"
-        accessibilityLabel="Notifications"
-        accessibilityHint={
-          notifications.unreadCountLabel === ''
-            ? ''
-            : `${notifications.unreadCountLabel} unread`
-        }
-      />
-      <Btn
-        testID="bottomBarProfileBtn"
-        icon={
-          <View style={styles.ctrlIconSizingWrapper}>
-            {isAtMyProfile ? (
-              <View
-                style={[
-                  styles.ctrlIcon,
-                  pal.text,
-                  styles.profileIcon,
-                  styles.onProfile,
-                  {borderColor: pal.text.color},
-                ]}>
-                <UserAvatar
-                  avatar={store.me.avatar}
-                  size={27}
-                  // See https://github.com/bluesky-social/social-app/pull/1801:
-                  usePlainRNImage={true}
+
+      {hasSession && (
+        <>
+          <Btn
+            testID="bottomBarNotificationsBtn"
+            icon={
+              isAtNotifications ? (
+                <BellIconSolid
+                  size={24}
+                  strokeWidth={1.9}
+                  style={[styles.ctrlIcon, pal.text, styles.bellIcon]}
                 />
-              </View>
-            ) : (
-              <View style={[styles.ctrlIcon, pal.text, styles.profileIcon]}>
-                <UserAvatar
-                  avatar={store.me.avatar}
-                  size={28}
-                  // See https://github.com/bluesky-social/social-app/pull/1801:
-                  usePlainRNImage={true}
+              ) : (
+                <BellIcon
+                  size={24}
+                  strokeWidth={1.9}
+                  style={[styles.ctrlIcon, pal.text, styles.bellIcon]}
                 />
+              )
+            }
+            onPress={onPressNotifications}
+            notificationCount={numUnreadNotifications}
+            accessible={true}
+            accessibilityRole="tab"
+            accessibilityLabel={_(msg`Notifications`)}
+            accessibilityHint={
+              numUnreadNotifications === ''
+                ? ''
+                : `${numUnreadNotifications} unread`
+            }
+          />
+          <Btn
+            testID="bottomBarProfileBtn"
+            icon={
+              <View style={styles.ctrlIconSizingWrapper}>
+                {isAtMyProfile ? (
+                  <View
+                    style={[
+                      styles.ctrlIcon,
+                      pal.text,
+                      styles.profileIcon,
+                      styles.onProfile,
+                      {borderColor: pal.text.color},
+                    ]}>
+                    <UserAvatar
+                      avatar={profile?.avatar}
+                      size={27}
+                      // See https://github.com/bluesky-social/social-app/pull/1801:
+                      usePlainRNImage={true}
+                    />
+                  </View>
+                ) : (
+                  <View style={[styles.ctrlIcon, pal.text, styles.profileIcon]}>
+                    <UserAvatar
+                      avatar={profile?.avatar}
+                      size={28}
+                      // See https://github.com/bluesky-social/social-app/pull/1801:
+                      usePlainRNImage={true}
+                    />
+                  </View>
+                )}
               </View>
-            )}
-          </View>
-        }
-        onPress={onPressProfile}
-        onLongPress={onLongPressProfile}
-        accessibilityRole="tab"
-        accessibilityLabel="Profile"
-        accessibilityHint=""
-      />
+            }
+            onPress={onPressProfile}
+            onLongPress={onLongPressProfile}
+            accessibilityRole="tab"
+            accessibilityLabel={_(msg`Profile`)}
+            accessibilityHint=""
+          />
+        </>
+      )}
     </Animated.View>
   )
-})
+}
 
 interface BtnProps
   extends Pick<
diff --git a/src/view/shell/bottom-bar/BottomBarStyles.tsx b/src/view/shell/bottom-bar/BottomBarStyles.tsx
index c175ed848..ae9381440 100644
--- a/src/view/shell/bottom-bar/BottomBarStyles.tsx
+++ b/src/view/shell/bottom-bar/BottomBarStyles.tsx
@@ -65,7 +65,4 @@ export const styles = StyleSheet.create({
     borderWidth: 1,
     borderRadius: 100,
   },
-  disabled: {
-    pointerEvents: 'none',
-  },
 })
diff --git a/src/view/shell/bottom-bar/BottomBarWeb.tsx b/src/view/shell/bottom-bar/BottomBarWeb.tsx
index ebcc527a1..3a60bd3b1 100644
--- a/src/view/shell/bottom-bar/BottomBarWeb.tsx
+++ b/src/view/shell/bottom-bar/BottomBarWeb.tsx
@@ -1,6 +1,4 @@
 import React from 'react'
-import {observer} from 'mobx-react-lite'
-import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useNavigationState} from '@react-navigation/native'
 import Animated from 'react-native-reanimated'
@@ -23,9 +21,10 @@ import {Link} from 'view/com/util/Link'
 import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
 import {makeProfileLink} from 'lib/routes/links'
 import {CommonNavigatorParams} from 'lib/routes/types'
+import {useSession} from '#/state/session'
 
-export const BottomBarWeb = observer(function BottomBarWebImpl() {
-  const store = useStores()
+export function BottomBarWeb() {
+  const {hasSession, currentAccount} = useSession()
   const pal = usePalette('default')
   const safeAreaInsets = useSafeAreaInsets()
   const {footerMinimalShellTransform} = useMinimalShellMode()
@@ -76,55 +75,69 @@ export const BottomBarWeb = observer(function BottomBarWebImpl() {
           )
         }}
       </NavItem>
-      <NavItem routeName="Notifications" href="/notifications">
-        {({isActive}) => {
-          const Icon = isActive ? BellIconSolid : BellIcon
-          return (
-            <Icon
-              size={24}
-              strokeWidth={1.9}
-              style={[styles.ctrlIcon, pal.text, styles.bellIcon]}
-            />
-          )
-        }}
-      </NavItem>
-      <NavItem routeName="Profile" href={makeProfileLink(store.me)}>
-        {({isActive}) => {
-          const Icon = isActive ? UserIconSolid : UserIcon
-          return (
-            <Icon
-              size={28}
-              strokeWidth={1.5}
-              style={[styles.ctrlIcon, pal.text, styles.profileIcon]}
-            />
-          )
-        }}
-      </NavItem>
+
+      {hasSession && (
+        <>
+          <NavItem routeName="Notifications" href="/notifications">
+            {({isActive}) => {
+              const Icon = isActive ? BellIconSolid : BellIcon
+              return (
+                <Icon
+                  size={24}
+                  strokeWidth={1.9}
+                  style={[styles.ctrlIcon, pal.text, styles.bellIcon]}
+                />
+              )
+            }}
+          </NavItem>
+          <NavItem
+            routeName="Profile"
+            href={
+              currentAccount
+                ? makeProfileLink({
+                    did: currentAccount.did,
+                    handle: currentAccount.handle,
+                  })
+                : '/'
+            }>
+            {({isActive}) => {
+              const Icon = isActive ? UserIconSolid : UserIcon
+              return (
+                <Icon
+                  size={28}
+                  strokeWidth={1.5}
+                  style={[styles.ctrlIcon, pal.text, styles.profileIcon]}
+                />
+              )
+            }}
+          </NavItem>
+        </>
+      )}
     </Animated.View>
   )
-})
+}
 
 const NavItem: React.FC<{
   children: (props: {isActive: boolean}) => React.ReactChild
   href: string
   routeName: string
 }> = ({children, href, routeName}) => {
+  const {currentAccount} = useSession()
   const currentRoute = useNavigationState(state => {
     if (!state) {
       return {name: 'Home'}
     }
     return getCurrentRoute(state)
   })
-  const store = useStores()
   const isActive =
     currentRoute.name === 'Profile'
       ? isTab(currentRoute.name, routeName) &&
         (currentRoute.params as CommonNavigatorParams['Profile']).name ===
-          store.me.handle
+          currentAccount?.handle
       : isTab(currentRoute.name, routeName)
 
   return (
-    <Link href={href} style={styles.ctrl}>
+    <Link href={href} style={styles.ctrl} navigationAction="navigate">
       {children({isActive})}
     </Link>
   )