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/public/images/templar.jpeg b/public/images/templar.jpeg new file mode 100644 index 0000000..ca0f0a2 Binary files /dev/null and b/public/images/templar.jpeg differ diff --git a/src/components/CommentSection.tsx b/src/components/CommentSection.tsx index 8d9069b..54ceb59 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,35 +17,63 @@ 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; } - + 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); + + // 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(); + setError(data.message || 'Something went wrong. Please try again later.'); + setIsSubmitting(false); + } } catch (err) { setError('Something went wrong. Please try again later.'); setIsSubmitting(false); @@ -49,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}
)} - +
@@ -75,6 +109,12 @@ 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={() => { + if (typeof window !== 'undefined') { + const savedName = localStorage.getItem('name'); + if (savedName) setName(savedName); + } + }} />
@@ -88,10 +128,16 @@ 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={() => { + if (typeof window !== 'undefined') { + const savedEmail = localStorage.getItem('email'); + if (savedEmail) setEmail(savedEmail); + } + }} />
- +
- -
+ + {/*
{ + 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'); + } + } + }} /> -
- +
*/} +
- - {/* 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. -

-
+ ))}
diff --git a/src/pages/api/comments.ts b/src/pages/api/comments.ts new file mode 100644 index 0000000..4c2f5a8 --- /dev/null +++ b/src/pages/api/comments.ts @@ -0,0 +1,54 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { MongoClient } from 'mongodb'; + +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') { + 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' }); + } + } else if (req.method === 'GET') { + const { postId } = req.query; + + 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 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 }) => { ))}
- - {/* */} + +
diff --git a/src/posts/christian_nationalism.md b/src/posts/christian_nationalism.md new file mode 100644 index 0000000..40ab244 --- /dev/null +++ b/src/posts/christian_nationalism.md @@ -0,0 +1,29 @@ +--- +title: "Against Ethnocentric Christian Nationalism" +date: "2025-04-05" +author: "@Auggie2LBCF" +excerpt: "TBD" +tags: ["christianity", "nationalism", "theology", "ethics", "identity", "political philosophy", "church and state"] +coverImage: "/images/templar.jpeg" +--- +## Definitions +I will start by defining what *exactly* I mean by each of the words in the title. This is to prevent any confusion with my position and to help see what I am seeing. +### Christian +With where society is at with Christianity. It will be helpful to fence what I mean by Christian. Here are 5 points that I would use when describing a Christian: +1. **Those who have been renerated with an effectual call.** They have been given a new heart and spiritual life (John 3:3), drawing them irresistibly to Christ (2 Timothy 1:9). +2. **Those who have a saving faith.** A wholehearted trust and reliance *solely* upon Jesus Christ (Ephesians 2:8-9), this faith is understood as a gift from God (WSC Q. 86). +3. **Those who have repenantce unto life.** Saving faith is always accompanied by repentance -a heartfelt sorrow for sin, a turning away from it, and a sincere turning towards God and His commands (Acts 20:21), again, as a grace from God. +4. **Those who have been justified.** The believer has been declared righteous by God, not on their merits but solely on Christ's righteousness being imputed (credited) to them (Romans 3:24-25a, Heidelberg Q. 60). +5. **Those who have union with Christ.** The believer is united with Christ (2 Corinthians 5:17) and adopted into God's family as His child. + +When I refer to Christian, I do not refer to those who fall into the reformed baptist category, but those who are heirs with Christ with me. This includes people such as Sam Waldron to Mike Winger. + +### Christian Nationalism +Christian nationalism is a totality of national action, consisting of civil laws and social customs, conducted by a Christian nation as a Christian nation, in order to procure for itself both earthly and heavenly good in Christ. (*The Case for Christian Nationalism*, Stephen Wolfe) + +### Ethnocentric +Ethnocentric is the + +## Systematic Theology +Then God said, "Let us make man in our image, after our likeness. And let them have dominion over the fish of the sea and over the birds of the heavens and over the livestock and over all the earth and over every creeping thing that creeps on the earth." +## Historical Theology \ No newline at end of file