Update Post Page

This commit is contained in:
2025-04-13 06:25:48 -04:00
parent e5029db51a
commit 8f1dac4937
3 changed files with 164 additions and 128 deletions

View File

@@ -1,150 +1,175 @@
"use client"; "use client";
import { useDevice } from "@/lib/context/DeviceContext"; import { useDevice } from "@/lib/context/DeviceContext";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
export default function PostsPage() { export default function PostsPage() {
const [postText, setPostText] = useState(""); const [postText, setPostText] = useState("");
const [posts, setPosts] = useState<any[]>([]); const [posts, setPosts] = useState<any[]>([]);
const [userReactions, setUserReactions] = useState<{ const [userReactions, setUserReactions] = useState<{
[index: number]: { liked: boolean; warned: boolean }; [index: number]: { liked: boolean; warned: boolean };
}>({}); }>({});
const { isAuthenticated, session } = useDevice(); const [imageFile, setImageFile] = useState<File | null>(null);
const { isAuthenticated, session } = useDevice();
useEffect(() => { useEffect(() => {
if (isAuthenticated && session?.username) { if (isAuthenticated && session?.username) {
fetch(`/api/user/${session.username}`).then((res) => res.json()); fetch(`/api/user/${session.username}`).then((res) => res.json());
} }
}, [isAuthenticated, session?.username]); }, [isAuthenticated, session?.username]);
const handlePostSubmit = (e: React.FormEvent) => { const handlePostSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
const newPost = {
text: postText,
date: new Date().toLocaleString(),
likes: 0,
warnings: 0,
imageUrl: "", // placeholder for image logick
author: session.username, // add username to track authorship
};
setPosts([newPost, ...posts]);
setPostText("");
};
const handleLike = (index: number) => { if (!imageFile) {
const updatedPosts = [...posts]; alert("Please select an image to upload.");
const reactions = { ...userReactions }; return;
}
const alreadyLiked = reactions[index]?.liked; const formData = new FormData();
formData.append("image", imageFile);
formData.append("text", postText);
updatedPosts[index].likes += alreadyLiked ? -1 : 1; try {
const response = await fetch("/api/post", {
method: "POST",
body: formData,
});
reactions[index] = { const data = await response.json();
...reactions[index], if (response.ok) {
liked: !alreadyLiked, alert("Post uploaded successfully!");
}; setPosts([data.postData, ...posts]);
setPostText("");
setImageFile(null);
} else {
alert(data.message || "Failed to upload post.");
}
} catch (error) {
console.error("Error uploading post:", error);
alert("An error occurred while uploading the post.");
}
};
setPosts(updatedPosts); const handleLike = (index: number) => {
setUserReactions(reactions); const updatedPosts = [...posts];
}; const reactions = { ...userReactions };
const handleWarning = (index: number) => { const alreadyLiked = reactions[index]?.liked;
const updatedPosts = [...posts];
const reactions = { ...userReactions };
const alreadyWarned = reactions[index]?.warned; updatedPosts[index].likes += alreadyLiked ? -1 : 1;
updatedPosts[index].warnings += alreadyWarned ? -1 : 1; reactions[index] = {
...reactions[index],
liked: !alreadyLiked,
};
reactions[index] = { setPosts(updatedPosts);
...reactions[index], setUserReactions(reactions);
warned: !alreadyWarned, };
};
setPosts(updatedPosts); const handleWarning = (index: number) => {
setUserReactions(reactions); const updatedPosts = [...posts];
}; const reactions = { ...userReactions };
return ( const alreadyWarned = reactions[index]?.warned;
<div className="px-6 py-10 max-w-full lg:max-w-2xl mx-auto font-sans text-neutral-100">
<div className="bg-[color:var(--color-surface-700)]/70 backdrop-blur-md rounded-xl px-6 py-5 mb-8 shadow-sm">
<h1 className="text-3xl sm:text-4xl font-bold mb-0 text-[color:var(--color-warning-300)]">
Posts
</h1>
</div>
<div className="bg-[color:var(--color-surface-600)]/70 backdrop-blur-md rounded-xl px-6 py-5 mb-8 shadow-sm"> updatedPosts[index].warnings += alreadyWarned ? -1 : 1;
<form onSubmit={handlePostSubmit} className="space-y-3">
<textarea
className="w-full p-3 rounded bg-neutral-800 text-white"
placeholder="Share your beverage..."
value={postText}
onChange={(e) => setPostText(e.target.value)}
rows={4}
/>
<button
type="submit"
className="px-4 py-2 bg-success-600 text-white rounded font-semibold"
>
Post
</button>
</form>
</div>
<div className="space-y-6"> reactions[index] = {
{posts.map((post, index) => ( ...reactions[index],
<div warned: !alreadyWarned,
key={index} };
className="bg-[color:var(--color-surface-600)]/80 rounded-xl px-6 py-5 shadow-md"
>
<div className="flex items-center gap-4 mb-2">
<div className="w-10 h-10 rounded-full bg-neutral-800 border border-gray-300" />
<div>
<p className="font-semibold text-[color:var(--color-warning-300)]">
{post.author || "Anonymous"}
</p>
<p className="text-sm text-gray-400">{post.date}</p>
</div>
</div>
{post.imageUrl && ( setPosts(updatedPosts);
<img setUserReactions(reactions);
src={post.imageUrl} };
alt="Post related"
className="w-full max-h-64 object-cover rounded mb-4"
/>
)}
<p className="text-base text-neutral-100 mb-4">{post.text}</p> return (
<div className="px-6 py-10 max-w-full lg:max-w-2xl mx-auto font-sans text-neutral-100">
<div className="bg-[color:var(--color-surface-700)]/70 backdrop-blur-md rounded-xl px-6 py-5 mb-8 shadow-sm">
<h1 className="text-3xl sm:text-4xl font-bold mb-0 text-[color:var(--color-warning-300)]">
Posts
</h1>
</div>
<div className="flex gap-4 items-center"> <div className="bg-[color:var(--color-surface-600)]/70 backdrop-blur-md rounded-xl px-6 py-5 mb-8 shadow-sm">
<button <form onSubmit={handlePostSubmit} className="space-y-3">
onClick={() => handleLike(index)} <textarea
className={`px-3 py-1 rounded text-sm ${ className="w-full p-3 rounded bg-neutral-800 text-white"
userReactions[index]?.liked placeholder="Share your beverage..."
? "bg-success-800" value={postText}
: "bg-success-600 hover:bg-primary-600" onChange={(e) => setPostText(e.target.value)}
} text-white`} rows={4}
> />
👍 Like ({post.likes}) <input
</button> type="file"
<button accept="image/*"
onClick={() => handleWarning(index)} className="w-full p-2 rounded bg-neutral-800 text-white"
className={`px-3 py-1 rounded text-sm ${ onChange={(e) => setImageFile(e.target.files?.[0] || null)}
userReactions[index]?.warned />
? "bg-red-800" <button
: "bg-primary-500 hover:bg-red-600" type="submit"
} text-white`} className="px-4 py-2 bg-success-600 text-white rounded font-semibold"
> >
😭 Stop drinking that ({post.warnings}) Post
</button> </button>
</div> </form>
</div> </div>
))}
</div>
<div className="h-10" /> <div className="space-y-6">
</div> {posts.map((post, index) => (
); <div
key={index}
className="bg-[color:var(--color-surface-600)]/80 rounded-xl px-6 py-5 shadow-md"
>
<div className="flex items-center gap-4 mb-2">
<div className="w-10 h-10 rounded-full bg-neutral-800 border border-gray-300" />
<div>
<p className="font-semibold text-[color:var(--color-warning-300)]">
{post.author || "Anonymous"}
</p>
<p className="text-sm text-gray-400">{post.date}</p>
</div>
</div>
{post.imageUrl && (
<img
src={post.imageUrl}
alt="Post related"
className="w-full max-h-64 object-cover rounded mb-4"
/>
)}
<p className="text-base text-neutral-100 mb-4">{post.text}</p>
<div className="flex gap-4 items-center">
<button
onClick={() => handleLike(index)}
className={`px-3 py-1 rounded text-sm ${
userReactions[index]?.liked
? "bg-success-800"
: "bg-success-600 hover:bg-primary-600"
} text-white`}
>
👍 Like ({post.likes})
</button>
<button
onClick={() => handleWarning(index)}
className={`px-3 py-1 rounded text-sm ${
userReactions[index]?.warned
? "bg-red-800"
: "bg-primary-500 hover:bg-red-600"
} text-white`}
>
😭 Stop drinking that ({post.warnings})
</button>
</div>
</div>
))}
</div>
<div className="h-10" />
</div>
);
} }

View File

@@ -21,7 +21,9 @@ async function authenticateUser() {
export async function POST(req: Request) { export async function POST(req: Request) {
try { try {
// if (!(await authenticateUser())) return;
let userData = await authenticateUser();
if (!userData) return NextResponse.json({ message: "User not found" }, { status: 404 });
const formData = await req.formData(); const formData = await req.formData();
const file = formData.get("image"); const file = formData.get("image");
@@ -39,7 +41,14 @@ export async function POST(req: Request) {
const prompt = `Generate a 1-3 sentence description for this image.`; const prompt = `Generate a 1-3 sentence description for this image.`;
const data = await gemini.generateDescription(prompt, buffer); const data = await gemini.generateDescription(prompt, buffer);
let postData = await db.posts.create("6gi1f", data?.description); let postData = await db.posts.create(userData.id, data?.description, buffer);
if (!postData) {
return NextResponse.json(
{ message: "Failed to create post" },
{ status: 500 }
);
}
return NextResponse.json( return NextResponse.json(
{ message: "Image uploaded successfully", postData }, { message: "Image uploaded successfully", postData },

View File

@@ -11,6 +11,7 @@ const postSchema = new mongoose.Schema({
timeStamp: Date, timeStamp: Date,
reactions: Array, reactions: Array,
userId: reqString, userId: reqString,
image: Buffer
}); });
export class Post { export class Post {
@@ -31,13 +32,14 @@ export class Post {
return result.join(''); return result.join('');
} }
async create(userId:string, imageDes: string) { async create(userId:string, imageDes: string, image: Buffer) {
const newEntry = new this.model({ const newEntry = new this.model({
id: this.makeId(5), id: this.makeId(5),
imageDes: imageDes, imageDes: imageDes,
timeStamp: new Date().toISOString(), timeStamp: new Date().toISOString(),
reactions: [], reactions: [],
userId: userId userId: userId,
image
}); });
await newEntry.save(); await newEntry.save();
return newEntry; return newEntry;