Example call

  • pastikan kamu sudah mempunyai component dropbox untuk upload file apabila belum ada kamu bisa mengubahnya menggunakan storage firebase atau apapun itu

  • pastikan di import kamu menginstall package json yang ada

  • pastikan kamu membuat folder file src > Components > Quill > RichTextEditor.jsx


import React, { useRef, useState, useEffect, useCallback } from 'react';
import ReactQuill, { Quill } from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import ImageDropAndPaste from 'quill-image-drop-and-paste';
import { useToast } from '@chakra-ui/react';

import './RichTextEditor.css';
import useUserStore from '../../Hooks/Zustand/Store';
import UploadFileToDropbox from '../DropBox/UploadFileToDropbox';
import { getSingleDocumentFirebase } from '../../Api/firebaseApi';
import { decryptToken } from '../../Utils/encrypToken';

import ProgressCircle from '../Progress/ProgressCircle';


function RichTextEditor({ value, onChange }) {
  const quillRef = useRef();
  const [editorValue, setEditorValue] = useState(value);
  const [uploading, setUploading] = useState(false);
  const globalState = useUserStore();
  const toast = useToast();
  const [progress, setProgress] = useState(0)




  let imageDropAndPasteRegistered = false;

  if (!imageDropAndPasteRegistered) {
    Quill.register('modules/imageDropAndPaste', ImageDropAndPaste);
    imageDropAndPasteRegistered = true;
  }


  const imageHandler = useCallback(async (dataUrl, type, imageData) => {
    try {
      setUploading(true);
      setProgress(0)
      // Menampilkan indikator loading saat mengunggah gambar

      // Mengubah dataUrl menjadi objek File
      const byteString = atob(dataUrl.split(',')[1]);
      const mimeString = dataUrl.split(',')[0].split(':')[1].split(';')[0];
      const arrayBuffer = new ArrayBuffer(byteString.length);
      const uintArray = new Uint8Array(arrayBuffer);

      for (let i = 0; i < byteString.length; i++) {
        uintArray[i] = byteString.charCodeAt(i);
      }

      const file = new File([arrayBuffer], imageData.name, {
        type: mimeString,
      });

      const token = await getSingleDocumentFirebase('token', 'dropbox');
      const decryptResult = decryptToken(`${token?.access_token}`);

      // Upload gambar ke Dropbox menggunakan fungsi UploadFileToDropbox yang telah disediakan
      const parentPath = `/${globalState?.currentCompany}/${globalState?.currentProject}/kanban`; // Ganti dengan path folder di Dropbox yang ingin Anda gunakan
      const dropboxLink = await UploadFileToDropbox(
        file,
        parentPath,
        // globalState.accessToken
        decryptResult,
        setProgress
      );

      if (dropboxLink) {
        // Jika upload berhasil, masukkan tautan berbagi sebagai sumber gambar di editor
        const editor = quillRef.current.getEditor();
        editor.insertEmbed(imageData.index, 'image', dropboxLink.link);
      }
    } catch (error) {
      toast({
        title: 'Oops!',
        description: `An error occured, ${error}`,
        status: 'error',
        duration: 2000,
        isClosable: true,
      });
    } finally {
      setUploading(false); // Sembunyikan indikator loading setelah selesai mengunggah gambar
    }
  }, []);

  useEffect(() => {
    setEditorValue(value);
  }, [value]);

  const quillConfig = {
    theme: 'snow',
    modules: {
      toolbar: [
        [{ header: [1, 2, 3, 4, 5, 6, false] }],
        ['bold', 'italic', 'underline', 'strike'],
        [{ color: [] }, { background: [] }],
        [
          { list: 'ordered' },
          { list: 'bullet' },
          { indent: '-1' },
          { indent: '+1' },
        ],
        ['blockquote', 'code-block'],
        ['link', 'image', 'video'],
        ['clean'],
        [
          {
            color: [
              '#000000',
              '#e60000',
              '#ff9900',
              '#ffff00',
              '#008a00',
              '#0066cc',
              '#9933ff',
              '#ffffff',
              '#facccc',
              '#ffebcc',
              '#ffffcc',
              '#cce8cc',
              '#cce0f5',
              '#ebd6ff',
              '#bbbbbb',
              '#f06666',
              '#ffc266',
              '#ffff66',
              '#66b966',
              '#66a3e0',
              '#c285ff',
              '#888888',
              '#a10000',
              '#b26b00',
              '#b2b200',
              '#006100',
              '#0047b2',
              '#6b24b2',
              '#444444',
              '#5c0000',
              '#663d00',
              '#666600',
              '#003700',
              '#002966',
              '#3d1466',
            ],
          },
        ],
      ],
      imageDropAndPaste: {
        handler: imageHandler,
      },
    },
  };

  const handleContentChange = useCallback(
    (value) => {
      setEditorValue(value);
      if (onChange) {
        onChange(value);
      }
    },
    [onChange]
  );

  return (
    <>
      <ReactQuill
        ref={quillRef}
        value={editorValue}
        onChange={handleContentChange}
        modules={quillConfig.modules}
        theme={quillConfig.theme}
        style={{ minHeight: '200px', overflow: 'hidden', padding: 5 }}
      />
      {uploading && <div>
        <ProgressCircle value={progress} />
        Uploading Image...</div>} {/* Indikator loading */}
    </>
  );
}

export default RichTextEditor;



  • di component yang kamu ingin taroh silahkan panggil component tersebut

import React, { useState } from 'react'
import RichTextEditor from '../Quill/RichTextEditor'

function TaskCardAddComment() {

  const [value, setValue] = useState('');


    
  const handleContentChange = (value) => {
    setValue(value);
  };

  return (
    <RichTextEditor value={value} onChange={handleContentChange} />
    )
}

export default TaskCardAddComment

Last updated