diff --git a/client/kb-frontend/src/components/ArticleEdit.jsx b/client/kb-frontend/src/components/ArticleEdit.jsx
index a852a54..e98243a 100644
--- a/client/kb-frontend/src/components/ArticleEdit.jsx
+++ b/client/kb-frontend/src/components/ArticleEdit.jsx
@@ -5,6 +5,9 @@ import 'react-quill/dist/quill.snow.css';
import './ArticleEdit.css';
import MediaGallery from './MediaGallery';
import BlotFormatter from 'quill-blot-formatter';
+import { useClickOutside } from '../hooks/useClickOutside';
+import { useToastHelpers } from '../hooks/useToast';
+import Toast from './Toast';
Quill.register('modules/blotFormatter', BlotFormatter);
const BlockEmbed = Quill.import('blots/block/embed');
@@ -69,6 +72,19 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
const [newCategoryInput, setNewCategoryInput] = useState('');
const [showTagSuggestions, setShowTagSuggestions] = useState(false);
const quillRef = useRef(null);
+ const categoryDropdownRef = useRef(null);
+ const tagDropdownRef = useRef(null);
+ const { toast, hideToast, showSuccess, showError } = useToastHelpers();
+
+ useClickOutside(categoryDropdownRef, () => {
+ setShowCategoryDropdown(false);
+ setShowCreateCategory(false);
+ setNewCategoryInput('');
+ }, showCategoryDropdown);
+
+ useClickOutside(tagDropdownRef, () => {
+ setShowTagSuggestions(false);
+ }, showTagSuggestions);
useEffect(() => {
fetchCategories();
@@ -84,27 +100,22 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
}
}, [article]);
- // Add padding and scroll when gallery opens
useEffect(() => {
const editorElement = document.querySelector('.article-editor');
if (isGalleryOpen) {
- // Add padding equal to drawer height (40vh + some extra space)
editorElement.style.paddingBottom = 'calc(40vh + 2rem)';
-
- // Scroll down smoothly so editor is visible above drawer
+
setTimeout(() => {
window.scrollTo({
top: document.body.scrollHeight,
behavior: 'smooth'
});
- }, 100); // Small delay to let padding apply first
+ }, 100);
} else {
- // Remove padding when closed
editorElement.style.paddingBottom = '';
}
- // Cleanup on unmount
return () => {
if (editorElement) {
editorElement.style.paddingBottom = '';
@@ -184,16 +195,26 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
};
const handleSaveDraft = async () => {
- await saveArticle('draft');
+ try {
+ await saveArticle('draft');
+ showSuccess('Draft saved successfully!');
+ } catch (err) {
+ showError('Failed to save draft');
+ }
};
const handlePublish = async () => {
if (!title.trim()) {
- alert('Title is required to publish');
+ showError('Title is required to publish');
return;
}
- await saveArticle('published');
+ try {
+ await saveArticle('published');
+ showSuccess('Article published successfully!');
+ } catch (err) {
+ showError('Failed to publish article');
+ }
}
const handleInsertMedia = (mediaItem) => {
@@ -340,7 +361,7 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
-
+