2026-08-14 11:18:27 +05:30

155 lines
6.6 KiB
TypeScript

"use client";
import Link from 'next/link';
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import Cookies from 'universal-cookie';
import Swal from 'sweetalert2';
import { buildApiUrl } from '@/utils/BaseUrl.utils';
import { showMessage } from '@/utils/CommonFunction.utils';
interface BlogItem {
id: number;
title: string;
slug: string;
image: string;
description: string;
author: string;
profile: string;
date: string;
}
const Blog = () => {
const [blogs, setBlogs] = useState<BlogItem[]>([]);
const [loading, setLoading] = useState(true);
const fetchBlogs = async () => {
try {
const res = await axios.get(buildApiUrl('blogs'));
if (res.data && res.data.success) {
setBlogs(res.data.data);
}
} catch (error) {
console.error("Error fetching blogs:", error);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchBlogs();
}, []);
const handleDelete = async (id: number) => {
try {
const result = await Swal.fire({
title: 'Are you sure?',
text: "You won't be able to revert this!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete it!'
});
if (result.isConfirmed) {
const cookies = new Cookies();
const token = cookies.get('token');
if (!token) {
showMessage('Access denied. Please sign in first.', 'error');
return;
}
await axios.delete(buildApiUrl(`blogs/${id}`), {
headers: {
Authorization: `Bearer ${token}`,
},
});
setBlogs(prev => prev.filter(b => b.id !== id));
showMessage("Blog Deleted Successfully", "success");
}
} catch (error: any) {
console.error("Error deleting blog:", error);
showMessage(error?.response?.data?.message || "Error deleting blog", "error");
}
};
const stripHtml = (htmlStr: string) => {
if (!htmlStr) return '';
return htmlStr.replace(/<[^>]*>/g, '');
};
if (loading) {
return (
<div className="flex items-center justify-center min-h-[400px]">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
</div>
);
}
return (
<div className="mt-10">
<h3 className="mb-6 text-xl font-bold md:text-3xl">Blogs</h3>
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 xl:grid-cols-4">
{/* ✅ First box: Create New Blog */}
<Link href="/create-blog" className="flex items-center justify-center space-y-5 rounded-md border border-dashed border-blue-500 bg-blue-50 p-5 text-center shadow hover:bg-blue-100 transition dark:border-blue-800 dark:bg-blue-900 dark:hover:bg-blue-800 min-h-[300px]">
<div>
<div className="mb-3 text-5xl text-blue-600 dark:text-white">+</div>
<h5 className="text-lg font-semibold text-blue-800 dark:text-white">Create New Blog</h5>
</div>
</Link>
{blogs.map((blog) => {
const cleanText = stripHtml(blog.description);
const excerpt = cleanText.length > 120 ? cleanText.substring(0, 120) + '...' : cleanText;
return (
<div
key={blog.id}
className="flex flex-col justify-between space-y-4 rounded-md border border-white-light bg-white p-5 shadow-[0px_0px_2px_0px_rgba(145,158,171,0.20),0px_12px_24px_-4px_rgba(145,158,171,0.12)] dark:border-[#1B2E4B] dark:bg-black"
>
<div>
<div className="max-h-56 overflow-hidden rounded-md mb-4 bg-gray-100 flex items-center justify-center aspect-video">
<img src={blog.image || '/assets/images/blog/image-1.jpg'} alt={blog.title} className="w-full h-full object-cover" />
</div>
<h5 className="text-lg font-semibold dark:text-white line-clamp-2" title={blog.title}>{blog.title}</h5>
<p className="text-sm text-gray-600 dark:text-gray-400 mt-2 line-clamp-3">{excerpt || 'No description provided.'}</p>
<p className="text-xs text-gray-400 mt-3">By {blog.author} on {blog.date}</p>
</div>
{/* ✅ Actions (View, Edit and Delete) */}
<div className="flex justify-between items-center pt-3 border-t border-gray-100 dark:border-gray-800 space-x-2">
<a
href={`http://localhost:3000/blog-single?slug=${blog.slug}`}
target="_blank"
rel="noopener noreferrer"
className="inline-block rounded-lg bg-blue-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-blue-700 transition"
>
View Blog
</a>
<div className="flex space-x-2">
<Link
href={`/edit-blog/${blog.id}`}
className="inline-block rounded-lg bg-green-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-green-700 transition"
>
Edit
</Link>
<button
onClick={() => handleDelete(blog.id)}
className="rounded-lg bg-red-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-red-700 transition"
>
Delete
</button>
</div>
</div>
</div>
);
})}
</div>
</div>
);
};
export default Blog;