Added support to update blogs
This commit is contained in:
parent
c091baf334
commit
2d8cc1e7de
@ -58,6 +58,40 @@ class BlogSerializer(serializers.ModelSerializer):
|
||||
]
|
||||
|
||||
|
||||
class UnifiedCategoryBlogSerializer(serializers.ModelSerializer):
|
||||
blog_metadata = serializers.SerializerMethodField() # Custom field for related blogs
|
||||
|
||||
class Meta:
|
||||
model = Category
|
||||
fields = [
|
||||
'category_id',
|
||||
'name',
|
||||
'cover_image',
|
||||
'tagline',
|
||||
'description',
|
||||
'featured_id',
|
||||
'blog_metadata'
|
||||
]
|
||||
|
||||
def get_blog_metadata(self, obj):
|
||||
# Serializes all blogs related to the category, assuming `blogs` as the related_name
|
||||
blogs = obj.blogs.all()
|
||||
return [{
|
||||
'blog_id': blog.blog_id, # Using UUID
|
||||
'name': blog.name,
|
||||
'description': blog.description,
|
||||
'cover_image': blog.cover_image,
|
||||
'tagline': blog.tagline,
|
||||
'parent_category': blog.parent_category.category_id
|
||||
# Assuming parent_category is a reference to a Category object
|
||||
} for blog in blogs]
|
||||
|
||||
def to_representation(self, instance):
|
||||
representation = super().to_representation(instance)
|
||||
# Set a featured blog based on some logic, e.g., the first blog
|
||||
representation['featured_id'] = instance.blogs.first().blog_id if instance.blogs.exists() else None
|
||||
return representation
|
||||
|
||||
class MediaSerializer(serializers.Serializer):
|
||||
media = serializers.ListField(
|
||||
child=serializers.FileField(max_length=100000, allow_empty_file=False, use_url=False)
|
||||
|
||||
@ -24,6 +24,7 @@ from .serializers import (
|
||||
ThemeDataSerializer,
|
||||
CategorySerializer,
|
||||
BlogSerializer,
|
||||
UnifiedCategoryBlogSerializer,
|
||||
MediaSerializer
|
||||
)
|
||||
################################################################
|
||||
@ -76,6 +77,16 @@ class CategoryDeleteAPIView(generics.DestroyAPIView):
|
||||
queryset = Category.objects.all()
|
||||
serializer_class = CategorySerializer
|
||||
lookup_field = 'category_id'
|
||||
|
||||
class BlogsByCategoryAPIView(APIView):
|
||||
def get(self, request, category_id):
|
||||
try:
|
||||
category = Category.objects.get(category_id=category_id)
|
||||
except Category.DoesNotExist:
|
||||
return Response({'message': 'Category not found'}, status=404)
|
||||
|
||||
serializer = UnifiedCategoryBlogSerializer(category)
|
||||
return Response(serializer.data)
|
||||
################################################################
|
||||
|
||||
#Blog related views##################################################
|
||||
@ -94,15 +105,14 @@ class BlogRetrieveAPIView(generics.RetrieveAPIView):
|
||||
serializer_class = BlogSerializer
|
||||
lookup_field = 'blog_id'
|
||||
|
||||
class BlogsByCategoryAPIView(APIView):
|
||||
class CategoryDetailView(APIView):
|
||||
def get(self, request, category_id):
|
||||
try:
|
||||
category = Category.objects.get(category_id=category_id)
|
||||
except Category.DoesNotExist:
|
||||
return Response({'message': 'Category not found'}, status=404)
|
||||
|
||||
blogs = category.blogs.all()
|
||||
serializer = BlogSerializer(blogs, many=True)
|
||||
serializer = UnifiedCategoryBlogSerializer(category)
|
||||
return Response(serializer.data)
|
||||
|
||||
class BlogDeleteAPIView(generics.DestroyAPIView):
|
||||
|
||||
@ -31,7 +31,7 @@ from apimanager.views import (
|
||||
BlogUpdateAPIView,
|
||||
BlogRetrieveAPIView,
|
||||
BlogDeleteAPIView,
|
||||
BlogsByCategoryAPIView
|
||||
BlogsByCategoryAPIView,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { useEffect, useState } from 'react';
|
||||
import DataService from '../../services/data-service';
|
||||
import EditableDataService from '../../services/editable-data-service';
|
||||
import MediaService from '../../services/media-service';
|
||||
import CardListViewer from './shared/card-list-viewer';
|
||||
import CategoryBar from './shared/category-bar';
|
||||
@ -26,61 +26,59 @@ function BlogList(props) {
|
||||
const ThemeConfig = props.ThemeConfig;
|
||||
|
||||
const [categoryData, setCategoryData] = useState('loading');
|
||||
const [featuredBlogData, setFeaturedBlogData] = useState('loading');
|
||||
const [currentPage, setCurrentPage] = useState('loading');
|
||||
|
||||
useEffect(() => {
|
||||
DataService.getData(`category/${categoryID}/category-data`).then(response =>{
|
||||
setCategoryData(response.data);
|
||||
console.log(response.data)
|
||||
if (response.data.featuredBlog){
|
||||
DataService.getData(`blog/${response.data.featuredBlog}/blog-data`).then(response =>
|
||||
setFeaturedBlogData(response.data)
|
||||
);
|
||||
EditableDataService.getData(`/data/category/${categoryID}/`).then(response => {
|
||||
let responseData = response.data
|
||||
let blogMetadata = []
|
||||
console.log(responseData)
|
||||
let localCategoryData = {
|
||||
"id": responseData["category_id"],
|
||||
"name": responseData["name"],
|
||||
"coverImage": responseData["cover_image"],
|
||||
"tagLine": responseData["tagline"],
|
||||
"description": responseData["description"],
|
||||
"featuredBlog": responseData["featured_id"],
|
||||
"blogMetadata": responseData["blog_metadata"]
|
||||
}
|
||||
for (let eachBlog of responseData["blog_metadata"]){
|
||||
blogMetadata.push({
|
||||
"id": eachBlog["blog_id"],
|
||||
"name": eachBlog["name"],
|
||||
"description": eachBlog["description"],
|
||||
"tagLine": eachBlog["tagline"],
|
||||
"coverImage": eachBlog["cover_image"],
|
||||
"parentCategory": eachBlog["parent_category"]
|
||||
})
|
||||
}
|
||||
localCategoryData.blogMetadata = blogMetadata
|
||||
setCategoryData(localCategoryData)
|
||||
}
|
||||
else
|
||||
setFeaturedBlogData("nodata")
|
||||
}
|
||||
);
|
||||
}, [categoryID]);
|
||||
|
||||
if (GlobalTheme && ThemeConfig) {
|
||||
return (
|
||||
<Container fluid className={` mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
|
||||
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/>
|
||||
<Row className="justify-content-center align-items-center">
|
||||
<Col className="d-flex flex-column align-items-center">
|
||||
<div className="w-100">
|
||||
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{width: "100%", border: "none"}}>
|
||||
<CardBody>
|
||||
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1">
|
||||
{`Blogs in ${categoryData.name}`}
|
||||
</CardTitle>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="" style={{ width: '70%', margin: 'auto', display: 'flex', flexWrap: 'wrap', gap: '1rem' }}>
|
||||
<h3 className={`${ThemeConfig[GlobalTheme].textColor}`}>
|
||||
{`Featured`}
|
||||
</h3>
|
||||
{
|
||||
featuredBlogData === 'loading' ? <Spinner /> :
|
||||
<CardListViewer
|
||||
key={featuredBlogData.id}
|
||||
totalItems={featuredBlogData === 'nodata' ? 0 : 1}
|
||||
cardType={"longCard"}
|
||||
resourceType={"blog"}
|
||||
textColor={ThemeConfig[GlobalTheme].textColor}
|
||||
bgColor={ThemeConfig[GlobalTheme].background}
|
||||
borderColor={ThemeConfig[GlobalTheme].borderColor}
|
||||
itemObject={featuredBlogData}
|
||||
/>
|
||||
}
|
||||
{
|
||||
categoryData === 'loading' ? <Spinner /> :
|
||||
return (
|
||||
<Container fluid className={`mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
|
||||
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} />
|
||||
<Row className="justify-content-center align-items-center">
|
||||
<Col className="d-flex flex-column align-items-center">
|
||||
<div className="w-100">
|
||||
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{ width: "100%", border: "none" }}>
|
||||
<CardBody>
|
||||
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1">
|
||||
{`Blogs in ${categoryData.name}`}
|
||||
</CardTitle>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="" style={{ width: '70%', margin: 'auto', display: 'flex', flexWrap: 'wrap', gap: '1rem' }}>
|
||||
<h3 className={`${ThemeConfig[GlobalTheme].textColor}`}>
|
||||
{categoryData === 'loading' ? <Spinner /> :
|
||||
categoryData.blogMetadata.map((item, index) => (
|
||||
<CardListViewer
|
||||
key={item.id}
|
||||
key={item.blog_id} // Ensuring keys are unique and correct
|
||||
totalItems={categoryData.blogMetadata.length}
|
||||
cardType={"smallCard"}
|
||||
resourceType={"blog"}
|
||||
@ -91,11 +89,12 @@ function BlogList(props) {
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
);
|
||||
</h3>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
|
||||
import DataService from '../../services/data-service';
|
||||
import EditableDataService from '../../services/editable-data-service';
|
||||
import MediaService from '../../services/media-service'
|
||||
import CategoryBar from './shared/category-bar';
|
||||
import EditorComponent from './shared/tiptap';
|
||||
@ -25,21 +25,37 @@ function Blog(props) {
|
||||
const [blogContent, setBlogContent] = useState();
|
||||
|
||||
const setInfo = (event) => {
|
||||
let localEditedBlogData = {...blogData};
|
||||
localEditedBlogData["name"] = nameField.current.value;
|
||||
localEditedBlogData["description"] = descriptionField.current.value;
|
||||
localEditedBlogData["tagLine"] = tagLineField.current.value;
|
||||
localEditedBlogData["contentBody"] = blogContent
|
||||
setBlogData(localEditedBlogData);
|
||||
props.notificationToggler('Data saved!');
|
||||
EditableDataService.updateData(`/data/blog/update/${blogID}/`,{
|
||||
"name": nameField.current.value,
|
||||
"description": descriptionField.current.value,
|
||||
"tagline": tagLineField.current.value,
|
||||
"content_body": blogContent
|
||||
}).then(response => {
|
||||
props.notificationToggler('Blog data saved!');
|
||||
getInfo()
|
||||
}).catch(error => {
|
||||
props.notificationToggler('Failed to update blog!', 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
const getInfo = () => {
|
||||
EditableDataService.getData(`/data/blog/${blogID}/`).then(response => {
|
||||
let responseData = response.data
|
||||
setBlogData({
|
||||
"id": responseData["blog_id"],
|
||||
"name": responseData["name"],
|
||||
"description": responseData["description"],
|
||||
"tagLine": responseData["tagline"],
|
||||
"coverImage": responseData["cover_image"],
|
||||
"parentCategory": responseData["parent_category"]
|
||||
})
|
||||
setBlogContent(responseData["content_body"])
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
DataService.getData(`blog/${blogID}/blog-data`).then(response =>{
|
||||
setBlogData(response.data)
|
||||
setBlogContent(response.data.contentBody)
|
||||
}
|
||||
);
|
||||
getInfo()
|
||||
}, []);
|
||||
|
||||
if (GlobalTheme && ThemeConfig && blogData) {
|
||||
@ -89,7 +105,7 @@ function Blog(props) {
|
||||
<Col xs="3" className="d-none d-md-block"></Col>
|
||||
|
||||
<Col className={`blogContent ${ThemeConfig[GlobalTheme].textColor}`} style={{marginBottom: '25px'}}>
|
||||
<EditorComponent setContent={setBlogContent} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} content={blogData.contentBody}/>
|
||||
<EditorComponent setContent={setBlogContent} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} content={blogContent}/>
|
||||
<ButtonGroup className='mt-4'>
|
||||
<Button onClick={(event) => setInfo(event)} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button>
|
||||
<Button color={ThemeConfig[GlobalTheme].buttonColor} outline>Publish Data</Button>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import DataService from '../../../services/data-service';
|
||||
import EditableDataService from '../../../services/editable-data-service';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Container, Row, Col, Button, Spinner, ListGroup, ListGroupItem, ButtonGroup } from 'reactstrap';
|
||||
|
||||
@ -7,10 +7,26 @@ function CategoryBar(props) {
|
||||
|
||||
const [categoryMetadata, setCategoryMetadata] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
DataService.getData('category/category-metadata').then(response =>
|
||||
setCategoryMetadata(response.data)
|
||||
const setCategoryData = () => {
|
||||
EditableDataService.getData('/data/category/').then(response => {
|
||||
let responseData = response.data
|
||||
let localCategoryMetadata = []
|
||||
for (let eachResponse of responseData){
|
||||
localCategoryMetadata.push({
|
||||
"id": eachResponse["category_id"],
|
||||
"name": eachResponse["name"],
|
||||
"featuredBlog": eachResponse["featured_id"],
|
||||
"description": eachResponse["description"],
|
||||
"tagLine": eachResponse["tagline"],
|
||||
"coverImage": eachResponse["cover_image"]
|
||||
})
|
||||
}
|
||||
setCategoryMetadata(localCategoryMetadata)
|
||||
}
|
||||
);
|
||||
}
|
||||
useEffect(() => {
|
||||
setCategoryData();
|
||||
}, []);
|
||||
|
||||
const rowStyle = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user