Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: post festival page #420

Merged
merged 3 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 13 additions & 35 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,27 @@ import { getNow } from '@/utils/getNow'
import { getArweaveById } from '@/utils/getArweaveById'
import { getDropDate } from '@/utils/getDropDate'
import { siteDataSuffix } from '@/components/MintDialog/types'
import { Drop } from '@/config/partners/types'
import { Drop, Partner } from '@/config/partners/types'
import { Gift } from '@/components/icons/Gift'
import { DropCardList } from '@/components/DropCard/DropCardList'
import { getCollections } from '@/utils/getCollections'
import { ArrowRight } from '@/components/icons/ArrowRight'
import { CBSubscribeDialog } from '@/components/CBSubscribeDialog'
import { PostFestivalPage } from '@/components/PostFestivalPage/PostFestivalPage'
import { BasedChallenge } from '@/components/BasedChallenge/BasedChallenge'

type Props = {
searchParams: { [key: string]: string | string[] | undefined }
}

const CHALLENGE_IMAGES = [
{ url: '/challenge/1.png', alt: 'Based NFT Drop' },
{ url: '/challenge/2.png', alt: '' },
{ url: '/challenge/3.png', alt: '' },
{ url: '/challenge/4.png', alt: '' },
]

const Home = async ({ searchParams }: Props) => {
const spoofDateParam = searchParams.spoofDate
const spoofDate = Array.isArray(spoofDateParam)
? spoofDateParam[0]
: spoofDateParam
const { partner, tabs, article, tweets, activeDrops } =
await getPageData(spoofDate)
const { drops, name, icon } = partner
const { drops, name, icon } = partner || { drops: [], name: '', icon: '' }

const dropAddressParam = searchParams.drop

Expand All @@ -55,6 +50,10 @@ const Home = async ({ searchParams }: Props) => {
const { featuredDrop, remainingDrops } = getDrops(drops, dropAddress)
const collections = await getCollections(drops)

if (!partner) {
return <PostFestivalPage activeDrops={activeDrops} tabs={tabs} />
}

return (
<PageContainer subNavOverlap>
<div className="flex h-full flex-col items-center justify-between relative pb-36 gap-10 md:gap-[54px]">
Expand All @@ -64,29 +63,8 @@ const Home = async ({ searchParams }: Props) => {
staticHeadline={!!dropAddress}
floorAsk={collections[featuredDrop.address.toLowerCase()]?.floorAsk}
/>
<section className="bg-ocs-light-gray w-full shadow-large rounded-3xl p-6 flex flex-col gap-6 lg:flex-row">
<div className="flex flex-col gap-4 max-w-[520px]">
<h2 className="desktop-h2">Join the Based Challenge</h2>
<p className="desktop-body">
Claim your free onchain art, then watch it evolve as you mint more
on Base during Onchain Summer. Scan the QR code to get started.
</p>
<CBSubscribeDialog>
<Button>
<span>Claim now</span>{' '}
<span className="hidden md:inline">on Coinbase Wallet</span>
<ArrowRight className="ml-auto" />
</Button>
</CBSubscribeDialog>
</div>
<div className="grid gap-6 grid-cols-2 sm:grid-cols-4 lg:grid-cols-2 xl:grid-cols-4 w-full items-center max-w-[624px] lg:ml-auto">
{CHALLENGE_IMAGES.map(({ url, alt }) => (
<div key={url} className="relative z-20 w-full aspect-square">
<Image fill src={url} alt={alt} className="object-cover" />
</div>
))}
</div>
</section>

<BasedChallenge />
{remainingDrops?.length > 0 || article?.content ? (
<section className="bg-ocs-light-gray w-full shadow-large rounded-3xl">
<div className="p-[20px] lg:p-4 rounded-3xl">
Expand Down Expand Up @@ -243,7 +221,7 @@ const INITIAL_TABS: TabsComponentProps = {
pastDrops: [],
}

interface DropWithPartnerData extends Drop {
export interface DropWithPartnerData extends Drop {
partner: string
partnerIcon: string
}
Expand All @@ -252,7 +230,7 @@ async function getPageData(spoofDate?: string) {
const now = getNow(spoofDate)
const today = getDropDate(spoofDate)

const featuredPartner = schedule[today] || schedule[Object.keys(schedule)[0]]
const featuredPartner = (schedule[today] || null) as Partner | null

const tabs: TabsComponentProps = Object.keys(schedule).reduce((acc, date) => {
const scheduleDate = new Date(date)
Expand Down Expand Up @@ -314,7 +292,7 @@ async function getPageData(spoofDate?: string) {
.sort((a, b) => (a?.sequence ?? 0) - (b?.sequence ?? 0))

const [article, tweets] = await Promise.all([
getArweaveById(featuredPartner.aarweaveDigest),
getArweaveById(featuredPartner?.aarweaveDigest ?? ''),
getTweets(),
])

Expand Down
40 changes: 40 additions & 0 deletions src/components/BasedChallenge/BasedChallenge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { FC } from 'react'
import { CBSubscribeDialog } from '../CBSubscribeDialog'
import { Button } from '../Button'
import { ArrowRight } from '../icons/ArrowRight'
import Image from 'next/image'

const CHALLENGE_IMAGES = [
{ url: '/challenge/1.png', alt: 'Based NFT Drop' },
{ url: '/challenge/2.png', alt: '' },
{ url: '/challenge/3.png', alt: '' },
{ url: '/challenge/4.png', alt: '' },
]

export const BasedChallenge: FC = ({}) => {
return (
<section className="bg-ocs-light-gray w-full shadow-large rounded-3xl p-6 flex flex-col gap-6 lg:flex-row">
<div className="flex flex-col gap-4 max-w-[520px]">
<h2 className="desktop-h2">Join the Based Challenge</h2>
<p className="desktop-body">
Claim your free onchain art, then watch it evolve as you mint more on
Base during Onchain Summer. Scan the QR code to get started.
</p>
<CBSubscribeDialog>
<Button>
<span>Claim now</span>{' '}
<span className="hidden md:inline">on Coinbase Wallet</span>
<ArrowRight className="ml-auto" />
</Button>
</CBSubscribeDialog>
</div>
<div className="grid gap-6 grid-cols-2 sm:grid-cols-4 lg:grid-cols-2 xl:grid-cols-4 w-full items-center max-w-[624px] lg:ml-auto">
{CHALLENGE_IMAGES.map(({ url, alt }) => (
<div key={url} className="relative z-20 w-full aspect-square">
<Image fill src={url} alt={alt} className="object-cover" />
</div>
))}
</div>
</section>
)
}
10 changes: 10 additions & 0 deletions src/components/PageContainer/PageContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ interface PageContainerProps {
children: ReactNode
subNavBgColor?: string
subNavOverlap?: boolean
postFestival?: boolean
}

export const PageContainer: React.FC<PageContainerProps> = ({
children,
subNavBgColor,
subNavOverlap = false,
postFestival = false,
}) => {
const isMismatched = useIsMisMatched()

Expand All @@ -26,6 +28,14 @@ export const PageContainer: React.FC<PageContainerProps> = ({
return (
<>
<SubNav subNavBgColor={subNavBgColor} />
{postFestival ? (
<div className="flex flex-col gap-6 bg-ocs-blue items-center justify-center pb-24 pt-14 w-full">
<div className="w-14 h-14 bg-ocs-yellow rounded-full" />
<h1 className="text-white text-center font-display text-[64px] font-bold leading-[120%] uppercase">
Summer Never Ends
</h1>
</div>
) : null}
<div className={clsx('px-6 md:px-20', mt)}>
<main className="w-full max-w-7xl mx-auto">{children}</main>
</div>
Expand Down
87 changes: 87 additions & 0 deletions src/components/PostFestivalPage/PostFestivalPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'use client'

import { FC } from 'react'
import { PageContainer } from '../PageContainer'
import { Gift } from '../icons/Gift'
import { DropCardList } from '../DropCard/DropCardList'
import { DropWithPartnerData } from '@/app/page'
import { DropCard } from '../DropCard'
import { siteDataSuffix } from '@/components/MintDialog/types'
import { Trending, TrendingQueryResult } from '../Trending'
import { Tabs, TabsComponentProps } from '../Tabs'
import { BasedChallenge } from '../BasedChallenge/BasedChallenge'
import { useAccount } from 'wagmi'
import { l2 } from '@/config/chain'
import { useQuery } from 'react-query'
import { getTrendingData } from '@/utils/getTrendingData'

interface PostFestivalPageProps {
activeDrops: DropWithPartnerData[]
tabs: TabsComponentProps
}

export const PostFestivalPage: FC<PostFestivalPageProps> = ({
activeDrops,
tabs,
}) => {
const { address: connectedWallet } = useAccount()
const chainId = l2.id

const { data, error, isLoading } = useQuery<TrendingQueryResult>({
queryKey: [connectedWallet, chainId],
queryFn: ({ queryKey }) => {
const [connectedWallet, chainId] = queryKey

return getTrendingData(connectedWallet as string, chainId as number)
},
})

const hasActiveSection =
activeDrops.length > 0 ||
(!isLoading && (data?.collections.length ?? 0) > 0)

return (
<PageContainer postFestival>
<div className="flex h-full flex-col items-center justify-between relative pb-36 gap-10 md:gap-[54px]">
{hasActiveSection ? (
<section className="w-full shadow-large rounded-3xl bg-[#EFEFEF] p-[20px]">
<div className="mb-4 flex gap-2 items-center">
<div className="flex justify-center items-center h-[64px] w-[64px] rounded-2xl bg-ocs-turquoise">
<Gift />
</div>
<div className="">
<h2 className="text-[32px] text-display">Active Mints</h2>
</div>
</div>

<div className="-mr-4 mb-4">
<DropCardList>
{activeDrops.map((drop) => (
<DropCard
{...drop}
key={drop.name}
partner={drop.partner}
partnerIcon={drop.partnerIcon}
openSeaLink={drop.openSeaLink}
interactWithNFTLink={drop.interactWithNFTLink}
dataSuffix={siteDataSuffix}
dropDataSuffix={drop.dataSuffix}
buttonText={drop.buttonText}
description={drop.description}
/>
))}
</DropCardList>
</div>

<Trending />
</section>
) : null}

<section className="w-full" id="drops">
<Tabs {...tabs} />
</section>
<BasedChallenge />
</div>
</PageContainer>
)
}
8 changes: 5 additions & 3 deletions src/components/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ export interface TabsComponentProps {
}

export const Tabs: FC<TabsComponentProps> = ({ upcomingDrops, pastDrops }) => {
const hasUpcomingDrops = upcomingDrops.length > 0

return (
<section className="p-4 bg-ocs-light-gray rounded-3xl shadow-large">
<TabsComponent.Root defaultValue="tab1">
<TabsComponent.Root defaultValue={hasUpcomingDrops ? 'upcoming' : 'past'}>
<TabsComponent.List
className="flex [@media(max-width:374px)]:flex-wrap gap-2"
aria-label="Manage your account"
Expand All @@ -25,7 +27,7 @@ export const Tabs: FC<TabsComponentProps> = ({ upcomingDrops, pastDrops }) => {
pastLength={pastDrops.length}
/>
</TabsComponent.List>
<TabsComponent.Content value="tab1">
<TabsComponent.Content value="upcoming">
{upcomingDrops.map(
({ name, drops, banner, description, slug, brandColor }) => (
<div key={name} className="my-8 first:mt-6 last:mb-0">
Expand All @@ -43,7 +45,7 @@ export const Tabs: FC<TabsComponentProps> = ({ upcomingDrops, pastDrops }) => {
)
)}
</TabsComponent.Content>
<TabsComponent.Content className="" value="tab2">
<TabsComponent.Content className="" value="past">
{pastDrops.map(
({ name, drops, banner, description, slug, brandColor }) => (
<div key={name} className="my-8 first:mt-6 last:mb-0">
Expand Down
27 changes: 15 additions & 12 deletions src/components/Tabs/TabsListItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,28 @@ export const TabsListItems: FC<TabsListItemsProps> = ({
upcomingLength,
pastLength,
}) => {
const hasUpcomingDrops = upcomingLength > 0
return (
<>
<Tabs.Trigger
className="md:min-w-[200px] border-2 border-solid border-ocs-dark-gray radix-state-active:border-ocs-yellow radix-state-active:bg-ocs-yellow px-3 pt-10 pb-2 md:px-4 rounded-2xl relative"
value="tab1"
>
<div className="flex items-center desktop-h3 md:desktop-h2">
upcoming{' '}
<div className="h-[24px] w-[24px] py-[1px] text-[12px] bg-neutral-950 text-white rounded-full flex items-center justify-center mx-2 relative bottom-3">
<span className="text-center text-lg">{upcomingLength}</span>
{hasUpcomingDrops ? (
<Tabs.Trigger
className="md:min-w-[200px] border-2 border-solid border-ocs-dark-gray radix-state-active:border-ocs-yellow radix-state-active:bg-ocs-yellow px-3 pt-10 pb-2 md:px-4 rounded-2xl relative"
value="upcoming"
>
<div className="flex items-center desktop-h3 md:desktop-h2">
upcoming{' '}
<div className="h-[24px] w-[24px] py-[1px] text-[12px] bg-neutral-950 text-white rounded-full flex items-center justify-center mx-2 relative bottom-3">
<span className="text-center text-lg">{upcomingLength}</span>
</div>
</div>
</div>
</Tabs.Trigger>
</Tabs.Trigger>
) : null}
<Tabs.Trigger
className="md:min-w-[200px] border-2 border-solid border-ocs-dark-gray radix-state-active:border-none radix-state-active:bg-ocs-yellow px-3 pt-10 pb-2 md:px-4 rounded-2xl relative"
value="tab2"
value="past"
>
<div className="flex items-center desktop-h3 md:desktop-h2">
active{' '}
{hasUpcomingDrops ? 'active' : 'mints'}{' '}
<div className="h-[24px] w-[24px] py-[1px] text-[12px] bg-neutral-950 text-white rounded-full flex items-center justify-center mx-2 relative bottom-3">
<span className="text-center text-lg">{pastLength}</span>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Trending/Trending.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ import { MintType, siteDataSuffix } from '@/components/MintDialog/types'

export interface TrendingComponentProps {}

interface QueryResult {
export interface TrendingQueryResult {
collections: Collection[]
}

export const Trending: FC<TrendingComponentProps> = () => {
const { address: connectedWallet } = useAccount()
const chainId = l2.id

const { data, error, isLoading } = useQuery<QueryResult>({
const { data, error, isLoading } = useQuery<TrendingQueryResult>({
queryKey: [connectedWallet, chainId],
queryFn: ({ queryKey }) => {
const [connectedWallet, chainId] = queryKey
Expand Down
1 change: 1 addition & 0 deletions src/config/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,5 @@ export const schedule: Record<string, Partner> = {
'2023-08-29': openSea,
'2023-08-30': fwbBonfire,
'2023-08-31': fini,
'2023-09-01': fini,
}