Refactor editor as hook / fix infinite submit bug

Move state of editor back up to parent
We have to do this later anyways to allow parent to edit
This commit is contained in:
Sinclair Chen 2022-07-06 16:58:48 -07:00
parent 5fa2925ba8
commit 3f30becb93
2 changed files with 26 additions and 45 deletions

View File

@ -4,33 +4,20 @@ import { useEditor, EditorContent, JSONContent, Content } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit' import StarterKit from '@tiptap/starter-kit'
import clsx from 'clsx' import clsx from 'clsx'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useWarnUnsavedChanges } from 'web/hooks/use-warn-unsaved-changes'
import { Linkify } from './linkify' import { Linkify } from './linkify'
const LINE_HEIGHT = 2 const LINE_HEIGHT = 2
const proseClass = 'prose prose-sm prose-p:my-0 prose-li:my-0 max-w-none' const proseClass = 'prose prose-sm prose-p:my-0 prose-li:my-0 max-w-none'
export function TextEditor(props: { export function useTextEditor(props: {
className?: string
rows?: number rows?: number
placeholder?: string placeholder?: string
max?: number max?: number
defaultValue?: Content defaultValue?: Content
onSend: (data: JSONContent) => void
sending: boolean
disabled?: boolean disabled?: boolean
}) { }) {
const { const { rows, placeholder, max, defaultValue = '', disabled } = props
className,
rows,
placeholder,
max,
defaultValue = '',
onSend,
sending,
disabled,
} = props
const rowsClass = rows && `box-content min-h-[${LINE_HEIGHT * rows}em]` const rowsClass = rows && `box-content min-h-[${LINE_HEIGHT * rows}em]`
@ -49,16 +36,10 @@ export function TextEditor(props: {
}) })
useEffect(() => { useEffect(() => {
if (sending && editor) onSend(editor.getJSON()) editor?.setEditable(!disabled)
}, [sending, editor, onSend]) }, [editor, disabled])
useEffect(() => { return editor
editor?.setEditable(!disabled && !sending)
}, [editor, disabled, sending])
useWarnUnsavedChanges(!sending && editor != null && !editor.isEmpty)
return <EditorContent editor={editor} className={className} />
} }
function RichContent(props: { content: JSONContent }) { function RichContent(props: { content: JSONContent }) {

View File

@ -27,8 +27,8 @@ import { track } from 'web/lib/service/analytics'
import { GroupSelector } from 'web/components/groups/group-selector' import { GroupSelector } from 'web/components/groups/group-selector'
import { CATEGORIES } from 'common/categories' import { CATEGORIES } from 'common/categories'
import { User } from 'common/user' import { User } from 'common/user'
import { TextEditor } from 'web/components/editor' import { useTextEditor } from 'web/components/editor'
import { JSONContent } from '@tiptap/react' import { EditorContent } from '@tiptap/react'
type NewQuestionParams = { type NewQuestionParams = {
groupId?: string groupId?: string
@ -163,8 +163,6 @@ export function NewContract(props: {
// get days from today until the end of this year: // get days from today until the end of this year:
const daysLeftInTheYear = dayjs().endOf('year').diff(dayjs(), 'day') const daysLeftInTheYear = dayjs().endOf('year').diff(dayjs(), 'day')
useWarnUnsavedChanges(!isSubmitting && Boolean(question))
const isValid = const isValid =
(outcomeType === 'BINARY' ? initialProb >= 5 && initialProb <= 95 : true) && (outcomeType === 'BINARY' ? initialProb >= 5 && initialProb <= 95 : true) &&
question.length > 0 && question.length > 0 &&
@ -185,25 +183,39 @@ export function NewContract(props: {
min < initialValue && min < initialValue &&
initialValue < max)) initialValue < max))
const descriptionPlaceholder =
outcomeType === 'BINARY'
? `e.g. This question resolves to "YES" if they receive the majority of votes...`
: `e.g. I will choose the answer according to...`
const editor = useTextEditor({
rows: 3,
max: MAX_DESCRIPTION_LENGTH,
placeholder: descriptionPlaceholder,
disabled: isSubmitting,
})
useWarnUnsavedChanges(
!isSubmitting && (Boolean(question) || (editor != null && !editor.isEmpty))
)
function setCloseDateInDays(days: number) { function setCloseDateInDays(days: number) {
const newCloseDate = dayjs().add(days, 'day').format('YYYY-MM-DD') const newCloseDate = dayjs().add(days, 'day').format('YYYY-MM-DD')
setCloseDate(newCloseDate) setCloseDate(newCloseDate)
} }
function submit() { async function submit() {
// TODO: Tell users why their contract is invalid // TODO: Tell users why their contract is invalid
if (!creator || !isValid) return if (!creator || !isValid) return
setIsSubmitting(true) setIsSubmitting(true)
}
async function onSubmit(description?: JSONContent) {
// TODO: add contract id to the group contractIds // TODO: add contract id to the group contractIds
try { try {
const result = await createMarket( const result = await createMarket(
removeUndefinedProps({ removeUndefinedProps({
question, question,
outcomeType, outcomeType,
description, description: editor?.getJSON(),
initialProb, initialProb,
ante, ante,
closeTime, closeTime,
@ -232,11 +244,6 @@ export function NewContract(props: {
} }
} }
const descriptionPlaceholder =
outcomeType === 'BINARY'
? `e.g. This question resolves to "YES" if they receive the majority of votes...`
: `e.g. I will choose the answer according to...`
if (!creator) return <></> if (!creator) return <></>
return ( return (
@ -440,14 +447,7 @@ export function NewContract(props: {
<span className="mb-1">Description</span> <span className="mb-1">Description</span>
<InfoTooltip text="Optional. Describe how you will resolve this question." /> <InfoTooltip text="Optional. Describe how you will resolve this question." />
</label> </label>
<TextEditor <EditorContent editor={editor} className="w-full" />
className="w-full"
rows={3}
max={MAX_DESCRIPTION_LENGTH}
placeholder={descriptionPlaceholder}
sending={isSubmitting}
onSend={onSubmit}
/>
</div> </div>
<Spacer h={6} /> <Spacer h={6} />