438 lines
11 KiB
TypeScript
438 lines
11 KiB
TypeScript
import { API_CONFIG } from '../config/api';
|
|
|
|
// Types for Blog API
|
|
export interface BlogAuthor {
|
|
id: number;
|
|
name: string;
|
|
email?: string;
|
|
bio?: string;
|
|
avatar?: string;
|
|
}
|
|
|
|
export interface BlogCategory {
|
|
id: number;
|
|
title: string;
|
|
slug: string;
|
|
description?: string;
|
|
display_order: number;
|
|
posts_count?: number;
|
|
}
|
|
|
|
export interface BlogTag {
|
|
id: number;
|
|
name: string;
|
|
slug: string;
|
|
}
|
|
|
|
export interface BlogPost {
|
|
id: number;
|
|
title: string;
|
|
slug: string;
|
|
content?: string;
|
|
excerpt: string;
|
|
thumbnail?: string;
|
|
featured_image?: string;
|
|
author?: BlogAuthor;
|
|
author_name?: string;
|
|
category?: BlogCategory;
|
|
category_title?: string;
|
|
category_slug?: string;
|
|
tags?: BlogTag[];
|
|
meta_description?: string;
|
|
meta_keywords?: string;
|
|
published: boolean;
|
|
featured: boolean;
|
|
views_count: number;
|
|
reading_time: number;
|
|
published_at: string;
|
|
created_at: string;
|
|
updated_at: string;
|
|
related_posts?: BlogPost[];
|
|
}
|
|
|
|
export interface BlogPostListResponse {
|
|
count: number;
|
|
next: string | null;
|
|
previous: string | null;
|
|
results: BlogPost[];
|
|
}
|
|
|
|
export interface BlogComment {
|
|
id: number;
|
|
post: number;
|
|
name: string;
|
|
email: string;
|
|
content: string;
|
|
parent?: number;
|
|
is_approved: boolean;
|
|
created_at: string;
|
|
updated_at: string;
|
|
replies?: BlogComment[];
|
|
}
|
|
|
|
export interface BlogCommentCreateData {
|
|
post: number;
|
|
name: string;
|
|
email: string;
|
|
content: string;
|
|
parent?: number;
|
|
}
|
|
|
|
// Helper function to build query string
|
|
const buildQueryString = (params: Record<string, any>): string => {
|
|
const searchParams = new URLSearchParams();
|
|
Object.entries(params).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== null && value !== '') {
|
|
searchParams.append(key, value.toString());
|
|
}
|
|
});
|
|
return searchParams.toString();
|
|
};
|
|
|
|
// Blog API functions
|
|
export const blogService = {
|
|
// Get all blog posts with optional filtering
|
|
getPosts: async (params?: {
|
|
category?: string;
|
|
tag?: string;
|
|
author?: number;
|
|
search?: string;
|
|
featured?: boolean;
|
|
ordering?: string;
|
|
page?: number;
|
|
page_size?: number;
|
|
}): Promise<BlogPostListResponse> => {
|
|
try {
|
|
const queryString = params ? buildQueryString(params) : '';
|
|
const url = `${API_CONFIG.BASE_URL}/api/blog/posts/${queryString ? `?${queryString}` : ''}`;
|
|
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching blog posts:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get a single blog post by slug
|
|
getPostBySlug: async (slug: string): Promise<BlogPost> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/posts/${slug}/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching blog post:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get featured blog posts
|
|
getFeaturedPosts: async (): Promise<BlogPost[]> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/posts/featured/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching featured posts:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get latest blog posts
|
|
getLatestPosts: async (limit: number = 5): Promise<BlogPost[]> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/posts/latest/?limit=${limit}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching latest posts:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get popular blog posts
|
|
getPopularPosts: async (limit: number = 5): Promise<BlogPost[]> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/posts/popular/?limit=${limit}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching popular posts:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get related posts for a specific post
|
|
getRelatedPosts: async (postSlug: string): Promise<BlogPost[]> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/posts/${postSlug}/related/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching related posts:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get all blog categories
|
|
getCategories: async (): Promise<BlogCategory[]> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/categories/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return Array.isArray(data) ? data : data.results || [];
|
|
} catch (error) {
|
|
console.error('Error fetching blog categories:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get categories with posts
|
|
getCategoriesWithPosts: async (): Promise<BlogCategory[]> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/categories/with_posts/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching categories with posts:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get a single category by slug
|
|
getCategoryBySlug: async (slug: string): Promise<BlogCategory> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/categories/${slug}/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching blog category:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get all blog tags
|
|
getTags: async (): Promise<BlogTag[]> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/tags/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return Array.isArray(data) ? data : data.results || [];
|
|
} catch (error) {
|
|
console.error('Error fetching blog tags:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get posts by tag
|
|
getPostsByTag: async (tagSlug: string): Promise<BlogPostListResponse> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/tags/${tagSlug}/posts/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching posts by tag:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get all blog authors
|
|
getAuthors: async (): Promise<BlogAuthor[]> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/authors/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return Array.isArray(data) ? data : data.results || [];
|
|
} catch (error) {
|
|
console.error('Error fetching blog authors:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get posts by author
|
|
getPostsByAuthor: async (authorId: number): Promise<BlogPostListResponse> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/authors/${authorId}/posts/`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error fetching posts by author:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Get comments for a post
|
|
getComments: async (postId: number): Promise<BlogComment[]> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/comments/?post=${postId}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return Array.isArray(data) ? data : data.results || [];
|
|
} catch (error) {
|
|
console.error('Error fetching comments:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
// Create a new comment
|
|
createComment: async (commentData: BlogCommentCreateData): Promise<{ message: string; data: BlogComment }> => {
|
|
try {
|
|
const response = await fetch(`${API_CONFIG.BASE_URL}/api/blog/comments/`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(commentData),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Error creating comment:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
};
|
|
|