Merge pull request #15815 from overleaf/td-persist-unsaved-comment

Persist unsaved comment in the front end after not submitting

GitOrigin-RevId: a7ffee6f5fbfb7151a2ef7233ba4412d0db33e19
This commit is contained in:
Tim Down 2023-11-21 14:12:19 +00:00 committed by Copybot
parent 7029a0822b
commit 86c06d8c99
5 changed files with 44 additions and 17 deletions

View file

@ -509,6 +509,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
const [navHeight, setNavHeight] = useState(0) const [navHeight, setNavHeight] = useState(0)
const [toolbarHeight, setToolbarHeight] = useState(0) const [toolbarHeight, setToolbarHeight] = useState(0)
const [layoutSuspended, setLayoutSuspended] = useState(false) const [layoutSuspended, setLayoutSuspended] = useState(false)
const [unsavedComment, setUnsavedComment] = useState('')
// listen for events from the CodeMirror 6 track changes extension // listen for events from the CodeMirror 6 track changes extension
useEffect(() => { useEffect(() => {
@ -573,6 +574,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
trackChangesForGuestsAvailable, trackChangesForGuestsAvailable,
formattedProjectMembers, formattedProjectMembers,
layoutSuspended, layoutSuspended,
unsavedComment,
}), }),
[ [
collapsed, collapsed,
@ -599,6 +601,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
trackChangesForGuestsAvailable, trackChangesForGuestsAvailable,
formattedProjectMembers, formattedProjectMembers,
layoutSuspended, layoutSuspended,
unsavedComment,
] ]
) )
@ -630,6 +633,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
setNavHeight, setNavHeight,
setToolbarHeight, setToolbarHeight,
setLayoutSuspended, setLayoutSuspended,
setUnsavedComment,
}), }),
[ [
handleSetSubview, handleSetSubview,
@ -657,6 +661,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
setNavHeight, setNavHeight,
setToolbarHeight, setToolbarHeight,
setLayoutSuspended, setLayoutSuspended,
setUnsavedComment,
] ]
) )

View file

@ -130,7 +130,7 @@ function CurrentFileContainer() {
} }
if (entry.type === 'add-comment' && permissions.comment) { if (entry.type === 'add-comment' && permissions.comment) {
return <AddCommentEntry key={id} entryId={entry.type} /> return <AddCommentEntry key={id} />
} }
if (entry.type === 'bulk-actions') { if (entry.type === 'bulk-actions') {

View file

@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useEffect, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import EntryContainer from './entry-container' import EntryContainer from './entry-container'
import EntryCallout from './entry-callout' import EntryCallout from './entry-callout'
import EntryActions from './entry-actions' import EntryActions from './entry-actions'
@ -11,20 +11,19 @@ import {
useReviewPanelValueContext, useReviewPanelValueContext,
} from '../../../context/review-panel/review-panel-context' } from '../../../context/review-panel/review-panel-context'
import classnames from 'classnames' import classnames from 'classnames'
import { ReviewPanelAddCommentEntry } from '../../../../../../../types/review-panel/entry'
type AddCommentEntryProps = { function AddCommentEntry() {
entryId: ReviewPanelAddCommentEntry['type']
}
function AddCommentEntry({ entryId }: AddCommentEntryProps) {
const { t } = useTranslation() const { t } = useTranslation()
const { isAddingComment } = useReviewPanelValueContext() const { isAddingComment, unsavedComment } = useReviewPanelValueContext()
const { setIsAddingComment, submitNewComment, handleLayoutChange } = const {
useReviewPanelUpdaterFnsContext() setIsAddingComment,
submitNewComment,
handleLayoutChange,
setUnsavedComment,
} = useReviewPanelUpdaterFnsContext()
const [content, setContent] = useState('') const [content, setContent] = useState(unsavedComment)
const [isSubmitting, setIsSubmiting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false)
const handleStartNewComment = () => { const handleStartNewComment = () => {
setIsAddingComment(true) setIsAddingComment(true)
@ -32,14 +31,14 @@ function AddCommentEntry({ entryId }: AddCommentEntryProps) {
} }
const handleSubmitNewComment = async () => { const handleSubmitNewComment = async () => {
setIsSubmiting(true) setIsSubmitting(true)
try { try {
await submitNewComment(content) await submitNewComment(content)
setIsSubmiting(false) setIsSubmitting(false)
setIsAddingComment(false) setIsAddingComment(false)
setContent('') setContent('')
} catch (err) { } catch (err) {
setIsSubmiting(false) setIsSubmitting(false)
} }
handleLayoutChange({ async: true }) handleLayoutChange({ async: true })
} }
@ -56,6 +55,20 @@ function AddCommentEntry({ entryId }: AddCommentEntryProps) {
} }
}, [setIsAddingComment]) }, [setIsAddingComment])
const unsavedCommentRef = useRef(unsavedComment)
// Keep unsaved comment ref up to date for use when the component unmounts
useEffect(() => {
unsavedCommentRef.current = content
}, [content])
// Store the unsaved comment in the context on unmount
useEffect(() => {
return () => {
setUnsavedComment(unsavedCommentRef.current)
}
}, [setUnsavedComment])
const handleCommentKeyPress = ( const handleCommentKeyPress = (
e: React.KeyboardEvent<HTMLTextAreaElement> e: React.KeyboardEvent<HTMLTextAreaElement>
) => { ) => {
@ -76,7 +89,7 @@ function AddCommentEntry({ entryId }: AddCommentEntryProps) {
} }
return ( return (
<EntryContainer id={entryId}> <EntryContainer id="add-comment">
<EntryCallout className="rp-entry-callout-add-comment" /> <EntryCallout className="rp-entry-callout-add-comment" />
<div <div
className={classnames('rp-entry', 'rp-entry-add-comment', { className={classnames('rp-entry', 'rp-entry-add-comment', {

View file

@ -137,6 +137,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
const [navHeight, setNavHeight] = useState(0) const [navHeight, setNavHeight] = useState(0)
const [toolbarHeight, setToolbarHeight] = useState(0) const [toolbarHeight, setToolbarHeight] = useState(0)
const [layoutSuspended, setLayoutSuspended] = useState(false) const [layoutSuspended, setLayoutSuspended] = useState(false)
const [unsavedComment, setUnsavedComment] = useState('')
const values = useMemo<ReviewPanelState['values']>( const values = useMemo<ReviewPanelState['values']>(
() => ({ () => ({
@ -164,6 +165,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
trackChangesForGuestsAvailable, trackChangesForGuestsAvailable,
formattedProjectMembers, formattedProjectMembers,
layoutSuspended, layoutSuspended,
unsavedComment,
}), }),
[ [
collapsed, collapsed,
@ -190,6 +192,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
trackChangesForGuestsAvailable, trackChangesForGuestsAvailable,
formattedProjectMembers, formattedProjectMembers,
layoutSuspended, layoutSuspended,
unsavedComment,
] ]
) )
@ -221,6 +224,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
setNavHeight, setNavHeight,
setToolbarHeight, setToolbarHeight,
setLayoutSuspended, setLayoutSuspended,
setUnsavedComment,
}), }),
[ [
handleSetSubview, handleSetSubview,
@ -248,6 +252,7 @@ function useAngularReviewPanelState(): ReviewPanelState {
setNavHeight, setNavHeight,
setToolbarHeight, setToolbarHeight,
setLayoutSuspended, setLayoutSuspended,
setUnsavedComment,
] ]
) )

View file

@ -46,6 +46,7 @@ export interface ReviewPanelState {
} }
> >
layoutSuspended: boolean layoutSuspended: boolean
unsavedComment: string
} }
updaterFns: { updaterFns: {
handleSetSubview: (subView: SubView) => void handleSetSubview: (subView: SubView) => void
@ -88,6 +89,9 @@ export interface ReviewPanelState {
setLayoutSuspended: React.Dispatch< setLayoutSuspended: React.Dispatch<
React.SetStateAction<Value<'layoutSuspended'>> React.SetStateAction<Value<'layoutSuspended'>>
> >
setUnsavedComment: React.Dispatch<
React.SetStateAction<Value<'unsavedComment'>>
>
} }
} }
/* eslint-enable no-use-before-define */ /* eslint-enable no-use-before-define */