Separate free response answers & comments (#100)
* Just for playing with, bad code * Whiten answer cards * Separate answers and comments in FR markets * Highlight FR answer in bet w/ comment * Darken answer text and move classname * Normalcase Comment
This commit is contained in:
parent
9270d48e12
commit
7722c723c4
2
functions/.gitignore
vendored
2
functions/.gitignore
vendored
|
@ -16,4 +16,4 @@ package-lock.json
|
||||||
ui-debug.log
|
ui-debug.log
|
||||||
firebase-debug.log
|
firebase-debug.log
|
||||||
firestore-debug.log
|
firestore-debug.log
|
||||||
firestore_export/
|
firestore_export/
|
||||||
|
|
|
@ -68,7 +68,7 @@ export type BetGroupItem = BaseActivityItem & {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AnswerGroupItem = BaseActivityItem & {
|
export type AnswerGroupItem = BaseActivityItem & {
|
||||||
type: 'answergroup'
|
type: 'answergroup' | 'answer'
|
||||||
answer: Answer
|
answer: Answer
|
||||||
items: ActivityItem[]
|
items: ActivityItem[]
|
||||||
}
|
}
|
||||||
|
@ -256,6 +256,38 @@ function getAnswerGroups(
|
||||||
return answerGroups
|
return answerGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAnswers(
|
||||||
|
contract: FullContract<DPM, FreeResponse>,
|
||||||
|
bets: Bet[],
|
||||||
|
user: User | undefined | null
|
||||||
|
) {
|
||||||
|
let outcomes = _.uniq(bets.map((bet) => bet.outcome)).filter(
|
||||||
|
(outcome) => getOutcomeProbability(contract, outcome) > 0.0001
|
||||||
|
)
|
||||||
|
outcomes = _.sortBy(outcomes, (outcome) =>
|
||||||
|
getOutcomeProbability(contract, outcome)
|
||||||
|
)
|
||||||
|
|
||||||
|
const answerGroups = outcomes
|
||||||
|
.map((outcome) => {
|
||||||
|
const answer = contract.answers?.find(
|
||||||
|
(answer) => answer.id === outcome
|
||||||
|
) as Answer
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: outcome,
|
||||||
|
type: 'answer' as const,
|
||||||
|
contract,
|
||||||
|
answer,
|
||||||
|
items: [] as ActivityItem[],
|
||||||
|
user,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((group) => group.answer)
|
||||||
|
|
||||||
|
return answerGroups
|
||||||
|
}
|
||||||
|
|
||||||
function groupBetsAndComments(
|
function groupBetsAndComments(
|
||||||
bets: Bet[],
|
bets: Bet[],
|
||||||
comments: Comment[],
|
comments: Comment[],
|
||||||
|
@ -328,19 +360,37 @@ export function getAllContractActivityItems(
|
||||||
: [{ type: 'description', id: '0', contract }]
|
: [{ type: 'description', id: '0', contract }]
|
||||||
|
|
||||||
if (outcomeType === 'FREE_RESPONSE') {
|
if (outcomeType === 'FREE_RESPONSE') {
|
||||||
|
const onlyUsersBetsOrBetsWithComments = bets.filter((bet) =>
|
||||||
|
comments.some(
|
||||||
|
(comment) => comment.betId === bet.id || bet.userId === user?.id
|
||||||
|
)
|
||||||
|
)
|
||||||
items.push(
|
items.push(
|
||||||
...getAnswerGroups(
|
...groupBetsAndComments(
|
||||||
contract as FullContract<DPM, FreeResponse>,
|
onlyUsersBetsOrBetsWithComments,
|
||||||
bets,
|
|
||||||
comments,
|
comments,
|
||||||
user,
|
contract,
|
||||||
|
user?.id,
|
||||||
{
|
{
|
||||||
sortByProb: true,
|
hideOutcome: false,
|
||||||
abbreviated,
|
abbreviated,
|
||||||
|
smallAvatar: false,
|
||||||
reversed,
|
reversed,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
const commentsByBetId = mapCommentsByBetId(comments)
|
||||||
|
items.push({
|
||||||
|
type: 'commentInput',
|
||||||
|
id: 'commentInput',
|
||||||
|
bets,
|
||||||
|
commentsByBetId,
|
||||||
|
contract,
|
||||||
|
})
|
||||||
|
|
||||||
|
items.push(
|
||||||
|
...getAnswers(contract as FullContract<DPM, FreeResponse>, bets, user)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
items.push(
|
items.push(
|
||||||
...groupBetsAndComments(bets, comments, contract, user?.id, {
|
...groupBetsAndComments(bets, comments, contract, user?.id, {
|
||||||
|
@ -359,14 +409,16 @@ export function getAllContractActivityItems(
|
||||||
items.push({ type: 'resolve', id: `${contract.resolutionTime}`, contract })
|
items.push({ type: 'resolve', id: `${contract.resolutionTime}`, contract })
|
||||||
}
|
}
|
||||||
|
|
||||||
const commentsByBetId = mapCommentsByBetId(comments)
|
if (outcomeType === 'BINARY') {
|
||||||
items.push({
|
const commentsByBetId = mapCommentsByBetId(comments)
|
||||||
type: 'commentInput',
|
items.push({
|
||||||
id: 'commentInput',
|
type: 'commentInput',
|
||||||
bets,
|
id: 'commentInput',
|
||||||
commentsByBetId,
|
bets,
|
||||||
contract,
|
commentsByBetId,
|
||||||
})
|
contract,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (reversed) items.reverse()
|
if (reversed) items.reverse()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// From https://tailwindui.com/components/application-ui/lists/feeds
|
// From https://tailwindui.com/components/application-ui/lists/feeds
|
||||||
import { Fragment, useRef, useState } from 'react'
|
import React, { Fragment, useRef, useState } from 'react'
|
||||||
import * as _ from 'lodash'
|
import * as _ from 'lodash'
|
||||||
import {
|
import {
|
||||||
BanIcon,
|
BanIcon,
|
||||||
|
@ -67,7 +67,12 @@ export function FeedItems(props: {
|
||||||
<div className={clsx('flow-root pr-2 md:pr-0', className)} ref={ref}>
|
<div className={clsx('flow-root pr-2 md:pr-0', className)} ref={ref}>
|
||||||
<div className={clsx(tradingAllowed(contract) ? '' : '-mb-6')}>
|
<div className={clsx(tradingAllowed(contract) ? '' : '-mb-6')}>
|
||||||
{items.map((item, activityItemIdx) => (
|
{items.map((item, activityItemIdx) => (
|
||||||
<div key={item.id} className="relative pb-6">
|
<div
|
||||||
|
key={item.id}
|
||||||
|
className={
|
||||||
|
item.type === 'answer' ? 'relative pb-2' : 'relative pb-6'
|
||||||
|
}
|
||||||
|
>
|
||||||
{activityItemIdx !== items.length - 1 ||
|
{activityItemIdx !== items.length - 1 ||
|
||||||
item.type === 'answergroup' ? (
|
item.type === 'answergroup' ? (
|
||||||
<span
|
<span
|
||||||
|
@ -104,6 +109,8 @@ function FeedItem(props: { item: ActivityItem }) {
|
||||||
return <FeedBetGroup {...item} />
|
return <FeedBetGroup {...item} />
|
||||||
case 'answergroup':
|
case 'answergroup':
|
||||||
return <FeedAnswerGroup {...item} />
|
return <FeedAnswerGroup {...item} />
|
||||||
|
case 'answer':
|
||||||
|
return <FeedAnswerGroup {...item} />
|
||||||
case 'close':
|
case 'close':
|
||||||
return <FeedClose {...item} />
|
return <FeedClose {...item} />
|
||||||
case 'resolve':
|
case 'resolve':
|
||||||
|
@ -195,10 +202,6 @@ export function CommentInput(props: {
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const [comment, setComment] = useState('')
|
const [comment, setComment] = useState('')
|
||||||
|
|
||||||
if (outcomeType === 'FREE_RESPONSE') {
|
|
||||||
return <div />
|
|
||||||
}
|
|
||||||
|
|
||||||
let canCommentOnABet = false
|
let canCommentOnABet = false
|
||||||
bets.some((bet) => {
|
bets.some((bet) => {
|
||||||
// make sure there is not already a comment with a matching bet id:
|
// make sure there is not already a comment with a matching bet id:
|
||||||
|
@ -224,34 +227,38 @@ export function CommentInput(props: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<Row className={'flex w-full gap-2 pt-5'}>
|
||||||
<Avatar avatarUrl={user?.avatarUrl} username={user?.username} />
|
<div>
|
||||||
</div>
|
<Avatar avatarUrl={user?.avatarUrl} username={user?.username} />
|
||||||
<div className={'min-w-0 flex-1 py-1.5'}>
|
</div>
|
||||||
<div className="text-sm text-gray-500">
|
<div className={'min-w-0 flex-1 py-1.5'}>
|
||||||
<div className="mt-2">
|
<div className="text-sm text-gray-500">
|
||||||
<Textarea
|
<div className="mt-2">
|
||||||
value={comment}
|
<Textarea
|
||||||
onChange={(e) => setComment(e.target.value)}
|
value={comment}
|
||||||
className="textarea textarea-bordered w-full resize-none"
|
onChange={(e) => setComment(e.target.value)}
|
||||||
placeholder="Add a comment..."
|
className="textarea textarea-bordered w-full resize-none"
|
||||||
rows={3}
|
placeholder="Add a comment..."
|
||||||
maxLength={MAX_COMMENT_LENGTH}
|
rows={3}
|
||||||
onKeyDown={(e) => {
|
maxLength={MAX_COMMENT_LENGTH}
|
||||||
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
|
onKeyDown={(e) => {
|
||||||
submitComment()
|
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
|
||||||
|
submitComment()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className={
|
||||||
|
'btn btn-outline btn-sm text-transform: mt-1 capitalize'
|
||||||
}
|
}
|
||||||
}}
|
onClick={submitComment}
|
||||||
/>
|
>
|
||||||
<button
|
{user ? 'Comment' : 'Sign in to comment'}
|
||||||
className="btn btn-outline btn-sm mt-1"
|
</button>
|
||||||
onClick={submitComment}
|
</div>
|
||||||
>
|
|
||||||
Comment
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Row>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -644,8 +651,9 @@ function FeedAnswerGroup(props: {
|
||||||
contract: FullContract<any, FreeResponse>
|
contract: FullContract<any, FreeResponse>
|
||||||
answer: Answer
|
answer: Answer
|
||||||
items: ActivityItem[]
|
items: ActivityItem[]
|
||||||
|
type: string
|
||||||
}) {
|
}) {
|
||||||
const { answer, items, contract } = props
|
const { answer, items, contract, type } = props
|
||||||
const { username, avatarUrl, name, text } = answer
|
const { username, avatarUrl, name, text } = answer
|
||||||
|
|
||||||
const prob = getDpmOutcomeProbability(contract.totalShares, answer.id)
|
const prob = getDpmOutcomeProbability(contract.totalShares, answer.id)
|
||||||
|
@ -653,7 +661,13 @@ function FeedAnswerGroup(props: {
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className="flex-1 gap-2">
|
<Col
|
||||||
|
className={
|
||||||
|
type === 'answer'
|
||||||
|
? 'border-base-200 bg-base-200 flex-1 rounded-md p-3'
|
||||||
|
: 'flex-1 gap-2'
|
||||||
|
}
|
||||||
|
>
|
||||||
<Modal open={open} setOpen={setOpen}>
|
<Modal open={open} setOpen={setOpen}>
|
||||||
<AnswerBetPanel
|
<AnswerBetPanel
|
||||||
answer={answer}
|
answer={answer}
|
||||||
|
|
|
@ -27,6 +27,7 @@ export function OutcomeLabel(props: {
|
||||||
contract={contract as FullContract<DPM, FreeResponse>}
|
contract={contract as FullContract<DPM, FreeResponse>}
|
||||||
resolution={outcome}
|
resolution={outcome}
|
||||||
truncate={truncate}
|
truncate={truncate}
|
||||||
|
answerClassName={'font-bold text-base-400'}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user