[WIKI-874] refactor: description input component (#8544)
* refactor: description input component * fix: add missing prop to rich text editor
This commit is contained in:
parent
c3a9f99789
commit
2e429e5198
4 changed files with 87 additions and 78 deletions
|
|
@ -28,6 +28,7 @@ const workspaceService = new WorkspaceService();
|
||||||
type TFormData = {
|
type TFormData = {
|
||||||
id: string;
|
id: string;
|
||||||
description_html: string;
|
description_html: string;
|
||||||
|
description_json?: object;
|
||||||
isMigrationUpdate: boolean;
|
isMigrationUpdate: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -67,7 +68,13 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* @description Submit handler, the actual function which will be called when the form is submitted
|
* @description Submit handler, the actual function which will be called when the form is submitted
|
||||||
*/
|
*/
|
||||||
onSubmit: (value: string, isMigrationUpdate?: boolean) => Promise<void>;
|
onSubmit: (
|
||||||
|
value: {
|
||||||
|
description_html: string;
|
||||||
|
description_json: object | undefined;
|
||||||
|
},
|
||||||
|
isMigrationUpdate?: boolean
|
||||||
|
) => Promise<void>;
|
||||||
/**
|
/**
|
||||||
* @description Placeholder, if not provided, the placeholder will be the default placeholder
|
* @description Placeholder, if not provided, the placeholder will be the default placeholder
|
||||||
*/
|
*/
|
||||||
|
|
@ -107,13 +114,13 @@ export const DescriptionInput = observer(function DescriptionInput(props: Props)
|
||||||
entityId,
|
entityId,
|
||||||
fileAssetType,
|
fileAssetType,
|
||||||
initialValue,
|
initialValue,
|
||||||
|
issueSequenceId,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
placeholder,
|
placeholder,
|
||||||
projectId,
|
projectId,
|
||||||
setIsSubmitting,
|
setIsSubmitting,
|
||||||
swrDescription,
|
swrDescription,
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
issueSequenceId,
|
|
||||||
} = props;
|
} = props;
|
||||||
// states
|
// states
|
||||||
const [localDescription, setLocalDescription] = useState<TFormData>({
|
const [localDescription, setLocalDescription] = useState<TFormData>({
|
||||||
|
|
@ -144,7 +151,13 @@ export const DescriptionInput = observer(function DescriptionInput(props: Props)
|
||||||
// submit handler
|
// submit handler
|
||||||
const handleDescriptionFormSubmit = useCallback(
|
const handleDescriptionFormSubmit = useCallback(
|
||||||
async (formData: TFormData) => {
|
async (formData: TFormData) => {
|
||||||
await onSubmit(formData.description_html, formData.isMigrationUpdate);
|
await onSubmit(
|
||||||
|
{
|
||||||
|
description_html: formData.description_html,
|
||||||
|
description_json: formData.description_json,
|
||||||
|
},
|
||||||
|
formData.isMigrationUpdate
|
||||||
|
);
|
||||||
// Update lastSavedContent after successful save
|
// Update lastSavedContent after successful save
|
||||||
lastSavedContent.current = formData.description_html;
|
lastSavedContent.current = formData.description_html;
|
||||||
},
|
},
|
||||||
|
|
@ -209,80 +222,76 @@ export const DescriptionInput = observer(function DescriptionInput(props: Props)
|
||||||
|
|
||||||
if (!workspaceDetails) return null;
|
if (!workspaceDetails) return null;
|
||||||
|
|
||||||
|
if (!localDescription.description_html) return <DescriptionInputLoader />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Controller
|
||||||
{localDescription.description_html ? (
|
name="description_html"
|
||||||
<Controller
|
control={control}
|
||||||
name="description_html"
|
render={({ field: { onChange } }) => (
|
||||||
control={control}
|
<RichTextEditor
|
||||||
render={({ field: { onChange } }) => (
|
key={entityId}
|
||||||
<RichTextEditor
|
editable={!disabled}
|
||||||
key={entityId}
|
ref={editorRef}
|
||||||
editable={!disabled}
|
id={entityId}
|
||||||
ref={editorRef}
|
issueSequenceId={issueSequenceId}
|
||||||
id={entityId}
|
disabledExtensions={disabledExtensions}
|
||||||
issueSequenceId={issueSequenceId}
|
initialValue={localDescription.description_html ?? "<p></p>"}
|
||||||
disabledExtensions={disabledExtensions}
|
value={swrDescription ?? null}
|
||||||
initialValue={localDescription.description_html ?? "<p></p>"}
|
workspaceSlug={workspaceSlug}
|
||||||
value={swrDescription ?? null}
|
workspaceId={workspaceDetails.id}
|
||||||
workspaceSlug={workspaceSlug}
|
projectId={projectId}
|
||||||
workspaceId={workspaceDetails.id}
|
dragDropEnabled
|
||||||
projectId={projectId}
|
onChange={(description_json, description_html, options) => {
|
||||||
dragDropEnabled
|
if (description_html === lastSavedContent.current) return;
|
||||||
onChange={(_description, description_html, options) => {
|
setIsSubmitting("submitting");
|
||||||
// Skip if content hasn't actually changed (handles editor normalization on init)
|
onChange(description_html);
|
||||||
if (description_html === lastSavedContent.current) return;
|
setValue("isMigrationUpdate", !!options?.isMigrationUpdate);
|
||||||
setIsSubmitting("submitting");
|
setValue("description_json", description_json);
|
||||||
onChange(description_html);
|
hasUnsavedChanges.current = true;
|
||||||
setValue("isMigrationUpdate", options?.isMigrationUpdate ?? false);
|
debouncedFormSave();
|
||||||
hasUnsavedChanges.current = true;
|
}}
|
||||||
debouncedFormSave();
|
placeholder={placeholder ?? ((isFocused, value) => t(getDescriptionPlaceholderI18n(isFocused, value)))}
|
||||||
}}
|
searchMentionCallback={async (payload) =>
|
||||||
placeholder={placeholder ?? ((isFocused, value) => t(getDescriptionPlaceholderI18n(isFocused, value)))}
|
await workspaceService.searchEntity(workspaceSlug?.toString() ?? "", {
|
||||||
searchMentionCallback={async (payload) =>
|
...payload,
|
||||||
await workspaceService.searchEntity(workspaceSlug?.toString() ?? "", {
|
project_id: projectId,
|
||||||
...payload,
|
})
|
||||||
project_id: projectId,
|
}
|
||||||
})
|
containerClassName={containerClassName}
|
||||||
}
|
uploadFile={async (blockId, file) => {
|
||||||
containerClassName={containerClassName}
|
try {
|
||||||
uploadFile={async (blockId, file) => {
|
const { asset_id } = await uploadEditorAsset({
|
||||||
try {
|
blockId,
|
||||||
const { asset_id } = await uploadEditorAsset({
|
data: {
|
||||||
blockId,
|
entity_identifier: entityId,
|
||||||
data: {
|
entity_type: fileAssetType,
|
||||||
entity_identifier: entityId,
|
},
|
||||||
entity_type: fileAssetType,
|
file,
|
||||||
},
|
projectId,
|
||||||
file,
|
workspaceSlug,
|
||||||
projectId,
|
});
|
||||||
workspaceSlug,
|
return asset_id;
|
||||||
});
|
} catch (error) {
|
||||||
return asset_id;
|
console.log("Error in uploading asset:", error);
|
||||||
} catch (error) {
|
throw new Error("Asset upload failed. Please try again later.");
|
||||||
console.log("Error in uploading asset:", error);
|
}
|
||||||
throw new Error("Asset upload failed. Please try again later.");
|
}}
|
||||||
}
|
duplicateFile={async (assetId: string) => {
|
||||||
}}
|
try {
|
||||||
duplicateFile={async (assetId: string) => {
|
const { asset_id } = await duplicateEditorAsset({
|
||||||
try {
|
assetId,
|
||||||
const { asset_id } = await duplicateEditorAsset({
|
entityType: fileAssetType,
|
||||||
assetId,
|
projectId,
|
||||||
entityType: fileAssetType,
|
workspaceSlug,
|
||||||
projectId,
|
});
|
||||||
workspaceSlug,
|
return asset_id;
|
||||||
});
|
} catch {
|
||||||
return asset_id;
|
throw new Error("Asset duplication failed. Please try again later.");
|
||||||
} catch {
|
}
|
||||||
throw new Error("Asset duplication failed. Please try again later.");
|
}}
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
|
||||||
<DescriptionInputLoader />
|
|
||||||
)}
|
)}
|
||||||
</>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ export const InboxIssueMainContent = observer(function InboxIssueMainContent(pro
|
||||||
onSubmit={async (value, isMigrationUpdate) => {
|
onSubmit={async (value, isMigrationUpdate) => {
|
||||||
if (!issue.id || !issue.project_id) return;
|
if (!issue.id || !issue.project_id) return;
|
||||||
await issueOperations.update(workspaceSlug, issue.project_id, issue.id, {
|
await issueOperations.update(workspaceSlug, issue.project_id, issue.id, {
|
||||||
description_html: value,
|
description_html: value.description_html,
|
||||||
...(isMigrationUpdate ? { skip_activity: "true" } : {}),
|
...(isMigrationUpdate ? { skip_activity: "true" } : {}),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ export const IssueMainContent = observer(function IssueMainContent(props: Props)
|
||||||
onSubmit={async (value, isMigrationUpdate) => {
|
onSubmit={async (value, isMigrationUpdate) => {
|
||||||
if (!issue.id || !issue.project_id) return;
|
if (!issue.id || !issue.project_id) return;
|
||||||
await issueOperations.update(workspaceSlug, issue.project_id, issue.id, {
|
await issueOperations.update(workspaceSlug, issue.project_id, issue.id, {
|
||||||
description_html: value,
|
description_html: value.description_html,
|
||||||
...(isMigrationUpdate ? { skip_activity: "true" } : {}),
|
...(isMigrationUpdate ? { skip_activity: "true" } : {}),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ export const PeekOverviewIssueDetails = observer(function PeekOverviewIssueDetai
|
||||||
onSubmit={async (value, isMigrationUpdate) => {
|
onSubmit={async (value, isMigrationUpdate) => {
|
||||||
if (!issue.id || !issue.project_id) return;
|
if (!issue.id || !issue.project_id) return;
|
||||||
await issueOperations.update(workspaceSlug, issue.project_id, issue.id, {
|
await issueOperations.update(workspaceSlug, issue.project_id, issue.id, {
|
||||||
description_html: value,
|
description_html: value.description_html,
|
||||||
...(isMigrationUpdate ? { skip_activity: "true" } : {}),
|
...(isMigrationUpdate ? { skip_activity: "true" } : {}),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue