From 8bb9885aee1f804061e471382b712a27501a6d7b Mon Sep 17 00:00:00 2001 From: Sinclair Chen Date: Mon, 10 Oct 2022 18:47:02 -0700 Subject: [PATCH] Fix @mention 500 error and can't close market bug (#1021) * Fix @mention 500 error. Refactor text concat exts * lint --- common/util/parse.ts | 7 ++-- .../contract/contract-description.tsx | 12 ++++-- web/components/contract/contract-details.tsx | 5 +-- web/components/editor.tsx | 42 +++++++++---------- web/components/editor/contract-mention.tsx | 3 +- web/components/editor/mention.tsx | 3 +- web/package.json | 1 + 7 files changed, 39 insertions(+), 34 deletions(-) diff --git a/common/util/parse.ts b/common/util/parse.ts index 3cd53ef2..53874c9e 100644 --- a/common/util/parse.ts +++ b/common/util/parse.ts @@ -52,7 +52,7 @@ export function parseMentions(data: JSONContent): string[] { } // can't just do [StarterKit, Image...] because it doesn't work with cjs imports -export const exhibitExts = [ +const stringParseExts = [ Blockquote, Bold, BulletList, @@ -72,7 +72,8 @@ export const exhibitExts = [ Image, Link, - Mention.extend({ name: 'contract-mention' }), + Mention, // user @mention + Mention.extend({ name: 'contract-mention' }), // market %mention Iframe, TiptapTweet, TiptapSpoiler, @@ -96,7 +97,7 @@ export function richTextToString(text?: JSONContent) { current.type = 'text' } }) - return generateText(newText, exhibitExts) + return generateText(newText, stringParseExts) } const dfs = (data: JSONContent, f: (current: JSONContent) => any) => { diff --git a/web/components/contract/contract-description.tsx b/web/components/contract/contract-description.tsx index dc94d339..40532c21 100644 --- a/web/components/contract/contract-description.tsx +++ b/web/components/contract/contract-description.tsx @@ -2,13 +2,16 @@ import clsx from 'clsx' import dayjs from 'dayjs' import { useState } from 'react' import { Contract, MAX_DESCRIPTION_LENGTH } from 'common/contract' -import { exhibitExts } from 'common/util/parse' import { useAdmin } from 'web/hooks/use-admin' import { useUser } from 'web/hooks/use-user' import { updateContract } from 'web/lib/firebase/contracts' import { Row } from '../layout/row' import { Content } from '../editor' -import { TextEditor, useTextEditor } from 'web/components/editor' +import { + TextEditor, + editorExtensions, + useTextEditor, +} from 'web/components/editor' import { Button } from '../button' import { Spacer } from '../layout/spacer' import { Editor, Content as ContentType } from '@tiptap/react' @@ -118,7 +121,10 @@ function EditQuestion(props: { } 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') insertContent(editor, newContent) return editor.getJSON() diff --git a/web/components/contract/contract-details.tsx b/web/components/contract/contract-details.tsx index 33c8d6aa..a277ae4d 100644 --- a/web/components/contract/contract-details.tsx +++ b/web/components/contract/contract-details.tsx @@ -8,7 +8,6 @@ import clsx from 'clsx' import { Editor } from '@tiptap/react' import dayjs from 'dayjs' import Link from 'next/link' - import { Row } from '../layout/row' import { formatMoney } from 'common/util/format' import { Contract, updateContract } from 'web/lib/firebase/contracts' @@ -20,7 +19,6 @@ import NewContractBadge from '../new-contract-badge' import { MiniUserFollowButton } from '../follow-button' import { DAY_MS } from 'common/util/time' import { useUser, useUserById } from 'web/hooks/use-user' -import { exhibitExts } from 'common/util/parse' import { Button } from 'web/components/button' import { Modal } from 'web/components/layout/modal' import { Col } from 'web/components/layout/col' @@ -41,6 +39,7 @@ import { BountiedContractSmallBadge, } from 'web/components/contract/bountied-contract-badge' import { Input } from '../input' +import { editorExtensions } from '../editor' export type ShowTime = 'resolve-date' | 'close-date' @@ -421,7 +420,7 @@ function EditableCloseDate(props: { const content = contract.description 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') insertContent( editor, diff --git a/web/components/editor.tsx b/web/components/editor.tsx index f84e62e2..17cabc38 100644 --- a/web/components/editor.tsx +++ b/web/components/editor.tsx @@ -8,6 +8,7 @@ import { Content, Editor, mergeAttributes, + Extensions, } from '@tiptap/react' import StarterKit from '@tiptap/starter-kit' import { Image } from '@tiptap/extension-image' @@ -19,9 +20,7 @@ import { uploadImage } from 'web/lib/firebase/storage' import { useMutation } from 'react-query' import { FileUploadButton } from './file-upload-button' import { linkClass } from './site-link' -import { mentionSuggestion } from './editor/mention-suggestion' import { DisplayMention } from './editor/mention' -import { contractMentionSuggestion } from './editor/contract-mention-suggestion' import { DisplayContractMention } from './editor/contract-mention' import Iframe from 'common/util/tiptap-iframe' 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( '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' @@ -89,29 +104,13 @@ export function useTextEditor(props: { const editor = useEditor({ editorProps: { attributes: { class: editorClass } }, extensions: [ - StarterKit.configure({ - heading: simple ? false : { levels: [1, 2, 3] }, - horizontalRule: simple ? false : {}, - }), + ...editorExtensions(simple), Placeholder.configure({ placeholder, emptyEditorClass: 'before:content-[attr(data-placeholder)] before:text-slate-500 before:float-left before:h-0 cursor-text', }), 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, }) @@ -334,10 +333,7 @@ export function RichContent(props: { smallImage ? DisplayImage : Image, DisplayLink.configure({ openOnClick: false }), // stop link opening twice (browser still opens) DisplayMention, - DisplayContractMention.configure({ - // Needed to set a different PluginKey for Prosemirror - suggestion: contractMentionSuggestion, - }), + DisplayContractMention, Iframe, TiptapTweet, TiptapSpoiler.configure({ diff --git a/web/components/editor/contract-mention.tsx b/web/components/editor/contract-mention.tsx index ea0d6e0d..74df03c5 100644 --- a/web/components/editor/contract-mention.tsx +++ b/web/components/editor/contract-mention.tsx @@ -8,6 +8,7 @@ import clsx from 'clsx' import { useContract } from 'web/hooks/use-contract' import { ContractMention } from 'web/components/contract/contract-mention' import Link from 'next/link' +import { contractMentionSuggestion } from './contract-mention-suggestion' const name = 'contract-mention-component' @@ -42,4 +43,4 @@ export const DisplayContractMention = Mention.extend({ parseHTML: () => [{ tag: name }], renderHTML: ({ HTMLAttributes }) => [name, mergeAttributes(HTMLAttributes)], addNodeView: () => ReactNodeViewRenderer(ContractMentionComponent), -}) +}).configure({ suggestion: contractMentionSuggestion }) diff --git a/web/components/editor/mention.tsx b/web/components/editor/mention.tsx index 5ccea6f5..ea38a9f7 100644 --- a/web/components/editor/mention.tsx +++ b/web/components/editor/mention.tsx @@ -6,6 +6,7 @@ import { } from '@tiptap/react' import clsx from 'clsx' import { Linkify } from '../linkify' +import { mentionSuggestion } from './mention-suggestion' const name = 'mention-component' @@ -27,4 +28,4 @@ export const DisplayMention = Mention.extend({ renderHTML: ({ HTMLAttributes }) => [name, mergeAttributes(HTMLAttributes)], addNodeView: () => ReactNodeViewRenderer(MentionComponent, { className: 'inline-block' }), -}) +}).configure({ suggestion: mentionSuggestion }) diff --git a/web/package.json b/web/package.json index 93ec7ee5..f64b79e8 100644 --- a/web/package.json +++ b/web/package.json @@ -14,6 +14,7 @@ "build": "next build", "start": "next start", "lint": "next lint", + "lint-fix": "next lint --fix", "format": "npx prettier --write .", "verify": "(cd .. && yarn verify)", "verify:dir": "npx prettier --check .; yarn lint --max-warnings 0; tsc --pretty --project tsconfig.json --noEmit"