about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--__e2e__/tests/home-screen.test.ts25
-rw-r--r--src/lib/constants.ts4
-rw-r--r--src/state/queries/feed.ts11
-rw-r--r--src/view/com/pager/FeedsTabBar.web.tsx33
-rw-r--r--src/view/com/pager/FeedsTabBarMobile.tsx34
-rw-r--r--src/view/com/pager/PagerWithHeader.tsx2
-rw-r--r--src/view/com/pager/TabBar.tsx2
-rw-r--r--src/view/screens/Profile.tsx1
-rw-r--r--src/view/screens/ProfileFeed.tsx1
-rw-r--r--src/view/shell/desktop/Feeds.tsx2
10 files changed, 101 insertions, 14 deletions
diff --git a/__e2e__/tests/home-screen.test.ts b/__e2e__/tests/home-screen.test.ts
index 7647b55cb..b6cd19195 100644
--- a/__e2e__/tests/home-screen.test.ts
+++ b/__e2e__/tests/home-screen.test.ts
@@ -4,7 +4,7 @@ import {openApp, loginAsAlice, createServer} from '../util'
 
 describe('Home screen', () => {
   beforeAll(async () => {
-    await createServer('?users&follows&posts')
+    await createServer('?users&follows&posts&feeds')
     await openApp({permissions: {notifications: 'YES'}})
   })
 
@@ -13,6 +13,23 @@ describe('Home screen', () => {
     await element(by.id('homeScreenFeedTabs-Following')).tap()
   })
 
+  it('Can go to feeds page using feeds button in tab bar', async () => {
+    await element(by.id('homeScreenFeedTabs-Feeds ✨')).tap()
+    await expect(element(by.text('Discover new feeds'))).toBeVisible()
+  })
+
+  it('Feeds button disappears after pinning a feed', async () => {
+    await element(by.id('bottomBarProfileBtn')).tap()
+    await element(by.id('profilePager-selector')).swipe('left')
+    await element(by.id('profilePager-selector-4')).tap()
+    await element(by.id('feed-alice-favs')).tap()
+    await element(by.id('pinBtn')).tap()
+    await element(by.id('bottomBarHomeBtn')).tap()
+    await expect(
+      element(by.id('homeScreenFeedTabs-Feeds ✨')),
+    ).not.toBeVisible()
+  })
+
   it('Can like posts', async () => {
     const carlaPosts = by.id('feedItem-by-carla.test')
     await expect(
@@ -65,14 +82,14 @@ describe('Home screen', () => {
 
   it('Can swipe between feeds', async () => {
     await element(by.id('homeScreen')).swipe('left', 'fast', 0.75)
-    await expect(element(by.id('whatshotFeedPage'))).toBeVisible()
+    await expect(element(by.id('customFeedPage'))).toBeVisible()
     await element(by.id('homeScreen')).swipe('right', 'fast', 0.75)
     await expect(element(by.id('followingFeedPage'))).toBeVisible()
   })
 
   it('Can tap between feeds', async () => {
-    await element(by.id("homeScreenFeedTabs-What's hot")).tap()
-    await expect(element(by.id('whatshotFeedPage'))).toBeVisible()
+    await element(by.id('homeScreenFeedTabs-alice-favs')).tap()
+    await expect(element(by.id('customFeedPage'))).toBeVisible()
     await element(by.id('homeScreenFeedTabs-Following')).tap()
     await expect(element(by.id('followingFeedPage'))).toBeVisible()
   })
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index f8f651305..aa5983be7 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -116,8 +116,8 @@ export async function DEFAULT_FEEDS(
   } else {
     // production
     return {
-      pinned: [PROD_DEFAULT_FEED('whats-hot')],
-      saved: [PROD_DEFAULT_FEED('whats-hot')],
+      pinned: [],
+      saved: [],
     }
   }
 }
diff --git a/src/state/queries/feed.ts b/src/state/queries/feed.ts
index b5d491a5c..3266b0f6b 100644
--- a/src/state/queries/feed.ts
+++ b/src/state/queries/feed.ts
@@ -246,13 +246,20 @@ const FOLLOWING_FEED_STUB: FeedSourceInfo = {
   likeUri: '',
 }
 
-export function usePinnedFeedsInfos(): FeedSourceInfo[] {
+export function usePinnedFeedsInfos(): {
+  feeds: FeedSourceInfo[]
+  hasPinnedCustomFeedOrList: boolean
+} {
   const queryClient = useQueryClient()
   const [tabs, setTabs] = React.useState<FeedSourceInfo[]>([
     FOLLOWING_FEED_STUB,
   ])
   const {data: preferences} = usePreferencesQuery()
 
+  const hasPinnedCustomFeedOrList = React.useMemo<boolean>(() => {
+    return tabs.some(tab => tab !== FOLLOWING_FEED_STUB)
+  }, [tabs])
+
   React.useEffect(() => {
     if (!preferences?.feeds?.pinned) return
     const uris = preferences.feeds.pinned
@@ -300,5 +307,5 @@ export function usePinnedFeedsInfos(): FeedSourceInfo[] {
     fetchFeedInfo()
   }, [queryClient, setTabs, preferences?.feeds?.pinned])
 
-  return tabs
+  return {feeds: tabs, hasPinnedCustomFeedOrList}
 }
diff --git a/src/view/com/pager/FeedsTabBar.web.tsx b/src/view/com/pager/FeedsTabBar.web.tsx
index fdb4df171..2445d4523 100644
--- a/src/view/com/pager/FeedsTabBar.web.tsx
+++ b/src/view/com/pager/FeedsTabBar.web.tsx
@@ -12,6 +12,9 @@ import {usePinnedFeedsInfos} from '#/state/queries/feed'
 import {useSession} from '#/state/session'
 import {TextLink} from '#/view/com/util/Link'
 import {CenteredView} from '../util/Views'
+import {isWeb} from 'platform/detection'
+import {useNavigation} from '@react-navigation/native'
+import {NavigationProp} from 'lib/routes/types'
 
 export function FeedsTabBar(
   props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
@@ -79,12 +82,37 @@ function FeedsTabBarPublic() {
 function FeedsTabBarTablet(
   props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
 ) {
-  const feeds = usePinnedFeedsInfos()
+  const {feeds, hasPinnedCustomFeedOrList} = usePinnedFeedsInfos()
   const pal = usePalette('default')
   const {hasSession} = useSession()
+  const navigation = useNavigation<NavigationProp>()
   const {headerMinimalShellTransform} = useMinimalShellMode()
   const {headerHeight} = useShellLayout()
-  const items = hasSession ? feeds.map(f => f.displayName) : []
+  const pinnedDisplayNames = hasSession ? feeds.map(f => f.displayName) : []
+  const showFeedsLinkInTabBar = hasSession && !hasPinnedCustomFeedOrList
+  const items = showFeedsLinkInTabBar
+    ? pinnedDisplayNames.concat('Feeds ✨')
+    : pinnedDisplayNames
+
+  const onPressDiscoverFeeds = React.useCallback(() => {
+    if (isWeb) {
+      navigation.navigate('Feeds')
+    } else {
+      navigation.navigate('FeedsTab')
+      navigation.popToTop()
+    }
+  }, [navigation])
+
+  const onSelect = React.useCallback(
+    (index: number) => {
+      if (showFeedsLinkInTabBar && index === items.length - 1) {
+        onPressDiscoverFeeds()
+      } else if (props.onSelect) {
+        props.onSelect(index)
+      }
+    },
+    [items.length, onPressDiscoverFeeds, props, showFeedsLinkInTabBar],
+  )
 
   return (
     // @ts-ignore the type signature for transform wrong here, translateX and translateY need to be in separate objects -prf
@@ -96,6 +124,7 @@ function FeedsTabBarTablet(
       <TabBar
         key={items.join(',')}
         {...props}
+        onSelect={onSelect}
         items={items}
         indicatorColor={pal.colors.link}
       />
diff --git a/src/view/com/pager/FeedsTabBarMobile.tsx b/src/view/com/pager/FeedsTabBarMobile.tsx
index 735aa1bac..fc9eb8f14 100644
--- a/src/view/com/pager/FeedsTabBarMobile.tsx
+++ b/src/view/com/pager/FeedsTabBarMobile.tsx
@@ -18,6 +18,9 @@ import {useSetDrawerOpen} from '#/state/shell/drawer-open'
 import {useShellLayout} from '#/state/shell/shell-layout'
 import {useSession} from '#/state/session'
 import {usePinnedFeedsInfos} from '#/state/queries/feed'
+import {isWeb} from 'platform/detection'
+import {useNavigation} from '@react-navigation/native'
+import {NavigationProp} from 'lib/routes/types'
 
 export function FeedsTabBar(
   props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
@@ -26,11 +29,36 @@ export function FeedsTabBar(
   const {isSandbox, hasSession} = useSession()
   const {_} = useLingui()
   const setDrawerOpen = useSetDrawerOpen()
-  const feeds = usePinnedFeedsInfos()
+  const navigation = useNavigation<NavigationProp>()
+  const {feeds, hasPinnedCustomFeedOrList} = usePinnedFeedsInfos()
   const brandBlue = useColorSchemeStyle(s.brandBlue, s.blue3)
   const {headerHeight} = useShellLayout()
   const {headerMinimalShellTransform} = useMinimalShellMode()
-  const items = hasSession ? feeds.map(f => f.displayName) : []
+  const pinnedDisplayNames = hasSession ? feeds.map(f => f.displayName) : []
+  const showFeedsLinkInTabBar = hasSession && !hasPinnedCustomFeedOrList
+  const items = showFeedsLinkInTabBar
+    ? pinnedDisplayNames.concat('Feeds ✨')
+    : pinnedDisplayNames
+
+  const onPressFeedsLink = React.useCallback(() => {
+    if (isWeb) {
+      navigation.navigate('Feeds')
+    } else {
+      navigation.navigate('FeedsTab')
+      navigation.popToTop()
+    }
+  }, [navigation])
+
+  const onSelect = React.useCallback(
+    (index: number) => {
+      if (showFeedsLinkInTabBar && index === items.length - 1) {
+        onPressFeedsLink()
+      } else if (props.onSelect) {
+        props.onSelect(index)
+      }
+    },
+    [items.length, onPressFeedsLink, props, showFeedsLinkInTabBar],
+  )
 
   const onPressAvi = React.useCallback(() => {
     setDrawerOpen(true)
@@ -84,7 +112,7 @@ export function FeedsTabBar(
           key={items.join(',')}
           onPressSelected={props.onPressSelected}
           selectedPage={props.selectedPage}
-          onSelect={props.onSelect}
+          onSelect={onSelect}
           testID={props.testID}
           items={items}
           indicatorColor={pal.colors.link}
diff --git a/src/view/com/pager/PagerWithHeader.tsx b/src/view/com/pager/PagerWithHeader.tsx
index 3d2a3c55f..2c7640c43 100644
--- a/src/view/com/pager/PagerWithHeader.tsx
+++ b/src/view/com/pager/PagerWithHeader.tsx
@@ -108,6 +108,7 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
                 pointerEvents: isHeaderReady ? 'auto' : 'none',
               }}>
               <TabBar
+                testID={testID}
                 items={items}
                 selectedPage={currentPage}
                 onSelect={props.onSelect}
@@ -127,6 +128,7 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
         isMobile,
         onTabBarLayout,
         onHeaderOnlyLayout,
+        testID,
       ],
     )
 
diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx
index 0e08b22d8..c3a95c5c0 100644
--- a/src/view/com/pager/TabBar.tsx
+++ b/src/view/com/pager/TabBar.tsx
@@ -68,6 +68,7 @@ export function TabBar({
   return (
     <View testID={testID} style={[pal.view, styles.outer]}>
       <DraggableScrollView
+        testID={`${testID}-selector`}
         horizontal={true}
         showsHorizontalScrollIndicator={false}
         ref={scrollElRef}
@@ -76,6 +77,7 @@ export function TabBar({
           const selected = i === selectedPage
           return (
             <PressableWithHover
+              testID={`${testID}-selector-${i}`}
               key={item}
               onLayout={e => onItemLayout(e, i)}
               style={[styles.item, selected && indicatorStyle]}
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index 89dec5f97..3e9a59929 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -267,6 +267,7 @@ function ProfileScreenLoaded({
       screenDescription="profile"
       moderation={moderation.account}>
       <PagerWithHeader
+        testID="profilePager"
         isHeaderReady={true}
         items={sectionTitles}
         onPageSelected={onPageSelected}
diff --git a/src/view/screens/ProfileFeed.tsx b/src/view/screens/ProfileFeed.tsx
index 6d4c0c237..e38543e6b 100644
--- a/src/view/screens/ProfileFeed.tsx
+++ b/src/view/screens/ProfileFeed.tsx
@@ -353,6 +353,7 @@ export function ProfileFeedScreenInner({
               style={styles.btn}
             />
             <Button
+              testID={isPinned ? 'unpinBtn' : 'pinBtn'}
               disabled={isPinPending || isUnpinPending}
               type={isPinned ? 'default' : 'inverted'}
               label={isPinned ? 'Unpin' : 'Pin to home'}
diff --git a/src/view/shell/desktop/Feeds.tsx b/src/view/shell/desktop/Feeds.tsx
index eeeca4fd8..ff51ffe22 100644
--- a/src/view/shell/desktop/Feeds.tsx
+++ b/src/view/shell/desktop/Feeds.tsx
@@ -11,7 +11,7 @@ import {usePinnedFeedsInfos} from '#/state/queries/feed'
 export function DesktopFeeds() {
   const pal = usePalette('default')
   const {_} = useLingui()
-  const feeds = usePinnedFeedsInfos()
+  const {feeds} = usePinnedFeedsInfos()
 
   const route = useNavigationState(state => {
     if (!state) {