import { GetServerSideProps, InferGetServerSidePropsType, NextPage } from 'next' import { Text, Flex, Box } from 'components/primitives' import Layout from 'components/Layout' import { ComponentPropsWithoutRef, useContext, useEffect, useRef, useState, } from 'react' import { useMediaQuery } from 'react-responsive' import { useMounted } from 'hooks' import { paths } from '@reservoir0x/reservoir-sdk' import { useCollections } from '@reservoir0x/reservoir-kit-ui' import fetcher from 'utils/fetcher' import { NORMALIZE_ROYALTIES } from '../../../_app' import supportedChains, { DefaultChain } from 'utils/chains' import { CollectionRankingsTable } from 'components/rankings/CollectionRankingsTable' import { useIntersectionObserver } from 'usehooks-ts' import LoadingSpinner from 'components/common/LoadingSpinner' import CollectionsTimeDropdown, { CollectionsSortingOption, } from 'components/common/CollectionsTimeDropdown' import ChainToggle from 'components/common/ChainToggle' import { Head } from 'components/Head' import { ChainContext } from 'context/ChainContextProvider' import { useRouter } from 'next/router' type Props = InferGetServerSidePropsType const IndexPage: NextPage = ({ ssr }) => { const router = useRouter() const isSSR = typeof window === 'undefined' const isMounted = useMounted() const compactToggleNames = useMediaQuery({ query: '(max-width: 800px)' }) const [sortByTime, setSortByTime] = useState('1DayVolume') let collectionQuery: Parameters['0'] = { limit: 20, sortBy: sortByTime, includeMintStages: true, } const { chain, switchCurrentChain } = useContext(ChainContext) useEffect(() => { if (router.query.chain) { let chainIndex: number | undefined for (let i = 0; i < supportedChains.length; i++) { if (supportedChains[i].routePrefix == router.query.chain) { chainIndex = supportedChains[i].id } } if (chainIndex !== -1 && chainIndex) { switchCurrentChain(chainIndex) } } }, [router.query]) if (chain.collectionSetId) { collectionQuery.collectionsSetId = chain.collectionSetId } else if (chain.community) { collectionQuery.community = chain.community } const { data, fetchNextPage, isFetchingPage, isValidating } = useCollections( collectionQuery, { fallbackData: [ssr.collection], } ) let collections = data || [] const loadMoreRef = useRef(null) const loadMoreObserver = useIntersectionObserver(loadMoreRef, {}) useEffect(() => { let isVisible = !!loadMoreObserver?.isIntersecting if (isVisible) { fetchNextPage() } }, [loadMoreObserver?.isIntersecting]) let volumeKey: ComponentPropsWithoutRef< typeof CollectionRankingsTable >['volumeKey'] = 'allTime' switch (sortByTime) { case '1DayVolume': volumeKey = '1day' break case '7DayVolume': volumeKey = '7day' break case '30DayVolume': volumeKey = '30day' break } return ( Trending Collections { setSortByTime(option) }} /> {isSSR || !isMounted ? null : ( )} {(isFetchingPage || isValidating) && ( )} ) } type CollectionSchema = paths['/collections/v7']['get']['responses']['200']['schema'] export const getServerSideProps: GetServerSideProps<{ ssr: { collection: CollectionSchema } }> = async ({ res, params }) => { const collectionQuery: paths['/collections/v7']['get']['parameters']['query'] = { sortBy: '1DayVolume', normalizeRoyalties: NORMALIZE_ROYALTIES, limit: 20, } const chainPrefix = params?.chain || '' const chain = supportedChains.find((chain) => chain.routePrefix === chainPrefix) || DefaultChain const query = { ...collectionQuery } if (chain.collectionSetId) { query.collectionsSetId = chain.collectionSetId } else if (chain.community) { query.community = chain.community } const response = await fetcher( `${chain.reservoirBaseUrl}/collections/v7`, query, { headers: { 'x-api-key': process.env.RESERVOIR_API_KEY || '', }, } ) res.setHeader( 'Cache-Control', 'public, s-maxage=30, stale-while-revalidate=60' ) return { props: { ssr: { collection: response.data } }, } } export default IndexPage