diff --git a/admin/src/pages/ContactMessages.tsx b/admin/src/pages/ContactMessages.tsx index 66fbf30..9c74662 100644 --- a/admin/src/pages/ContactMessages.tsx +++ b/admin/src/pages/ContactMessages.tsx @@ -8,6 +8,7 @@ import 'react-responsive-modal/styles.css'; import '../styles/Model.css' import { ColorRing } from 'react-loader-spinner'; import { MdMessage } from "react-icons/md"; +import { TbReportAnalytics } from "react-icons/tb"; const ContactMessages = () => { const [contactMessages, setContactMessages] = useState([]); @@ -37,6 +38,27 @@ const ContactMessages = () => { fetchMessages(); }, [token]); + const downloadContactMessagesReport = async () => { + try { + const response = await axios.get('/api/v1/admin/downloadcontactmessagereport', { + headers: { + Authorization: `Bearer ${token}`, + }, + responseType: 'blob', + }); + + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', 'StyleShare_Contact_Messages_Report.pdf'); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } catch (error) { + console.error('Error downloading the Contact Messages report:', error); + } + }; + const handleOpenModal = (message: IContactMessage) => { setSelectedMessage(message); setOpen(true); @@ -68,6 +90,7 @@ const ContactMessages = () => { /> : + <>
@@ -112,6 +135,12 @@ const ContactMessages = () => {
+
+ +
+ } diff --git a/admin/src/pages/Posts.tsx b/admin/src/pages/Posts.tsx index 5ed5118..f2cdc2d 100644 --- a/admin/src/pages/Posts.tsx +++ b/admin/src/pages/Posts.tsx @@ -7,6 +7,7 @@ import toast from "react-hot-toast"; import { Link } from "react-router-dom"; import { ColorRing } from 'react-loader-spinner'; import { BsFillPostcardFill } from "react-icons/bs"; +import { TbReportAnalytics } from "react-icons/tb"; const Posts = () => { const [posts, setPosts] = useState([]); @@ -48,6 +49,27 @@ const Posts = () => { } }; + const downloadPostsReport = async () => { + try { + const response = await axios.get('/api/v1/admin/downloadpostsreport', { + headers: { + Authorization: `Bearer ${token}`, + }, + responseType: 'blob', + }); + + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', 'StyleShare_Posts_Report.pdf'); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } catch (error) { + console.error('Error downloading the Posts report:', error); + } + }; + return (
@@ -69,6 +91,7 @@ const Posts = () => { />
: + <>
@@ -107,6 +130,12 @@ const Posts = () => {
+
+ +
+ }
diff --git a/admin/src/pages/Users.tsx b/admin/src/pages/Users.tsx index 2f05513..8624fbd 100644 --- a/admin/src/pages/Users.tsx +++ b/admin/src/pages/Users.tsx @@ -6,6 +6,7 @@ import toast from "react-hot-toast"; import { IUser } from "../types"; import { ColorRing } from 'react-loader-spinner'; import { FaUsers } from "react-icons/fa"; +import { TbReportAnalytics } from "react-icons/tb"; const Users = () => { const [allUsers, setAllUsers] = useState([]); @@ -72,6 +73,27 @@ const Users = () => { } }; + const downloadUsersReport = async () => { + try { + const response = await axios.get('/api/v1/admin/downloadusersreport', { + headers: { + Authorization: `Bearer ${token}`, + }, + responseType: 'blob', + }); + + const url = window.URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', 'StyleShare_Users_Report.pdf'); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } catch (error) { + console.error('Error downloading the Users report:', error); + } + }; + return (
@@ -93,6 +115,7 @@ const Users = () => { />
: + <>
@@ -136,6 +159,12 @@ const Users = () => {
+
+ +
+ }
diff --git a/backend/src/routes/admin/controller.ts b/backend/src/routes/admin/controller.ts index ce0c02f..f0eb039 100644 --- a/backend/src/routes/admin/controller.ts +++ b/backend/src/routes/admin/controller.ts @@ -688,4 +688,188 @@ export const toggleFeedbackVisibility = async (req: Request, res: Response) => { console.error('Error toggling feedback visibility:', error); res.status(500).json({ error: 'An unexpected error occurred!' }); } +}; + +export const downloadUsersReportController = async (req: Request, res: Response) => { + try { + const currentDate = new Date().toLocaleDateString(); + + const users = await prisma.user.findMany({ + select: { + username: true, + email: true, + createdAt: true, + blocked: true, + }, + }); + + const totalUsers = users.length; + + const doc = new PDFDocument(); + let filename = `StyleShare_Users_Report.pdf`; + filename = encodeURIComponent(filename); + + res.setHeader('Content-disposition', `attachment; filename="${filename}"`); + res.setHeader('Content-type', 'application/pdf'); + + doc.pipe(res); + + doc.fontSize(25).text('StyleShare Users Report', { + align: 'center' + }); + + doc.moveDown(); + doc.fontSize(20).text('Overview', { + align: 'center' + }); + doc.moveDown(); + doc.fontSize(15).text(`Date: ${currentDate}`); + doc.moveDown(); + + doc.fontSize(12).text(`Total Users: ${totalUsers}`); + doc.moveDown(); + + doc.fontSize(15).text('User Details:'); + doc.moveDown(); + + users.forEach(user => { + doc.text(`Username: ${user.username}`); + doc.text(`Email: ${user.email}`); + doc.text(`Created At: ${user.createdAt.toLocaleDateString()}`); + doc.text(`Blocked: ${user.blocked ? 'Yes' : 'No'}`); + doc.moveDown(); + }); + + doc.end(); + } catch (error) { + console.error(error); + res.status(500).json({ + error: "An unexpected exception occurred!", + }); + } +}; + +export const downloadPostsReportController = async (req: Request, res: Response) => { + try { + const currentDate = new Date().toLocaleDateString(); + + const posts = await prisma.post.findMany({ + select: { + title: true, + description: true, + createdAt: true, + author: { + select: { + username: true, + email: true, + }, + }, + }, + }); + + const totalPosts = posts.length; + + const doc = new PDFDocument(); + let filename = `StyleShare_Posts_Report.pdf`; + filename = encodeURIComponent(filename); + + res.setHeader('Content-disposition', `attachment; filename="${filename}"`); + res.setHeader('Content-type', 'application/pdf'); + + doc.pipe(res); + + doc.fontSize(25).text('StyleShare Posts Report', { + align: 'center' + }); + + doc.moveDown(); + doc.fontSize(20).text('Overview', { + align: 'center' + }); + doc.moveDown(); + doc.fontSize(15).text(`Date: ${currentDate}`); + doc.moveDown(); + + doc.fontSize(12).text(`Total Posts: ${totalPosts}`); + doc.moveDown(); + + doc.fontSize(15).text('Post Details:'); + doc.moveDown(); + + posts.forEach(post => { + doc.text(`Title: ${post.title}`); + doc.text(`Description: ${post.description}`); + doc.text(`Created At: ${post.createdAt.toLocaleDateString()}`); + doc.text(`Author: ${post.author.username} (${post.author.email})`); + doc.moveDown(); + }); + + doc.end(); + } catch (error) { + console.error(error); + res.status(500).json({ + error: "An unexpected exception occurred!", + }); + } +}; + +export const downloadContactMessagesReportController = async (req: Request, res: Response) => { + try { + const currentDate = new Date().toLocaleDateString(); + + const contactMessages = await prisma.contactMessage.findMany({ + select: { + name: true, + email: true, + subject: true, + message: true, + createdAt: true, + }, + }); + + const totalContactMessages = contactMessages.length; + + const doc = new PDFDocument(); + let filename = `StyleShare_Contact_Messages_Report.pdf`; + filename = encodeURIComponent(filename); + + res.setHeader('Content-disposition', `attachment; filename="${filename}"`); + res.setHeader('Content-type', 'application/pdf'); + + doc.pipe(res); + + doc.fontSize(25).text('StyleShare Contact Messages Report', { + align: 'center' + }); + + doc.moveDown(); + doc.fontSize(20).text('Overview', { + align: 'center' + }); + doc.moveDown(); + doc.fontSize(15).text(`Date: ${currentDate}`); + doc.moveDown(); + + doc.fontSize(12).text(`Total Contact Messages: ${totalContactMessages}`); + doc.moveDown(); + + doc.fontSize(15).text('Contact Message Details:'); + doc.moveDown(); + + contactMessages.forEach(message => { + doc.text(`Name: ${message.name}`); + doc.text(`Email: ${message.email}`); + doc.text(`Subject: ${message.subject}`); + doc.text(`Message: ${message.message}`); + doc.text(`Created At: ${message.createdAt.toLocaleDateString()}`); + doc.moveDown(); + }); + + doc.end(); + } catch (error) { + console.error(error); + res.status(500).json({ + error: "An unexpected exception occurred!", + }); + } }; \ No newline at end of file diff --git a/backend/src/routes/admin/route.ts b/backend/src/routes/admin/route.ts index 29fad70..d750cdc 100644 --- a/backend/src/routes/admin/route.ts +++ b/backend/src/routes/admin/route.ts @@ -1,5 +1,5 @@ import {Router} from 'express'; -import { getPostReactionsController,getFavoritesController,adminLoginController, adminProfileController, allUserForAdmin, blockUserController, unblockUserController, getAdminPostsController, getAdminTrendingPostsController, getAdminStatsController, getGraphsStatsController, updatePostController, deletePostController, getPostByIdController, getAllContactMessages, deleteCommentController, downloadReportController, getFeedbacks, toggleFeedbackVisibility } from './controller'; +import { getPostReactionsController,getFavoritesController,adminLoginController, adminProfileController, allUserForAdmin, blockUserController, unblockUserController, getAdminPostsController, getAdminTrendingPostsController, getAdminStatsController, getGraphsStatsController, updatePostController, deletePostController, getPostByIdController, getAllContactMessages, deleteCommentController, downloadReportController, getFeedbacks, toggleFeedbackVisibility, downloadUsersReportController, downloadContactMessagesReportController, downloadPostsReportController } from './controller'; import { isAdmin } from '../../middleware/adminAuth'; const adminRouter = Router(); @@ -38,6 +38,12 @@ adminRouter.get('/favorites', isAdmin, getFavoritesController); adminRouter.get('/downloadReport',isAdmin, downloadReportController); +adminRouter.get('/downloadusersreport',isAdmin, downloadUsersReportController); + +adminRouter.get('/downloadpostsreport',isAdmin, downloadPostsReportController); + +adminRouter.get('/downloadcontactmessagereport',isAdmin, downloadContactMessagesReportController); + adminRouter.get('/getfeedback',isAdmin, getFeedbacks); adminRouter.patch('/toggleFeedbackVisibility/:id', isAdmin, toggleFeedbackVisibility);