From c38d389aff5e25be8b8aa379359caf50ee2d2a5e Mon Sep 17 00:00:00 2001 From: James Grugett Date: Thu, 8 Sep 2022 01:01:04 -0500 Subject: [PATCH] Merge branch 'main' into new-home --- common/comment.ts | 12 +- firestore.rules | 4 + functions/src/place-bet.ts | 2 +- web/components/answers/answer-bet-panel.tsx | 2 +- web/components/arrange-home.tsx | 2 +- web/components/bet-button.tsx | 2 +- web/components/bet-panel.tsx | 12 +- web/components/comment-input.tsx | 175 +++++++++++ web/components/contract-search.tsx | 2 +- web/components/contract/contract-details.tsx | 2 +- .../contract/contract-info-dialog.tsx | 2 +- .../contract/contract-leaderboard.tsx | 2 +- web/components/contract/contract-tabs.tsx | 4 +- web/components/feed/contract-activity.tsx | 4 +- .../feed/feed-answer-comment-group.tsx | 4 +- web/components/feed/feed-comments.tsx | 273 +++++------------- web/components/landing-page-panel.tsx | 17 +- web/components/nav/nav-bar.tsx | 2 +- web/components/nav/profile-menu.tsx | 2 +- web/components/play-money-disclaimer.tsx | 4 +- .../portfolio/portfolio-value-section.tsx | 1 + web/components/profile/loans-modal.tsx | 2 +- web/components/resolution-panel.tsx | 4 +- web/components/sign-up-prompt.tsx | 2 +- web/components/tipper.tsx | 4 +- web/components/user-page.tsx | 2 +- web/components/yes-no-selector.tsx | 2 +- web/hooks/use-comments.ts | 18 +- web/hooks/use-tip-txns.ts | 7 +- web/lib/firebase/comments.ts | 109 +++++-- web/lib/firebase/groups.ts | 3 +- web/lib/firebase/txns.ts | 14 + web/pages/api/v0/group/by-id/[id]/markets.ts | 5 +- web/pages/experimental/home/index.tsx | 4 +- web/pages/group/[...slugs]/index.tsx | 1 + web/pages/leaderboards.tsx | 17 +- web/pages/notifications.tsx | 4 +- web/pages/post/[...slugs]/index.tsx | 77 ++++- web/posts/post-comments.tsx | 172 +++++++++++ 39 files changed, 687 insertions(+), 290 deletions(-) create mode 100644 web/components/comment-input.tsx create mode 100644 web/posts/post-comments.tsx diff --git a/common/comment.ts b/common/comment.ts index 3a4bd9ac..7ecbb6d4 100644 --- a/common/comment.ts +++ b/common/comment.ts @@ -1,6 +1,6 @@ import type { JSONContent } from '@tiptap/core' -export type AnyCommentType = OnContract | OnGroup +export type AnyCommentType = OnContract | OnGroup | OnPost // Currently, comments are created after the bet, not atomically with the bet. // They're uniquely identified by the pair contractId/betId. @@ -20,7 +20,7 @@ export type Comment = { userAvatarUrl?: string } & T -type OnContract = { +export type OnContract = { commentType: 'contract' contractId: string answerOutcome?: string @@ -35,10 +35,16 @@ type OnContract = { betOutcome?: string } -type OnGroup = { +export type OnGroup = { commentType: 'group' groupId: string } +export type OnPost = { + commentType: 'post' + postId: string +} + export type ContractComment = Comment export type GroupComment = Comment +export type PostComment = Comment diff --git a/firestore.rules b/firestore.rules index 15b60d0f..30bf0ec9 100644 --- a/firestore.rules +++ b/firestore.rules @@ -203,6 +203,10 @@ service cloud.firestore { .affectedKeys() .hasOnly(['name', 'content']); allow delete: if isAdmin() || request.auth.uid == resource.data.creatorId; + match /comments/{commentId} { + allow read; + allow create: if request.auth != null && commentMatchesUser(request.auth.uid, request.resource.data) ; + } } } } diff --git a/functions/src/place-bet.ts b/functions/src/place-bet.ts index 404fda50..d98430c1 100644 --- a/functions/src/place-bet.ts +++ b/functions/src/place-bet.ts @@ -135,7 +135,7 @@ export const placebet = newEndpoint({}, async (req, auth) => { !isFinite(newP) || Math.min(...Object.values(newPool ?? {})) < CPMM_MIN_POOL_QTY) ) { - throw new APIError(400, 'Bet too large for current liquidity pool.') + throw new APIError(400, 'Trade too large for current liquidity pool.') } const betDoc = contractDoc.collection('bets').doc() diff --git a/web/components/answers/answer-bet-panel.tsx b/web/components/answers/answer-bet-panel.tsx index ace06b6c..dbf7ff11 100644 --- a/web/components/answers/answer-bet-panel.tsx +++ b/web/components/answers/answer-bet-panel.tsx @@ -120,7 +120,7 @@ export function AnswerBetPanel(props: {
- Bet on {isModal ? `"${answer.text}"` : 'this answer'} + Buy answer: {isModal ? `"${answer.text}"` : 'this answer'}
{!isModal && ( diff --git a/web/components/arrange-home.tsx b/web/components/arrange-home.tsx index c1c86a0e..ae02e3ea 100644 --- a/web/components/arrange-home.tsx +++ b/web/components/arrange-home.tsx @@ -111,7 +111,7 @@ export const getHomeItems = ( { label: 'Trending', id: 'score' }, { label: 'Newest', id: 'newest' }, { label: 'Close date', id: 'close-date' }, - { label: 'Your bets', id: 'your-bets' }, + { label: 'Your trades', id: 'your-bets' }, ...groups.map((g) => ({ label: g.name, id: g.id, diff --git a/web/components/bet-button.tsx b/web/components/bet-button.tsx index 7d84bbc0..77b17678 100644 --- a/web/components/bet-button.tsx +++ b/web/components/bet-button.tsx @@ -38,7 +38,7 @@ export default function BetButton(props: { className={clsx('my-auto inline-flex min-w-[75px] ', btnClassName)} onClick={() => setOpen(true)} > - Bet + Trade ) : ( diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx index c48e92a9..1f2b9bd3 100644 --- a/web/components/bet-panel.tsx +++ b/web/components/bet-panel.tsx @@ -281,7 +281,7 @@ function BuyPanel(props: { title="Whoa, there!" text={`You might not want to spend ${formatPercent( bankrollFraction - )} of your balance on a single bet. \n\nCurrent balance: ${formatMoney( + )} of your balance on a single trade. \n\nCurrent balance: ${formatMoney( user?.balance ?? 0 )}`} /> @@ -379,11 +379,11 @@ function BuyPanel(props: { )} onClick={betDisabled ? undefined : submitBet} > - {isSubmitting ? 'Submitting...' : 'Submit bet'} + {isSubmitting ? 'Submitting...' : 'Submit trade'} )} - {wasSubmitted &&
Bet submitted!
} + {wasSubmitted &&
Trade submitted!
} ) } @@ -569,7 +569,7 @@ function LimitOrderPanel(props: {
- Bet {isPseudoNumeric ? : } up to + Buy {isPseudoNumeric ? : } up to
- Bet {isPseudoNumeric ? : } down to + Buy {isPseudoNumeric ? : } down to
-
Bet
+
Trade
{!hideToggle && ( void + className?: string + presetId?: string +}) { + const { + parentAnswerOutcome, + parentCommentId, + replyToUser, + onSubmitComment, + presetId, + } = props + const user = useUser() + + const { editor, upload } = useTextEditor({ + simple: true, + max: MAX_COMMENT_LENGTH, + placeholder: + !!parentCommentId || !!parentAnswerOutcome + ? 'Write a reply...' + : 'Write a comment...', + }) + + const [isSubmitting, setIsSubmitting] = useState(false) + + async function submitComment(betId: string | undefined) { + if (!editor || editor.isEmpty || isSubmitting) return + setIsSubmitting(true) + onSubmitComment?.(editor, betId) + setIsSubmitting(false) + } + + if (user?.isBannedFromPosting) return <> + + return ( + + +
+ +
+
+ ) +} + +export function CommentInputTextArea(props: { + user: User | undefined | null + replyToUser?: { id: string; username: string } + editor: Editor | null + upload: Parameters[0]['upload'] + submitComment: (id?: string) => void + isSubmitting: boolean + submitOnEnter?: boolean + presetId?: string +}) { + const { + user, + editor, + upload, + submitComment, + presetId, + isSubmitting, + submitOnEnter, + replyToUser, + } = props + const isMobile = (useWindowSize().width ?? 0) < 768 // TODO: base off input device (keybord vs touch) + + useEffect(() => { + editor?.setEditable(!isSubmitting) + }, [isSubmitting, editor]) + + const submit = () => { + submitComment(presetId) + editor?.commands?.clearContent() + } + + useEffect(() => { + if (!editor) { + return + } + // submit on Enter key + editor.setOptions({ + editorProps: { + handleKeyDown: (view, event) => { + if ( + submitOnEnter && + event.key === 'Enter' && + !event.shiftKey && + (!isMobile || event.ctrlKey || event.metaKey) && + // mention list is closed + !(view.state as any).mention$.active + ) { + submit() + event.preventDefault() + return true + } + return false + }, + }, + }) + // insert at mention and focus + if (replyToUser) { + editor + .chain() + .setContent({ + type: 'mention', + attrs: { label: replyToUser.username, id: replyToUser.id }, + }) + .insertContent(' ') + .focus() + .run() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [editor]) + + return ( + <> + + {user && !isSubmitting && ( + + )} + + {isSubmitting && ( + + )} + + + {!user && ( + + )} + + + ) +} diff --git a/web/components/contract-search.tsx b/web/components/contract-search.tsx index a7c22d80..668dbaf3 100644 --- a/web/components/contract-search.tsx +++ b/web/components/contract-search.tsx @@ -444,7 +444,7 @@ function ContractSearchControls(props: { selected={state.pillFilter === 'your-bets'} onSelect={selectPill('your-bets')} > - Your bets + Your trades
)} diff --git a/web/components/contract/contract-details.tsx b/web/components/contract/contract-details.tsx index 48528029..c383d349 100644 --- a/web/components/contract/contract-details.tsx +++ b/web/components/contract/contract-details.tsx @@ -294,7 +294,7 @@ export function ExtraMobileContractDetails(props: { {volumeTranslation} diff --git a/web/components/contract/contract-info-dialog.tsx b/web/components/contract/contract-info-dialog.tsx index f376a04a..ae586725 100644 --- a/web/components/contract/contract-info-dialog.tsx +++ b/web/components/contract/contract-info-dialog.tsx @@ -135,7 +135,7 @@ export function ContractInfoDialog(props: { */} - Bettors + Traders {bettorsCount} diff --git a/web/components/contract/contract-leaderboard.tsx b/web/components/contract/contract-leaderboard.tsx index ce5c7da6..1eaf7043 100644 --- a/web/components/contract/contract-leaderboard.tsx +++ b/web/components/contract/contract-leaderboard.tsx @@ -49,7 +49,7 @@ export function ContractLeaderboard(props: { return users && users.length > 0 ? ( {!user ? ( diff --git a/web/components/feed/contract-activity.tsx b/web/components/feed/contract-activity.tsx index 0878e570..55b8a958 100644 --- a/web/components/feed/contract-activity.tsx +++ b/web/components/feed/contract-activity.tsx @@ -6,7 +6,7 @@ import { getOutcomeProbability } from 'common/calculate' import { FeedBet } from './feed-bets' import { FeedLiquidity } from './feed-liquidity' import { FeedAnswerCommentGroup } from './feed-answer-comment-group' -import { FeedCommentThread, CommentInput } from './feed-comments' +import { FeedCommentThread, ContractCommentInput } from './feed-comments' import { User } from 'common/user' import { CommentTipMap } from 'web/hooks/use-tip-txns' import { LiquidityProvision } from 'common/liquidity-provision' @@ -72,7 +72,7 @@ export function ContractCommentsActivity(props: { return ( <> -