Update Post Page
This commit is contained in:
@@ -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>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 },
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user