unlayer / react-email-editor

Drag-n-Drop Email Editor Component for React.js
https://unlayer.com/
MIT License
4.62k stars 742 forks source link

[Bug]: Can't use custom image with selectImage callback #331

Open maitrungduc1410 opened 1 year ago

maitrungduc1410 commented 1 year ago

Hi all, I'm trying to implement custom image library. It was working fine in 1.5.0 but with latest version it's not working any more (1.7.6)

idea:

export default function App() {
  const [uploadDialogVisible, setUploadDialogVisible] =
    useState<boolean>(false);
  const editorSelectImageCallbackRef = useRef<any>();

  const onReady = () => {
    emailEditorRef.current!.registerCallback(
      "image",
      function (file: FileInfo, done: FileUploadDoneCallback) {
        console.log("selected image:", file);
      }
    );

    (emailEditorRef.current as any).registerCallback(
      "selectImage",
      function (_data: any, done: any) {
        setUploadDialogVisible(true);
        editorSelectImageCallbackRef.current = done;
      }
    );
  };

  return (
    <>
      <EmailEditor
        ref={emailEditorRef}
        onReady={onReady}
        options={{ mergeTags: MERGE_TAGS }}
        style={{ height: "80vh" }}
      />

      <UploadDialogComponent>
        {/* some logics */}
      </UploadDialogComponent>
    </>
  );
}

When I first drag the new image to editor, it looks fine:

Screenshot 2023-04-02 at 2 19 27 PM

After click Upload button to show my UploadDialogComponent:

Screenshot 2023-04-02 at 2 19 34 PM

my dialog component is showing fine, but the image element on the editor is deleted, I figure out it's because of the component is re-rendered, and somehow the image element is deleted, not sure what's going on.

I'm using Next 13. I tried disable React Strict Mode, but it didn't help.

It's weird, it was working in older version of react-image-editor

Please help, thanks

AkshaySharma008 commented 1 year ago

Hi, @maitrungduc1410 can you tell me how is your options={{ mergeTags: MERGE_TAGS }} MERGE_TAGS list looks like? I am getting some issues integrating merge tags.

Apologies to put some other doubt in your issue :)

richLpf commented 1 year ago

I have the same problem

maitrungduc1410 commented 1 year ago

Hi, @maitrungduc1410 can you tell me how is your options={{ mergeTags: MERGE_TAGS }} MERGE_TAGS list looks like? I am getting some issues integrating merge tags.

Apologies to put some other doubt in your issue :)

@AkshaySharma008

import { MergeTag } from "react-email-editor";

export const MERGE_TAGS: MergeTag[] = [
  {
    name: "Email",
    value: "{{ email }}",
  },
  {
    name: "Address",
    value: "{{ address }}",
  },
  {
    name: "Username",
    value: "{{ username }}",
  },
  {
    name: "UserName",
    value: "{{ userName }}",
  },
  {
    name: "FullName",
    value: "{{ fullName }}",
  },
  {
    name: "Fullname",
    value: "{{ fullname }}",
  },
  {
    name: "Location",
    value: "{{ location }}",
  },
  {
    name: "Birthday",
    value: "{{ birthday }}",
  },
  {
    name: "Grade",
    value: "{{ grade }}",
  },
  {
    name: "Phone",
    value: "{{ phone }}",
  },
  {
    name: "Country",
    value: "{{ country }}",
  },
];
richLpf commented 1 year ago

@maitrungduc1410 hello, I want to know how you solve this problem, “my dialog component is showing fine, but the image element on the editor is deleted, I figure out it's because of the component is re-rendered, and somehow the image element is deleted, not sure what's going on.”

maitrungduc1410 commented 1 year ago

Downgrade to 1.5.0 is my solution for now. @richLpf

richLpf commented 1 year ago

@maitrungduc1410 thank you. but it's doesn't work yet. this is my code

const editorCallbackRef = useRef()
const onLoad = () => {
    // change file storage URL
    editorRef.current.registerCallback('selectImage', async (_, done) => {
      setOpenMaterial(true);
      // console.log("done", done)
      editorCallbackRef.current = done;
    });
  };

  function uploadMaterial(FileContent, FileName, FileType) {
    UploadMaterial({ FileContent, FileName, FileType }).then((res) => {
      const { RetCode, Url } = res;
      if (RetCode === 0) {
        editorCallbackRef.current({ progress: 100, url: transferHttps(Url) });
        setOpenMaterial(false)
      }
    });
  }

return <>
    <EmailEditor
        ref={editorRef}
        onLoad={onLoad}
        onReady={onReady}
        appearance={{
          theme: 'dark'
        }}
      />
      <AddMaterial 
        visible={openMaterial} 
        setVisible={setOpenMaterial} 
        addImage={addImage}
        loading={confirmLoading}
      />
</>

When the second time I click on the upload Image button, Images and content will be the last time

richLpf commented 1 year ago

@maitrungduc1410 I solved,My problem is a different problem

image

onLoad is exec every time,so my editor is reset every time

maitrungduc1410 commented 1 year ago

@maitrungduc1410 I solved,My problem is a different problem

image

onLoad is exec every time,so my editor is reset every time

How can its called everytime.

Please check your code, you may have memory leak, review your useEffect if you're create the editor inside it

maitrungduc1410 commented 1 year ago

@maitrungduc1410 thank you. but it's doesn't work yet. this is my code


const editorCallbackRef = useRef()

const onLoad = () => {

    // change file storage URL

    editorRef.current.registerCallback('selectImage', async (_, done) => {

      setOpenMaterial(true);

      // console.log("done", done)

      editorCallbackRef.current = done;

    });

  };

  function uploadMaterial(FileContent, FileName, FileType) {

    UploadMaterial({ FileContent, FileName, FileType }).then((res) => {

      const { RetCode, Url } = res;

      if (RetCode === 0) {

        editorCallbackRef.current({ progress: 100, url: transferHttps(Url) });

        setOpenMaterial(false)

      }

    });

  }

return <>

    <EmailEditor

        ref={editorRef}

        onLoad={onLoad}

        onReady={onReady}

        appearance={{

          theme: 'dark'

        }}

      />

      <AddMaterial 

        visible={openMaterial} 

        setVisible={setOpenMaterial} 

        addImage={addImage}

        loading={confirmLoading}

      />

</>

When the second time I click on the upload Image button, Images and content will be the last time

Hardcode exact version to 1.5.0 in your package.json and rerun "npm install"

After that open package-lock find your package and make sure its exactly 1.5.0

cjsewell commented 1 year ago

For me, to work around this, I only run my onReady once:

const emailEditorRef = useRef<EditorRef>(null);
const initialized = useRef(false); // Has onReady been called?
const onReady = () => {
    if (!initialized.current && emailEditorRef.current) { // Dont run again if onReady has already been called
        initialized.current = true;
        try {
            const data = JSON.parse(value) as HtmlExport;
            if (data) {
                emailEditorRef.current?.editor?.loadDesign(data?.design);
            }

            emailEditorRef.current.registerCallback('selectImage' as never, (file, callback) => {
                handleFileModelOpen(callback as FileSelectedCallback);
            });

            emailEditorRef.current.addEventListener('design:updated', () => {
                save();
            });

        } catch (e) {
            console.error(e);
        }
    }
};