AKKUL GAUTAM
AKKUL GAUTAM

Reputation: 11

React quill Formula and List

I am using React-quill in my project and have encountered 2 issues

  1. whenever i write something using ordered and unordered lists (bullets and numbers) and then save to my database and then fetch whenever required and then show(dangerouslySetInnerHTML) then it shows the content but not the bullets and number list which i have used

  2. whenever i click on formula button of react-quill the formula bar moves out of modal i am using and is not fixed at one place sometimes it comes at center of page sometimes moves out of modal which i am using

  3. Images of Problem 1 I.this is when i write content using lists

    II. this is when i want to show it (number points not showing)

  4. Images of Problem 2 I.formula toolbar moves out of modal

    II.Not fixed at one place

Codes: This is react Quill Configuration

import React, { useState, useEffect } from 'react';
     import axios from 'axios';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import Modal from './Modal';
import { toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { FaEdit } from 'react-icons/fa';
import katex from "katex";
import "katex/dist/katex.min.css";
import CustomToolbar from './CustomToolbar';
import 'quill-emoji/dist/quill-emoji.css';

window.katex = katex;

const QuillEditorTextModal = ({
  isVisible,
  onClose,
  isEditorial,
  initialValue,
  contestId,
  contestPlatform,
  questionNo,
  onSubmit,
  problemName,
}) => {
  const [editorValue, setEditorValue] = useState('');
  const [previousValue, setPreviousValue] = useState('');
  const [isEditing, setIsEditing] = useState(false);

  useEffect(() => {
    if (isEditorial) {
      getEditorialDeltas();
    } else {
      setEditorValue(initialValue || 'No Editorial Added Yet For This Question');
    }
  }, [isEditorial, initialValue]);

  const getEditorialDeltas = async () => {
    try {
      const response = await axios.get('http://localhost:8080/getEditorial', {
        params: {
          contestPlatform: contestPlatform,
          contestId: contestId,
          questionNo: questionNo,
        },
      });

      const deltas = response.data?.editorial[0] || '';
      setEditorValue(deltas);
      setPreviousValue(deltas);
    } catch (error) {
      console.error(error);
    }
  };

  const handleCancelClick = () => {
    setEditorValue(previousValue);
    setIsEditing(false);
  };

  const handleEditClick = (e) => {
    e.stopPropagation();
    setIsEditing(true);
  };

  const saveEditorialData = async (deltas) => {
    try {
      await axios.patch('http://localhost:8080/updateEditorial', {
        contestPlatform: contestPlatform,
        contestId: contestId,
        questionNo: questionNo,
        deltas,
      });

      onSubmit();
      toast.success('Data submitted successfully!');
    } catch (error) {
      console.error(error);
      toast.error('Failed to submit data. Please try again.');
    }
  };

  const handleEditorModalSubmit = () => {
    saveEditorialData(editorValue);
    setIsEditing(false);
  };

  const handleQuillChange = (value) => {
    console.log(value);
    setEditorValue(value);
  };

  const modules = {
    toolbar: {
      container: "#toolbar",
    },
  };
  const formats = [
    'font', 'size',
    'bold', 'italic', 'underline', 'strike',
    'color', 'background',
    'script',
    'header', 'blockquote', 'code-block',
    'indent', 'list',
    'direction', 'align',
    'link', 'image', 'video', 'formula',
  ];

  return (
    <Modal isVisible={isVisible} onClose={onClose}>
      <div className="p-8 text-center relative">
        <div className="mb-3">
          <h3 className="text-xl font-semibold text-grey-900">{isEditorial ? 'Editorial' : 'Edit Editorial'}</h3>
          <h4 className="text-lg font-semibold mb-2">{problemName}</h4>
        </div>
        <div className="flex justify-end items-start mt-3 absolute top-0 right-0">
          {isEditing ? (
            <FaEdit className="cursor-pointer ml-2 text-blue-500" onClick={handleCancelClick} />
          ) : (
            <FaEdit className="cursor-pointer ml-2 text-blue-500" onClick={handleEditClick} />
          )}
          {!isEditing && <span className="text-gray-500 italic ignore-close">Click pencil to edit</span>}
        </div>
        {isEditing ? (
          <>
            <CustomToolbar />
            <ReactQuill
              value={editorValue}
              onChange={handleQuillChange}
              placeholder={isEditorial ? 'Edit your text here' : 'Enter your text here'}
              modules={modules}
              formats={formats}
              className="quill-editor"
            />
          </>
        ) : (
          <div className="quill-editor" dangerouslySetInnerHTML={{ __html: editorValue }} />
        )}
        {isEditing && (
          <div className="flex justify-end mt-4">
            <button className="text-gray-500 italic mr-4 ignore-close" onClick={handleCancelClick}>
              Cancel
            </button>
            <button
              className="bg-blue-500 text-black py-2 px-4 rounded hover:bg-blue-700"
              onClick={handleEditorModalSubmit}
            >
              {isEditorial ? 'Update Editorial' : 'Submit Editorial'}
            </button>
          </div>
        )}
      </div>
    </Modal>
  );
};

export default QuillEditorTextModal;

this is custom toolbar

import React from "react";
import formats from "./ToolbarOptions";
const renderOptions = (formatData)=>{
    const {className,options} = formatData;
    return (
        <select className = {className}>
            <option selected="selected"></option>
            {
                options.map(value =>{
                    return (
                        <option value={value}></option>
                    )
                })
            }
        </select>
    )
}
const renderSingle = (formatData)=>{
    const {className,value} = formatData;
    return (
        <button className = {className} value = {value}></button>
    )
}
const CustomToolbar = () => (
    <div id="toolbar">
        {
            formats.map(classes => {
                return (
                    <span className = "ql-formats">
                        {
                            classes.map(formatData => {
                                return formatData.options?renderOptions(formatData):renderSingle(formatData)
                            })
                        }
                    </span>
                )
            })
        }
    </div>
  )
  export default CustomToolbar;

This is my modal code

import React from 'react';

const Modal = ({ isVisible, onClose, children }) => {
  if (!isVisible) return null;

  const handleClose = (e) => {
    if (e.target.id === 'wrapper' || e.target.classList.contains('close-button')) {
      onClose();
    }
  };

  return (
    <div className='fixed inset-0 flex justify-center items-center' id='wrapper' onClick={handleClose}>
      <div className='fixed inset-0 bg-black bg-opacity-25'></div>
      <div className='relative z-10 bg-white p-6 rounded w-1/2 h-3/4 max-h-[75%] max-w-[50%] overflow-y-auto'>
        <button className='absolute top-2 right-2 text-black text-xl close-button' onClick={handleClose}>
          X
        </button>
        {children}
      </div>
    </div>
  );
};

export default Modal;

Kindly help i am stuck here for past 1 week

Upvotes: 1

Views: 455

Answers (1)

Charaka_96
Charaka_96

Reputation: 1

For the first question you've asked, when ever you need to display the contents exactly as you've written them in the Quill editor, you'll need to import the 'react-quill/dist/quill.snow.css' file.

Upvotes: 0

Related Questions