import { DatumValue } from '@nivo/core' import { ResponsiveLine } from '@nivo/line' import dayjs from 'dayjs' import { groupBy, sortBy, sumBy } from 'lodash' import { memo } from 'react' import { Bet } from 'common/bet' import { FreeResponseContract } from 'common/contract' import { getOutcomeProbability } from 'common/calculate' import { useBets } from 'web/hooks/use-bets' import { useWindowSize } from 'web/hooks/use-window-size' const NUM_LINES = 6 export const AnswersGraph = memo(function AnswersGraph(props: { contract: FreeResponseContract bets: Bet[] height?: number }) { const { contract, height } = props const { createdTime, resolutionTime, closeTime, answers } = contract const bets = useBets(contract.id) ?? props.bets const { probsByOutcome, sortedOutcomes } = computeProbsByOutcome( bets, contract ) const isClosed = !!closeTime && Date.now() > closeTime const latestTime = dayjs( resolutionTime && isClosed ? Math.min(resolutionTime, closeTime) : isClosed ? closeTime : resolutionTime ?? Date.now() ) const { width } = useWindowSize() const isLargeWidth = !width || width > 800 const labelLength = isLargeWidth ? 50 : 20 const endTime = resolutionTime || isClosed ? latestTime.valueOf() : // Add a fake datapoint in future so the line continues horizontally // to the right. latestTime.add(1, 'month').valueOf() const times = sortBy([ createdTime, ...bets.map((bet) => bet.createdTime), endTime, ]) const dateTimes = times.map((time) => new Date(time)) const data = sortedOutcomes.map((outcome) => { const betProbs = probsByOutcome[outcome] // Add extra point for contract start and end. const probs = [0, ...betProbs, betProbs[betProbs.length - 1]] const points = probs.map((prob, i) => ({ x: dateTimes[i], y: Math.round(prob * 100), })) const answer = answers?.find((answer) => answer.id === outcome)?.text ?? 'None' const answerText = answer.slice(0, labelLength) + (answer.length > labelLength ? '...' : '') return { id: answerText, data: points } }) data.reverse() const yTickValues = [0, 25, 50, 75, 100] const numXTickValues = isLargeWidth ? 5 : 2 const hoursAgo = latestTime.subtract(5, 'hours') const startDate = dayjs(contract.createdTime).isBefore(hoursAgo) ? new Date(contract.createdTime) : hoursAgo.toDate() const lessThanAWeek = dayjs(startDate).add(1, 'week').isAfter(latestTime) return (