From d647bf15015395cd97c6bc4b7b3cf72cdbd1d573 Mon Sep 17 00:00:00 2001 From: dinidusachintha Date: Mon, 14 Oct 2024 13:06:00 +0530 Subject: [PATCH] update (#118) * add speechgenarator * css updated * add validations --- backend/package.json | 1 + backend/routes/Blog.js | 38 ++++- frontend/src/Components/Home/BlogHeader.jsx | 2 +- frontend/src/Pages/blog manage/AddBlog.jsx | 131 ++++++++++++------ frontend/src/Pages/blog manage/BlogList.jsx | 14 +- .../src/Pages/blog manage/CommentList.jsx | 10 +- .../src/Pages/blog manage/InduvidualBlog.jsx | 121 +++++++++++++--- frontend/src/Pages/blog manage/UpdateBlog.jsx | 4 +- frontend/src/Pages/blog manage/UserBlog.jsx | 20 +-- .../Pages/common/speech/SpeechGenerator.jsx | 16 +-- frontend/src/Pages/dashboard/Admin.jsx | 8 +- .../ishanka dahsbaord/UpdateBlogDashbaord.jsx | 6 +- 12 files changed, 266 insertions(+), 105 deletions(-) diff --git a/backend/package.json b/backend/package.json index 2c89a0d5..8a8c3a2c 100644 --- a/backend/package.json +++ b/backend/package.json @@ -31,6 +31,7 @@ "jspdf": "^2.5.2", "jspdf-autotable": "^3.8.3", "mongoose": "^8.4.3", + "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", "nodemailer": "^6.9.14", "pdfkit": "^0.15.0", diff --git a/backend/routes/Blog.js b/backend/routes/Blog.js index af9f8a72..c0be2905 100644 --- a/backend/routes/Blog.js +++ b/backend/routes/Blog.js @@ -3,12 +3,28 @@ import Blog from '../models/Blog.js' // Blog model const router = Router() -// Function to validate required fields +// Function to validate required fields with enhanced rules const validateBlogFields = (title, content, author) => { const errors = {} - if (!title) errors.title = 'Title is required.' - if (!content) errors.content = 'Content is required.' - if (!author) errors.author = 'Author is required.' + + if (!title) { + errors.title = 'Title is required.' + } else if (title.length < 5) { + errors.title = 'Title must be at least 5 characters long.' + } + + if (!content) { + errors.content = 'Content is required.' + } else if (content.length < 10) { + errors.content = 'Content must be at least 10 characters long.' + } + + if (!author) { + errors.author = 'Author is required.' + } else if (author.trim().length === 0) { + errors.author = 'Author name cannot be empty.' + } + return errors } @@ -20,7 +36,11 @@ router.post('/add', async (req, res) => { // Validate required fields const errors = validateBlogFields(title, content, author) if (Object.keys(errors).length) { - return res.status(400).json({ errors }) + // Return a structured response showing all validation errors + return res.status(400).json({ + message: 'Validation failed. Please fix the errors below.', + errors, + }) } const newBlog = new Blog({ @@ -75,7 +95,13 @@ router.put('/update/:id', async (req, res) => { // Validate required fields const errors = validateBlogFields(title, content, author) if (Object.keys(errors).length) { - return res.status(400).json({ errors }) + + // Return a structured response showing all validation errors + return res.status(400).json({ + message: 'Validation failed. Please fix the errors below.', + errors, + }) + } // Find the blog post by ID and update it diff --git a/frontend/src/Components/Home/BlogHeader.jsx b/frontend/src/Components/Home/BlogHeader.jsx index b5fba388..6d2caafc 100644 --- a/frontend/src/Components/Home/BlogHeader.jsx +++ b/frontend/src/Components/Home/BlogHeader.jsx @@ -18,7 +18,7 @@ const BlogHeader = ({ loading }) => { {/* Update the link to the shop */} diff --git a/frontend/src/Pages/blog manage/BlogList.jsx b/frontend/src/Pages/blog manage/BlogList.jsx index 5adeafed..dd41fd56 100644 --- a/frontend/src/Pages/blog manage/BlogList.jsx +++ b/frontend/src/Pages/blog manage/BlogList.jsx @@ -51,9 +51,9 @@ function BlogList() { return ( <> -
+
-

+

Blog List

@@ -62,23 +62,23 @@ function BlogList() { {blogs.map((blog) => (
{blog.title}
-

+

{blog.title}

-

+

Author: {blog.author}

-

+

{blog.content.substring(0, 50)}...

diff --git a/frontend/src/Pages/blog manage/CommentList.jsx b/frontend/src/Pages/blog manage/CommentList.jsx index 39abde96..a1eee868 100644 --- a/frontend/src/Pages/blog manage/CommentList.jsx +++ b/frontend/src/Pages/blog manage/CommentList.jsx @@ -34,9 +34,9 @@ const CommentList = () => { } return ( -
+
-

+

Comments List

@@ -45,13 +45,13 @@ const CommentList = () => { {comments.map((comment) => (
-

+

Comment by: {comment.name}

-

+

{comment.comment}

diff --git a/frontend/src/Pages/blog manage/InduvidualBlog.jsx b/frontend/src/Pages/blog manage/InduvidualBlog.jsx index 7e47b89f..82eafdbb 100644 --- a/frontend/src/Pages/blog manage/InduvidualBlog.jsx +++ b/frontend/src/Pages/blog manage/InduvidualBlog.jsx @@ -11,7 +11,8 @@ export default function IndividualBlog() { const [blog, setBlog] = useState({}) const [comments, setComments] = useState([]) const [newComment, setNewComment] = useState({ name: '', comment: '' }) - + // Variables to handle speech synthesis state + let speechUtterance = null useEffect(() => { if (!id) return @@ -60,26 +61,73 @@ export default function IndividualBlog() { // Ensure the logo is loaded before generating the PDF logoImg.onload = () => { - doc.addImage(logoImg, 'PNG', 10, 10, 40, 5) // Add logo + // Center the logo + const pageWidth = doc.internal.pageSize.getWidth() + const logoWidth = 40 + const logoX = (pageWidth - logoWidth) / 2 + doc.addImage(logoImg, 'PNG', logoX, 10, logoWidth, 10) // Centered logo + + // Add company details below the logo, centered + doc.setFontSize(12) + doc.text( + 'FarmCart Lanka (PVT.) LTD', + pageWidth / 2, + 35, + null, + null, + 'center' + ) + doc.text( + 'No.78, Malabe, Colombo', + pageWidth / 2, + 40, + null, + null, + 'center' + ) + doc.text( + 'Phone: (+94) 011 34 56 837', + pageWidth / 2, + 45, + null, + null, + 'center' + ) + doc.text( + 'Website: www.farmcart.com', + pageWidth / 2, + 50, + null, + null, + 'center' + ) + + // Add blog title below the company details, centered and bold doc.setFontSize(22) - doc.text(blog.title, 10, 60) // Blog title + doc.setFont('helvetica', 'bold') // Make the title bold + doc.text(blog.title, pageWidth / 2, 70, null, null, 'center') + + // Reset the font style to normal for the rest of the content + doc.setFont('helvetica', 'normal') + + // Add blog author and date information below the title, left-aligned doc.setFontSize(12) - doc.text(`By: ${blog.author}`, 10, 70) // Author + doc.text(`By: ${blog.author}`, 10, 80) doc.text( `Date: ${new Date(blog.createdAt).toLocaleDateString()}`, 10, - 80 - ) // Date + 85 + ) - // Adding blog image if it exists + // Add blog content if (blog.newsImage) { - const imageUrl = `${blog.newsImage}` + const imageUrl = blog.newsImage const blogImg = new Image() blogImg.src = imageUrl blogImg.onload = () => { doc.addImage(blogImg, 'JPEG', 10, 90, 180, 100) // Blog image - addContentToPDF(doc, blog.content, blog.title) // Add content + addContentToPDF(doc, blog.content, blog.title) // Function to add the blog content } blogImg.onerror = () => { @@ -99,34 +147,58 @@ export default function IndividualBlog() { const addContentToPDF = (doc, content, title) => { let yPosition = 200 // Starting position for content doc.setFontSize(10) - doc.text('Content:', 10, yPosition) + yPosition += 10 // Move down after header // Split content into lines that fit within the page width const contentLines = doc.splitTextToSize(content, 180) - // Loop through content lines and add them to the PDF + // Manually justify content by adjusting spaces between words contentLines.forEach((line) => { if (yPosition > 280) { doc.addPage() yPosition = 10 // Reset Y position for new page doc.text(title, 10, 10) // Title on new page - doc.text('Content:', 10, 20) // Content header on new page + yPosition = 30 // Reset position for content } doc.text(line, 10, yPosition) // Add line to PDF yPosition += 10 // Move down for next line }) - doc.save(`${title}.pdf`) // Save the PDF + doc.save(`${title}`.pdf) // Save the PDF } - // Function to handle document download const handleDownloadDocument = () => { const downloadUrl = `/BlogDocuments/${blog.document}` // Assuming document field holds the filename window.open(downloadUrl, '_blank') // Open the document URL } + // Function to generate speech from blog content + const speakBlogContent = () => { + if ('speechSynthesis' in window) { + if (speechSynthesis.speaking && !speechSynthesis.paused) { + // If already speaking, pause the speech + speechSynthesis.pause() + } else if (speechSynthesis.paused) { + // If speech is paused, resume it + speechSynthesis.resume() + } else { + // If not speaking, start the speech + speechUtterance = new SpeechSynthesisUtterance(blog.content) + speechUtterance.lang = 'en-US' // You can set the language here + speechSynthesis.speak(speechUtterance) + } + } else { + alert('Your browser does not support text-to-speech functionality.') + } + } + // Function to stop the speech + const stopSpeech = () => { + if ('speechSynthesis' in window && speechSynthesis.speaking) { + speechSynthesis.cancel() + } + } return (
{/* */} @@ -170,13 +242,28 @@ export default function IndividualBlog() {
- +
+ + +
{/* Comment Form */}

@@ -202,7 +289,7 @@ export default function IndividualBlog() { /> diff --git a/frontend/src/Pages/blog manage/UpdateBlog.jsx b/frontend/src/Pages/blog manage/UpdateBlog.jsx index 54a09490..6b4961bf 100644 --- a/frontend/src/Pages/blog manage/UpdateBlog.jsx +++ b/frontend/src/Pages/blog manage/UpdateBlog.jsx @@ -133,7 +133,9 @@ export default function UpdateBlogForm() {

Update Blog

{error &&
{error}
} {successMessage && ( -
{successMessage}
+ +
{successMessage}
+ )} {errors.title &&
{errors.title}
} {errors.content && ( diff --git a/frontend/src/Pages/blog manage/UserBlog.jsx b/frontend/src/Pages/blog manage/UserBlog.jsx index 5757521e..07c99718 100644 --- a/frontend/src/Pages/blog manage/UserBlog.jsx +++ b/frontend/src/Pages/blog manage/UserBlog.jsx @@ -79,7 +79,7 @@ export default function TourismBlog() { {/* Latest News Section */}
-

+

Trending Blogs!

@@ -128,8 +128,8 @@ export default function TourismBlog() {
-
-