Skip to content

Commit

Permalink
refactor(explorer): prefetch guilds on the server
Browse files Browse the repository at this point in the history
  • Loading branch information
BrickheadJohnny committed Jul 11, 2024
1 parent 2ad30be commit d4fdd34
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 171 deletions.
59 changes: 59 additions & 0 deletions src/app/explorer/_components/Explorer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"use client"

import { walletSelectorModalAtom } from "@/components/Providers/atoms"
import { useWeb3ConnectionManager } from "@/components/Web3ConnectionManager/hooks/useWeb3ConnectionManager"
import { Button } from "@/components/ui/Button"
import { Card } from "@/components/ui/Card"
import { SignIn } from "@phosphor-icons/react"
import { GuildSearchBar } from "app/explorer/_components/GuildSearchBar"
import { YourGuilds } from "app/explorer/_components/YourGuilds"
import useIsStuck from "hooks/useIsStuck"
import { useSetAtom } from "jotai"
import { Suspense } from "react"
import Robot from "/public/landing/robot.svg"
import { guildQueryAtom, isSearchStuckAtom } from "../atoms"
import { ActiveSection } from "../types"
import { GuildInfiniteScroll } from "./GuildInfiniteScroll"
import { StickyBar } from "./StickyBar"

export const Explorer = () => {
const { isWeb3Connected } = useWeb3ConnectionManager()
const setIsSearchStuck = useSetAtom(isSearchStuckAtom)
const setIsWalletSelectorModalOpen = useSetAtom(walletSelectorModalAtom)

const { ref: searchRef } = useIsStuck(setIsSearchStuck)

return (
<>
<StickyBar />

{isWeb3Connected ? (
<YourGuilds />
) : (
<Card className="my-2 mb-12 flex flex-col items-stretch justify-between gap-8 p-6 font-semibold sm:flex-row sm:items-center">
<div className="flex items-center gap-4">
<Robot className="size-8 min-w-8 text-white" />
<span>Sign in to view your guilds / create new ones</span>
</div>
<Button
className="space-x-2"
onClick={() => setIsWalletSelectorModalOpen(true)}
>
<SignIn />
<span className="text-md">Sign in</span>
</Button>
</Card>
)}

<section id={ActiveSection.ExploreGuilds}>
<h2 className="font-bold text-lg tracking-tight">Explore verified guilds</h2>
<div className="sticky top-8 z-10" ref={searchRef}>
<Suspense>
<GuildSearchBar queryAtom={guildQueryAtom} />
</Suspense>
</div>
<GuildInfiniteScroll queryAtom={guildQueryAtom} />
</section>
</>
)
}
11 changes: 11 additions & 0 deletions src/app/explorer/_components/ExplorerSWRProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use client"

import { PropsWithChildren } from "react"
import { SWRConfig, type SWRConfiguration } from "swr"

export const ExplorerSWRProvider = ({
children,
value,
}: PropsWithChildren<{ value: SWRConfiguration }>) => {
return <SWRConfig value={value}>{children}</SWRConfig>
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
"use client"

import { Spinner } from "@phosphor-icons/react"
import useUser from "components/[guild]/hooks/useUser"
import { env } from "env"
import { useScrollBatchedRendering } from "hooks/useScrollBatchedRendering"
import { PrimitiveAtom, useAtomValue } from "jotai"
import { memo, useRef } from "react"
import { SWRConfiguration } from "swr"
import { SWRConfiguration, useSWRConfig } from "swr"
import useSWRInfinite from "swr/infinite"
import { GuildBase } from "types"
import { fetcherWithSign } from "utils/fetcher"
import { GuildCardSkeleton, GuildCardWithLink } from "./GuildCard"
import {
GuildCardSkeleton,
GuildCardWithLink,
} from "../../../v2/components/GuildCard"

const BATCH_SIZE = 24

Expand All @@ -21,16 +26,13 @@ const GuildCards = ({ guildData }: { guildData?: GuildBase[] }) => {
return Array.from({ length: BATCH_SIZE }, (_, i) => <GuildCardSkeleton key={i} />)
}

const useExploreGuilds = (
searchParams: URLSearchParams,
guildsInitial: GuildBase[]
) => {
const useExploreGuilds = (searchParams: URLSearchParams) => {
const { isSuperAdmin } = useUser()
const options: SWRConfiguration = {
fallbackData: guildsInitial,
dedupingInterval: 60000, // one minute
dedupingInterval: 60_000,
}

const { cache } = useSWRConfig()
// sending authed request for superAdmins, so they can see unverified & hideFromExplorer guilds too
// @ts-expect-error TODO: resolve this type error
return useSWRInfinite<GuildBase[]>(
Expand All @@ -39,6 +41,7 @@ const useExploreGuilds = (
return null
const url = new URL("/v2/guilds", env.NEXT_PUBLIC_API)
const params: Record<string, string> = {
order: "FEATURED",
...Object.fromEntries(searchParams.entries()),
offset: (BATCH_SIZE * pageIndex).toString(),
limit: BATCH_SIZE.toString(),
Expand Down Expand Up @@ -69,7 +72,7 @@ export const GuildInfiniteScroll = ({
setSize,
isValidating,
isLoading,
} = useExploreGuilds(searchParams, [])
} = useExploreGuilds(searchParams)
const renderedGuilds = filteredGuilds?.flat()

useScrollBatchedRendering({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import useDebouncedState from "hooks/useDebouncedState"
import { PrimitiveAtom, useSetAtom } from "jotai"
import { usePathname, useSearchParams } from "next/navigation"
import { useEffect, useState } from "react"
import { Input } from "./ui/Input"
import { ToggleGroup, ToggleGroupItem } from "./ui/ToggleGroup"
import { Input } from "../../../v2/components/ui/Input"
import { ToggleGroup, ToggleGroupItem } from "../../../v2/components/ui/ToggleGroup"

enum Order {
Featured = "FEATURED",
Expand Down
23 changes: 23 additions & 0 deletions src/app/explorer/_components/HeaderBackground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client"

import { cn } from "@/lib/utils"
import { useAtomValue } from "jotai"
import { isNavStuckAtom, isSearchStuckAtom } from "../atoms"

export const HeaderBackground = () => {
const isNavStuck = useAtomValue(isNavStuckAtom)
const isSearchStuck = useAtomValue(isSearchStuckAtom)

return (
<div
className={cn(
"fixed inset-x-0 top-0 z-10 h-0 bg-background shadow-md transition-all duration-200",
{
"h-16": isNavStuck,
"h-[calc(theme(space.28)-theme(space.2))] bg-gradient-to-b from-background to-card-secondary":
isSearchStuck,
}
)}
/>
)
}
94 changes: 94 additions & 0 deletions src/app/explorer/_components/StickyBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"use client"

import { useWeb3ConnectionManager } from "@/components/Web3ConnectionManager/hooks/useWeb3ConnectionManager"
import { Button } from "@/components/ui/Button"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/ToggleGroup"
import { cn } from "@/lib/utils"
import { Plus } from "@phosphor-icons/react"
import useIsStuck from "hooks/useIsStuck"
import useScrollspy from "hooks/useScrollSpy"
import { useAtom, useAtomValue, useSetAtom } from "jotai"
import { useEffect } from "react"
import { activeSectionAtom, isNavStuckAtom, isSearchStuckAtom } from "../atoms"
import { ActiveSection } from "../types"

const Nav = () => {
const isNavStuck = useAtomValue(isNavStuckAtom)
const isSearchStuck = useAtomValue(isSearchStuckAtom)
const [activeSection, setActiveSection] = useAtom(activeSectionAtom)
const spyActiveSection = useScrollspy(Object.values(ActiveSection), 100)
useEffect(() => {
if (!spyActiveSection) return
setActiveSection(spyActiveSection as ActiveSection)
}, [spyActiveSection, setActiveSection])

return (
<ToggleGroup
type="single"
className="gap-2"
size={isSearchStuck ? "sm" : "lg"}
variant={isNavStuck ? "default" : "mono"}
onValueChange={(value) => value && setActiveSection(value as ActiveSection)}
value={activeSection}
>
<ToggleGroupItem
value={ActiveSection.YourGuilds}
className={cn("rounded-xl transition-all", {
"rounded-lg": isSearchStuck,
})}
asChild
>
<a href={`#${ActiveSection.YourGuilds}`}>Your guilds</a>
</ToggleGroupItem>
<ToggleGroupItem
value={ActiveSection.ExploreGuilds}
className={cn("rounded-xl transition-all", {
"rounded-lg": isSearchStuck,
})}
asChild
>
<a href={`#${ActiveSection.ExploreGuilds}`}>Explore guilds</a>
</ToggleGroupItem>
</ToggleGroup>
)
}

const CreateGuildLink = () => {
const isNavStuck = useAtomValue(isNavStuckAtom)
return (
<Button
variant="ghost"
size="sm"
className={cn("gap-1.5", {
"text-white": !isNavStuck,
})}
>
<Plus />
<span>Create guild</span>
</Button>
)
}

export const StickyBar = () => {
const { isWeb3Connected } = useWeb3ConnectionManager()
const setIsNavStuck = useSetAtom(isNavStuckAtom)
const isSearchStuck = useAtomValue(isSearchStuckAtom)
const { ref: navToggleRef } = useIsStuck(setIsNavStuck)

return (
<div
className={cn(
"sticky top-0 z-10 flex h-16 w-full items-center transition-all",
{
"h-12": isSearchStuck,
}
)}
ref={navToggleRef}
>
<div className="relative flex w-full items-center justify-between">
<Nav />
{isWeb3Connected && <CreateGuildLink />}
</div>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import useSWRWithOptionalAuth from "hooks/useSWRWithOptionalAuth"
import { GuildBase } from "types"
import { GuildCardSkeleton, GuildCardWithLink } from "./GuildCard"
import {
GuildCardSkeleton,
GuildCardWithLink,
} from "../../../v2/components/GuildCard"

const useYourGuilds = () =>
useSWRWithOptionalAuth<GuildBase[]>(
Expand Down
Loading

0 comments on commit d4fdd34

Please sign in to comment.