mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-30 12:24:25 +02:00
Disable Resolve Comment button while comment text is being entered (#27465)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> GitOrigin-RevId: 05a2c522b6cc49237eec859f50bad8759050f9f9
This commit is contained in:
@@ -7,13 +7,13 @@ import { EditorSelection } from '@codemirror/state'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useThreadsActionsContext } from '../context/threads-context'
|
||||
import { removeNewCommentRangeEffect } from '@/features/source-editor/extensions/review-tooltip'
|
||||
import useSubmittableTextInput from '../hooks/use-submittable-text-input'
|
||||
import AutoExpandingTextArea from '@/shared/components/auto-expanding-text-area'
|
||||
import { ReviewPanelEntry } from './review-panel-entry'
|
||||
import { ThreadId } from '../../../../../types/review-panel/review-panel'
|
||||
import { useModalsContext } from '@/features/ide-react/context/modals-context'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
import { isFormSubmitKeypressEvent } from '@/features/review-panel-new/utils/form-events'
|
||||
|
||||
export const ReviewPanelAddComment = memo<{
|
||||
docId: string
|
||||
@@ -28,6 +28,7 @@ export const ReviewPanelAddComment = memo<{
|
||||
const { addComment } = useThreadsActionsContext()
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const { showGenericMessageModal } = useModalsContext()
|
||||
const [content, setContent] = useState('')
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
view.dispatch({
|
||||
@@ -35,32 +36,56 @@ export const ReviewPanelAddComment = memo<{
|
||||
})
|
||||
}, [view, threadId])
|
||||
|
||||
const submitForm = useCallback(
|
||||
async (message: string) => {
|
||||
setSubmitting(true)
|
||||
const submitForm = useCallback(async () => {
|
||||
if (content.trim().length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const content = view.state.sliceDoc(from, to)
|
||||
setSubmitting(true)
|
||||
|
||||
try {
|
||||
await addComment(from, content, message)
|
||||
handleClose()
|
||||
view.dispatch({
|
||||
selection: EditorSelection.cursor(view.state.selection.main.anchor),
|
||||
})
|
||||
} catch (err) {
|
||||
debugConsole.error(err)
|
||||
showGenericMessageModal(
|
||||
t('add_comment_error_title'),
|
||||
t('add_comment_error_message')
|
||||
)
|
||||
const text = view.state.sliceDoc(from, to)
|
||||
|
||||
try {
|
||||
await addComment(from, text, content)
|
||||
handleClose()
|
||||
view.dispatch({
|
||||
selection: EditorSelection.cursor(view.state.selection.main.anchor),
|
||||
})
|
||||
} catch (err) {
|
||||
debugConsole.error(err)
|
||||
showGenericMessageModal(
|
||||
t('add_comment_error_title'),
|
||||
t('add_comment_error_message')
|
||||
)
|
||||
}
|
||||
setSubmitting(false)
|
||||
}, [
|
||||
content,
|
||||
view,
|
||||
from,
|
||||
to,
|
||||
addComment,
|
||||
handleClose,
|
||||
showGenericMessageModal,
|
||||
t,
|
||||
])
|
||||
|
||||
const handleKeyPress = useCallback(
|
||||
(event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
if (isFormSubmitKeypressEvent(event)) {
|
||||
event.preventDefault()
|
||||
submitForm()
|
||||
}
|
||||
setSubmitting(false)
|
||||
},
|
||||
[addComment, view, handleClose, from, to, showGenericMessageModal, t]
|
||||
[submitForm]
|
||||
)
|
||||
|
||||
const { handleChange, handleKeyPress, content } =
|
||||
useSubmittableTextInput(submitForm)
|
||||
const handleChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setContent(e.target.value)
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const handleBlur = useCallback(() => {
|
||||
if (content === '') {
|
||||
@@ -73,9 +98,9 @@ export const ReviewPanelAddComment = memo<{
|
||||
const handleSubmit = useCallback<FormEventHandler>(
|
||||
event => {
|
||||
event.preventDefault()
|
||||
submitForm(content)
|
||||
submitForm()
|
||||
},
|
||||
[submitForm, content]
|
||||
[submitForm]
|
||||
)
|
||||
|
||||
// We only ever want to focus the element once
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Dispatch, memo, SetStateAction, useCallback, useState } from 'react'
|
||||
import { memo, useCallback, useState } from 'react'
|
||||
import { Change, CommentOperation } from '../../../../../types/change'
|
||||
import { ReviewPanelMessage } from './review-panel-message'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@@ -6,12 +6,12 @@ import { useThreadsContext } from '../context/threads-context'
|
||||
import AutoExpandingTextArea from '@/shared/components/auto-expanding-text-area'
|
||||
import ReviewPanelResolvedMessage from './review-panel-resolved-message'
|
||||
import { ReviewPanelResolvedCommentThread } from '../../../../../types/review-panel/comment-thread'
|
||||
import useSubmittableTextInput from '../hooks/use-submittable-text-input'
|
||||
import {
|
||||
CommentId,
|
||||
ThreadId,
|
||||
} from '../../../../../types/review-panel/review-panel'
|
||||
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
|
||||
import { isFormSubmitKeypressEvent } from '@/features/review-panel-new/utils/form-events'
|
||||
|
||||
export const ReviewPanelCommentContent = memo<{
|
||||
comment: Change<CommentOperation>
|
||||
@@ -39,27 +39,46 @@ export const ReviewPanelCommentContent = memo<{
|
||||
const threads = useThreadsContext()
|
||||
const permissions = usePermissionsContext()
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [content, setContent] = useState('')
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(content: string, setContent: Dispatch<SetStateAction<string>>) => {
|
||||
if (!onReply || submitting) {
|
||||
return
|
||||
const hasActiveContent = content.trim().length > 0
|
||||
|
||||
const handleSubmit = useCallback(() => {
|
||||
if (!onReply || submitting) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!hasActiveContent) {
|
||||
return
|
||||
}
|
||||
|
||||
setSubmitting(true)
|
||||
|
||||
return onReply(content)
|
||||
.then(() => {
|
||||
setContent('')
|
||||
})
|
||||
.finally(() => {
|
||||
setSubmitting(false)
|
||||
})
|
||||
}, [onReply, submitting, content, hasActiveContent])
|
||||
|
||||
const handleKeyPress = useCallback(
|
||||
(event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
if (isFormSubmitKeypressEvent(event)) {
|
||||
event.preventDefault()
|
||||
handleSubmit()
|
||||
}
|
||||
|
||||
setSubmitting(true)
|
||||
onReply(content)
|
||||
.then(() => {
|
||||
setContent('')
|
||||
})
|
||||
.finally(() => {
|
||||
setSubmitting(false)
|
||||
})
|
||||
},
|
||||
[onReply, submitting]
|
||||
[handleSubmit]
|
||||
)
|
||||
|
||||
const { handleChange, handleKeyPress, content } =
|
||||
useSubmittableTextInput(handleSubmit)
|
||||
const handleChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setContent(e.target.value)
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const thread = threads?.[comment.op.t]
|
||||
if (!thread) {
|
||||
@@ -85,6 +104,7 @@ export const ReviewPanelCommentContent = memo<{
|
||||
isReply={isReply}
|
||||
hasReplies={!isReply && thread.messages.length > 1}
|
||||
onResolve={onResolve}
|
||||
hasActiveContent={hasActiveContent}
|
||||
onEdit={onEdit}
|
||||
onDelete={() =>
|
||||
isReply
|
||||
|
||||
@@ -21,6 +21,7 @@ export const ReviewPanelMessage: FC<{
|
||||
hasReplies: boolean
|
||||
isReply: boolean
|
||||
onResolve?: () => Promise<void>
|
||||
hasActiveContent?: boolean
|
||||
onEdit?: (commentId: CommentId, content: string) => Promise<void>
|
||||
onDelete?: () => void
|
||||
isThreadResolved: boolean
|
||||
@@ -32,6 +33,7 @@ export const ReviewPanelMessage: FC<{
|
||||
onEdit,
|
||||
onDelete,
|
||||
isThreadResolved,
|
||||
hasActiveContent = false,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [editing, setEditing] = useState(false)
|
||||
@@ -80,18 +82,21 @@ export const ReviewPanelMessage: FC<{
|
||||
description={t('resolve_comment')}
|
||||
tooltipProps={{ className: 'review-panel-tooltip' }}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
tabIndex={0}
|
||||
className="btn"
|
||||
onClick={onResolve}
|
||||
>
|
||||
<MaterialIcon
|
||||
type="check"
|
||||
className="review-panel-entry-actions-icon"
|
||||
accessibilityLabel={t('resolve_comment')}
|
||||
/>
|
||||
</button>
|
||||
<span>
|
||||
<button
|
||||
type="button"
|
||||
tabIndex={0}
|
||||
className="btn"
|
||||
onClick={onResolve}
|
||||
disabled={hasActiveContent}
|
||||
>
|
||||
<MaterialIcon
|
||||
type="check"
|
||||
className="review-panel-entry-actions-icon"
|
||||
accessibilityLabel={t('resolve_comment')}
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
</OLTooltip>
|
||||
</PreventSelectingEntry>
|
||||
)}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
import { useCallback, useState, Dispatch, SetStateAction } from 'react'
|
||||
|
||||
export default function useSubmittableTextInput(
|
||||
handleSubmit: (
|
||||
content: string,
|
||||
setContent: Dispatch<SetStateAction<string>>
|
||||
) => void
|
||||
) {
|
||||
const [content, setContent] = useState('')
|
||||
|
||||
const handleKeyPress = useCallback(
|
||||
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey && !e.metaKey) {
|
||||
e.preventDefault()
|
||||
if (content.trim().length > 0) {
|
||||
handleSubmit(content, setContent)
|
||||
}
|
||||
}
|
||||
},
|
||||
[content, handleSubmit]
|
||||
)
|
||||
|
||||
const handleChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setContent(e.target.value)
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
return { handleChange, handleKeyPress, content }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export const isFormSubmitKeypressEvent = (
|
||||
event: React.KeyboardEvent<HTMLTextAreaElement>
|
||||
) => {
|
||||
return (
|
||||
event.key === 'Enter' && !event.shiftKey && !event.ctrlKey && !event.metaKey
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user