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):
|
class MediaSerializer(serializers.Serializer):
|
||||||
media = serializers.ListField(
|
media = serializers.ListField(
|
||||||
child=serializers.FileField(max_length=100000, allow_empty_file=False, use_url=False)
|
child=serializers.FileField(max_length=100000, allow_empty_file=False, use_url=False)
|
||||||
|
|||||||
@ -24,6 +24,7 @@ from .serializers import (
|
|||||||
ThemeDataSerializer,
|
ThemeDataSerializer,
|
||||||
CategorySerializer,
|
CategorySerializer,
|
||||||
BlogSerializer,
|
BlogSerializer,
|
||||||
|
UnifiedCategoryBlogSerializer,
|
||||||
MediaSerializer
|
MediaSerializer
|
||||||
)
|
)
|
||||||
################################################################
|
################################################################
|
||||||
@ -76,6 +77,16 @@ class CategoryDeleteAPIView(generics.DestroyAPIView):
|
|||||||
queryset = Category.objects.all()
|
queryset = Category.objects.all()
|
||||||
serializer_class = CategorySerializer
|
serializer_class = CategorySerializer
|
||||||
lookup_field = 'category_id'
|
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##################################################
|
#Blog related views##################################################
|
||||||
@ -94,15 +105,14 @@ class BlogRetrieveAPIView(generics.RetrieveAPIView):
|
|||||||
serializer_class = BlogSerializer
|
serializer_class = BlogSerializer
|
||||||
lookup_field = 'blog_id'
|
lookup_field = 'blog_id'
|
||||||
|
|
||||||
class BlogsByCategoryAPIView(APIView):
|
class CategoryDetailView(APIView):
|
||||||
def get(self, request, category_id):
|
def get(self, request, category_id):
|
||||||
try:
|
try:
|
||||||
category = Category.objects.get(category_id=category_id)
|
category = Category.objects.get(category_id=category_id)
|
||||||
except Category.DoesNotExist:
|
except Category.DoesNotExist:
|
||||||
return Response({'message': 'Category not found'}, status=404)
|
return Response({'message': 'Category not found'}, status=404)
|
||||||
|
|
||||||
blogs = category.blogs.all()
|
serializer = UnifiedCategoryBlogSerializer(category)
|
||||||
serializer = BlogSerializer(blogs, many=True)
|
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
class BlogDeleteAPIView(generics.DestroyAPIView):
|
class BlogDeleteAPIView(generics.DestroyAPIView):
|
||||||
|
|||||||
@ -31,7 +31,7 @@ from apimanager.views import (
|
|||||||
BlogUpdateAPIView,
|
BlogUpdateAPIView,
|
||||||
BlogRetrieveAPIView,
|
BlogRetrieveAPIView,
|
||||||
BlogDeleteAPIView,
|
BlogDeleteAPIView,
|
||||||
BlogsByCategoryAPIView
|
BlogsByCategoryAPIView,
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { useEffect, useState } from 'react';
|
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 MediaService from '../../services/media-service';
|
||||||
import CardListViewer from './shared/card-list-viewer';
|
import CardListViewer from './shared/card-list-viewer';
|
||||||
import CategoryBar from './shared/category-bar';
|
import CategoryBar from './shared/category-bar';
|
||||||
@ -26,61 +26,59 @@ function BlogList(props) {
|
|||||||
const ThemeConfig = props.ThemeConfig;
|
const ThemeConfig = props.ThemeConfig;
|
||||||
|
|
||||||
const [categoryData, setCategoryData] = useState('loading');
|
const [categoryData, setCategoryData] = useState('loading');
|
||||||
const [featuredBlogData, setFeaturedBlogData] = useState('loading');
|
|
||||||
const [currentPage, setCurrentPage] = useState('loading');
|
const [currentPage, setCurrentPage] = useState('loading');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
DataService.getData(`category/${categoryID}/category-data`).then(response =>{
|
EditableDataService.getData(`/data/category/${categoryID}/`).then(response => {
|
||||||
setCategoryData(response.data);
|
let responseData = response.data
|
||||||
console.log(response.data)
|
let blogMetadata = []
|
||||||
if (response.data.featuredBlog){
|
console.log(responseData)
|
||||||
DataService.getData(`blog/${response.data.featuredBlog}/blog-data`).then(response =>
|
let localCategoryData = {
|
||||||
setFeaturedBlogData(response.data)
|
"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]);
|
}, [categoryID]);
|
||||||
|
|
||||||
if (GlobalTheme && ThemeConfig) {
|
if (GlobalTheme && ThemeConfig) {
|
||||||
return (
|
return (
|
||||||
<Container fluid className={` mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
|
<Container fluid className={`mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
|
||||||
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/>
|
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} />
|
||||||
<Row className="justify-content-center align-items-center">
|
<Row className="justify-content-center align-items-center">
|
||||||
<Col className="d-flex flex-column align-items-center">
|
<Col className="d-flex flex-column align-items-center">
|
||||||
<div className="w-100">
|
<div className="w-100">
|
||||||
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{width: "100%", border: "none"}}>
|
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{ width: "100%", border: "none" }}>
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1">
|
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1">
|
||||||
{`Blogs in ${categoryData.name}`}
|
{`Blogs in ${categoryData.name}`}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<div className="" style={{ width: '70%', margin: 'auto', display: 'flex', flexWrap: 'wrap', gap: '1rem' }}>
|
<div className="" style={{ width: '70%', margin: 'auto', display: 'flex', flexWrap: 'wrap', gap: '1rem' }}>
|
||||||
<h3 className={`${ThemeConfig[GlobalTheme].textColor}`}>
|
<h3 className={`${ThemeConfig[GlobalTheme].textColor}`}>
|
||||||
{`Featured`}
|
{categoryData === 'loading' ? <Spinner /> :
|
||||||
</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 /> :
|
|
||||||
categoryData.blogMetadata.map((item, index) => (
|
categoryData.blogMetadata.map((item, index) => (
|
||||||
<CardListViewer
|
<CardListViewer
|
||||||
key={item.id}
|
key={item.blog_id} // Ensuring keys are unique and correct
|
||||||
totalItems={categoryData.blogMetadata.length}
|
totalItems={categoryData.blogMetadata.length}
|
||||||
cardType={"smallCard"}
|
cardType={"smallCard"}
|
||||||
resourceType={"blog"}
|
resourceType={"blog"}
|
||||||
@ -91,11 +89,12 @@ function BlogList(props) {
|
|||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</h3>
|
||||||
</Col>
|
</div>
|
||||||
</Row>
|
</Col>
|
||||||
</Container>
|
</Row>
|
||||||
);
|
</Container>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useState, useRef } from 'react';
|
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 MediaService from '../../services/media-service'
|
||||||
import CategoryBar from './shared/category-bar';
|
import CategoryBar from './shared/category-bar';
|
||||||
import EditorComponent from './shared/tiptap';
|
import EditorComponent from './shared/tiptap';
|
||||||
@ -25,21 +25,37 @@ function Blog(props) {
|
|||||||
const [blogContent, setBlogContent] = useState();
|
const [blogContent, setBlogContent] = useState();
|
||||||
|
|
||||||
const setInfo = (event) => {
|
const setInfo = (event) => {
|
||||||
let localEditedBlogData = {...blogData};
|
EditableDataService.updateData(`/data/blog/update/${blogID}/`,{
|
||||||
localEditedBlogData["name"] = nameField.current.value;
|
"name": nameField.current.value,
|
||||||
localEditedBlogData["description"] = descriptionField.current.value;
|
"description": descriptionField.current.value,
|
||||||
localEditedBlogData["tagLine"] = tagLineField.current.value;
|
"tagline": tagLineField.current.value,
|
||||||
localEditedBlogData["contentBody"] = blogContent
|
"content_body": blogContent
|
||||||
setBlogData(localEditedBlogData);
|
}).then(response => {
|
||||||
props.notificationToggler('Data saved!');
|
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(() => {
|
useEffect(() => {
|
||||||
DataService.getData(`blog/${blogID}/blog-data`).then(response =>{
|
getInfo()
|
||||||
setBlogData(response.data)
|
|
||||||
setBlogContent(response.data.contentBody)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (GlobalTheme && ThemeConfig && blogData) {
|
if (GlobalTheme && ThemeConfig && blogData) {
|
||||||
@ -89,7 +105,7 @@ function Blog(props) {
|
|||||||
<Col xs="3" className="d-none d-md-block"></Col>
|
<Col xs="3" className="d-none d-md-block"></Col>
|
||||||
|
|
||||||
<Col className={`blogContent ${ThemeConfig[GlobalTheme].textColor}`} style={{marginBottom: '25px'}}>
|
<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'>
|
<ButtonGroup className='mt-4'>
|
||||||
<Button onClick={(event) => setInfo(event)} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button>
|
<Button onClick={(event) => setInfo(event)} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button>
|
||||||
<Button color={ThemeConfig[GlobalTheme].buttonColor} outline>Publish Data</Button>
|
<Button color={ThemeConfig[GlobalTheme].buttonColor} outline>Publish Data</Button>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react';
|
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 { Link } from 'react-router-dom';
|
||||||
import { Container, Row, Col, Button, Spinner, ListGroup, ListGroupItem, ButtonGroup } from 'reactstrap';
|
import { Container, Row, Col, Button, Spinner, ListGroup, ListGroupItem, ButtonGroup } from 'reactstrap';
|
||||||
|
|
||||||
@ -7,10 +7,26 @@ function CategoryBar(props) {
|
|||||||
|
|
||||||
const [categoryMetadata, setCategoryMetadata] = useState([]);
|
const [categoryMetadata, setCategoryMetadata] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
const setCategoryData = () => {
|
||||||
DataService.getData('category/category-metadata').then(response =>
|
EditableDataService.getData('/data/category/').then(response => {
|
||||||
setCategoryMetadata(response.data)
|
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 = {
|
const rowStyle = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user