Skip to content

Commit

Permalink
add rich text editor, separate blog page.
Browse files Browse the repository at this point in the history
  • Loading branch information
AdityaRaj0001 committed Jun 25, 2024
1 parent c333b56 commit e36d444
Show file tree
Hide file tree
Showing 15 changed files with 713 additions and 55 deletions.
504 changes: 504 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"clsx": "^2.1.1",
"embla-carousel-react": "^8.1.5",
"framer-motion": "^11.2.11",
"html-react-parser": "^5.1.10",
"lucide-react": "^0.379.0",
"mongoose": "^8.4.0",
"next": "^14.2.3",
Expand All @@ -30,6 +31,7 @@
"react-dom": "^18",
"react-hook-form": "^7.51.5",
"react-icons": "^5.2.1",
"react-quill": "^2.0.0",
"react-router-dom": "^6.23.1",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
Expand Down
11 changes: 7 additions & 4 deletions src/app/actions/BlogActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { auth } from "@/auth";

const FormSchema = z.object({
title: z.string().min(1, "Title is required."),
brief: z.string().min(1, "Brief is required.").max(100,"Brief is too Long, keep it below 100 characters"),
content: z.string().min(1, "Content is required."),
author: z.string().min(1, "Author is required."),
club: z.string().min(1, "Club is required."),
Expand All @@ -19,6 +20,7 @@ export async function createBlog(prevState, formData) {
// Validate form using Zod
const validatedFields = FormSchema.safeParse({
title: formData.get("title"),
brief: formData.get("brief"),
content: formData.get("content"),
author: formData.get("author"),
club: _club,
Expand All @@ -34,12 +36,12 @@ export async function createBlog(prevState, formData) {
}

// Extract validated data
const { title, content, author, club } = validatedFields.data;
const { title, brief, content, author, club } = validatedFields.data;

// Insert data into the database
try {
await connectMongoDB();
await Blog.create({ title, content, author, club });
await Blog.create({ title, brief, content, author, club });
} catch (error) {
// If a database error occurs, return a more specific error.
return {
Expand All @@ -59,6 +61,7 @@ export async function updateBlog(_id, prevState, formData) {
// Validate form using Zod
const validatedFields = FormSchema.safeParse({
title: formData.get("title"),
brief: formData.get("brief"),
content: formData.get("content"),
author: formData.get("author"),
club: _club,
Expand All @@ -73,12 +76,12 @@ export async function updateBlog(_id, prevState, formData) {
}

// Extract validated data
const { title, content, author } = validatedFields.data;
const { title, brief, content, author } = validatedFields.data;

// Insert data into the database
try {
await connectMongoDB();
await Blog.findByIdAndUpdate(_id, { title, content, author });
await Blog.findByIdAndUpdate(_id, { title, brief, content, author });
} catch (error) {
// If a database error occurs, return a more specific error.
return {
Expand Down
18 changes: 18 additions & 0 deletions src/app/blogs/[blogid]/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import { getBlogById } from "@/app/actions/BlogData";
import parse from "html-react-parser";

const page = async ({ params }) => {
const blogid = params.blogid;
const blogDetails = await getBlogById(blogid);
return <div className="min-h-[70vh] flex flex-col gap-8 items-center py-8">
<h1 className="w-full text-center text-3xl">{blogDetails.title}</h1>
<p className="w-4/5 text-xl max-w-[750px]">{parse(blogDetails.content)}</p>
<div className="flex items-center w-4/5 max-w-[750px] justify-between text-sm">
<span className="bg-gray-300 p-1 sm:p-2 rounded-sm">Author: {blogDetails.author}</span>
<span className="bg-gray-300 p-1 sm:p-2 rounded-sm">Club: {blogDetails.club}</span>
</div>
</div>;
};

export default page;
2 changes: 1 addition & 1 deletion src/app/dashboard/blogs/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react'
import Table from '@/components/Blog/table';

const page = () => {
let columnData = ["Title", "Content", "Author", "Club", "Edit/Delete"];
let columnData = ["Title", "Brief", "Author", "Club", "Edit/Delete"];


return (
Expand Down
51 changes: 47 additions & 4 deletions src/components/Blog/create-form.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
"use client";
import React from "react";
import React,{useState} from "react";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { useFormState } from "react-dom";
import { createBlog } from "@/app/actions/BlogActions";
import Editor from "../editor";

const Form = () => {
const initialState = { message: null, errors: {} };
const [state, dispatch] = useFormState(createBlog, initialState);
const [blogHtmlContent, setBlogHtmlContent] = useState("");

const handleSubmit=(event)=>{
event.preventDefault();
const formData = new FormData(event.target);
formData.set("content", blogHtmlContent); // Set the image URL in the form data
dispatch(formData);
}

return (
<form action={dispatch}>
<form onSubmit={handleSubmit}>
<div className="text-xl font-bold text-primary mb-4">
<h2>Add a blog</h2>
</div>
Expand Down Expand Up @@ -38,9 +47,31 @@ const Form = () => {
))}
</div>
</div>
{/* Brief */}
<div className="mb-4">
<label htmlFor="brief" className="mb-2 block text-sm font-medium">
Brief
</label>
<input
id="brief"
name="brief"
type="text"
className="peer block w-full rounded-md border border-gray-200 py-2 pl-3 text-sm outline-2 placeholder:text-gray-500"
placeholder="What the blog is about?"
aria-describedby="brief-error"
/>
<div id="brief-error" aria-live="polite" aria-atomic="true">
{state.errors?.brief &&
state.errors.brief.map((error) => (
<p className="mt-2 text-sm text-red-500" key={error}>
{error}
</p>
))}
</div>
</div>

{/* Body */}
<div className="mb-4">
{/* <div className="mb-4">
<label htmlFor="content" className="mb-2 block text-sm font-medium">
Content
</label>
Expand All @@ -60,7 +91,19 @@ const Form = () => {
</p>
))}
</div>
</div>
</div> */}
<label htmlFor="Content" className="mb-2 block text-sm font-medium">
Content
</label>
<Editor value={blogHtmlContent} setValue={setBlogHtmlContent}/>
<div id="content-error" className="mb-4" aria-live="polite" aria-atomic="true">
{state.errors?.content &&
state.errors.content.map((error) => (
<p className="mt-2 text-sm text-red-500" key={error}>
{error}
</p>
))}
</div>

{/* Author */}
<div className="mb-4">
Expand Down
78 changes: 55 additions & 23 deletions src/components/Blog/edit-form.jsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
"use client";
import React from "react";
import React, { useState } from "react";
import { Button } from "@/components/ui/button";
import Link from "next/link";
// import { UserCircleIcon } from '@heroicons/react/solid';
import { useFormState } from "react-dom";
import { updateBlog } from "@/app/actions/BlogActions";
import Editor from "../editor";

const Form = ({ blogDetails }) => {
const initialState = { message: null, errors: {} };
const updateBlogById = updateBlog.bind(null, blogDetails._id);
const [state, dispatch] = useFormState(updateBlogById, initialState);
const [blogHtmlContent, setBlogHtmlContent] = useState(
blogDetails.content || " "
);

const handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData(event.target);
formData.set("content", blogHtmlContent); // Set the image URL in the form data
dispatch(formData);
};

return (
<form action={dispatch}>
<form onSubmit={handleSubmit}>
<div className="text-xl font-bold text-primary mb-4">
<h2>Edit blog</h2>
</div>

<div className="rounded-md bg-gray-50 p-4 md:p-6">


{/* Title */}
<div className="mb-4">
<label htmlFor="title" className="mb-2 block text-sm font-medium">
Expand All @@ -43,10 +52,33 @@ const Form = ({ blogDetails }) => {
))}
</div>
</div>
{/* Brief */}
<div className="mb-4">
<label htmlFor="brief" className="mb-2 block text-sm font-medium">
Brief
</label>
<input
id="brief"
name="brief"
type="text"
defaultValue={blogDetails.brief}
className="peer block w-full rounded-md border border-gray-200 py-2 pl-3 text-sm outline-2 placeholder:text-gray-500"
placeholder="What the blog is about?"
aria-describedby="brief-error"
/>
<div id="brief-error" aria-live="polite" aria-atomic="true">
{state.errors?.brief &&
state.errors.brief.map((error) => (
<p className="mt-2 text-sm text-red-500" key={error}>
{error}
</p>
))}
</div>
</div>

{/* content */}
<div className="mb-4">
<label htmlFor="content" className="mb-2 block text-sm font-medium">
{/* <label htmlFor="content" className="mb-2 block text-sm font-medium">
Content
</label>
<textarea
Expand All @@ -57,15 +89,16 @@ const Form = ({ blogDetails }) => {
placeholder="Enter content text"
rows="5"
aria-describedby="content-error"
></textarea>
></textarea> */}
<Editor value={blogHtmlContent} setValue={setBlogHtmlContent} />
<div id="content-error" aria-live="polite" aria-atomic="true">
{state.errors?.content &&
state.errors.content.map((error) => (
<p className="mt-2 text-sm text-red-500" key={error}>
{error}
</p>
))}
</div>
{state.errors?.content &&
state.errors.content.map((error) => (
<p className="mt-2 text-sm text-red-500" key={error}>
{error}
</p>
))}
</div>
</div>

{/* Author */}
Expand All @@ -91,17 +124,16 @@ const Form = ({ blogDetails }) => {
))}
</div>
</div>
<div className="mt-6 flex justify-end gap-4">
<Link
href="/dashboard/blogs"
className="flex h-10 items-center rounded-lg bg-secondary px-4 text-sm font-medium text-primary transition-colors hover:bg-gray-200"
>
Cancel
</Link>
<Button type="submit">Update Blog</Button>
</div>
<div className="mt-6 flex justify-end gap-4">
<Link
href="/dashboard/blogs"
className="flex h-10 items-center rounded-lg bg-secondary px-4 text-sm font-medium text-primary transition-colors hover:bg-gray-200"
>
Cancel
</Link>
<Button type="submit">Update Blog</Button>
</div>
</div>

</form>
);
};
Expand Down
6 changes: 3 additions & 3 deletions src/components/Blog/table.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ export default async function Table(props) {
<TableRow key={rest.id}>
<TableCell className="font-medium">{rest.title}</TableCell>
<TableCell className="text-sm">
{rest.content.length > 50
? `${rest.content.substring(0, 50)}...`
: rest.content}
{rest.brief.length > 50
? `${rest.brief.substring(0, 50)}...`
: rest.brief}
</TableCell>
<TableCell>{rest.author}</TableCell>
<TableCell>{rest.club}</TableCell>
Expand Down
5 changes: 3 additions & 2 deletions src/components/ClubPageComponents/OurBlogs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ export default async function OurBlogs({club}) {
</h2>

<div className="gap-6 flex flex-row flex-wrap justify-center items-center w-full ">
{Blogs.map(({ id, title, content, author, club }, index) => (
{Blogs.map(({ id, title, brief, author, club }, index) => (
<BlogCard
key={id}
title={title}
content={content}
id={id}
brief={brief}
author={author}
club={club}
/>
Expand Down
7 changes: 3 additions & 4 deletions src/components/Home/OurBlogs.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import React from "react";
import TeamMember from "../ui/TeamMember";
import { getAllTeamMembers } from "@/app/actions/TeamData";
import { getAllBlogs } from "@/app/actions/BlogData";
import { BlogCard } from "../ui/BlogCard";

Expand All @@ -13,11 +11,12 @@ export default async function OurBlogs() {
</h2>

<div className="gap-6 flex flex-row flex-wrap justify-center items-center w-full ">
{Blogs.map(({ id, title, content, author, club }, index) => (
{Blogs.map(({ id, title, brief, author, club }, index) => (
<BlogCard
key={id}
id={id}
title={title}
content={content}
brief={brief}
author={author}
club={club}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Navbar/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default function Navbar({ session }) {
</SheetContent>
</Sheet>
<Link className="mr-6 hidden lg:flex" href="/">
<img src="./Logo.png" className=" h-[60px]"></img>
<img src="/Logo.png" className=" h-[60px]"></img>
</Link>
<nav className="ml-auto hidden lg:flex gap-6">
{session ? (
Expand Down Expand Up @@ -109,7 +109,7 @@ export default function Navbar({ session }) {
)}
</nav>
<Link href="/" className="lg:hidden">
<img src="./Logo.png" className=" h-[60px]"></img>
<img src="/Logo.png" className=" h-[60px]"></img>
</Link>
</header>
);
Expand Down
Loading

0 comments on commit e36d444

Please sign in to comment.