forked from github/plane
saving with debounce logic added and it's stored in backend
This commit is contained in:
parent
50e7c5924c
commit
a6ae849a81
@ -1,21 +1,11 @@
|
|||||||
import { FC, useCallback, useEffect, useState } from "react";
|
import { FC, useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
import dynamic from "next/dynamic";
|
|
||||||
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// hooks
|
// hooks
|
||||||
import useReloadConfirmations from "hooks/use-reload-confirmation";
|
import useReloadConfirmations from "hooks/use-reload-confirmation";
|
||||||
// components
|
// components
|
||||||
import { Loader, TextArea } from "components/ui";
|
import { TextArea } from "components/ui";
|
||||||
// const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), {
|
|
||||||
// ssr: false,
|
|
||||||
// loading: () => (
|
|
||||||
// <Loader>
|
|
||||||
// <Loader.Item height="12rem" width="100%" />
|
|
||||||
// </Loader>
|
|
||||||
// ),
|
|
||||||
// });
|
|
||||||
|
|
||||||
import Tiptap from "./tiptap";
|
import Tiptap from "./tiptap";
|
||||||
// types
|
// types
|
||||||
@ -65,7 +55,8 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
|
|
||||||
const handleDescriptionFormSubmit = useCallback(
|
const handleDescriptionFormSubmit = useCallback(
|
||||||
async (formData: Partial<IIssue>) => {
|
async (formData: Partial<IIssue>) => {
|
||||||
if (!formData.name || formData.name.length === 0 || formData.name.length > 255) return;
|
console.log("formdata", formData)
|
||||||
|
if (!formData?.name || formData?.name.length === 0 || formData?.name.length > 255) return;
|
||||||
|
|
||||||
await handleFormSubmit({
|
await handleFormSubmit({
|
||||||
name: formData.name ?? "",
|
name: formData.name ?? "",
|
||||||
@ -122,51 +113,29 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
<Controller
|
<Controller
|
||||||
name="description"
|
name="description"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { value } }) => {
|
render={({ field: { value, onChange } }) => {
|
||||||
if (!value && !watch("description_html")) return <></>;
|
if (!value && !watch("description_html")) return <></>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tiptap value={
|
<Tiptap
|
||||||
!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
|
}
|
||||||
}
|
setIsSubmitting={setIsSubmitting}
|
||||||
|
onChange={(description: Object, description_html: string) => {
|
||||||
|
onChange(description);
|
||||||
|
setValue("description_html", description_html);
|
||||||
|
handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting(false));
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
// <RemirrorRichTextEditor
|
|
||||||
// value = {
|
|
||||||
// !value ||
|
|
||||||
// value === "" ||
|
|
||||||
// (typeof value === "object" && Object.keys(value).length === 0)
|
|
||||||
// ? watch("description_html")
|
|
||||||
// : value
|
|
||||||
// }
|
|
||||||
// onJSONChange={(jsonValue) => {
|
|
||||||
// setShowAlert(true);
|
|
||||||
// setValue("description", jsonValue);
|
|
||||||
// }}
|
|
||||||
// onHTMLChange={(htmlValue) => {
|
|
||||||
// setShowAlert(true);
|
|
||||||
// setValue("description_html", htmlValue);
|
|
||||||
// }}
|
|
||||||
// onBlur={() => {
|
|
||||||
// setIsSubmitting(true);
|
|
||||||
// handleSubmit(handleDescriptionFormSubmit)()
|
|
||||||
// .then(() => setShowAlert(false))
|
|
||||||
// .finally(() => setIsSubmitting(false));
|
|
||||||
// }}
|
|
||||||
// placeholder="Description"
|
|
||||||
// editable={isAllowed}
|
|
||||||
// />
|
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{isSubmitting && (
|
<div className="absolute right-5 top-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">
|
||||||
<div className="absolute bottom-1 right-1 text-xs text-custom-text-200 bg-custom-background-100 p-3 z-10">
|
{isSubmitting ? "Saving..." : "Saved"}
|
||||||
Saving...
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import Placeholder from '@tiptap/extension-placeholder';
|
|
||||||
import { useEditor, EditorContent } from '@tiptap/react';
|
import { useEditor, EditorContent } from '@tiptap/react';
|
||||||
import StarterKit from '@tiptap/starter-kit';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
import { EditorBubbleMenu } from './EditorBubbleMenu';
|
import { EditorBubbleMenu } from './EditorBubbleMenu';
|
||||||
import { TiptapExtensions } from './extensions';
|
import { TiptapExtensions } from './extensions';
|
||||||
import { TiptapEditorProps } from "./props";
|
import { TiptapEditorProps } from "./props";
|
||||||
@ -10,21 +9,29 @@ type TiptapProps = {
|
|||||||
noBorder?: boolean;
|
noBorder?: boolean;
|
||||||
borderOnFocus?: boolean;
|
borderOnFocus?: boolean;
|
||||||
customClassName?: string;
|
customClassName?: string;
|
||||||
|
onChange?: (json: any, html: string) => void;
|
||||||
|
setIsSubmitting?: (isSubmitting: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tiptap = ({ value, noBorder, borderOnFocus, customClassName }: TiptapProps) => {
|
const Tiptap = ({ onChange, setIsSubmitting, value, noBorder, borderOnFocus, customClassName }: TiptapProps) => {
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
editorProps: TiptapEditorProps,
|
editorProps: TiptapEditorProps,
|
||||||
extensions: TiptapExtensions,
|
extensions: TiptapExtensions,
|
||||||
// extensions: [
|
|
||||||
// StarterKit,
|
|
||||||
// Placeholder.configure({
|
|
||||||
// placeholder: 'Description...',
|
|
||||||
// })
|
|
||||||
// ],
|
|
||||||
content: value,
|
content: value,
|
||||||
|
onUpdate: async ({ editor }) => {
|
||||||
|
setIsSubmitting(true);
|
||||||
|
debouncedUpdates({ onChange, editor });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => {
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (onChange) {
|
||||||
|
onChange(editor.getJSON(), editor.getHTML());
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
const editorClassNames = `mt-2 p-3 relative focus:outline-none rounded-md focus:border-custom-border-200
|
const editorClassNames = `mt-2 p-3 relative focus:outline-none rounded-md focus:border-custom-border-200
|
||||||
${noBorder ? '' : 'border border-custom-border-200'
|
${noBorder ? '' : 'border border-custom-border-200'
|
||||||
} ${borderOnFocus ? 'focus:border border-custom-border-200' : 'focus:border-0'
|
} ${borderOnFocus ? 'focus:border border-custom-border-200' : 'focus:border-0'
|
||||||
|
Loading…
Reference in New Issue
Block a user