Fix @mention 500 error and can't close market bug (#1021)

* Fix @mention 500 error. Refactor text concat exts

* lint
This commit is contained in:
Sinclair Chen 2022-10-10 18:47:02 -07:00 committed by GitHub
parent c46c384d1d
commit 8bb9885aee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 39 additions and 34 deletions

View File

@ -52,7 +52,7 @@ export function parseMentions(data: JSONContent): string[] {
} }
// can't just do [StarterKit, Image...] because it doesn't work with cjs imports // can't just do [StarterKit, Image...] because it doesn't work with cjs imports
export const exhibitExts = [ const stringParseExts = [
Blockquote, Blockquote,
Bold, Bold,
BulletList, BulletList,
@ -72,7 +72,8 @@ export const exhibitExts = [
Image, Image,
Link, Link,
Mention.extend({ name: 'contract-mention' }), Mention, // user @mention
Mention.extend({ name: 'contract-mention' }), // market %mention
Iframe, Iframe,
TiptapTweet, TiptapTweet,
TiptapSpoiler, TiptapSpoiler,
@ -96,7 +97,7 @@ export function richTextToString(text?: JSONContent) {
current.type = 'text' current.type = 'text'
} }
}) })
return generateText(newText, exhibitExts) return generateText(newText, stringParseExts)
} }
const dfs = (data: JSONContent, f: (current: JSONContent) => any) => { const dfs = (data: JSONContent, f: (current: JSONContent) => any) => {

View File

@ -2,13 +2,16 @@ import clsx from 'clsx'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useState } from 'react' import { useState } from 'react'
import { Contract, MAX_DESCRIPTION_LENGTH } from 'common/contract' import { Contract, MAX_DESCRIPTION_LENGTH } from 'common/contract'
import { exhibitExts } from 'common/util/parse'
import { useAdmin } from 'web/hooks/use-admin' import { useAdmin } from 'web/hooks/use-admin'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import { updateContract } from 'web/lib/firebase/contracts' import { updateContract } from 'web/lib/firebase/contracts'
import { Row } from '../layout/row' import { Row } from '../layout/row'
import { Content } from '../editor' import { Content } from '../editor'
import { TextEditor, useTextEditor } from 'web/components/editor' import {
TextEditor,
editorExtensions,
useTextEditor,
} from 'web/components/editor'
import { Button } from '../button' import { Button } from '../button'
import { Spacer } from '../layout/spacer' import { Spacer } from '../layout/spacer'
import { Editor, Content as ContentType } from '@tiptap/react' import { Editor, Content as ContentType } from '@tiptap/react'
@ -118,7 +121,10 @@ function EditQuestion(props: {
} }
function joinContent(oldContent: ContentType, newContent: string) { function joinContent(oldContent: ContentType, newContent: string) {
const editor = new Editor({ content: oldContent, extensions: exhibitExts }) const editor = new Editor({
content: oldContent,
extensions: editorExtensions(),
})
editor.commands.focus('end') editor.commands.focus('end')
insertContent(editor, newContent) insertContent(editor, newContent)
return editor.getJSON() return editor.getJSON()

View File

@ -8,7 +8,6 @@ import clsx from 'clsx'
import { Editor } from '@tiptap/react' import { Editor } from '@tiptap/react'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import Link from 'next/link' import Link from 'next/link'
import { Row } from '../layout/row' import { Row } from '../layout/row'
import { formatMoney } from 'common/util/format' import { formatMoney } from 'common/util/format'
import { Contract, updateContract } from 'web/lib/firebase/contracts' import { Contract, updateContract } from 'web/lib/firebase/contracts'
@ -20,7 +19,6 @@ import NewContractBadge from '../new-contract-badge'
import { MiniUserFollowButton } from '../follow-button' import { MiniUserFollowButton } from '../follow-button'
import { DAY_MS } from 'common/util/time' import { DAY_MS } from 'common/util/time'
import { useUser, useUserById } from 'web/hooks/use-user' import { useUser, useUserById } from 'web/hooks/use-user'
import { exhibitExts } from 'common/util/parse'
import { Button } from 'web/components/button' import { Button } from 'web/components/button'
import { Modal } from 'web/components/layout/modal' import { Modal } from 'web/components/layout/modal'
import { Col } from 'web/components/layout/col' import { Col } from 'web/components/layout/col'
@ -41,6 +39,7 @@ import {
BountiedContractSmallBadge, BountiedContractSmallBadge,
} from 'web/components/contract/bountied-contract-badge' } from 'web/components/contract/bountied-contract-badge'
import { Input } from '../input' import { Input } from '../input'
import { editorExtensions } from '../editor'
export type ShowTime = 'resolve-date' | 'close-date' export type ShowTime = 'resolve-date' | 'close-date'
@ -421,7 +420,7 @@ function EditableCloseDate(props: {
const content = contract.description const content = contract.description
const formattedCloseDate = dayjs(newCloseTime).format('YYYY-MM-DD h:mm a') const formattedCloseDate = dayjs(newCloseTime).format('YYYY-MM-DD h:mm a')
const editor = new Editor({ content, extensions: exhibitExts }) const editor = new Editor({ content, extensions: editorExtensions() })
editor.commands.focus('end') editor.commands.focus('end')
insertContent( insertContent(
editor, editor,

View File

@ -8,6 +8,7 @@ import {
Content, Content,
Editor, Editor,
mergeAttributes, mergeAttributes,
Extensions,
} from '@tiptap/react' } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit' import StarterKit from '@tiptap/starter-kit'
import { Image } from '@tiptap/extension-image' import { Image } from '@tiptap/extension-image'
@ -19,9 +20,7 @@ import { uploadImage } from 'web/lib/firebase/storage'
import { useMutation } from 'react-query' import { useMutation } from 'react-query'
import { FileUploadButton } from './file-upload-button' import { FileUploadButton } from './file-upload-button'
import { linkClass } from './site-link' import { linkClass } from './site-link'
import { mentionSuggestion } from './editor/mention-suggestion'
import { DisplayMention } from './editor/mention' import { DisplayMention } from './editor/mention'
import { contractMentionSuggestion } from './editor/contract-mention-suggestion'
import { DisplayContractMention } from './editor/contract-mention' import { DisplayContractMention } from './editor/contract-mention'
import Iframe from 'common/util/tiptap-iframe' import Iframe from 'common/util/tiptap-iframe'
import TiptapTweet from './editor/tiptap-tweet' import TiptapTweet from './editor/tiptap-tweet'
@ -64,6 +63,22 @@ const DisplayLink = Link.extend({
}, },
}) })
export const editorExtensions = (simple = false): Extensions => [
StarterKit.configure({
heading: simple ? false : { levels: [1, 2, 3] },
horizontalRule: simple ? false : {},
}),
simple ? DisplayImage : Image,
DisplayLink,
DisplayMention,
DisplayContractMention,
Iframe,
TiptapTweet,
TiptapSpoiler.configure({
spoilerOpenClass: 'rounded-sm bg-greyscale-2',
}),
]
const proseClass = clsx( const proseClass = clsx(
'prose prose-p:my-0 prose-ul:my-0 prose-ol:my-0 prose-li:my-0 prose-blockquote:not-italic max-w-none prose-quoteless leading-relaxed', 'prose prose-p:my-0 prose-ul:my-0 prose-ol:my-0 prose-li:my-0 prose-blockquote:not-italic max-w-none prose-quoteless leading-relaxed',
'font-light prose-a:font-light prose-blockquote:font-light' 'font-light prose-a:font-light prose-blockquote:font-light'
@ -89,29 +104,13 @@ export function useTextEditor(props: {
const editor = useEditor({ const editor = useEditor({
editorProps: { attributes: { class: editorClass } }, editorProps: { attributes: { class: editorClass } },
extensions: [ extensions: [
StarterKit.configure({ ...editorExtensions(simple),
heading: simple ? false : { levels: [1, 2, 3] },
horizontalRule: simple ? false : {},
}),
Placeholder.configure({ Placeholder.configure({
placeholder, placeholder,
emptyEditorClass: emptyEditorClass:
'before:content-[attr(data-placeholder)] before:text-slate-500 before:float-left before:h-0 cursor-text', 'before:content-[attr(data-placeholder)] before:text-slate-500 before:float-left before:h-0 cursor-text',
}), }),
CharacterCount.configure({ limit: max }), CharacterCount.configure({ limit: max }),
simple ? DisplayImage : Image,
DisplayLink,
DisplayMention.configure({
suggestion: mentionSuggestion,
}),
DisplayContractMention.configure({
suggestion: contractMentionSuggestion,
}),
Iframe,
TiptapTweet,
TiptapSpoiler.configure({
spoilerOpenClass: 'rounded-sm bg-greyscale-2',
}),
], ],
content: defaultValue, content: defaultValue,
}) })
@ -334,10 +333,7 @@ export function RichContent(props: {
smallImage ? DisplayImage : Image, smallImage ? DisplayImage : Image,
DisplayLink.configure({ openOnClick: false }), // stop link opening twice (browser still opens) DisplayLink.configure({ openOnClick: false }), // stop link opening twice (browser still opens)
DisplayMention, DisplayMention,
DisplayContractMention.configure({ DisplayContractMention,
// Needed to set a different PluginKey for Prosemirror
suggestion: contractMentionSuggestion,
}),
Iframe, Iframe,
TiptapTweet, TiptapTweet,
TiptapSpoiler.configure({ TiptapSpoiler.configure({

View File

@ -8,6 +8,7 @@ import clsx from 'clsx'
import { useContract } from 'web/hooks/use-contract' import { useContract } from 'web/hooks/use-contract'
import { ContractMention } from 'web/components/contract/contract-mention' import { ContractMention } from 'web/components/contract/contract-mention'
import Link from 'next/link' import Link from 'next/link'
import { contractMentionSuggestion } from './contract-mention-suggestion'
const name = 'contract-mention-component' const name = 'contract-mention-component'
@ -42,4 +43,4 @@ export const DisplayContractMention = Mention.extend({
parseHTML: () => [{ tag: name }], parseHTML: () => [{ tag: name }],
renderHTML: ({ HTMLAttributes }) => [name, mergeAttributes(HTMLAttributes)], renderHTML: ({ HTMLAttributes }) => [name, mergeAttributes(HTMLAttributes)],
addNodeView: () => ReactNodeViewRenderer(ContractMentionComponent), addNodeView: () => ReactNodeViewRenderer(ContractMentionComponent),
}) }).configure({ suggestion: contractMentionSuggestion })

View File

@ -6,6 +6,7 @@ import {
} from '@tiptap/react' } from '@tiptap/react'
import clsx from 'clsx' import clsx from 'clsx'
import { Linkify } from '../linkify' import { Linkify } from '../linkify'
import { mentionSuggestion } from './mention-suggestion'
const name = 'mention-component' const name = 'mention-component'
@ -27,4 +28,4 @@ export const DisplayMention = Mention.extend({
renderHTML: ({ HTMLAttributes }) => [name, mergeAttributes(HTMLAttributes)], renderHTML: ({ HTMLAttributes }) => [name, mergeAttributes(HTMLAttributes)],
addNodeView: () => addNodeView: () =>
ReactNodeViewRenderer(MentionComponent, { className: 'inline-block' }), ReactNodeViewRenderer(MentionComponent, { className: 'inline-block' }),
}) }).configure({ suggestion: mentionSuggestion })

View File

@ -14,6 +14,7 @@
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"lint-fix": "next lint --fix",
"format": "npx prettier --write .", "format": "npx prettier --write .",
"verify": "(cd .. && yarn verify)", "verify": "(cd .. && yarn verify)",
"verify:dir": "npx prettier --check .; yarn lint --max-warnings 0; tsc --pretty --project tsconfig.json --noEmit" "verify:dir": "npx prettier --check .; yarn lint --max-warnings 0; tsc --pretty --project tsconfig.json --noEmit"