diff --git a/web/components/usa-map/state-election-map.tsx b/web/components/usa-map/state-election-map.tsx index 5e5a9a64..ac642fa0 100644 --- a/web/components/usa-map/state-election-map.tsx +++ b/web/components/usa-map/state-election-map.tsx @@ -3,12 +3,9 @@ import Router from 'next/router' import { useEffect, useState } from 'react' import { getProbability } from 'common/calculate' -import { Contract, CPMMBinaryContract } from 'common/contract' +import { CPMMBinaryContract } from 'common/contract' import { Customize, USAMap } from './usa-map' -import { - getContractFromSlug, - listenForContract, -} from 'web/lib/firebase/contracts' +import { listenForContract } from 'web/lib/firebase/contracts' import { interpolateColor } from 'common/util/color' export interface StateElectionMarket { @@ -18,10 +15,14 @@ export interface StateElectionMarket { state: string } -export function StateElectionMap(props: { markets: StateElectionMarket[] }) { +export function StateElectionMap(props: { + markets: StateElectionMarket[] + contracts: CPMMBinaryContract[] +}) { const { markets } = props + const [contracts, setContracts] = useState(props.contracts) + useUpdateContracts(contracts, setContracts) - const contracts = useContracts(markets.map((m) => m.slug)) const probs = contracts.map((c) => c ? getProbability(c as CPMMBinaryContract) : 0.5 ) @@ -50,29 +51,23 @@ const probToColor = (prob: number, isWinRepublican: boolean) => { return interpolateColor('#ebe4ec', color, Math.abs(p - 0.5) * 2) } -const useContracts = (slugs: string[]) => { - const [contracts, setContracts] = useState<(Contract | undefined)[]>( - slugs.map(() => undefined) - ) - - useEffect(() => { - Promise.all(slugs.map((slug) => getContractFromSlug(slug))).then( - (contracts) => setContracts(contracts) - ) - }, [slugs]) - +const useUpdateContracts = ( + contracts: CPMMBinaryContract[], + setContracts: (newContracts: CPMMBinaryContract[]) => void +) => { useEffect(() => { if (contracts.some((c) => c === undefined)) return // listen to contract updates - const unsubs = (contracts as Contract[]).map((c, i) => + const unsubs = contracts.map((c, i) => listenForContract( c.id, - (newC) => newC && setContracts(setAt(contracts, i, newC)) + (newC) => + newC && setContracts(setAt(contracts, i, newC as CPMMBinaryContract)) ) ) return () => unsubs.forEach((u) => u()) - }, [contracts]) + }, [contracts, setContracts]) return contracts } diff --git a/web/components/usa-map/usa-map.tsx b/web/components/usa-map/usa-map.tsx index c372397e..d8d0128b 100644 --- a/web/components/usa-map/usa-map.tsx +++ b/web/components/usa-map/usa-map.tsx @@ -1,6 +1,7 @@ // https://github.com/jb-1980/usa-map-react // MIT License +import clsx from 'clsx' import { DATA } from './data' import { USAState } from './usa-state' @@ -65,40 +66,38 @@ export const USAMap = ({ const stateClickHandler = (state: string) => customize?.[state]?.clickHandler return ( -
- - {title} - - {States({ - hideStateTitle, - fillStateColor, - stateClickHandler, - })} - - - - + + {title} + + {States({ + hideStateTitle, + fillStateColor, + stateClickHandler, + })} + + + - -
+ + ) } diff --git a/web/pages/midterms.tsx b/web/pages/midterms.tsx index 47930bc1..e838ca3f 100644 --- a/web/pages/midterms.tsx +++ b/web/pages/midterms.tsx @@ -1,11 +1,15 @@ +import { CPMMBinaryContract } from 'common/contract' +import { useEffect } from 'react' import { Col } from 'web/components/layout/col' import { Spacer } from 'web/components/layout/spacer' import { Page } from 'web/components/page' +import { SEO } from 'web/components/SEO' import { Title } from 'web/components/title' import { StateElectionMarket, StateElectionMap, } from 'web/components/usa-map/state-election-map' +import { getContractFromSlug } from 'web/lib/firebase/contracts' const senateMidterms: StateElectionMarket[] = [ { @@ -175,27 +179,60 @@ const governorMidterms: StateElectionMarket[] = [ }, ] -const App = () => { +export async function getStaticProps() { + const senateContracts = await Promise.all( + senateMidterms.map((m) => getContractFromSlug(m.slug)) + ) + + const governorContracts = await Promise.all( + governorMidterms.map((m) => getContractFromSlug(m.slug)) + ) + + return { + props: { senateContracts, governorContracts }, + revalidate: 60, // regenerate after a minute + } +} + +const App = (props: { + senateContracts: CPMMBinaryContract[] + governorContracts: CPMMBinaryContract[] +}) => { + useSetIframeBackbroundColor() + const { senateContracts, governorContracts } = props + return ( + <SEO + title="2022 US Midterm Elections" + description="Bet on the midterm elections using prediction markets. See Manifold's state-by-state breakdown of senate and governor races." + /> <div className="mt-2 text-2xl">Senate</div> - <StateElectionMap markets={senateMidterms} /> + <StateElectionMap + markets={senateMidterms} + contracts={senateContracts} + /> <iframe src="https://manifold.markets/TomShlomi/will-the-gop-control-the-us-senate" frameBorder="0" className="mt-8 flex h-96 w-full" ></iframe> <Spacer h={8} /> + <div className="mt-8 text-2xl">Governors</div> - <StateElectionMap markets={governorMidterms} /> + <StateElectionMap + markets={governorMidterms} + contracts={governorContracts} + /> <iframe src="https://manifold.markets/ManifoldMarkets/democrats-go-down-at-least-one-gove" frameBorder="0" className="mt-8 flex h-96 w-full" ></iframe> <Spacer h={8} /> + <div className="mt-8 text-2xl">House</div> <iframe src="https://manifold.markets/BoltonBailey/will-democrats-maintain-control-of" @@ -203,6 +240,7 @@ const App = () => { className="mt-8 flex h-96 w-full" ></iframe> <Spacer h={8} /> + <div className="mt-8 text-2xl">Related markets</div> <iframe src="https://manifold.markets/BoltonBailey/balance-of-power-in-us-congress-aft" @@ -232,4 +270,13 @@ const App = () => { ) } +const useSetIframeBackbroundColor = () => { + useEffect(() => { + if (window.location.host !== 'manifold.markets') return + for (let i = 0; i < self.frames.length; i++) { + self.frames[i].document.body.style.backgroundColor = '#f9fafb' + } + }, []) +} + export default App