From ec3d2998c36020cd930ab2d0a0c5f81916ab6da7 Mon Sep 17 00:00:00 2001 From: auggie2lbcf Date: Tue, 8 Apr 2025 13:12:04 -0500 Subject: [PATCH 1/7] test --- package-lock.json | 1 - src/components/CommentSection.tsx | 41 ++++++++++++---------- src/pages/api/comments.ts | 32 +++++++++++++++++ src/pages/api/mongodb_client_connection.ts | 27 -------------- src/pages/posts/[id].tsx | 5 +-- 5 files changed, 58 insertions(+), 48 deletions(-) create mode 100644 src/pages/api/comments.ts delete mode 100644 src/pages/api/mongodb_client_connection.ts diff --git a/package-lock.json b/package-lock.json index 47eb8f2..be4a50c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5119,7 +5119,6 @@ "version": "6.15.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.15.0.tgz", "integrity": "sha512-ifBhQ0rRzHDzqp9jAQP6OwHSH7dbYIQjD3SbJs9YYk9AikKEettW/9s/tbSFDTpXcRbF+u1aLrhHxDFaYtZpFQ==", - "license": "Apache-2.0", "dependencies": { "@mongodb-js/saslprep": "^1.1.9", "bson": "^6.10.3", diff --git a/src/components/CommentSection.tsx b/src/components/CommentSection.tsx index 8d9069b..b1d055d 100644 --- a/src/components/CommentSection.tsx +++ b/src/components/CommentSection.tsx @@ -14,32 +14,37 @@ const CommentSection: React.FC = ({ postId }) => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - + // Basic validation if (!name.trim() || !email.trim() || !comment.trim()) { setError('All fields are required'); return; } - + setIsSubmitting(true); setError(null); - + try { - // In a real implementation, you would send this data to your API - // For now, we'll just simulate a successful submission - await new Promise(resolve => setTimeout(resolve, 1000)); - - // Clear form and show success message - setName(''); - setEmail(''); - setComment(''); - setIsSubmitted(true); - setIsSubmitting(false); - - // Reset success message after 5 seconds - setTimeout(() => { - setIsSubmitted(false); - }, 5000); + const response = await fetch('/api/comments', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name, email, comment, postId }), + }); + + if (response.ok) { + setName(''); + setEmail(''); + setComment(''); + setIsSubmitted(true); + setIsSubmitting(false); + + // Reset success message after 5 seconds + setTimeout(() => setIsSubmitted(false), 5000); + } else { + const data = await response.json(); + setError(data.message || 'Something went wrong. Please try again later.'); + setIsSubmitting(false); + } } catch (err) { setError('Something went wrong. Please try again later.'); setIsSubmitting(false); diff --git a/src/pages/api/comments.ts b/src/pages/api/comments.ts new file mode 100644 index 0000000..a9d830b --- /dev/null +++ b/src/pages/api/comments.ts @@ -0,0 +1,32 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { MongoClient } from 'mongodb'; + +const uri = process.env.MONGODB_URI || 'your-mongodb-uri'; // Replace with your MongoDB URI +const dbName = 'your-database-name'; // Replace with your database name + +const client = new MongoClient(uri); + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== 'POST') { + return res.status(405).json({ message: 'Method not allowed' }); + } + + const { name, email, comment, postId } = req.body; + + if (!name || !email || !comment || !postId) { + return res.status(400).json({ message: 'All fields are required' }); + } + + try { + if (!client.db(dbName)) await client.connect(); + const db = client.db(dbName); + const collection = db.collection('comments'); + + await collection.insertOne({ name, email, comment, postId, createdAt: new Date() }); + + res.status(201).json({ message: 'Comment submitted successfully' }); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Internal server error' }); + } +} \ No newline at end of file diff --git a/src/pages/api/mongodb_client_connection.ts b/src/pages/api/mongodb_client_connection.ts deleted file mode 100644 index 6f7419f..0000000 --- a/src/pages/api/mongodb_client_connection.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MongoClient } from 'mongodb'; - -const uri = process.env.MONGODB_URI || ''; // Load URI from environment variables -const options = {}; - -let client: MongoClient; -let clientPromise: Promise; - -if (!process.env.MONGODB_URI) { - throw new Error('Please add your MongoDB URI to .env.local'); -} - -// Reuse the client instance for serverless deployments -if (process.env.NODE_ENV === 'development') { - // Create a global instance to preserve the same client during HMR in development - if (!(global as typeof globalThis & { _mongoClientPromise?: Promise })._mongoClientPromise) { - client = new MongoClient(uri, options); - (global as typeof globalThis & { _mongoClientPromise?: Promise })._mongoClientPromise = client.connect(); - } - clientPromise = (global as typeof globalThis & { _mongoClientPromise?: Promise })._mongoClientPromise!; -} else { - // In production, create a new client connection - client = new MongoClient(uri, options); - clientPromise = client.connect(); -} - -export default clientPromise; \ No newline at end of file diff --git a/src/pages/posts/[id].tsx b/src/pages/posts/[id].tsx index d4f4d12..281c6ec 100644 --- a/src/pages/posts/[id].tsx +++ b/src/pages/posts/[id].tsx @@ -8,6 +8,7 @@ import { GetStaticPaths, GetStaticProps } from 'next'; import Image from 'next/image'; import Link from 'next/link'; import React from 'react'; +import CommentSection from "@/components/CommentSection"; interface PostProps { post: PostData; @@ -96,8 +97,8 @@ const Post: React.FC = ({ post, morePosts }) => { ))} - - {/* */} + +
From dc193022d8124024542993f11c137c33e48f7d11 Mon Sep 17 00:00:00 2001 From: auggie2lbcf Date: Tue, 8 Apr 2025 13:21:30 -0500 Subject: [PATCH 2/7] fixed db name --- src/pages/api/comments.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/api/comments.ts b/src/pages/api/comments.ts index a9d830b..632f17d 100644 --- a/src/pages/api/comments.ts +++ b/src/pages/api/comments.ts @@ -1,8 +1,8 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { MongoClient } from 'mongodb'; -const uri = process.env.MONGODB_URI || 'your-mongodb-uri'; // Replace with your MongoDB URI -const dbName = 'your-database-name'; // Replace with your database name +const uri = process.env.MONGODB_URI || 'dontstealmyuri'; +const dbName = 'comments'; const client = new MongoClient(uri); From da8e914a31a18cb3fae2f7854d9c2727c6064cf1 Mon Sep 17 00:00:00 2001 From: auggie2lbcf Date: Tue, 8 Apr 2025 13:41:35 -0500 Subject: [PATCH 3/7] comment section? --- src/components/CommentSection.tsx | 91 +++++++++++++++++++------------ 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/src/components/CommentSection.tsx b/src/components/CommentSection.tsx index b1d055d..35857a8 100644 --- a/src/components/CommentSection.tsx +++ b/src/components/CommentSection.tsx @@ -1,9 +1,15 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; interface CommentFormProps { postId: string; } +interface Comment { + name: string; + comment: string; + createdAt: string; +} + const CommentSection: React.FC = ({ postId }) => { const [name, setName] = useState(''); const [email, setEmail] = useState(''); @@ -11,11 +17,29 @@ const CommentSection: React.FC = ({ postId }) => { const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitted, setIsSubmitted] = useState(false); const [error, setError] = useState(null); + const [comments, setComments] = useState([]); + + useEffect(() => { + const fetchComments = async () => { + try { + const response = await fetch(`/api/comments?postId=${postId}`); + if (response.ok) { + const data = await response.json(); + setComments(data); + } else { + console.error('Failed to fetch comments'); + } + } catch (err) { + console.error('Error fetching comments:', err); + } + }; + + fetchComments(); + }, [postId]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - // Basic validation if (!name.trim() || !email.trim() || !comment.trim()) { setError('All fields are required'); return; @@ -38,7 +62,12 @@ const CommentSection: React.FC = ({ postId }) => { setIsSubmitted(true); setIsSubmitting(false); - // Reset success message after 5 seconds + // Fetch updated comments + const updatedComments = await fetch(`/api/comments?postId=${postId}`).then((res) => + res.json() + ); + setComments(updatedComments); + setTimeout(() => setIsSubmitted(false), 5000); } else { const data = await response.json(); @@ -54,19 +83,19 @@ const CommentSection: React.FC = ({ postId }) => { return (

Leave a Comment

- + {isSubmitted && (
- Your comment has been submitted and is awaiting moderation. Thank you! + Your comment has been submitted. Thank you!
)} - + {error && (
{error}
)} - +
@@ -96,7 +125,7 @@ const CommentSection: React.FC = ({ postId }) => { />
- +
- +
= ({ postId }) => { Save my name and email for the next time I comment
- +
- - {/* Sample comments - in a real implementation, these would be fetched from an API */} +
-

Comments (2)

- +

Comments ({comments.length})

+
-
-
-
-

John Calvin

-

March 10, 2025

+ {comments.map((comment) => ( +
+
+
+

{comment.name}

+

+ {new Date(comment.createdAt).toLocaleDateString()} +

+
+

{comment.comment}

-

- A profound meditation on the doctrine of grace. I particularly appreciate your emphasis on how this truth transforms our daily lives, not just our theological understanding. -

-
- -
-
-
-

Martin Luther

-

March 5, 2025

-
-
-

- This post eloquently articulates what I've been trying to explain to my congregation. The way you connected Scripture with practical application was masterful. I'll be sharing this widely. -

-
+ ))}
From ef69a6c59891253469e1acb81725a725ff8750bc Mon Sep 17 00:00:00 2001 From: auggie2lbcf Date: Tue, 8 Apr 2025 13:45:31 -0500 Subject: [PATCH 4/7] updated handler --- src/pages/api/comments.ts | 58 +++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/pages/api/comments.ts b/src/pages/api/comments.ts index 632f17d..4c2f5a8 100644 --- a/src/pages/api/comments.ts +++ b/src/pages/api/comments.ts @@ -1,32 +1,54 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { MongoClient } from 'mongodb'; -const uri = process.env.MONGODB_URI || 'dontstealmyuri'; -const dbName = 'comments'; +const uri = process.env.MONGODB_URI || 'your-mongodb-uri'; +const dbName = 'confessions-of-grace'; const client = new MongoClient(uri); export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== 'POST') { - return res.status(405).json({ message: 'Method not allowed' }); - } + if (req.method === 'POST') { + const { name, email, comment, postId } = req.body; - const { name, email, comment, postId } = req.body; + if (!name || !email || !comment || !postId) { + return res.status(400).json({ message: 'All fields are required' }); + } - if (!name || !email || !comment || !postId) { - return res.status(400).json({ message: 'All fields are required' }); - } + try { + if (!client.db(dbName)) await client.connect(); + const db = client.db(dbName); + const collection = db.collection('comments'); - try { - if (!client.db(dbName)) await client.connect(); - const db = client.db(dbName); - const collection = db.collection('comments'); + await collection.insertOne({ name, email, comment, postId, createdAt: new Date() }); - await collection.insertOne({ name, email, comment, postId, createdAt: new Date() }); + res.status(201).json({ message: 'Comment submitted successfully' }); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Internal server error' }); + } + } else if (req.method === 'GET') { + const { postId } = req.query; - res.status(201).json({ message: 'Comment submitted successfully' }); - } catch (error) { - console.error(error); - res.status(500).json({ message: 'Internal server error' }); + if (!postId) { + return res.status(400).json({ message: 'Post ID is required' }); + } + + try { + if (!client.db(dbName)) await client.connect(); + const db = client.db(dbName); + const collection = db.collection('comments'); + + const comments = await collection + .find({ postId }) + .sort({ createdAt: -1 }) + .toArray(); + + res.status(200).json(comments); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Internal server error' }); + } + } else { + res.status(405).json({ message: 'Method not allowed' }); } } \ No newline at end of file From a6dc57e8a8881777da2a17874335969a4c4981a4 Mon Sep 17 00:00:00 2001 From: auggie2lbcf Date: Tue, 8 Apr 2025 13:48:11 -0500 Subject: [PATCH 5/7] saved email & name --- src/components/CommentSection.tsx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/components/CommentSection.tsx b/src/components/CommentSection.tsx index 35857a8..cca8040 100644 --- a/src/components/CommentSection.tsx +++ b/src/components/CommentSection.tsx @@ -109,6 +109,10 @@ const CommentSection: React.FC = ({ postId }) => { onChange={(e) => setName(e.target.value)} className="w-full px-4 py-2 border border-primary-300 rounded-md focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent" required + onFocus={() => { + const savedName = localStorage.getItem('name'); + if (savedName) setName(savedName); + }} />
@@ -122,6 +126,10 @@ const CommentSection: React.FC = ({ postId }) => { onChange={(e) => setEmail(e.target.value)} className="w-full px-4 py-2 border border-primary-300 rounded-md focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent" required + onFocus={() => { + const savedEmail = localStorage.getItem('email'); + if (savedEmail) setEmail(savedEmail); + }} />
@@ -145,6 +153,18 @@ const CommentSection: React.FC = ({ postId }) => { type="checkbox" id="save-info" className="h-4 w-4 text-accent border-primary-300 rounded focus:ring-accent" + checked={localStorage.getItem('saveInfo') === 'true'} + onChange={(e) => { + const saveInfo = e.target.checked; + localStorage.setItem('saveInfo', saveInfo.toString()); + if (saveInfo) { + localStorage.setItem('name', name); + localStorage.setItem('email', email); + } else { + localStorage.removeItem('name'); + localStorage.removeItem('email'); + } + }} />
@@ -127,8 +129,10 @@ const CommentSection: React.FC = ({ postId }) => { className="w-full px-4 py-2 border border-primary-300 rounded-md focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent" required onFocus={() => { - const savedEmail = localStorage.getItem('email'); - if (savedEmail) setEmail(savedEmail); + if (typeof window !== 'undefined') { + const savedEmail = localStorage.getItem('email'); + if (savedEmail) setEmail(savedEmail); + } }} /> @@ -153,16 +157,18 @@ const CommentSection: React.FC = ({ postId }) => { type="checkbox" id="save-info" className="h-4 w-4 text-accent border-primary-300 rounded focus:ring-accent" - checked={localStorage.getItem('saveInfo') === 'true'} + checked={typeof window !== 'undefined' && localStorage.getItem('saveInfo') === 'true'} onChange={(e) => { - const saveInfo = e.target.checked; - localStorage.setItem('saveInfo', saveInfo.toString()); - if (saveInfo) { - localStorage.setItem('name', name); - localStorage.setItem('email', email); - } else { - localStorage.removeItem('name'); - localStorage.removeItem('email'); + if (typeof window !== 'undefined') { + const saveInfo = e.target.checked; + localStorage.setItem('saveInfo', saveInfo.toString()); + if (saveInfo) { + localStorage.setItem('name', name); + localStorage.setItem('email', email); + } else { + localStorage.removeItem('name'); + localStorage.removeItem('email'); + } } }} /> From 9b0810772b72fef455d0abda9134b73a504098a6 Mon Sep 17 00:00:00 2001 From: auggie2lbcf Date: Tue, 8 Apr 2025 15:08:49 -0500 Subject: [PATCH 7/7] removed checkbox. will add back later --- src/components/CommentSection.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/CommentSection.tsx b/src/components/CommentSection.tsx index 6edee1c..54ceb59 100644 --- a/src/components/CommentSection.tsx +++ b/src/components/CommentSection.tsx @@ -152,7 +152,7 @@ const CommentSection: React.FC = ({ postId }) => { > -
+ {/*
= ({ postId }) => { -
+
*/}