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: '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) } /> ) }