import { ClockIcon } from '@heroicons/react/outline'
import { UsersIcon } from '@heroicons/react/solid'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import timezone from 'dayjs/plugin/timezone'
import utc from 'dayjs/plugin/utc'
import { zip } from 'lodash'
import Image, { ImageProps, StaticImageData } from 'next/image'
import Link from 'next/link'
import { useState } from 'react'
import { ContractCard } from 'web/components/contract/contract-card'
import { DateTimeTooltip } from 'web/components/datetime-tooltip'
import { Col } from 'web/components/layout/col'
import { Row } from 'web/components/layout/row'
import { Page } from 'web/components/page'
import { SEO } from 'web/components/SEO'
import { tournamentContractsByGroupSlugQuery } from 'web/lib/firebase/contracts'
import { getGroup, groupPath } from 'web/lib/firebase/groups'
import elon_pic from './_cspi/Will_Elon_Buy_Twitter.png'
import china_pic from './_cspi/Chinese_Military_Action_against_Taiwan.png'
import mpox_pic from './_cspi/Monkeypox_Cases.png'
import race_pic from './_cspi/Supreme_Court_Ban_Race_in_College_Admissions.png'
import { SiteLink } from 'web/components/site-link'
import { Carousel } from 'web/components/carousel'
import { usePagination } from 'web/hooks/use-pagination'
import { LoadingIndicator } from 'web/components/loading-indicator'
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(customParseFormat)
const toDate = (d: string) =>
dayjs(d, 'MMM D, YYYY').tz('America/Los_Angeles').valueOf()
type MarketImage = {
marketUrl: string
image: StaticImageData
}
type Tourney = {
title: string
blurb: string // actual description in the click-through
award?: string
endTime?: number
groupId: string
}
const Salem = {
title: 'CSPI/Salem Forecasting Tournament',
blurb: 'Top 5 traders qualify for a UT Austin research fellowship.',
url: 'https://salemcenter.manifold.markets/',
award: '$25,000',
endTime: toDate('Jul 31, 2023'),
contractIds: [],
images: [
{
marketUrl:
'https://salemcenter.manifold.markets/SalemCenter/will-elon-musk-buy-twitter',
image: elon_pic,
},
{
marketUrl:
'https://salemcenter.manifold.markets/SalemCenter/chinese-military-action-against-tai',
image: china_pic,
},
{
marketUrl:
'https://salemcenter.manifold.markets/SalemCenter/over-100000-monkeypox-cases-in-2022',
image: mpox_pic,
},
{
marketUrl:
'https://salemcenter.manifold.markets/SalemCenter/supreme-court-ban-race-in-college-a',
image: race_pic,
},
],
}
const tourneys: Tourney[] = [
{
title: 'Manifold F2P Tournament',
blurb:
'Who can amass the most mana starting from a free-to-play (F2P) account?',
award: 'Poem',
endTime: toDate('Sep 15, 2022'),
groupId: '6rrIja7tVW00lUVwtsYS',
},
// {
// title: 'Cause Exploration Prizes',
// blurb:
// 'Which new charity ideas will Open Philanthropy find most promising?',
// award: 'M$100k',
// endTime: toDate('Sep 9, 2022'),
// groupId: 'cMcpBQ2p452jEcJD2SFw',
// },
{
title: 'Fantasy Football Stock Exchange',
blurb: 'How many points will each NFL player score this season?',
award: '$2,500',
endTime: toDate('Jan 6, 2023'),
groupId: 'SxGRqXRpV3RAQKudbcNb',
},
{
title: 'SF 2022 Ballot',
blurb: 'Which ballot initiatives will pass this year in SF and CA?',
award: '',
endTime: toDate('Nov 8, 2022'),
groupId: 'VkWZyS5yxs8XWUJrX9eq',
},
// {
// title: 'Clearer Thinking Regrant Project',
// blurb: 'Something amazing',
// award: '$10,000',
// endTime: toDate('Sep 22, 2022'),
// groupId: '2VsVVFGhKtIdJnQRAXVb',
// },
]
type SectionInfo = {
tourney: Tourney
slug: string
numPeople: number
}
export async function getStaticProps() {
const groupIds = tourneys.map((data) => data.groupId)
const groups = await Promise.all(groupIds.map(getGroup))
const sections = zip(tourneys, groups)
.filter(([_tourney, group]) => group != null)
.map(([tourney, group]) => ({
tourney,
slug: group!.slug, // eslint-disable-line
numPeople: group!.totalMembers, // eslint-disable-line
}))
return { props: { sections } }
}
export default function TournamentPage(props: { sections: SectionInfo[] }) {
const { sections } = props
return (
{sections.map(({ tourney, slug, numPeople }) => (
{tourney.blurb}
))}
{Salem.blurb}
)
}
const SectionHeader = (props: {
url: string
title: string
ppl?: number
award?: string
endTime?: number
}) => {
const { url, title, ppl, award, endTime } = props
return (
{title}
{!!award && 🏆 {award}}
{!!ppl && (
{ppl}
)}
{endTime && (
{dayjs(endTime).format('MMM D')}
)}
)
}
const ImageCarousel = (props: { images: MarketImage[]; url: string }) => {
const { images, url } = props
return (
{images.map(({ marketUrl, image }) => (
))}
See more
)
}
const MarketCarousel = (props: { slug: string }) => {
const { slug } = props
const q = tournamentContractsByGroupSlugQuery(slug)
const { allItems, getNext } = usePagination({ q, pageSize: 6 })
const items = allItems()
// todo: would be nice to have indicator somewhere when it loads next page
return items.length === 0 ? (
) : (
{items.map((m) => (
))}
)
}
// stole: https://stackoverflow.com/questions/66845889/next-js-image-how-to-maintain-aspect-ratio-and-add-letterboxes-when-needed
const NaturalImage = (props: ImageProps) => {
const [ratio, setRatio] = useState(4 / 1)
return (
setRatio(naturalWidth / naturalHeight)
}
/>
)
}