Scrapboard.org client
at main 131 lines 4.1 kB view raw
1"use client"; 2 3import { Feed, feedAsMap } from "@/components/Feed"; 4import { useFetchTimeline } from "@/lib/hooks/useTimeline"; 5import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; 6import { useEffect, useState } from "react"; 7import { useFeedStore } from "@/lib/stores/feeds"; 8import { useFeeds } from "@/lib/hooks/useFeeds"; 9import { LoaderCircle } from "lucide-react"; 10import { useFeedDefsStore } from "@/lib/stores/feedDefs"; 11import { useAuth } from "@/lib/hooks/useAuth"; 12import { InfiniteScrollWrapper } from "@/components/InfiniteScrollWrapper"; 13 14export default function Home() { 15 const { fetchFeed } = useFetchTimeline(); 16 const feedStore = useFeedStore(); 17 const { isLoading } = useFeeds(); 18 const { feeds, defaultFeed, setDefaultFeed } = useFeedDefsStore(); 19 const { session, loading } = useAuth(); 20 const [feed, setFeed] = useState<"timeline" | string>( 21 defaultFeed ?? "timeline" 22 ); 23 24 const loadMore = async () => { 25 await fetchFeed(feed); 26 }; 27 28 useEffect(() => { 29 console.log(`Loading feed: ${feed}`); 30 loadMore(); 31 }, [feed]); 32 33 if (session == null) { 34 return ( 35 <div className="items-center justify-items-center text-center"> 36 <h1 className="text-lg mb-0.5 font-medium"> 37 You&apos;re not logged in 38 </h1> 39 <p>Log in to see your feeds</p> 40 </div> 41 ); 42 } 43 44 if (isLoading || loading) 45 return ( 46 <div className="flex justify-center py-6 text-sm text-black/70 dark:text-white/70"> 47 <LoaderCircle className="animate-spin" /> 48 </div> 49 ); 50 51 const triggerClass = 52 "shrink-0 cursor-pointer dark:hover:bg-white/5 hover:bg-black/5 transition-colors"; 53 54 const currentFeedData = 55 feed === "timeline" ? feedStore.timeline : feedStore.customFeeds[feed]; 56 57 const hasMore = 58 currentFeedData?.cursor !== null && currentFeedData?.cursor !== undefined; 59 const isLoadingMore = currentFeedData?.isLoading || false; 60 61 return ( 62 <main className="px-5"> 63 <Tabs defaultValue={defaultFeed} className="w-full"> 64 <TabsList 65 className="overflow-x-auto w-full justify-start" 66 style={{ justifyItems: "unset" }} 67 > 68 <TabsTrigger 69 onClick={() => { 70 setFeed("timeline"); 71 setDefaultFeed("timeline"); 72 }} 73 value="timeline" 74 className={triggerClass} 75 > 76 Timeline 77 </TabsTrigger> 78 {Object.entries(feeds).map(([value, it]) => ( 79 <TabsTrigger 80 onClick={() => { 81 setFeed(value); 82 setDefaultFeed(value); 83 }} 84 key={value} 85 value={value} 86 className={triggerClass} 87 > 88 {it?.displayName} 89 </TabsTrigger> 90 ))} 91 </TabsList> 92 93 <TabsContent value="timeline"> 94 <InfiniteScrollWrapper 95 hasMore={hasMore} 96 onLoadMore={loadMore} 97 isLoadingMore={isLoadingMore} 98 > 99 <Feed 100 feed={feedAsMap(feedStore.timeline.posts.map((it) => it.post))} 101 isLoading={ 102 feedStore.timeline.isLoading && 103 feedStore.timeline.posts.length === 0 104 } 105 /> 106 </InfiniteScrollWrapper> 107 </TabsContent> 108 109 {Object.entries(feeds) 110 .filter((it) => feedStore.customFeeds?.[it[0]] != null) 111 .map(([value]) => ( 112 <TabsContent key={value} value={value}> 113 <InfiniteScrollWrapper 114 hasMore={hasMore} 115 onLoadMore={loadMore} 116 isLoadingMore={isLoadingMore} 117 > 118 <Feed 119 feed={feedAsMap(feedStore.customFeeds[value].posts)} 120 isLoading={ 121 feedStore.customFeeds[value].isLoading && 122 feedStore.customFeeds[value].posts.length === 0 123 } 124 /> 125 </InfiniteScrollWrapper> 126 </TabsContent> 127 ))} 128 </Tabs> 129 </main> 130 ); 131}