fix: Comment form should not collapse with draft
This commit is contained in:
@@ -8,6 +8,7 @@ import { VisuallyHidden } from "reakit";
|
||||
import { toast } from "sonner";
|
||||
import { useTheme } from "styled-components";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { ProsemirrorData } from "@shared/types";
|
||||
import { getEventFiles } from "@shared/utils/files";
|
||||
import { AttachmentValidation, CommentValidation } from "@shared/validations";
|
||||
import Comment from "~/models/Comment";
|
||||
@@ -20,12 +21,15 @@ import Tooltip from "~/components/Tooltip";
|
||||
import type { Editor as SharedEditor } from "~/editor";
|
||||
import useCurrentUser from "~/hooks/useCurrentUser";
|
||||
import useOnClickOutside from "~/hooks/useOnClickOutside";
|
||||
import usePersistedState from "~/hooks/usePersistedState";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import CommentEditor from "./CommentEditor";
|
||||
import { Bubble } from "./CommentThreadItem";
|
||||
|
||||
type Props = {
|
||||
/** Callback when the draft should be saved. */
|
||||
onSaveDraft: (data: ProsemirrorData | undefined) => void;
|
||||
/** A draft comment for this thread. */
|
||||
draft?: ProsemirrorData;
|
||||
/** The document that the comment will be associated with */
|
||||
documentId: string;
|
||||
/** The comment thread that the comment will be associated with */
|
||||
@@ -51,6 +55,8 @@ type Props = {
|
||||
function CommentForm({
|
||||
documentId,
|
||||
thread,
|
||||
draft,
|
||||
onSaveDraft,
|
||||
onTyping,
|
||||
onFocus,
|
||||
onBlur,
|
||||
@@ -62,10 +68,6 @@ function CommentForm({
|
||||
...rest
|
||||
}: Props) {
|
||||
const { editor } = useDocumentContext();
|
||||
const [data, setData] = usePersistedState<Record<string, any> | undefined>(
|
||||
`draft-${documentId}-${!thread ? "new" : thread?.id}`,
|
||||
undefined
|
||||
);
|
||||
const formRef = React.useRef<HTMLFormElement>(null);
|
||||
const editorRef = React.useRef<SharedEditor>(null);
|
||||
const [forceRender, setForceRender] = React.useState(0);
|
||||
@@ -92,7 +94,7 @@ function CommentForm({
|
||||
const handleCreateComment = action(async (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
setData(undefined);
|
||||
onSaveDraft(undefined);
|
||||
setForceRender((s) => ++s);
|
||||
setInputFocused(false);
|
||||
|
||||
@@ -101,7 +103,7 @@ function CommentForm({
|
||||
new Comment(
|
||||
{
|
||||
documentId,
|
||||
data,
|
||||
data: draft,
|
||||
},
|
||||
comments
|
||||
);
|
||||
@@ -109,7 +111,7 @@ function CommentForm({
|
||||
comment
|
||||
.save({
|
||||
documentId,
|
||||
data,
|
||||
data: draft,
|
||||
})
|
||||
.catch(() => {
|
||||
comment.isNew = true;
|
||||
@@ -124,18 +126,18 @@ function CommentForm({
|
||||
|
||||
const handleCreateReply = action(async (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
if (!data) {
|
||||
if (!draft) {
|
||||
return;
|
||||
}
|
||||
|
||||
setData(undefined);
|
||||
onSaveDraft(undefined);
|
||||
setForceRender((s) => ++s);
|
||||
|
||||
const comment = new Comment(
|
||||
{
|
||||
parentCommentId: thread?.id,
|
||||
documentId,
|
||||
data,
|
||||
data: draft,
|
||||
},
|
||||
comments
|
||||
);
|
||||
@@ -161,10 +163,10 @@ function CommentForm({
|
||||
});
|
||||
|
||||
const handleChange = (
|
||||
value: (asString: boolean, trim: boolean) => Record<string, any>
|
||||
value: (asString: boolean, trim: boolean) => ProsemirrorData
|
||||
) => {
|
||||
const text = value(true, true);
|
||||
setData(text ? value(false, true) : undefined);
|
||||
onSaveDraft(text ? value(false, true) : undefined);
|
||||
onTyping?.();
|
||||
};
|
||||
|
||||
@@ -181,7 +183,7 @@ function CommentForm({
|
||||
};
|
||||
|
||||
const handleCancel = async () => {
|
||||
setData(undefined);
|
||||
onSaveDraft(undefined);
|
||||
setForceRender((s) => ++s);
|
||||
setInputFocused(false);
|
||||
await reset();
|
||||
@@ -274,7 +276,7 @@ function CommentForm({
|
||||
<CommentEditor
|
||||
key={`${forceRender}`}
|
||||
ref={editorRef}
|
||||
defaultValue={data}
|
||||
defaultValue={draft}
|
||||
onChange={handleChange}
|
||||
onSave={handleSave}
|
||||
onFocus={handleFocus}
|
||||
@@ -289,7 +291,7 @@ function CommentForm({
|
||||
: `${t("Add a reply")}…`)
|
||||
}
|
||||
/>
|
||||
{(inputFocused || data) && (
|
||||
{(inputFocused || draft) && (
|
||||
<Flex justify="space-between" reverse={dir === "rtl"} gap={8}>
|
||||
<Flex gap={8}>
|
||||
<ButtonSmall type="submit" borderOnHover>
|
||||
|
||||
@@ -7,6 +7,7 @@ import scrollIntoView from "smooth-scroll-into-view-if-needed";
|
||||
import styled, { css } from "styled-components";
|
||||
import breakpoint from "styled-components-breakpoint";
|
||||
import { s } from "@shared/styles";
|
||||
import { ProsemirrorData } from "@shared/types";
|
||||
import Comment from "~/models/Comment";
|
||||
import Document from "~/models/Document";
|
||||
import Avatar from "~/components/Avatar";
|
||||
@@ -17,6 +18,7 @@ import Typing from "~/components/Typing";
|
||||
import { WebsocketContext } from "~/components/WebsocketProvider";
|
||||
import useCurrentUser from "~/hooks/useCurrentUser";
|
||||
import useOnClickOutside from "~/hooks/useOnClickOutside";
|
||||
import usePersistedState from "~/hooks/usePersistedState";
|
||||
import usePolicy from "~/hooks/usePolicy";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import { hover } from "~/styles";
|
||||
@@ -138,6 +140,11 @@ function CommentThread({
|
||||
}
|
||||
}, [focused, thread.id]);
|
||||
|
||||
const [draft, onSaveDraft] = usePersistedState<ProsemirrorData | undefined>(
|
||||
`draft-${document.id}-${thread.id}`,
|
||||
undefined
|
||||
);
|
||||
|
||||
return (
|
||||
<Thread
|
||||
ref={topRef}
|
||||
@@ -159,7 +166,7 @@ function CommentThread({
|
||||
comment={comment}
|
||||
key={comment.id}
|
||||
firstOfThread={index === 0}
|
||||
lastOfThread={index === commentsInThread.length - 1}
|
||||
lastOfThread={index === commentsInThread.length - 1 && !draft}
|
||||
canReply={focused && can.comment}
|
||||
firstOfAuthor={firstOfAuthor}
|
||||
lastOfAuthor={lastOfAuthor}
|
||||
@@ -179,9 +186,11 @@ function CommentThread({
|
||||
))}
|
||||
|
||||
<ResizingHeightContainer hideOverflow={false}>
|
||||
{(focused || commentsInThread.length === 0) && can.comment && (
|
||||
{(focused || draft || commentsInThread.length === 0) && can.comment && (
|
||||
<Fade timing={100}>
|
||||
<CommentForm
|
||||
onSaveDraft={onSaveDraft}
|
||||
draft={draft}
|
||||
documentId={document.id}
|
||||
thread={thread}
|
||||
onTyping={setIsTyping}
|
||||
@@ -192,7 +201,7 @@ function CommentThread({
|
||||
</Fade>
|
||||
)}
|
||||
</ResizingHeightContainer>
|
||||
{!focused && !recessed && can.comment && (
|
||||
{!focused && !recessed && !draft && can.comment && (
|
||||
<Reply onClick={() => setAutoFocus(true)}>{t("Reply")}…</Reply>
|
||||
)}
|
||||
</Thread>
|
||||
|
||||
@@ -4,12 +4,14 @@ import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useRouteMatch } from "react-router-dom";
|
||||
import styled from "styled-components";
|
||||
import { ProsemirrorData } from "@shared/types";
|
||||
import Empty from "~/components/Empty";
|
||||
import Flex from "~/components/Flex";
|
||||
import Scrollable from "~/components/Scrollable";
|
||||
import useCurrentUser from "~/hooks/useCurrentUser";
|
||||
import useFocusedComment from "~/hooks/useFocusedComment";
|
||||
import useKeyDown from "~/hooks/useKeyDown";
|
||||
import usePersistedState from "~/hooks/usePersistedState";
|
||||
import usePolicy from "~/hooks/usePolicy";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import CommentForm from "./CommentForm";
|
||||
@@ -27,6 +29,11 @@ function Comments() {
|
||||
|
||||
useKeyDown("Escape", () => document && ui.collapseComments(document?.id));
|
||||
|
||||
const [draft, onSaveDraft] = usePersistedState<ProsemirrorData | undefined>(
|
||||
`draft-${document?.id}-new`,
|
||||
undefined
|
||||
);
|
||||
|
||||
if (!document) {
|
||||
return null;
|
||||
}
|
||||
@@ -69,6 +76,8 @@ function Comments() {
|
||||
<AnimatePresence initial={false}>
|
||||
{!focusedComment && can.comment && (
|
||||
<NewCommentForm
|
||||
draft={draft}
|
||||
onSaveDraft={onSaveDraft}
|
||||
documentId={document.id}
|
||||
placeholder={`${t("Add a comment")}…`}
|
||||
autoFocus={false}
|
||||
|
||||
Reference in New Issue
Block a user