course_web01 / frontend /src /components /QuillWrapper.tsx
trae-bot
2026032101
f45e448
import React, { useMemo, useRef } from 'react';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import { api } from '@/lib/api';
interface QuillWrapperProps {
value: string;
onChange: (value: string) => void;
placeholder?: string;
}
const QuillWrapper: React.FC<QuillWrapperProps> = ({ value, onChange, placeholder }) => {
const quillRef = useRef<ReactQuill>(null);
const imageHandler = () => {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = async () => {
const file = input.files ? input.files[0] : null;
if (file) {
const formData = new FormData();
formData.append('file', file);
try {
const res = await api.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
if (res.url) {
const quill = quillRef.current?.getEditor();
if (quill) {
const range = quill.getSelection(true);
quill.insertEmbed(range?.index || 0, 'image', res.url);
}
} else {
alert('Upload failed: ' + (res.message || 'Unknown error'));
}
} catch (error) {
console.error('Upload error:', error);
alert('Upload failed');
}
}
};
};
const modules = useMemo(
() => ({
toolbar: {
container: [
[{ header: [1, 2, 3, false] }],
['bold', 'italic', 'underline', 'strike'],
[{ list: 'ordered' }, { list: 'bullet' }],
['link', 'image'],
['clean'],
],
handlers: {
image: imageHandler,
},
},
}),
[]
);
return (
<ReactQuill
ref={quillRef}
theme="snow"
value={value}
onChange={onChange}
modules={modules}
placeholder={placeholder}
/>
);
};
export default QuillWrapper;