fix: Comment form should not collapse with draft

This commit is contained in:
Tom Moor
2023-12-28 21:31:40 -05:00
parent 0419e7dc52
commit 01c806d6ea
3 changed files with 39 additions and 19 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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}