[WEB-1244] fix: add better image insertion and replacement logic in the editor (#4508)

* fix: add better image insertion and replacement logic

* refactor: image handling in editor

* chore: remove passing uploadKey around

* refactor: remove unused code

* fix: redundant files removed

* fix: add is editor ready to discard api to control behvaiours from our app

* fix: focus issues and image insertion position when not using slash command

* fix: import order fixed
This commit is contained in:
M. Palanikannan 2024-05-29 18:25:03 +05:30 committed by GitHub
parent 061a447734
commit ade6eded69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 483 additions and 366 deletions

View file

@ -18,6 +18,7 @@ import { ISSUE_CREATED } from "@/constants/event-tracker";
import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
// hooks
import { useEventTracker, useProjectInbox, useWorkspace } from "@/hooks/store";
import useKeypress from "@/hooks/use-keypress";
type TInboxIssueCreateRoot = {
workspaceSlug: string;
@ -62,8 +63,33 @@ export const InboxIssueCreateRoot: FC<TInboxIssueCreateRoot> = observer((props)
[formData]
);
const handleEscKeyDown = (event: KeyboardEvent) => {
if (descriptionEditorRef.current?.isEditorReadyToDiscard()) {
handleModalClose();
} else {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Editor is still processing changes. Please wait before proceeding.",
});
event.preventDefault(); // Prevent default action if editor is not ready to discard
}
};
useKeypress("Escape", handleEscKeyDown);
const handleFormSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (descriptionEditorRef.current?.isEditorReadyToDiscard()) {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Editor is still processing changes. Please wait before proceeding.",
});
return;
}
const payload: Partial<TIssue> = {
name: formData.name || "",
description_html: formData.description_html || "<p></p>",
@ -155,7 +181,22 @@ export const InboxIssueCreateRoot: FC<TInboxIssueCreateRoot> = observer((props)
<span className="text-xs">Create more</span>
</div>
<div className="flex items-center gap-3">
<Button variant="neutral-primary" size="sm" type="button" onClick={handleModalClose}>
<Button
variant="neutral-primary"
size="sm"
type="button"
onClick={() => {
if (descriptionEditorRef.current?.isEditorReadyToDiscard()) {
handleModalClose();
} else {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Editor is still processing changes. Please wait before proceeding.",
});
}
}}
>
Discard
</Button>
<Button

View file

@ -29,6 +29,7 @@ import { getChangedIssuefields, getDescriptionPlaceholder } from "@/helpers/issu
import { shouldRenderProject } from "@/helpers/project.helper";
// hooks
import { useAppRouter, useEstimate, useInstance, useIssueDetail, useProject, useWorkspace } from "@/hooks/store";
import useKeypress from "@/hooks/use-keypress";
import { useProjectIssueProperties } from "@/hooks/use-project-issue-properties";
// services
import { AIService } from "@/services/ai.service";
@ -121,6 +122,21 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
const { getProjectById } = useProject();
const { areEstimatesEnabledForProject } = useEstimate();
function handleKeyDown(event: KeyboardEvent) {
if (editorRef.current?.isEditorReadyToDiscard()) {
onClose();
} else {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Editor is still processing changes. Please wait before proceeding.",
});
event.preventDefault(); // Prevent default action if editor is not ready to discard
}
}
useKeypress("Escape", handleKeyDown);
const {
issue: { getIssueById },
} = useIssueDetail();
@ -168,6 +184,16 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
const issueName = watch("name");
const handleFormSubmit = async (formData: Partial<TIssue>, is_draft_issue = false) => {
// Check if the editor is ready to discard
if (!editorRef.current?.isEditorReadyToDiscard()) {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Editor is not ready to discard changes.",
});
return;
}
const submitData = !data?.id
? formData
: {
@ -740,7 +766,22 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
)}
</div>
<div className="flex items-center gap-2">
<Button variant="neutral-primary" size="sm" onClick={onClose} tabIndex={getTabIndex("discard_button")}>
<Button
variant="neutral-primary"
size="sm"
onClick={() => {
if (editorRef.current?.isEditorReadyToDiscard()) {
onClose();
} else {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Editor is still processing changes. Please wait before proceeding.",
});
}
}}
tabIndex={getTabIndex("discard_button")}
>
Discard
</Button>
{isDraft && (

View file

@ -65,6 +65,7 @@ export const IssueView: FC<IIssueView> = observer((props) => {
},
issueId
);
const handleKeyDown = () => {
const slashCommandDropdownElement = document.querySelector("#slash-command");
const dropdownElement = document.activeElement?.tagName === "INPUT";
@ -74,6 +75,7 @@ export const IssueView: FC<IIssueView> = observer((props) => {
if (issueElement) issueElement?.focus();
}
};
useKeypress("Escape", handleKeyDown);
const handleRestore = async () => {

View file

@ -1,10 +1,10 @@
import { useEffect } from "react";
const useKeypress = (key: string, callback: () => void) => {
const useKeypress = (key: string, callback: (event: KeyboardEvent) => void) => {
useEffect(() => {
const handleKeydown = (event: KeyboardEvent) => {
if (event.key === key) {
callback();
callback(event);
}
};
@ -13,7 +13,7 @@ const useKeypress = (key: string, callback: () => void) => {
return () => {
document.removeEventListener("keydown", handleKeydown);
};
});
}, [key, callback]);
};
export default useKeypress;