import { zip } from 'lodash' import Router from 'next/router' import { useEffect, useState } from 'react' import { getProbability } from 'common/calculate' import { Contract, CPMMBinaryContract } from 'common/contract' import { Customize, USAMap } from './usa-map' import { getContractFromSlug, listenForContract, } from 'web/lib/firebase/contracts' import { interpolateColor } from 'common/util/color' export interface StateElectionMarket { creatorUsername: string slug: string isWinRepublican: boolean state: string } export function StateElectionMap(props: { markets: StateElectionMarket[] }) { const { markets } = props const contracts = useContracts(markets.map((m) => m.slug)) const probs = contracts.map((c) => c ? getProbability(c as CPMMBinaryContract) : 0.5 ) const marketsWithProbs = zip(markets, probs) as [ StateElectionMarket, number ][] const stateInfo = marketsWithProbs.map(([market, prob]) => [ market.state, { fill: probToColor(prob, market.isWinRepublican), clickHandler: () => Router.push(`/${market.creatorUsername}/${market.slug}`), }, ]) const config = Object.fromEntries(stateInfo) as Customize return } const probToColor = (prob: number, isWinRepublican: boolean) => { const p = isWinRepublican ? prob : 1 - prob const color = p > 0.5 ? '#e4534b' : '#5f6eb0' 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]) useEffect(() => { if (contracts.some((c) => c === undefined)) return // listen to contract updates const unsubs = (contracts as Contract[]).map((c, i) => listenForContract( c.id, (newC) => newC && setContracts(setAt(contracts, i, newC)) ) ) return () => unsubs.forEach((u) => u()) }, [contracts]) return contracts } function setAt(arr: T[], i: number, val: T) { const newArr = [...arr] newArr[i] = val return newArr }