From a82f447965c503c2284f373a3382506986fac8ea Mon Sep 17 00:00:00 2001 From: James Grugett Date: Sun, 2 Oct 2022 18:20:25 -0500 Subject: [PATCH 1/5] Fix free response comment threading --- web/components/contract/contract-tabs.tsx | 52 +++++++++++++---------- web/pages/labs/index.tsx | 2 +- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/web/components/contract/contract-tabs.tsx b/web/components/contract/contract-tabs.tsx index bf18fdbe..33c66c57 100644 --- a/web/components/contract/contract-tabs.tsx +++ b/web/components/contract/contract-tabs.tsx @@ -77,13 +77,34 @@ const CommentsTabContent = memo(function CommentsTabContent(props: { const comments = useComments(contract.id) ?? props.comments const [sort, setSort] = useState<'Newest' | 'Best'>('Newest') const me = useUser() + if (comments == null) { return } + + const tipsOrBountiesAwarded = + Object.keys(tips).length > 0 || comments.some((c) => c.bountiesAwarded) + + const sortedComments = sortBy(comments, (c) => + sort === 'Newest' + ? c.createdTime + : // Is this too magic? If there are tips/bounties, 'Best' shows your own comments made within the last 10 minutes first, then sorts by score + tipsOrBountiesAwarded && + c.createdTime > Date.now() - 10 * MINUTE_MS && + c.userId === me?.id + ? -Infinity + : -((c.bountiesAwarded ?? 0) + sum(Object.values(tips[c.id] ?? []))) + ) + + const commentsByParent = groupBy( + sortedComments, + (c) => c.replyToCommentId ?? '_' + ) + const topLevelComments = commentsByParent['_'] ?? [] + // Top level comments are reverse-chronological, while replies are chronological + if (sort === 'Newest') topLevelComments.reverse() + if (contract.outcomeType === 'FREE_RESPONSE') { - const generalComments = comments.filter( - (c) => c.answerOutcome === undefined && c.betId === undefined - ) const sortedAnswers = sortBy( contract.answers, (a) => -getOutcomeProbability(contract, a.id) @@ -92,6 +113,9 @@ const CommentsTabContent = memo(function CommentsTabContent(props: { comments, (c) => c.answerOutcome ?? c.betOutcome ?? '_' ) + const generalTopLevelComments = topLevelComments.filter( + (c) => c.answerOutcome === undefined && c.betId === undefined + ) return ( <> {sortedAnswers.map((answer) => ( @@ -115,12 +139,12 @@ const CommentsTabContent = memo(function CommentsTabContent(props: {
General Comments
- {generalComments.map((comment) => ( + {generalTopLevelComments.map((comment) => ( ))} @@ -128,24 +152,6 @@ const CommentsTabContent = memo(function CommentsTabContent(props: { ) } else { - const tipsOrBountiesAwarded = - Object.keys(tips).length > 0 || comments.some((c) => c.bountiesAwarded) - - const commentsByParent = groupBy( - sortBy(comments, (c) => - sort === 'Newest' - ? -c.createdTime - : // Is this too magic? If there are tips/bounties, 'Best' shows your own comments made within the last 10 minutes first, then sorts by score - tipsOrBountiesAwarded && - c.createdTime > Date.now() - 10 * MINUTE_MS && - c.userId === me?.id - ? -Infinity - : -((c.bountiesAwarded ?? 0) + sum(Object.values(tips[c.id] ?? []))) - ), - (c) => c.replyToCommentId ?? '_' - ) - - const topLevelComments = commentsByParent['_'] ?? [] return ( <> diff --git a/web/pages/labs/index.tsx b/web/pages/labs/index.tsx index bd1dbb35..79f44a64 100644 --- a/web/pages/labs/index.tsx +++ b/web/pages/labs/index.tsx @@ -16,7 +16,7 @@ export default function LabsPage() { url="/labs" /> - + <Title className="sm:!mt-0" text="🧪 Manifold Labs" /> <Masonry breakpointCols={{ default: 2, 768: 1 }} From bf8dca25b23e674531c2b4dff8a3dc114089519e Mon Sep 17 00:00:00 2001 From: Marshall Polaris <marshall@pol.rs> Date: Sun, 2 Oct 2022 16:56:29 -0700 Subject: [PATCH 2/5] Rewrite stats graphs using new machinery (#985) * Make curve configurable on generic charts * Extract SizedContainer helper component * Use new charts for stats page * Move analytics charts component * Fix up start date logic for graphs excluding data --- web/components/analytics/charts.tsx | 139 ------------------ web/components/charts/contract/binary.tsx | 2 + web/components/charts/contract/choice.tsx | 2 + .../charts/contract/pseudo-numeric.tsx | 2 + web/components/charts/generic-charts.tsx | 19 ++- web/components/charts/helpers.tsx | 12 +- web/components/charts/stats.tsx | 76 ++++++++++ web/components/contract/contract-overview.tsx | 35 ++--- web/components/sized-container.tsx | 35 +++++ web/pages/stats.tsx | 137 +++++++---------- 10 files changed, 200 insertions(+), 259 deletions(-) delete mode 100644 web/components/analytics/charts.tsx create mode 100644 web/components/charts/stats.tsx create mode 100644 web/components/sized-container.tsx diff --git a/web/components/analytics/charts.tsx b/web/components/analytics/charts.tsx deleted file mode 100644 index 131ce2a0..00000000 --- a/web/components/analytics/charts.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import { Point, ResponsiveLine } from '@nivo/line' -import clsx from 'clsx' -import { formatPercent } from 'common/util/format' -import dayjs from 'dayjs' -import { zip } from 'lodash' -import { useWindowSize } from 'web/hooks/use-window-size' -import { Col } from '../layout/col' - -export function DailyCountChart(props: { - startDate: number - dailyCounts: number[] - small?: boolean -}) { - const { dailyCounts, startDate, small } = props - const { width } = useWindowSize() - - const dates = dailyCounts.map((_, i) => - dayjs(startDate).add(i, 'day').toDate() - ) - - const points = zip(dates, dailyCounts).map(([date, betCount]) => ({ - x: date, - y: betCount, - })) - const data = [{ id: 'Count', data: points, color: '#11b981' }] - - const bottomAxisTicks = width && width < 600 ? 6 : undefined - - return ( - <div - className={clsx( - 'h-[250px] w-full overflow-hidden', - !small && 'md:h-[400px]' - )} - > - <ResponsiveLine - data={data} - yScale={{ type: 'linear', stacked: false }} - xScale={{ - type: 'time', - }} - axisBottom={{ - tickValues: bottomAxisTicks, - format: (date) => dayjs(date).format('MMM DD'), - }} - colors={{ datum: 'color' }} - pointSize={0} - pointBorderWidth={1} - pointBorderColor="#fff" - enableSlices="x" - enableGridX={!!width && width >= 800} - enableArea - margin={{ top: 20, right: 28, bottom: 22, left: 40 }} - sliceTooltip={({ slice }) => { - const point = slice.points[0] - return <Tooltip point={point} /> - }} - /> - </div> - ) -} - -export function DailyPercentChart(props: { - startDate: number - dailyPercent: number[] - small?: boolean - excludeFirstDays?: number -}) { - const { dailyPercent, startDate, small, excludeFirstDays } = props - const { width } = useWindowSize() - - const dates = dailyPercent.map((_, i) => - dayjs(startDate).add(i, 'day').toDate() - ) - - const points = zip(dates, dailyPercent) - .map(([date, percent]) => ({ - x: date, - y: percent, - })) - .slice(excludeFirstDays ?? 0) - const data = [{ id: 'Percent', data: points, color: '#11b981' }] - - const bottomAxisTicks = width && width < 600 ? 6 : undefined - - return ( - <div - className={clsx( - 'h-[250px] w-full overflow-hidden', - !small && 'md:h-[400px]' - )} - > - <ResponsiveLine - data={data} - yScale={{ type: 'linear', stacked: false }} - xScale={{ - type: 'time', - }} - axisLeft={{ - format: formatPercent, - }} - axisBottom={{ - tickValues: bottomAxisTicks, - format: (date) => dayjs(date).format('MMM DD'), - }} - colors={{ datum: 'color' }} - pointSize={0} - pointBorderWidth={1} - pointBorderColor="#fff" - enableSlices="x" - enableGridX={!!width && width >= 800} - enableArea - margin={{ top: 20, right: 28, bottom: 22, left: 40 }} - sliceTooltip={({ slice }) => { - const point = slice.points[0] - return <Tooltip point={point} isPercent /> - }} - /> - </div> - ) -} - -function Tooltip(props: { point: Point; isPercent?: boolean }) { - const { point, isPercent } = props - return ( - <Col className="border border-gray-300 bg-white py-2 px-3"> - <div - className="pb-1" - style={{ - color: point.serieColor, - }} - > - <strong>{point.serieId}</strong>{' '} - {isPercent ? formatPercent(+point.data.y) : Math.round(+point.data.y)} - </div> - <div>{dayjs(point.data.x).format('MMM DD')}</div> - </Col> - ) -} diff --git a/web/components/charts/contract/binary.tsx b/web/components/charts/contract/binary.tsx index 7e192767..c9b3bb0b 100644 --- a/web/components/charts/contract/binary.tsx +++ b/web/components/charts/contract/binary.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react' import { last, sortBy } from 'lodash' import { scaleTime, scaleLinear } from 'd3-scale' +import { curveStepAfter } from 'd3-shape' import { Bet } from 'common/bet' import { getProbability, getInitialProbability } from 'common/calculate' @@ -76,6 +77,7 @@ export const BinaryContractChart = (props: { yScale={yScale} data={data} color="#11b981" + curve={curveStepAfter} onMouseOver={onMouseOver} Tooltip={BinaryChartTooltip} pct diff --git a/web/components/charts/contract/choice.tsx b/web/components/charts/contract/choice.tsx index 65279b70..99e02fa8 100644 --- a/web/components/charts/contract/choice.tsx +++ b/web/components/charts/contract/choice.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react' import { last, sum, sortBy, groupBy } from 'lodash' import { scaleTime, scaleLinear } from 'd3-scale' +import { curveStepAfter } from 'd3-shape' import { Bet } from 'common/bet' import { Answer } from 'common/answer' @@ -214,6 +215,7 @@ export const ChoiceContractChart = (props: { yScale={yScale} data={data} colors={CATEGORY_COLORS} + curve={curveStepAfter} onMouseOver={onMouseOver} Tooltip={ChoiceTooltip} pct diff --git a/web/components/charts/contract/pseudo-numeric.tsx b/web/components/charts/contract/pseudo-numeric.tsx index e03d4ad9..9e06b368 100644 --- a/web/components/charts/contract/pseudo-numeric.tsx +++ b/web/components/charts/contract/pseudo-numeric.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react' import { last, sortBy } from 'lodash' import { scaleTime, scaleLog, scaleLinear } from 'd3-scale' +import { curveStepAfter } from 'd3-shape' import { Bet } from 'common/bet' import { DAY_MS } from 'common/util/time' @@ -97,6 +98,7 @@ export const PseudoNumericContractChart = (props: { xScale={xScale} yScale={yScale} data={data} + curve={curveStepAfter} onMouseOver={onMouseOver} Tooltip={PseudoNumericChartTooltip} color={NUMERIC_GRAPH_COLOR} diff --git a/web/components/charts/generic-charts.tsx b/web/components/charts/generic-charts.tsx index 152b264c..cb930484 100644 --- a/web/components/charts/generic-charts.tsx +++ b/web/components/charts/generic-charts.tsx @@ -4,11 +4,11 @@ import { axisBottom, axisLeft } from 'd3-axis' import { D3BrushEvent } from 'd3-brush' import { ScaleTime, ScaleContinuousNumeric } from 'd3-scale' import { + CurveFactory, + SeriesPoint, curveLinear, - curveStepAfter, stack, stackOrderReverse, - SeriesPoint, } from 'd3-shape' import { range } from 'lodash' @@ -52,10 +52,11 @@ export const DistributionChart = <P extends DistributionPoint>(props: { color: string xScale: ScaleContinuousNumeric<number, number> yScale: ScaleContinuousNumeric<number, number> + curve?: CurveFactory onMouseOver?: (p: P | undefined) => void Tooltip?: TooltipComponent<number, P> }) => { - const { color, data, yScale, w, h, Tooltip } = props + const { color, data, yScale, w, h, curve, Tooltip } = props const [viewXScale, setViewXScale] = useState<ScaleContinuousNumeric<number, number>>() @@ -100,7 +101,7 @@ export const DistributionChart = <P extends DistributionPoint>(props: { px={px} py0={py0} py1={py1} - curve={curveLinear} + curve={curve ?? curveLinear} /> </SVGChart> ) @@ -113,11 +114,12 @@ export const MultiValueHistoryChart = <P extends MultiPoint>(props: { colors: readonly string[] xScale: ScaleTime<number, number> yScale: ScaleContinuousNumeric<number, number> + curve?: CurveFactory onMouseOver?: (p: P | undefined) => void Tooltip?: TooltipComponent<Date, P> pct?: boolean }) => { - const { colors, data, yScale, w, h, Tooltip, pct } = props + const { colors, data, yScale, w, h, curve, Tooltip, pct } = props const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>() const xScale = viewXScale ?? props.xScale @@ -177,7 +179,7 @@ export const MultiValueHistoryChart = <P extends MultiPoint>(props: { px={px} py0={py0} py1={py1} - curve={curveStepAfter} + curve={curve ?? curveLinear} fill={colors[i]} /> ))} @@ -192,11 +194,12 @@ export const SingleValueHistoryChart = <P extends HistoryPoint>(props: { color: string xScale: ScaleTime<number, number> yScale: ScaleContinuousNumeric<number, number> + curve?: CurveFactory onMouseOver?: (p: P | undefined) => void Tooltip?: TooltipComponent<Date, P> pct?: boolean }) => { - const { color, data, yScale, w, h, Tooltip, pct } = props + const { color, data, yScale, w, h, curve, Tooltip, pct } = props const [viewXScale, setViewXScale] = useState<ScaleTime<number, number>>() const xScale = viewXScale ?? props.xScale @@ -246,7 +249,7 @@ export const SingleValueHistoryChart = <P extends HistoryPoint>(props: { px={px} py0={py0} py1={py1} - curve={curveStepAfter} + curve={curve ?? curveLinear} /> </SVGChart> ) diff --git a/web/components/charts/helpers.tsx b/web/components/charts/helpers.tsx index 96115dc0..b40ab7db 100644 --- a/web/components/charts/helpers.tsx +++ b/web/components/charts/helpers.tsx @@ -10,7 +10,7 @@ import { import { pointer, select } from 'd3-selection' import { Axis, AxisScale } from 'd3-axis' import { brushX, D3BrushEvent } from 'd3-brush' -import { area, line, curveStepAfter, CurveFactory } from 'd3-shape' +import { area, line, CurveFactory } from 'd3-shape' import { nanoid } from 'nanoid' import dayjs from 'dayjs' import clsx from 'clsx' @@ -73,11 +73,11 @@ const LinePathInternal = <P,>( data: P[] px: number | ((p: P) => number) py: number | ((p: P) => number) - curve?: CurveFactory + curve: CurveFactory } & SVGProps<SVGPathElement> ) => { const { data, px, py, curve, ...rest } = props - const d3Line = line<P>(px, py).curve(curve ?? curveStepAfter) + const d3Line = line<P>(px, py).curve(curve) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return <path {...rest} fill="none" d={d3Line(data)!} /> } @@ -89,11 +89,11 @@ const AreaPathInternal = <P,>( px: number | ((p: P) => number) py0: number | ((p: P) => number) py1: number | ((p: P) => number) - curve?: CurveFactory + curve: CurveFactory } & SVGProps<SVGPathElement> ) => { const { data, px, py0, py1, curve, ...rest } = props - const d3Area = area<P>(px, py0, py1).curve(curve ?? curveStepAfter) + const d3Area = area<P>(px, py0, py1).curve(curve) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return <path {...rest} d={d3Area(data)!} /> } @@ -105,7 +105,7 @@ export const AreaWithTopStroke = <P,>(props: { px: number | ((p: P) => number) py0: number | ((p: P) => number) py1: number | ((p: P) => number) - curve?: CurveFactory + curve: CurveFactory }) => { const { color, data, px, py0, py1, curve } = props return ( diff --git a/web/components/charts/stats.tsx b/web/components/charts/stats.tsx new file mode 100644 index 00000000..a630657a --- /dev/null +++ b/web/components/charts/stats.tsx @@ -0,0 +1,76 @@ +import { useMemo } from 'react' +import { scaleTime, scaleLinear } from 'd3-scale' +import { min, max } from 'lodash' +import dayjs from 'dayjs' + +import { formatPercent } from 'common/util/format' +import { Row } from '../layout/row' +import { HistoryPoint, SingleValueHistoryChart } from './generic-charts' +import { TooltipProps, MARGIN_X, MARGIN_Y } from './helpers' +import { SizedContainer } from 'web/components/sized-container' + +const getPoints = (startDate: number, dailyValues: number[]) => { + const startDateDayJs = dayjs(startDate) + return dailyValues.map((y, i) => ({ + x: startDateDayJs.add(i, 'day').toDate(), + y: y, + })) +} + +const DailyCountTooltip = (props: TooltipProps<Date, HistoryPoint>) => { + const { data, mouseX, xScale } = props + const d = xScale.invert(mouseX) + return ( + <Row className="items-center gap-2"> + <span className="font-semibold">{dayjs(d).format('MMM DD')}</span> + <span className="text-greyscale-6">{data.y}</span> + </Row> + ) +} + +const DailyPercentTooltip = (props: TooltipProps<Date, HistoryPoint>) => { + const { data, mouseX, xScale } = props + const d = xScale.invert(mouseX) + return ( + <Row className="items-center gap-2"> + <span className="font-semibold">{dayjs(d).format('MMM DD')}</span> + <span className="text-greyscale-6">{formatPercent(data.y)}</span> + </Row> + ) +} + +export function DailyChart(props: { + startDate: number + dailyValues: number[] + excludeFirstDays?: number + pct?: boolean +}) { + const { dailyValues, startDate, excludeFirstDays, pct } = props + + const data = useMemo( + () => getPoints(startDate, dailyValues).slice(excludeFirstDays ?? 0), + [startDate, dailyValues, excludeFirstDays] + ) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const minDate = min(data.map((d) => d.x))! + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const maxDate = max(data.map((d) => d.x))! + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const maxValue = max(data.map((d) => d.y))! + return ( + <SizedContainer fullHeight={250} mobileHeight={250}> + {(width, height) => ( + <SingleValueHistoryChart + w={width} + h={height} + xScale={scaleTime([minDate, maxDate], [0, width - MARGIN_X])} + yScale={scaleLinear([0, maxValue], [height - MARGIN_Y, 0])} + data={data} + Tooltip={pct ? DailyPercentTooltip : DailyCountTooltip} + color="#11b981" + pct={pct} + /> + )} + </SizedContainer> + ) +} diff --git a/web/components/contract/contract-overview.tsx b/web/components/contract/contract-overview.tsx index 2a6d5172..95600a8e 100644 --- a/web/components/contract/contract-overview.tsx +++ b/web/components/contract/contract-overview.tsx @@ -1,5 +1,3 @@ -import React, { useEffect, useRef, useState } from 'react' - import { tradingAllowed } from 'web/lib/firebase/contracts' import { Col } from '../layout/col' import { ContractChart } from 'web/components/charts/contract' @@ -24,6 +22,7 @@ import { BinaryContract, } from 'common/contract' import { ContractDetails } from './contract-details' +import { SizedContainer } from 'web/components/sized-container' const OverviewQuestion = (props: { text: string }) => ( <Linkify className="text-lg text-indigo-700 sm:text-2xl" text={props.text} /> @@ -49,32 +48,18 @@ const SizedContractChart = (props: { fullHeight: number mobileHeight: number }) => { - const { contract, bets, fullHeight, mobileHeight } = props - const containerRef = useRef<HTMLDivElement>(null) - const [chartWidth, setChartWidth] = useState<number>() - const [chartHeight, setChartHeight] = useState<number>() - useEffect(() => { - const handleResize = () => { - setChartHeight(window.innerWidth < 800 ? mobileHeight : fullHeight) - setChartWidth(containerRef.current?.clientWidth) - } - handleResize() - window.addEventListener('resize', handleResize) - return () => { - window.removeEventListener('resize', handleResize) - } - }, [fullHeight, mobileHeight]) + const { fullHeight, mobileHeight, contract, bets } = props return ( - <div ref={containerRef}> - {chartWidth != null && chartHeight != null && ( + <SizedContainer fullHeight={fullHeight} mobileHeight={mobileHeight}> + {(width, height) => ( <ContractChart + width={width} + height={height} contract={contract} bets={bets} - width={chartWidth} - height={chartHeight} /> )} - </div> + </SizedContainer> ) } @@ -114,7 +99,11 @@ const BinaryOverview = (props: { contract: BinaryContract; bets: Bet[] }) => { <ContractDetails contract={contract} /> <Row className="justify-between gap-4"> <OverviewQuestion text={contract.question} /> - <BinaryResolutionOrChance contract={contract} large /> + <BinaryResolutionOrChance + className="flex items-end" + contract={contract} + large + /> </Row> </Col> <SizedContractChart diff --git a/web/components/sized-container.tsx b/web/components/sized-container.tsx new file mode 100644 index 00000000..26532047 --- /dev/null +++ b/web/components/sized-container.tsx @@ -0,0 +1,35 @@ +import { ReactNode, useEffect, useRef, useState } from 'react' + +export const SizedContainer = (props: { + fullHeight: number + mobileHeight: number + mobileThreshold?: number + children: (width: number, height: number) => ReactNode +}) => { + const { children, fullHeight, mobileHeight } = props + const threshold = props.mobileThreshold ?? 800 + const containerRef = useRef<HTMLDivElement>(null) + const [width, setWidth] = useState<number>() + const [height, setHeight] = useState<number>() + useEffect(() => { + if (containerRef.current) { + const handleResize = () => { + setHeight(window.innerWidth <= threshold ? mobileHeight : fullHeight) + setWidth(containerRef.current?.clientWidth) + } + handleResize() + const resizeObserver = new ResizeObserver(handleResize) + resizeObserver.observe(containerRef.current) + window.addEventListener('resize', handleResize) + return () => { + window.removeEventListener('resize', handleResize) + resizeObserver.disconnect() + } + } + }, [threshold, fullHeight, mobileHeight]) + return ( + <div ref={containerRef}> + {width != null && height != null && children(width, height)} + </div> + ) +} diff --git a/web/pages/stats.tsx b/web/pages/stats.tsx index 19fab509..125af4bd 100644 --- a/web/pages/stats.tsx +++ b/web/pages/stats.tsx @@ -1,8 +1,5 @@ import { useEffect, useState } from 'react' -import { - DailyCountChart, - DailyPercentChart, -} from 'web/components/analytics/charts' +import { DailyChart } from 'web/components/charts/stats' import { Col } from 'web/components/layout/col' import { Spacer } from 'web/components/layout/spacer' import { Tabs } from 'web/components/layout/tabs' @@ -96,40 +93,36 @@ export function CustomAnalytics(props: Stats) { { title: 'Daily', content: ( - <DailyCountChart - dailyCounts={dailyActiveUsers} + <DailyChart + dailyValues={dailyActiveUsers} startDate={startDate} - small /> ), }, { title: 'Daily (7d avg)', content: ( - <DailyCountChart - dailyCounts={dailyActiveUsersWeeklyAvg} + <DailyChart + dailyValues={dailyActiveUsersWeeklyAvg} startDate={startDate} - small /> ), }, { title: 'Weekly', content: ( - <DailyCountChart - dailyCounts={weeklyActiveUsers} + <DailyChart + dailyValues={weeklyActiveUsers} startDate={startDate} - small /> ), }, { title: 'Monthly', content: ( - <DailyCountChart - dailyCounts={monthlyActiveUsers} + <DailyChart + dailyValues={monthlyActiveUsers} startDate={startDate} - small /> ), }, @@ -149,44 +142,44 @@ export function CustomAnalytics(props: Stats) { { title: 'D1', content: ( - <DailyPercentChart - dailyPercent={d1} + <DailyChart + dailyValues={d1} startDate={startDate} - small excludeFirstDays={1} + pct /> ), }, { title: 'D1 (7d avg)', content: ( - <DailyPercentChart - dailyPercent={d1WeeklyAvg} + <DailyChart + dailyValues={d1WeeklyAvg} startDate={startDate} - small excludeFirstDays={7} + pct /> ), }, { title: 'W1', content: ( - <DailyPercentChart - dailyPercent={weekOnWeekRetention} + <DailyChart + dailyValues={weekOnWeekRetention} startDate={startDate} - small excludeFirstDays={14} + pct /> ), }, { title: 'M1', content: ( - <DailyPercentChart - dailyPercent={monthlyRetention} + <DailyChart + dailyValues={monthlyRetention} startDate={startDate} - small excludeFirstDays={60} + pct /> ), }, @@ -207,33 +200,33 @@ export function CustomAnalytics(props: Stats) { { title: 'ND1', content: ( - <DailyPercentChart - dailyPercent={nd1} + <DailyChart + dailyValues={nd1} startDate={startDate} excludeFirstDays={1} - small + pct /> ), }, { title: 'ND1 (7d avg)', content: ( - <DailyPercentChart - dailyPercent={nd1WeeklyAvg} + <DailyChart + dailyValues={nd1WeeklyAvg} startDate={startDate} excludeFirstDays={7} - small + pct /> ), }, { title: 'NW1', content: ( - <DailyPercentChart - dailyPercent={nw1} + <DailyChart + dailyValues={nw1} startDate={startDate} excludeFirstDays={14} - small + pct /> ), }, @@ -249,41 +242,31 @@ export function CustomAnalytics(props: Stats) { { title: capitalize(PAST_BETS), content: ( - <DailyCountChart - dailyCounts={dailyBetCounts} - startDate={startDate} - small - /> + <DailyChart dailyValues={dailyBetCounts} startDate={startDate} /> ), }, { title: 'Markets created', content: ( - <DailyCountChart - dailyCounts={dailyContractCounts} + <DailyChart + dailyValues={dailyContractCounts} startDate={startDate} - small /> ), }, { title: 'Comments', content: ( - <DailyCountChart - dailyCounts={dailyCommentCounts} + <DailyChart + dailyValues={dailyCommentCounts} startDate={startDate} - small /> ), }, { title: 'Signups', content: ( - <DailyCountChart - dailyCounts={dailySignups} - startDate={startDate} - small - /> + <DailyChart dailyValues={dailySignups} startDate={startDate} /> ), }, ]} @@ -304,22 +287,22 @@ export function CustomAnalytics(props: Stats) { { title: 'Daily', content: ( - <DailyPercentChart - dailyPercent={dailyActivationRate} + <DailyChart + dailyValues={dailyActivationRate} startDate={startDate} excludeFirstDays={1} - small + pct /> ), }, { title: 'Daily (7d avg)', content: ( - <DailyPercentChart - dailyPercent={dailyActivationRateWeeklyAvg} + <DailyChart + dailyValues={dailyActivationRateWeeklyAvg} startDate={startDate} excludeFirstDays={7} - small + pct /> ), }, @@ -335,33 +318,33 @@ export function CustomAnalytics(props: Stats) { { title: 'Daily / Weekly', content: ( - <DailyPercentChart - dailyPercent={dailyDividedByWeekly} + <DailyChart + dailyValues={dailyDividedByWeekly} startDate={startDate} - small excludeFirstDays={7} + pct /> ), }, { title: 'Daily / Monthly', content: ( - <DailyPercentChart - dailyPercent={dailyDividedByMonthly} + <DailyChart + dailyValues={dailyDividedByMonthly} startDate={startDate} - small excludeFirstDays={30} + pct /> ), }, { title: 'Weekly / Monthly', content: ( - <DailyPercentChart - dailyPercent={weeklyDividedByMonthly} + <DailyChart + dailyValues={weeklyDividedByMonthly} startDate={startDate} - small excludeFirstDays={30} + pct /> ), }, @@ -380,31 +363,19 @@ export function CustomAnalytics(props: Stats) { { title: 'Daily', content: ( - <DailyCountChart - dailyCounts={manaBet.daily} - startDate={startDate} - small - /> + <DailyChart dailyValues={manaBet.daily} startDate={startDate} /> ), }, { title: 'Weekly', content: ( - <DailyCountChart - dailyCounts={manaBet.weekly} - startDate={startDate} - small - /> + <DailyChart dailyValues={manaBet.weekly} startDate={startDate} /> ), }, { title: 'Monthly', content: ( - <DailyCountChart - dailyCounts={manaBet.monthly} - startDate={startDate} - small - /> + <DailyChart dailyValues={manaBet.monthly} startDate={startDate} /> ), }, ]} From 503038d2a2e58f43eba264956c9fe41dff96c224 Mon Sep 17 00:00:00 2001 From: Marshall Polaris <marshall@pol.rs> Date: Sun, 2 Oct 2022 16:59:49 -0700 Subject: [PATCH 3/5] Fix a dumb bug on pseudo-numeric charts --- web/components/charts/contract/pseudo-numeric.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/components/charts/contract/pseudo-numeric.tsx b/web/components/charts/contract/pseudo-numeric.tsx index 9e06b368..e3edb11f 100644 --- a/web/components/charts/contract/pseudo-numeric.tsx +++ b/web/components/charts/contract/pseudo-numeric.tsx @@ -86,11 +86,11 @@ export const PseudoNumericContractChart = (props: { Date.now() ) const visibleRange = [start, rightmostDate] - const xScale = scaleTime(visibleRange, [0, width ?? 0 - MARGIN_X]) + const xScale = scaleTime(visibleRange, [0, width - MARGIN_X]) // clamp log scale to make sure zeroes go to the bottom const yScale = isLogScale - ? scaleLog([Math.max(min, 1), max], [height ?? 0 - MARGIN_Y, 0]).clamp(true) - : scaleLinear([min, max], [height ?? 0 - MARGIN_Y, 0]) + ? scaleLog([Math.max(min, 1), max], [height - MARGIN_Y, 0]).clamp(true) + : scaleLinear([min, max], [height - MARGIN_Y, 0]) return ( <SingleValueHistoryChart w={width} From f1ae54355d2d0d38e8b73f34069f1ccfc2277cbd Mon Sep 17 00:00:00 2001 From: mantikoros <sgrugett@gmail.com> Date: Sun, 2 Oct 2022 20:44:16 -0500 Subject: [PATCH 4/5] cowp: pointer cursor --- web/pages/cowp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/pages/cowp.tsx b/web/pages/cowp.tsx index 21494c37..a854f141 100644 --- a/web/pages/cowp.tsx +++ b/web/pages/cowp.tsx @@ -11,7 +11,7 @@ const App = () => { url="/cowp" /> <Link href="https://www.youtube.com/watch?v=FavUpD_IjVY"> - <img src="https://i.imgur.com/Lt54IiU.png" /> + <img src="https://i.imgur.com/Lt54IiU.png" className="cursor-pointer" /> </Link> </Page> ) From 80693620f00da10afc38ec1bc9970ec84264d787 Mon Sep 17 00:00:00 2001 From: James Grugett <jahooma@gmail.com> Date: Sun, 2 Oct 2022 22:46:04 -0500 Subject: [PATCH 5/5] Make alt contract card listen for updates --- web/components/contract/contract-card.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/components/contract/contract-card.tsx b/web/components/contract/contract-card.tsx index a8caf7bd..4b4a32b6 100644 --- a/web/components/contract/contract-card.tsx +++ b/web/components/contract/contract-card.tsx @@ -393,7 +393,9 @@ export function ContractCardProbChange(props: { noLinkAvatar?: boolean className?: string }) { - const { contract, noLinkAvatar, className } = props + const { noLinkAvatar, className } = props + const contract = useContractWithPreload(props.contract) as CPMMBinaryContract + return ( <Col className={clsx(