Skip to content

Commit

Permalink
Fix (#285):author will be able to update blogs (#294)
Browse files Browse the repository at this point in the history
  • Loading branch information
mutsinziisaac authored Dec 6, 2024
1 parent a36b93f commit e2c5387
Show file tree
Hide file tree
Showing 5 changed files with 722 additions and 238 deletions.
5 changes: 2 additions & 3 deletions src/components/home/Blogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ const BlogCard = ({ blog }: { blog: Blog }) => (
</Link>
<Link to={`/blogs/${blog.id}`}>
<h3 className="text-xl font-semibold mb-2">{blog.title}</h3>
<p className="mb-4 text-black-text dark:text-white overflow-hidden line-clamp-3">
{blog.content}
</p>
<div className="mb-4 text-black-text dark:text-white overflow-hidden line-clamp-3" dangerouslySetInnerHTML={{ __html: `${blog.content.substring(0, 150)}...`}}>
</div>
</Link>
</div>
</div>
Expand Down
170 changes: 94 additions & 76 deletions src/pages/Blogs/Blogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,89 +51,107 @@ const Blogs: React.FC = () => {
)}
</div>
{loading ? (
<div className="flex justify-center items-center h-screen">
<div className="spinner-border animate-spin inline-block w-8 h-8 border-4 rounded-full border-t-4 border-green-500" role="status">
<span className="sr-only">Loading...</span>
</div>
</div>
<div className="flex justify-center items-center h-screen">
<div
className="spinner-border animate-spin inline-block w-8 h-8 border-4 rounded-full border-t-4 border-green-500"
role="status"
>
<span className="sr-only">Loading...</span>
</div>
</div>
) : blogs.length > 0 ? (
<>
<div className="grid grid-cols-1 sm:grid-cols-3 md:grid-cols-1 gap-6 px-10">
<div className="grid grid-cols-1 sm:grid-cols-3 md:grid-cols-1 gap-6 px-10">
{blogs.map((blog) => (
<div
key={blog.id}
className="bg-gray-200 dark:bg-dark-frame-bg dark:text-white text-primary shadow-lg rounded-lg cursor-pointer hover:shadow-xl transition duration-300"
>
<Link to={`/blogs/${blog.id}`}>
<img
src={blog.coverImage}
alt={blog.title}
className="w-full h-40 object-cover mb-4"
/>
</Link>
<div className="p-3">
<div className="flex justify-between text-sm text-primary dark:text-white mb-4 items-center">
<div className="flex items-center gap-3">
<Link to={`/blogs/${blog.id}`}>
<div className="flex flex-wrap items-center gap-3">
<span className="font-semibold flex flex-row gap-2 items-center">
<FaUser size={20} className="dark:text-green" /> {blog.author.firstname}
</span>
<span className="ml-2 flex flex-row gap-2 items-center">
<FaCalendar size={20} className="dark:text-green" />
{blog.created_at
? new Date(Number(blog.created_at)).toLocaleDateString()
: "Unknown Date"}
</span>
<span className="flex flex-row gap-1 items-center">
<CiHeart size={20} className="dark:text-green" /> {blog.reactions.length || 0}
</span>
<span className="flex flex-row gap-1 items-center">
<FaCommentDots size={20} className="dark:text-green" /> {blog.comments.length || 0}
</span>
</div>
</Link>
</div>
</div>
<Link to={`/blogs/${blog.id}`}>
<h3 className="text-xl font-semibold mb-2">{blog.title}</h3>
<p className="mb-4 text-black-text dark:text-white overflow-hidden line-clamp-3">
{blog.content.substring(0, 150)}...
</p>
</Link>
<div className="flex flex-wrap gap-2 mt-3">
{blog.tags.map((tag) => (
<span
key={tag}
onClick={(e) => {
setSelectedTag(tag);
}}
className="bg-green-100 text-green-700 text-xs px-2 py-1 rounded cursor-pointer hover:bg-green-200"
>
#{tag}
</span>
))}
</div>
</div>

</div>

<div
key={blog.id}
className="bg-gray-200 dark:bg-dark-frame-bg dark:text-white text-primary shadow-lg rounded-lg cursor-pointer hover:shadow-xl transition duration-300"
>
<Link to={`/blogs/${blog.id}`}>
<img
src={blog.coverImage}
alt={blog.title}
className="w-full h-40 object-cover mb-4"
/>
</Link>
<div className="p-3">
<div className="flex justify-between text-sm text-primary dark:text-white mb-4 items-center">
<div className="flex items-center gap-3">
<Link to={`/blogs/${blog.id}`}>
<div className="flex flex-wrap items-center gap-3">
<span className="font-semibold flex flex-row gap-2 items-center">
<FaUser size={20} className="dark:text-green" />{" "}
{blog.author.firstname}
</span>
<span className="ml-2 flex flex-row gap-2 items-center">
<FaCalendar
size={20}
className="dark:text-green"
/>
{blog.created_at
? new Date(
Number(blog.created_at)
).toLocaleDateString()
: "Unknown Date"}
</span>
<span className="flex flex-row gap-1 items-center">
<CiHeart size={20} className="dark:text-green" />{" "}
{blog.reactions.length || 0}
</span>
<span className="flex flex-row gap-1 items-center">
<FaCommentDots
size={20}
className="dark:text-green"
/>{" "}
{blog.comments.length || 0}
</span>
</div>
</Link>
</div>
</div>
<Link to={`/blogs/${blog.id}`}>
<h3 className="text-xl font-semibold mb-2">
{blog.title}
</h3>
<div
className="mb-4 text-black-text dark:text-white overflow-hidden line-clamp-3"
dangerouslySetInnerHTML={{
__html: `${blog.content.substring(0, 150)}...`,
}}
></div>
</Link>
<div className="flex flex-wrap gap-2 mt-3">
{blog.tags.map((tag) => (
<span
key={tag}
onClick={(e) => {
setSelectedTag(tag);
}}
className="bg-green-100 text-green-700 text-xs px-2 py-1 rounded cursor-pointer hover:bg-green-200"
>
#{tag}
</span>
))}
</div>
</div>
</div>
))}
</div>

</>
</>
) : (
<div className="flex flex-col justify-center items-center h-screen text-center dark:bg-dark-bg bg-white px-6">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="w-16 h-16 text-gray-500 mb-4"
>
<path d="M12 2a10 10 0 11-10 10A10 10 0 0112 2zm5 11H7a1 1 0 000 2h10a1 1 0 000-2zm-1-4a1 1 0 01-1 1H9a1 1 0 010-2h6a1 1 0 011 1z" />
</svg>
<p className="text-lg text-gray-500 dark:text-gray-300">No blogs available at the moment. Check back later!</p>
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="w-16 h-16 text-gray-500 mb-4"
>
<path d="M12 2a10 10 0 11-10 10A10 10 0 0112 2zm5 11H7a1 1 0 000 2h10a1 1 0 000-2zm-1-4a1 1 0 01-1 1H9a1 1 0 010-2h6a1 1 0 011 1z" />
</svg>
<p className="text-lg text-gray-500 dark:text-gray-300">
No blogs available at the moment. Check back later!
</p>
</div>
)}
</div>
<Footer />
Expand Down
102 changes: 73 additions & 29 deletions src/pages/Blogs/allBlogs.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useState,ChangeEvent } from "react";
import { useNavigate } from "react-router-dom";
import { getAllBlogs, getBlogsByAuthor } from "../../redux/actions/blogActions";
import { createBlogAction } from "../../redux/actions/blogActions";
Expand All @@ -9,6 +9,9 @@ import { handleBlogImageUpload } from "../../utils/imageUploadUtil";
import { useAppDispatch, useAppSelector } from "../../hooks/hooks";
import AllBlogsSkeleton from "../../skeletons/allBlogsSkeleton";
import SingleBlogSkeleton from "skeletons/singleBlogSkeleton";
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import { AiOutlineClose } from 'react-icons/ai';
import HideUnhideButton from "../../components/hideBlog"

interface Comment {
Expand Down Expand Up @@ -67,6 +70,7 @@ const AllBlogs = () => {
const [addingBlog, setAddingBlog] = useState(false);
const [manyImaages, setManyImages] = useState(false);
const [tags, setTags] = useState('');
const [content, setContent] = useState('');
const [submitData, setSubmitData] = useState<SubmitData>({
title: "",
content: "",
Expand Down Expand Up @@ -226,20 +230,62 @@ const AllBlogs = () => {
await dispatch(createBlogAction(obj));
setAddingBlog(false);
removeModal();
dispatch(getBlogsByAuthor(String(userId)));

if (role == "applicant" || role == "trainee") {
dispatch(getBlogsByAuthor(String(userId)));
} else {
dispatch(getAllBlogs());
}

} catch (error) {
console.log(error);
} finally {
setIsUploading(false);
}
};

const modules = {
toolbar: [
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
['bold', 'italic', 'underline', 'strike'],
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
['link'],
[{ 'align': [] }],
[{ 'color': [] }, { 'background': [] }],
['clean']
]
};

const formats = [
'header',
'bold', 'italic', 'underline', 'strike',
'list', 'bullet',
'link', 'image',
'align',
'color', 'background'
];

const handleContentChange = (value: string) => {
setContent(value);

// Simulate an event object to match the expected input of handleInputChange
const syntheticEvent = {
target: {
name: 'content',
value: value
}
} as ChangeEvent<HTMLTextAreaElement>;

handleInputChange(syntheticEvent);
};



return (
<div className="min-h-screen bg-white w-full dark:bg-slate-900 dark:text-white p-6">
{addNewBlogModal && (
<div className="fixed inset-0 mt-16 p-0 flex items-center justify-center bg-black bg-opacity-20 dark:bg-opacity-40">
<div className="bg-white dark:bg-dark-bg w-11/12 md:w-3/5 lg:w-2/5 rounded-lg p-6">
<div className="bg-white dark:bg-dark-bg w-11/12 md:w-3/5 lg:w-2/5 rounded-lg p-6 max-h-[600px] overflow-y-scroll">
<div className="w-full flex mb-2 items-center justify-between">
<h3 className="font-bold text-m dark:text-white ">
CREATE A NEW BLOG
Expand Down Expand Up @@ -267,13 +313,14 @@ const AllBlogs = () => {
</div>
<div className="flex flex-col">
<label className="font-semibold text-sm">Blog Content</label>
<textarea
name="content"
value={submitData.content}
onChange={handleInputChange}
className="border rounded focus:ring-2 focus:ring-white dark:bg-black px-4 py-2 h-24"
<ReactQuill
value={content}
onChange={handleContentChange}
modules={modules}
formats={formats}
theme="snow"
className="border rounded dark:bg-black"
placeholder="Enter Blog Content"
maxLength={2000}
/>
{errors.content && (
<span className="text-red-500 text-xs">{errors.content}</span>
Expand Down Expand Up @@ -361,19 +408,18 @@ const AllBlogs = () => {
<div className="max-w-6xl mt-2 mx-auto">
<div className="mb-6 w-full flex items-center justify-between">
<h1 className="text-2xl font-semibold">All Blogs</h1>
{userId && role && (role == "applicant" || role == "trainee") && (
<div className="w-full sm:w-auto">
<button
disabled={isLoading}
onClick={Open}
className={`flex items-center justify-center w-full sm:w-auto ${
isLoading ? "bg-emerald-300" : "bg-primary dark:bg-[#56C870]"
} rounded-md py-2 px-4 text-white font-medium cursor-pointer hover:opacity-90 transition-opacity`}
>
<icons.AiOutlinePlus className="mr-2" /> Blog
</button>
</div>
)}

<div className="w-full sm:w-auto">
<button
disabled={isLoading}
onClick={Open}
className={`flex items-center justify-center w-full sm:w-auto ${
isLoading ? "bg-emerald-300" : "bg-primary dark:bg-[#56C870]"
} rounded-md py-2 px-4 text-white font-medium cursor-pointer hover:opacity-90 transition-opacity`}
>
<icons.AiOutlinePlus className="mr-2" /> Blog
</button>
</div>
</div>

<div className="space-y-4">
Expand All @@ -397,9 +443,10 @@ const AllBlogs = () => {
<p className="text-lg font-medium break-words whitespace-normal overflow-wrap-break-word transition-colors">
{blog.title}
</p>
<p className="dark:text-slate-400 text-slate-800 break break-words text-sm line-clamp-2">
{blog.content}
</p>
<div
className="dark:text-slate-400 text-slate-800 break break-words text-sm line-clamp-2"
dangerouslySetInnerHTML={{ __html: blog.content }}
></div>
</div>
<div className="w-1/6 flex flex-col items-end text-sm dar:text-slate-400">
<span>{`${blog.author.firstname} ${blog.author.lastname}`}</span>
Expand All @@ -408,10 +455,7 @@ const AllBlogs = () => {
</span>
</div>
{role === "admin" || role === "superAdmin" ? (
<HideUnhideButton
blogId={blog.id}
isHidden={blog.isHidden}
/>
<HideUnhideButton blogId={blog.id} isHidden={blog.isHidden} />
) : null}
</div>
))
Expand Down
Loading

0 comments on commit e2c5387

Please sign in to comment.