Fix appending to description

This commit is contained in:
Sinclair Chen 2022-07-11 13:06:27 -07:00
parent 12ec239b16
commit 129afebff6
6 changed files with 88 additions and 23 deletions

View File

@ -1,6 +1,23 @@
import { MAX_TAG_LENGTH } from '../contract'
import { generateText, JSONContent, Extension } from '@tiptap/core'
import * as StarterKit from '@tiptap/starter-kit' // needed for cjs import to work on firebase
import { generateText, JSONContent } from '@tiptap/core'
// Tiptap starter extensions
import { Blockquote } from '@tiptap/extension-blockquote'
import { Bold } from '@tiptap/extension-bold'
import { BulletList } from '@tiptap/extension-bullet-list'
import { Code } from '@tiptap/extension-code'
import { CodeBlock } from '@tiptap/extension-code-block'
import { Document } from '@tiptap/extension-document'
import { HardBreak } from '@tiptap/extension-hard-break'
import { Heading } from '@tiptap/extension-heading'
import { History } from '@tiptap/extension-history'
import { HorizontalRule } from '@tiptap/extension-horizontal-rule'
import { Italic } from '@tiptap/extension-italic'
import { ListItem } from '@tiptap/extension-list-item'
import { OrderedList } from '@tiptap/extension-ordered-list'
import { Paragraph } from '@tiptap/extension-paragraph'
import { Strike } from '@tiptap/extension-strike'
import { Text } from '@tiptap/extension-text'
// import * as StarterKit from '@tiptap/starter-kit'
import { Image } from '@tiptap/extension-image'
export function parseTags(text: string) {
@ -31,8 +48,30 @@ export function parseWordsAsTags(text: string) {
return parseTags(taggedText)
}
export function richTextToString(text: JSONContent | string) {
return typeof text === 'string'
? text
: generateText(text, [StarterKit as unknown as Extension, Image])
// can't just do [StarterKit, Image...] because it doesn't work with some imports
// see
export const exhibitExts = [
Blockquote,
Bold,
BulletList,
Code,
CodeBlock,
Document,
HardBreak,
Heading,
History,
HorizontalRule,
Italic,
ListItem,
OrderedList,
Paragraph,
Strike,
Text,
Image,
]
// export const exhibitExts = [StarterKit as unknown as Extension, Image]
export function richTextToString(text?: JSONContent) {
return !text ? '' : generateText(text, exhibitExts)
}

View File

@ -3,6 +3,7 @@ import { getUser } from './utils'
import { createNotification } from './create-notification'
import { Contract } from '../../common/contract'
import { richTextToString } from '../../common/util/parse'
import { JSONContent } from '@tiptap/core'
export const onCreateContract = functions.firestore
.document('contracts/{contractId}')
@ -19,7 +20,7 @@ export const onCreateContract = functions.firestore
'created',
contractCreator,
eventId,
richTextToString(contract.description),
richTextToString(contract.description as JSONContent),
contract
)
})

View File

@ -5,12 +5,13 @@ import Textarea from 'react-expanding-textarea'
import { CATEGORY_LIST } from '../../../common/categories'
import { Contract } from 'common/contract'
import { parseTags, richTextToString } from 'common/util/parse'
import { parseTags, exhibitExts } from 'common/util/parse'
import { useAdmin } from 'web/hooks/use-admin'
import { updateContract } from 'web/lib/firebase/contracts'
import { Row } from '../layout/row'
import { TagsList } from '../tags-list'
import { Content } from '../editor'
import { Editor } from '@tiptap/react'
export function ContractDescription(props: {
contract: Contract
@ -21,24 +22,33 @@ export function ContractDescription(props: {
const descriptionTimestamp = () => `${dayjs().format('MMM D, h:mma')}: `
const isAdmin = useAdmin()
const desc = contract.description ?? ''
// Append the new description (after a newline)
async function saveDescription(newText: string) {
// TODO: implement appending rich text description
const textDescription = richTextToString(contract.description)
const newDescription = `${textDescription}\n\n${newText}`.trim()
console.log(desc, exhibitExts)
const editor = new Editor({ content: desc, extensions: exhibitExts })
editor
.chain()
.focus('end')
.insertContent('<br /><br />')
.insertContent(newText.trim())
.run()
const tags = parseTags(
`${newDescription} ${contract.tags.map((tag) => `#${tag}`).join(' ')}`
`${editor.getText()} ${contract.tags.map((tag) => `#${tag}`).join(' ')}`
)
const lowercaseTags = tags.map((tag) => tag.toLowerCase())
await updateContract(contract.id, {
description: newDescription,
description: editor.getJSON(),
tags,
lowercaseTags,
})
}
if (!isCreator && !contract.description) return null
if (!isCreator) return null
const { tags } = contract
const categories = tags.filter((tag) =>
@ -52,7 +62,7 @@ export function ContractDescription(props: {
className
)}
>
<Content content={contract.description} />
<Content content={desc} />
{categories.length > 0 && (
<div className="mt-4">

View File

@ -31,6 +31,8 @@ import { DAY_MS } from 'common/util/time'
import { useGroupsWithContract } from 'web/hooks/use-group'
import { ShareIconButton } from 'web/components/share-icon-button'
import { useUser } from 'web/hooks/use-user'
import { Editor } from '@tiptap/react'
import { exhibitExts } from 'common/util/parse'
export type ShowTime = 'resolve-date' | 'close-date'
@ -268,13 +270,20 @@ function EditableCloseDate(props: {
const newCloseTime = dayjs(closeDate).valueOf()
if (newCloseTime === closeTime) setIsEditingCloseTime(false)
else if (newCloseTime > Date.now()) {
const { description } = contract
const content = contract.description
const formattedCloseDate = dayjs(newCloseTime).format('YYYY-MM-DD h:mm a')
const newDescription = `${description}\n\nClose date updated to ${formattedCloseDate}`
const editor = new Editor({ content, extensions: exhibitExts })
editor
.chain()
.focus('end')
.insertContent('<br /><br />')
.insertContent(`Close date updated to ${formattedCloseDate}`)
.run()
updateContract(contract.id, {
closeTime: newCloseTime,
description: newDescription,
description: editor.getJSON(),
})
setIsEditingCloseTime(false)

View File

@ -8,6 +8,7 @@ import { useEffect } from 'react'
import { Linkify } from './linkify'
import { uploadImage } from 'web/lib/firebase/storage'
import { useMutation } from 'react-query'
import { exhibitExts } from 'common/util/parse'
const proseClass =
'prose prose-sm prose-p:my-0 prose-li:my-0 prose-blockquote:not-italic max-w-none'
@ -80,10 +81,12 @@ function RichContent(props: { content: JSONContent }) {
const { content } = props
const editor = useEditor({
editorProps: { attributes: { class: proseClass } },
extensions: [StarterKit, Image],
extensions: exhibitExts,
content,
editable: false,
})
useEffect(() => void editor?.commands?.setContent(content), [editor, content])
return <EditorContent editor={editor} />
}

View File

@ -195,7 +195,7 @@ export function ContractPageContent(
{ogCardProps && (
<SEO
title={question}
description={richTextToString(ogCardProps.description)}
description={ogCardProps.description}
url={`/${props.username}/${props.slug}`}
ogCardProps={ogCardProps}
/>
@ -392,15 +392,18 @@ const getOpenGraphProps = (contract: Contract) => {
creatorUsername,
outcomeType,
creatorAvatarUrl,
description: desc,
} = contract
const probPercent =
outcomeType === 'BINARY' ? getBinaryProbPercent(contract) : undefined
const stringDesc = typeof desc === 'string' ? desc : richTextToString(desc)
const description = resolution
? `Resolved ${resolution}. ${contract.description}`
? `Resolved ${resolution}. ${stringDesc}`
: probPercent
? `${probPercent} chance. ${contract.description}`
: contract.description
? `${probPercent} chance. ${stringDesc}`
: stringDesc
return {
question,