mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
added debounced updates for title and removed saved state after timout
This commit is contained in:
parent
b6329da50f
commit
8b02f58498
@ -50,7 +50,6 @@ export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentD
|
|||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
|
|
||||||
onSubmit(formData);
|
onSubmit(formData);
|
||||||
console.log("watching", formData.comment_html);
|
|
||||||
|
|
||||||
editorRef.current?.setEditorValue(formData.comment_html);
|
editorRef.current?.setEditorValue(formData.comment_html);
|
||||||
showEditorRef.current?.setEditorValue(formData.comment_html);
|
showEditorRef.current?.setEditorValue(formData.comment_html);
|
||||||
|
@ -10,6 +10,7 @@ import { TextArea } from "components/ui";
|
|||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
import Tiptap from "components/tiptap";
|
import Tiptap from "components/tiptap";
|
||||||
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
|
|
||||||
export interface IssueDescriptionFormValues {
|
export interface IssueDescriptionFormValues {
|
||||||
name: string;
|
name: string;
|
||||||
@ -32,7 +33,7 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
handleFormSubmit,
|
handleFormSubmit,
|
||||||
isAllowed,
|
isAllowed,
|
||||||
}) => {
|
}) => {
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
||||||
const [characterLimit, setCharacterLimit] = useState(false);
|
const [characterLimit, setCharacterLimit] = useState(false);
|
||||||
|
|
||||||
const { setShowAlert } = useReloadConfirmations();
|
const { setShowAlert } = useReloadConfirmations();
|
||||||
@ -55,7 +56,6 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
|
|
||||||
const handleDescriptionFormSubmit = useCallback(
|
const handleDescriptionFormSubmit = useCallback(
|
||||||
async (formData: Partial<IIssue>) => {
|
async (formData: Partial<IIssue>) => {
|
||||||
// console.log("formdata", formData)
|
|
||||||
if (!formData?.name || formData?.name.length === 0 || formData?.name.length > 255) return;
|
if (!formData?.name || formData?.name.length === 0 || formData?.name.length > 255) return;
|
||||||
|
|
||||||
await handleFormSubmit({
|
await handleFormSubmit({
|
||||||
@ -67,6 +67,14 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
[handleFormSubmit]
|
[handleFormSubmit]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSubmitting === "submitted") {
|
||||||
|
setTimeout(async () => {
|
||||||
|
setIsSubmitting("saved");
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}, [isSubmitting]);
|
||||||
|
|
||||||
// reset form values
|
// reset form values
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!issue) return;
|
if (!issue) return;
|
||||||
@ -76,6 +84,12 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
});
|
});
|
||||||
}, [issue, reset]);
|
}, [issue, reset]);
|
||||||
|
|
||||||
|
const debouncedTitleSave = useDebouncedCallback(async () => {
|
||||||
|
setTimeout(async () => {
|
||||||
|
handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted"));
|
||||||
|
}, 500);
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@ -85,11 +99,10 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
placeholder="Enter issue name"
|
placeholder="Enter issue name"
|
||||||
register={register}
|
register={register}
|
||||||
onFocus={() => setCharacterLimit(true)}
|
onFocus={() => setCharacterLimit(true)}
|
||||||
onBlur={() => {
|
onChange={(e) => {
|
||||||
setCharacterLimit(false);
|
setCharacterLimit(false);
|
||||||
|
setIsSubmitting("submitting");
|
||||||
setIsSubmitting(true);
|
debouncedTitleSave();
|
||||||
handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting(false));
|
|
||||||
}}
|
}}
|
||||||
required={true}
|
required={true}
|
||||||
className="min-h-10 block w-full resize-none overflow-hidden rounded border-none bg-transparent px-3 py-2 text-xl outline-none ring-0 focus:ring-1 focus:ring-custom-primary"
|
className="min-h-10 block w-full resize-none overflow-hidden rounded border-none bg-transparent px-3 py-2 text-xl outline-none ring-0 focus:ring-1 focus:ring-custom-primary"
|
||||||
@ -99,9 +112,8 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
{characterLimit && (
|
{characterLimit && (
|
||||||
<div className="pointer-events-none absolute bottom-1 right-1 z-[2] rounded bg-custom-background-100 text-custom-text-200 p-0.5 text-xs">
|
<div className="pointer-events-none absolute bottom-1 right-1 z-[2] rounded bg-custom-background-100 text-custom-text-200 p-0.5 text-xs">
|
||||||
<span
|
<span
|
||||||
className={`${
|
className={`${watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : ""
|
||||||
watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : ""
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{watch("name").length}
|
{watch("name").length}
|
||||||
</span>
|
</span>
|
||||||
@ -121,8 +133,8 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
<Tiptap
|
<Tiptap
|
||||||
value={
|
value={
|
||||||
!value ||
|
!value ||
|
||||||
value === "" ||
|
value === "" ||
|
||||||
(typeof value === "object" && Object.keys(value).length === 0)
|
(typeof value === "object" && Object.keys(value).length === 0)
|
||||||
? watch("description_html")
|
? watch("description_html")
|
||||||
: value
|
: value
|
||||||
}
|
}
|
||||||
@ -131,18 +143,20 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
customClassName="min-h-[150px]"
|
customClassName="min-h-[150px]"
|
||||||
editorContentCustomClassNames="pb-9"
|
editorContentCustomClassNames="pb-9"
|
||||||
onChange={(description: Object, description_html: string) => {
|
onChange={(description: Object, description_html: string) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting("submitting");
|
||||||
onChange(description_html);
|
onChange(description_html);
|
||||||
setValue("description", description);
|
setValue("description", description);
|
||||||
handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting(false));
|
handleSubmit(handleDescriptionFormSubmit)().finally(() => {
|
||||||
|
setIsSubmitting("submitted");
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="absolute right-5 bottom-5 text-xs text-custom-text-200 border border-custom-border-400 rounded-xl w-[6.5rem] py-1 z-10 flex items-center justify-center">
|
{isSubmitting !== "saved" && (<div className="absolute right-5 bottom-5 text-xs text-custom-text-200 border border-custom-border-400 rounded-xl w-[6.5rem] py-1 z-10 flex items-center justify-center">
|
||||||
{isSubmitting ? "Saving..." : "Saved"}
|
{isSubmitting === "submitting" ? "Saving..." : "Saved"}
|
||||||
</div>
|
</div>)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -136,8 +136,6 @@ export const IssueForm: FC<IssueFormProps> = ({
|
|||||||
reValidateMode: "onChange",
|
reValidateMode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("values", getValues());
|
|
||||||
|
|
||||||
const issueName = watch("name");
|
const issueName = watch("name");
|
||||||
|
|
||||||
const handleCreateUpdateIssue = async (formData: Partial<IIssue>) => {
|
const handleCreateUpdateIssue = async (formData: Partial<IIssue>) => {
|
||||||
@ -164,7 +162,6 @@ export const IssueForm: FC<IssueFormProps> = ({
|
|||||||
const handleAiAssistance = async (response: string) => {
|
const handleAiAssistance = async (response: string) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
console.log(response)
|
|
||||||
setValue("description", {});
|
setValue("description", {});
|
||||||
setValue("description_html", `${watch("description_html")}<p>${response}</p>`);
|
setValue("description_html", `${watch("description_html")}<p>${response}</p>`);
|
||||||
editorRef.current?.setEditorValue(`${watch("description_html")}`);
|
editorRef.current?.setEditorValue(`${watch("description_html")}`);
|
||||||
|
@ -17,7 +17,7 @@ export interface ITiptapRichTextEditor {
|
|||||||
customClassName?: string;
|
customClassName?: string;
|
||||||
editorContentCustomClassNames?: string;
|
editorContentCustomClassNames?: string;
|
||||||
onChange?: (json: any, html: string) => void;
|
onChange?: (json: any, html: string) => void;
|
||||||
setIsSubmitting?: (isSubmitting: boolean) => void;
|
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void;
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
forwardedRef?: any;
|
forwardedRef?: any;
|
||||||
debouncedUpdatesEnabled?: boolean;
|
debouncedUpdatesEnabled?: boolean;
|
||||||
@ -44,7 +44,7 @@ const Tiptap = (props: ITiptapRichTextEditor) => {
|
|||||||
content: value,
|
content: value,
|
||||||
onUpdate: async ({ editor }) => {
|
onUpdate: async ({ editor }) => {
|
||||||
// for instant feedback loop
|
// for instant feedback loop
|
||||||
setIsSubmitting?.(true);
|
setIsSubmitting?.("submitting");
|
||||||
checkForNodeDeletions(editor);
|
checkForNodeDeletions(editor);
|
||||||
if (debouncedUpdatesEnabled) {
|
if (debouncedUpdatesEnabled) {
|
||||||
debouncedUpdates({ onChange, editor });
|
debouncedUpdates({ onChange, editor });
|
||||||
@ -58,7 +58,6 @@ const Tiptap = (props: ITiptapRichTextEditor) => {
|
|||||||
|
|
||||||
useImperativeHandle(forwardedRef, () => ({
|
useImperativeHandle(forwardedRef, () => ({
|
||||||
clearEditor: () => {
|
clearEditor: () => {
|
||||||
console.log("clearContent");
|
|
||||||
console.log(editorRef);
|
console.log(editorRef);
|
||||||
editorRef.current?.commands.clearContent();
|
editorRef.current?.commands.clearContent();
|
||||||
},
|
},
|
||||||
|
@ -83,7 +83,6 @@ export async function startImageUpload(file: File, view: EditorView, pos: number
|
|||||||
};
|
};
|
||||||
|
|
||||||
const src = await UploadImageHandler(file);
|
const src = await UploadImageHandler(file);
|
||||||
console.log(src, "src");
|
|
||||||
const { schema } = view.state;
|
const { schema } = view.state;
|
||||||
pos = findPlaceholder(view.state, id);
|
pos = findPlaceholder(view.state, id);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user