FollowingFeed.tsx raw

   1  import NormalFeed from '@/components/NormalFeed'
   2  import { Button } from '@/components/ui/button'
   3  import { usePrimaryPage } from '@/PageManager'
   4  import { useFeed } from '@/providers/FeedProvider'
   5  import { useFollowList } from '@/providers/FollowListProvider'
   6  import { useNostr } from '@/providers/NostrProvider'
   7  import client from '@/services/client.service'
   8  import { TFeedSubRequest } from '@/types'
   9  import { Compass, Search, UserPlus } from 'lucide-react'
  10  import { useEffect, useRef, useState } from 'react'
  11  import { useTranslation } from 'react-i18next'
  12  
  13  export default function FollowingFeed() {
  14    const { t } = useTranslation()
  15    const { pubkey } = useNostr()
  16    const { followingSet } = useFollowList()
  17    const { navigate } = usePrimaryPage()
  18    const { markFeedLoaded } = useFeed()
  19    const [subRequests, setSubRequests] = useState<TFeedSubRequest[]>([])
  20    const [hasFollowings, setHasFollowings] = useState<boolean | null>(null)
  21    const [refreshCount, setRefreshCount] = useState(0)
  22    const initializedRef = useRef(false)
  23  
  24    useEffect(() => {
  25      if (initializedRef.current) return
  26  
  27      async function init() {
  28        if (!pubkey) {
  29          setSubRequests([])
  30          setHasFollowings(null)
  31          return
  32        }
  33  
  34        const followings = await client.fetchFollowings(pubkey)
  35        setHasFollowings(followings.length > 0)
  36        setSubRequests(await client.generateSubRequestsForPubkeys([pubkey, ...followings], pubkey))
  37  
  38        if (followings.length) {
  39          initializedRef.current = true
  40        }
  41      }
  42  
  43      init()
  44    }, [pubkey, followingSet, refreshCount])
  45  
  46    // Show empty state when user has no followings
  47    useEffect(() => {
  48      if (hasFollowings === false) markFeedLoaded()
  49    }, [hasFollowings, markFeedLoaded])
  50  
  51    if (hasFollowings === false && subRequests.length > 0) {
  52      return (
  53        <div className="flex flex-col items-center justify-center min-h-[60vh] px-6 text-center">
  54          <UserPlus size={64} className="text-muted-foreground mb-4" strokeWidth={1.5} />
  55          <h2 className="text-2xl font-semibold mb-2">{t('Welcome to Smesh!')}</h2>
  56          <p className="text-muted-foreground mb-6 max-w-md">
  57            {t(
  58              'Your feed is empty because you are not following anyone yet. Start by exploring interesting content and following users you like!'
  59            )}
  60          </p>
  61          <div className="flex flex-col sm:flex-row gap-3 w-full max-w-md">
  62            <Button size="lg" onClick={() => navigate('explore')} className="w-full">
  63              <Compass className="size-5" />
  64              {t('Explore')}
  65            </Button>
  66            <Button size="lg" variant="outline" onClick={() => navigate('search')} className="w-full">
  67              <Search className="size-5" />
  68              {t('Search Users')}
  69            </Button>
  70          </div>
  71        </div>
  72      )
  73    }
  74  
  75    return (
  76      <NormalFeed
  77        subRequests={subRequests}
  78        onRefresh={() => {
  79          initializedRef.current = false
  80          setRefreshCount((count) => count + 1)
  81        }}
  82        onInitialLoad={markFeedLoaded}
  83        isMainFeed
  84      />
  85    )
  86  }
  87