Allow editing of comments on a market
This commit is contained in:
		
							parent
							
								
									dd6c5dc97a
								
							
						
					
					
						commit
						3b575080b0
					
				| 
						 | 
				
			
			@ -90,8 +90,10 @@ service cloud.firestore {
 | 
			
		|||
                                                                 .hasOnly(['description', 'closeTime', 'question'])
 | 
			
		||||
                       && resource.data.creatorId == request.auth.uid;
 | 
			
		||||
      allow update: if isAdmin();
 | 
			
		||||
 | 
			
		||||
      // TODO: This runs afoul of FirebaseError: Missing or insufficient permissions
 | 
			
		||||
      match /comments/{commentId} {
 | 
			
		||||
            allow create: if request.auth != null && commentMatchesUser(request.auth.uid, request.resource.data);
 | 
			
		||||
        allow create, update: if request.auth != null && commentMatchesUser(request.auth.uid, request.resource.data);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@ import { CopyLinkDateTimeComponent } from 'web/components/feed/copy-link-date-ti
 | 
			
		|||
import { firebaseLogin } from 'web/lib/firebase/users'
 | 
			
		||||
import {
 | 
			
		||||
  createCommentOnContract,
 | 
			
		||||
  editCommentOnContract,
 | 
			
		||||
  MAX_COMMENT_LENGTH,
 | 
			
		||||
} from 'web/lib/firebase/comments'
 | 
			
		||||
import { BetStatusText } from 'web/components/feed/feed-bets'
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +29,7 @@ import { Tipper } from '../tipper'
 | 
			
		|||
import { CommentTipMap, CommentTips } from 'web/hooks/use-tip-txns'
 | 
			
		||||
import { useWindowSize } from 'web/hooks/use-window-size'
 | 
			
		||||
import { Content, TextEditor, useTextEditor } from '../editor'
 | 
			
		||||
import { Editor } from '@tiptap/react'
 | 
			
		||||
import { Editor, JSONContent } from '@tiptap/react'
 | 
			
		||||
 | 
			
		||||
export function FeedCommentThread(props: {
 | 
			
		||||
  contract: Contract
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +114,8 @@ export function CommentRepliesList(props: {
 | 
			
		|||
    scrollAndOpenReplyInput,
 | 
			
		||||
    treatFirstIndexEqually,
 | 
			
		||||
  } = props
 | 
			
		||||
  const [editCommentId, setEditCommentId] = useState<string | undefined>()
 | 
			
		||||
  const user = useUser()
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      {commentsList.map((comment, commentIdx) => (
 | 
			
		||||
| 
						 | 
				
			
			@ -131,12 +134,24 @@ export function CommentRepliesList(props: {
 | 
			
		|||
              aria-hidden="true"
 | 
			
		||||
            />
 | 
			
		||||
          )}
 | 
			
		||||
          {editCommentId === comment.id ? (
 | 
			
		||||
            <CommentInput
 | 
			
		||||
              contract={contract}
 | 
			
		||||
              // TODO: These were Copilot-generated, examine more closely
 | 
			
		||||
              betsByCurrentUser={(user && betsByUserId[user.id]) ?? []}
 | 
			
		||||
              commentsByCurrentUser={commentsList.filter(
 | 
			
		||||
                (c) => c.userId === user?.id
 | 
			
		||||
              )}
 | 
			
		||||
              toEdit={comment}
 | 
			
		||||
            />
 | 
			
		||||
          ) : (
 | 
			
		||||
            <FeedComment
 | 
			
		||||
              contract={contract}
 | 
			
		||||
              comment={comment}
 | 
			
		||||
              tips={tips[comment.id]}
 | 
			
		||||
              betsBySameUser={betsByUserId[comment.userId] ?? []}
 | 
			
		||||
              onReplyClick={scrollAndOpenReplyInput}
 | 
			
		||||
              onEditClick={() => setEditCommentId(comment.id)}
 | 
			
		||||
              probAtCreatedTime={
 | 
			
		||||
                contract.outcomeType === 'BINARY'
 | 
			
		||||
                  ? minBy(bets, (bet) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -148,6 +163,7 @@ export function CommentRepliesList(props: {
 | 
			
		|||
              }
 | 
			
		||||
              smallAvatar={smallAvatar}
 | 
			
		||||
            />
 | 
			
		||||
          )}
 | 
			
		||||
        </div>
 | 
			
		||||
      ))}
 | 
			
		||||
    </>
 | 
			
		||||
| 
						 | 
				
			
			@ -162,6 +178,7 @@ export function FeedComment(props: {
 | 
			
		|||
  probAtCreatedTime?: number
 | 
			
		||||
  smallAvatar?: boolean
 | 
			
		||||
  onReplyClick?: (comment: ContractComment) => void
 | 
			
		||||
  onEditClick?: (comment: ContractComment) => void
 | 
			
		||||
}) {
 | 
			
		||||
  const {
 | 
			
		||||
    contract,
 | 
			
		||||
| 
						 | 
				
			
			@ -170,6 +187,7 @@ export function FeedComment(props: {
 | 
			
		|||
    betsBySameUser,
 | 
			
		||||
    probAtCreatedTime,
 | 
			
		||||
    onReplyClick,
 | 
			
		||||
    onEditClick,
 | 
			
		||||
  } = props
 | 
			
		||||
  const { text, content, userUsername, userName, userAvatarUrl, createdTime } =
 | 
			
		||||
    comment
 | 
			
		||||
| 
						 | 
				
			
			@ -199,6 +217,9 @@ export function FeedComment(props: {
 | 
			
		|||
    matchedBet ? [] : betsBySameUser
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const self = useUser()
 | 
			
		||||
  const canEdit = self?.id === comment.userId
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Row
 | 
			
		||||
      className={clsx(
 | 
			
		||||
| 
						 | 
				
			
			@ -266,6 +287,14 @@ export function FeedComment(props: {
 | 
			
		|||
              Reply
 | 
			
		||||
            </button>
 | 
			
		||||
          )}
 | 
			
		||||
          {canEdit && onEditClick ? (
 | 
			
		||||
            <button
 | 
			
		||||
              className="font-bold hover:underline"
 | 
			
		||||
              onClick={() => onEditClick(comment)}
 | 
			
		||||
            >
 | 
			
		||||
              Edit
 | 
			
		||||
            </button>
 | 
			
		||||
          ) : null}
 | 
			
		||||
        </Row>
 | 
			
		||||
      </div>
 | 
			
		||||
    </Row>
 | 
			
		||||
| 
						 | 
				
			
			@ -326,6 +355,7 @@ export function CommentInput(props: {
 | 
			
		|||
  // Reply to another comment
 | 
			
		||||
  parentCommentId?: string
 | 
			
		||||
  onSubmitComment?: () => void
 | 
			
		||||
  toEdit?: ContractComment
 | 
			
		||||
}) {
 | 
			
		||||
  const {
 | 
			
		||||
    contract,
 | 
			
		||||
| 
						 | 
				
			
			@ -335,6 +365,7 @@ export function CommentInput(props: {
 | 
			
		|||
    parentCommentId,
 | 
			
		||||
    replyToUser,
 | 
			
		||||
    onSubmitComment,
 | 
			
		||||
    toEdit,
 | 
			
		||||
  } = props
 | 
			
		||||
  const user = useUser()
 | 
			
		||||
  const { editor, upload } = useTextEditor({
 | 
			
		||||
| 
						 | 
				
			
			@ -344,6 +375,7 @@ export function CommentInput(props: {
 | 
			
		|||
      !!parentCommentId || !!parentAnswerOutcome
 | 
			
		||||
        ? 'Write a reply...'
 | 
			
		||||
        : 'Write a comment...',
 | 
			
		||||
    defaultValue: toEdit?.content,
 | 
			
		||||
  })
 | 
			
		||||
  const [isSubmitting, setIsSubmitting] = useState(false)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -362,6 +394,9 @@ export function CommentInput(props: {
 | 
			
		|||
    }
 | 
			
		||||
    if (!editor || editor.isEmpty || isSubmitting) return
 | 
			
		||||
    setIsSubmitting(true)
 | 
			
		||||
    if (toEdit) {
 | 
			
		||||
      await editCommentOnContract(toEdit, editor.getJSON())
 | 
			
		||||
    } else {
 | 
			
		||||
      await createCommentOnContract(
 | 
			
		||||
        contract.id,
 | 
			
		||||
        editor.getJSON(),
 | 
			
		||||
| 
						 | 
				
			
			@ -370,6 +405,8 @@ export function CommentInput(props: {
 | 
			
		|||
        parentAnswerOutcome,
 | 
			
		||||
        parentCommentId
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onSubmitComment?.()
 | 
			
		||||
    setIsSubmitting(false)
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,15 @@ export type { Comment }
 | 
			
		|||
 | 
			
		||||
export const MAX_COMMENT_LENGTH = 10000
 | 
			
		||||
 | 
			
		||||
export async function editCommentOnContract(
 | 
			
		||||
  toEdit: ContractComment,
 | 
			
		||||
  newContent: JSONContent
 | 
			
		||||
) {
 | 
			
		||||
  const { id, contractId } = toEdit
 | 
			
		||||
  const ref = doc(getCommentsCollection(contractId), id)
 | 
			
		||||
  await setDoc(ref, { content: newContent })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function createCommentOnContract(
 | 
			
		||||
  contractId: string,
 | 
			
		||||
  content: JSONContent,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user