diff --git a/web/components/answers/answers-panel.tsx b/web/components/answers/answers-panel.tsx index e22db8cc..dff36b6f 100644 --- a/web/components/answers/answers-panel.tsx +++ b/web/components/answers/answers-panel.tsx @@ -27,6 +27,13 @@ import { CHOICE_ANSWER_COLORS } from '../charts/contract/choice' import { useChartAnswers } from '../charts/contract/choice' import { ChatIcon } from '@heroicons/react/outline' +export function getAnswerColor(answer: Answer, answersArray: string[]) { + const colorIndex = answersArray.indexOf(answer.text) + return colorIndex != undefined && colorIndex < CHOICE_ANSWER_COLORS.length + ? CHOICE_ANSWER_COLORS[colorIndex] + : '#B1B1C7' +} + export function AnswersPanel(props: { contract: FreeResponseContract | MultipleChoiceContract onAnswerCommentClick: (answer: Answer) => void @@ -107,8 +114,8 @@ export function AnswersPanel(props: { ? 'checkbox' : undefined - const colorSortedAnswer = useChartAnswers(contract).map( - (value, _index) => value.text + const answersArray = useChartAnswers(contract).map( + (answer, _index) => answer.text ) return ( @@ -139,8 +146,8 @@ export function AnswersPanel(props: { key={item.id} answer={item} contract={contract} - colorIndex={colorSortedAnswer.indexOf(item.text)} onAnswerCommentClick={onAnswerCommentClick} + color={getAnswerColor(item, answersArray)} /> ))} {hasZeroBetAnswers && !showAllAnswers && ( @@ -185,18 +192,14 @@ export function AnswersPanel(props: { function OpenAnswer(props: { contract: FreeResponseContract | MultipleChoiceContract answer: Answer - colorIndex: number | undefined + color: string onAnswerCommentClick: (answer: Answer) => void }) { - const { answer, contract, colorIndex, onAnswerCommentClick } = props + const { answer, contract, onAnswerCommentClick, color } = props const { username, avatarUrl, text } = answer const prob = getDpmOutcomeProbability(contract.totalShares, answer.id) const probPercent = formatPercent(prob) const [open, setOpen] = useState(false) - const color = - colorIndex != undefined && colorIndex < CHOICE_ANSWER_COLORS.length - ? CHOICE_ANSWER_COLORS[colorIndex] + '55' // semi-transparent - : '#B1B1C755' const colorWidth = 100 * Math.max(prob, 0.01) return ( @@ -217,7 +220,7 @@ function OpenAnswer(props: { tradingAllowed(contract) ? 'text-greyscale-7' : 'text-greyscale-5' )} style={{ - background: `linear-gradient(to right, ${color} ${colorWidth}%, #FBFBFF ${colorWidth}%)`, + background: `linear-gradient(to right, ${color}90 ${colorWidth}%, #FBFBFF ${colorWidth}%)`, }} > diff --git a/web/components/comment-input.tsx b/web/components/comment-input.tsx index 385c7828..634fb7f0 100644 --- a/web/components/comment-input.tsx +++ b/web/components/comment-input.tsx @@ -8,10 +8,12 @@ import { useEffect, useState } from 'react' import { useUser } from 'web/hooks/use-user' import { MAX_COMMENT_LENGTH } from 'web/lib/firebase/comments' import Curve from 'web/public/custom-components/curve' +import { getAnswerColor } from './answers/answers-panel' import { Avatar } from './avatar' import { TextEditor, useTextEditor } from './editor' import { CommentsAnswer } from './feed/feed-answer-comment-group' import { ContractCommentInput } from './feed/feed-comments' +import { Col } from './layout/col' import { Row } from './layout/row' import { LoadingIndicator } from './loading-indicator' @@ -81,20 +83,30 @@ export function AnswerCommentInput(props: { contract: Contract answerResponse: Answer onCancelAnswerResponse?: () => void + answersArray: string[] }) { - const { contract, answerResponse, onCancelAnswerResponse } = props + const { contract, answerResponse, onCancelAnswerResponse, answersArray } = + props const replyTo = { id: answerResponse.id, username: answerResponse.username, } - + const color = getAnswerColor(answerResponse, answersArray) return ( <> - - -
- -
+ + +
+ +
+
+ +
+
-
+ ) } diff --git a/web/components/contract/contract-tabs.tsx b/web/components/contract/contract-tabs.tsx index b8b57510..68fbb257 100644 --- a/web/components/contract/contract-tabs.tsx +++ b/web/components/contract/contract-tabs.tsx @@ -2,11 +2,11 @@ import { memo, useState } from 'react' import { Pagination } from 'web/components/pagination' import { FeedBet } from '../feed/feed-bets' import { FeedLiquidity } from '../feed/feed-liquidity' -import { CommentsAnswer } from '../feed/feed-answer-comment-group' +import { FreeResponseComments } from '../feed/feed-answer-comment-group' import { FeedCommentThread, ContractCommentInput } from '../feed/feed-comments' import { groupBy, sortBy, sum } from 'lodash' import { Bet } from 'common/bet' -import { Contract } from 'common/contract' +import { AnyContractType, Contract } from 'common/contract' import { PAST_BETS } from 'common/user' import { ContractBetsTable } from '../bets-list' import { Spacer } from '../layout/spacer' @@ -35,9 +35,7 @@ import { } from 'web/hooks/use-persistent-state' import { safeLocalStorage } from 'web/lib/util/local' import TriangleDownFillIcon from 'web/lib/icons/triangle-down-fill-icon' -import Curve from 'web/public/custom-components/curve' import { Answer } from 'common/answer' -import { AnswerCommentInput } from '../comment-input' export function ContractTabs(props: { contract: Contract @@ -139,95 +137,27 @@ const CommentsTabContent = memo(function CommentsTabContent(props: { ) const topLevelComments = commentsByParent['_'] ?? [] - const sortRow = comments.length > 0 && ( - - - -
Sort by:
- -
-
- ) - if (contract.outcomeType === 'FREE_RESPONSE') { - return ( - <> - - {sortRow} - {answerResponse && ( - - )} - {topLevelComments.map((parent) => { - if (parent.answerOutcome === undefined) { - return ( - c.createdTime - )} - tips={tips} - /> - ) - } - const answer = contract.answers.find( - (answer) => answer.id === parent.answerOutcome - ) - if (answer === undefined) { - console.error('Could not find answer that matches ID') - return <> - } - return ( - <> - - - - -
- -
-
- c.createdTime - )} - tips={tips} - /> -
-
- - ) - })} - - ) - } else { - return ( - <> - - {sortRow} - - {topLevelComments.map((parent) => ( + return ( + <> + + setSort(sort === 'Newest' ? 'Best' : 'Newest')} + /> + {contract.outcomeType === 'FREE_RESPONSE' && ( + + )} + {contract.outcomeType !== 'FREE_RESPONSE' && + topLevelComments.map((parent) => ( ))} - - ) - } + + ) }) const BetsTabContent = memo(function BetsTabContent(props: { @@ -310,3 +239,33 @@ const BetsTabContent = memo(function BetsTabContent(props: { ) }) + +export function SortRow(props: { + comments: ContractComment[] + contract: Contract + sort: 'Best' | 'Newest' + onSortClick: () => void +}) { + const { comments, contract, sort, onSortClick } = props + if (comments.length <= 0) { + return <> + } + return ( + + + +
Sort by:
+ +
+
+ ) +} diff --git a/web/components/feed/feed-answer-comment-group.tsx b/web/components/feed/feed-answer-comment-group.tsx index e1b470a7..5f36aced 100644 --- a/web/components/feed/feed-answer-comment-group.tsx +++ b/web/components/feed/feed-answer-comment-group.tsx @@ -1,42 +1,154 @@ import { Answer } from 'common/answer' -import { Contract } from 'common/contract' -import React, { useEffect, useRef } from 'react' +import { + Contract, + FreeResponseContract, + MultipleChoiceContract, +} from 'common/contract' +import React, { useEffect, useRef, useState } from 'react' import { Col } from 'web/components/layout/col' import { Row } from 'web/components/layout/row' -import { Avatar } from 'web/components/avatar' import { CopyLinkDateTimeComponent } from 'web/components/feed/copy-link-date-time' import { useRouter } from 'next/router' import { UserLink } from 'web/components/user-link' +import { FeedCommentThread } from './feed-comments' +import { AnswerCommentInput } from '../comment-input' +import { ContractComment } from 'common/comment' +import { Dictionary, sortBy } from 'lodash' +import { getAnswerColor } from '../answers/answers-panel' +import Curve from 'web/public/custom-components/curve' +import { CommentTipMap } from 'web/hooks/use-tip-txns' +import { useChartAnswers } from '../charts/contract/choice' -export function CommentsAnswer(props: { answer: Answer; contract: Contract }) { - const { answer, contract } = props - const { username, avatarUrl, name, text } = answer +export function CommentsAnswer(props: { + answer: Answer + contract: Contract + color: string +}) { + const { answer, contract, color } = props + const { username, name, text } = answer const answerElementId = `answer-${answer.id}` - const router = useRouter() - const highlighted = router.asPath.endsWith(`#${answerElementId}`) + + const { isReady, asPath } = useRouter() + const [highlighted, setHighlighted] = useState(false) const answerRef = useRef(null) useEffect(() => { - if (highlighted && answerRef.current != null) { + if (isReady && asPath.endsWith(`#${answerElementId}`)) { + setHighlighted(true) + } + }, [isReady, asPath, answerElementId]) + + useEffect(() => { + if (highlighted && answerRef.current) { answerRef.current.scrollIntoView(true) } }, [highlighted]) return ( - - - -
- answered - -
-
-
{text}
- + +
+ + +
+ answered + +
+
+
{text}
+ + + ) +} + +export function FreeResponseComments(props: { + contract: FreeResponseContract | MultipleChoiceContract + answerResponse: Answer | undefined + onCancelAnswerResponse?: () => void + topLevelComments: ContractComment[] + commentsByParent: Dictionary<[ContractComment, ...ContractComment[]]> + tips: CommentTipMap +}) { + const { + contract, + answerResponse, + onCancelAnswerResponse, + topLevelComments, + commentsByParent, + tips, + } = props + const answersArray = useChartAnswers(contract).map((answer) => answer.text) + return ( + <> + {answerResponse && ( + + )} + {topLevelComments.map((parent) => { + if (parent.answerOutcome === undefined) { + return ( + c.createdTime + )} + tips={tips} + /> + ) + } + const answer = contract.answers.find( + (answer) => answer.id === parent.answerOutcome + ) + if (answer === undefined) { + console.error('Could not find answer that matches ID') + return <> + } + const color = getAnswerColor(answer, answersArray) + return ( + <> + +
+ +
+
+ +
+
+
+ c.createdTime + )} + tips={tips} + /> +
+ + ) + })} + ) } diff --git a/web/public/custom-components/curve.tsx b/web/public/custom-components/curve.tsx index 5a7b3437..3a8b0067 100644 --- a/web/public/custom-components/curve.tsx +++ b/web/public/custom-components/curve.tsx @@ -12,6 +12,7 @@ export default function Curve({ fill="none" stroke={color} strokeWidth={strokeWidth} + transform="rotate(90)" >