finished category and tag error correction.
This commit is contained in:
parent
893ccd558f
commit
40838bd134
@ -263,3 +263,64 @@
|
|||||||
.badge-remove:hover {
|
.badge-remove:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.create-new-section {
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new-section input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new-buttons button {
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new-buttons .create-btn {
|
||||||
|
background-color: #27ae60;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new-buttons .create-btn:hover {
|
||||||
|
background-color: #229954;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new-buttons .cancel-btn {
|
||||||
|
background-color: #95a5a6;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new-buttons .cancel-btn:hover {
|
||||||
|
background-color: #7f8c8d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new-button-dropdown {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem;
|
||||||
|
background-color: #27ae60;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new-button-dropdown:hover {
|
||||||
|
background-color: #229954;
|
||||||
|
}
|
||||||
@ -65,7 +65,8 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
|
|||||||
const [selectedTags, setSelectedTags] = useState([]);
|
const [selectedTags, setSelectedTags] = useState([]);
|
||||||
const [tagInput, setTagInput] = useState('');
|
const [tagInput, setTagInput] = useState('');
|
||||||
const [showCategoryDropdown, setShowCategoryDropdown] = useState(false);
|
const [showCategoryDropdown, setShowCategoryDropdown] = useState(false);
|
||||||
//const [showTagDropdown, setShowTagDropdown] = useState(false);
|
const [showCreateCategory, setShowCreateCategory] = useState(false);
|
||||||
|
const [newCategoryInput, setNewCategoryInput] = useState('');
|
||||||
const [showTagSuggestions, setShowTagSuggestions] = useState(false);
|
const [showTagSuggestions, setShowTagSuggestions] = useState(false);
|
||||||
const quillRef = useRef(null);
|
const quillRef = useRef(null);
|
||||||
|
|
||||||
@ -95,7 +96,7 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setAvailableCategories(data.map(cat => cat.name));
|
setAvailableCategories(data.map(cat => cat.name));
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.error('Error fetching categories:', err);
|
console.error('Error fetching categories:', err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -112,7 +113,7 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setAvailableTags(data.map(tag => tag.name));
|
setAvailableTags(data.map(tag => tag.name));
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.error('Error fetching tags:', err);
|
console.error('Error fetching tags:', err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -137,7 +138,7 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
|
|||||||
'Authorization': `Bearer ${token}`,
|
'Authorization': `Bearer ${token}`,
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ categories: selectedCategories })
|
body: JSON.stringify({ categories: selectedCategories })
|
||||||
});
|
});
|
||||||
|
|
||||||
await fetch(`http://localhost:9000/api/articles/${article.ka_number}/tags`, {
|
await fetch(`http://localhost:9000/api/articles/${article.ka_number}/tags`, {
|
||||||
@ -149,7 +150,7 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
|
|||||||
body: JSON.stringify({ tags: selectedTags })
|
body: JSON.stringify({ tags: selectedTags })
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
console.error('Error saving categories/tags:', err);
|
console.error('Error saving categories/tags:', err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -187,6 +188,35 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
|
|||||||
setIsGalleryOpen(!isGalleryOpen);
|
setIsGalleryOpen(!isGalleryOpen);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCreateNewCategory = async () => {
|
||||||
|
if (!newCategoryInput.trim()) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('http://localhost:9000/api/categories', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ name: newCategoryInput.trim() })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
setAvailableCategories([...availableCategories, data.name]);
|
||||||
|
setSelectedCategories([...selectedCategories, data.name]);
|
||||||
|
setNewCategoryInput('');
|
||||||
|
setShowCreateCategory(false);
|
||||||
|
} else {
|
||||||
|
const data = await response.json();
|
||||||
|
alert(data.error || 'Failed to create cateogry');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to create new category:', err);
|
||||||
|
alert('Failed to create new category');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const modules = {
|
const modules = {
|
||||||
toolbar: [
|
toolbar: [
|
||||||
[{ 'header': [1, 2, 3, false] }],
|
[{ 'header': [1, 2, 3, false] }],
|
||||||
@ -295,6 +325,51 @@ function ArticleEditor({ article, onSave, onCancel, token }) {
|
|||||||
|
|
||||||
{showCategoryDropdown && (
|
{showCategoryDropdown && (
|
||||||
<div className='category-dropdown'>
|
<div className='category-dropdown'>
|
||||||
|
{showCreateCategory ? (
|
||||||
|
<div className='create-new-section'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
placeholder='New category name...'
|
||||||
|
value={newCategoryInput}
|
||||||
|
onChange={(e) => setNewCategoryInput(e.target.value)}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
handleCreateNewCategory();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
<div className='create-new-buttons'>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
className='create-btn'
|
||||||
|
onClick={handleCreateNewCategory}
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
className='cancel-btn'
|
||||||
|
onClick={() => {
|
||||||
|
setShowCreateCategory(false);
|
||||||
|
setNewCategoryInput('');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
className='create-new-button-dropdown'
|
||||||
|
onClick={() => setShowCreateCategory(true)}
|
||||||
|
>
|
||||||
|
+ Create New Category
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
{availableCategories.length === 0 ? (
|
{availableCategories.length === 0 ? (
|
||||||
<div className='no-options'>No categories available</div>
|
<div className='no-options'>No categories available</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { StrictMode } from 'react'
|
import { StrictMode } from 'react'
|
||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
|
import './styles/variables.css';
|
||||||
|
import './styles/shared.css';
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import App from './App.jsx'
|
import App from './App.jsx'
|
||||||
|
|
||||||
|
|||||||
0
client/kb-frontend/src/styles/shared.css
Normal file
0
client/kb-frontend/src/styles/shared.css
Normal file
0
client/kb-frontend/src/styles/variable.css
Normal file
0
client/kb-frontend/src/styles/variable.css
Normal file
Loading…
x
Reference in New Issue
Block a user