Update App

This commit is contained in:
2025-04-13 07:43:11 -04:00
parent 2719927792
commit 814d5c1f1e
6 changed files with 174 additions and 52 deletions

View File

@@ -1,9 +1,50 @@
"use client"; "use client";
import { useDevice } from "@/lib/context/DeviceContext"; import { useDevice } from "@/lib/context/DeviceContext";
import React, { useEffect, useState } from "react";
import Post from "../../lib/components/Post";
function Mobile() { function Mobile() {
const { isAuthenticated, session } = useDevice(); const { isAuthenticated, session } = useDevice();
const [friendsPostsData, setFriendsPosts] = useState<any[]>([]);
function getFriendsPosts(friendId: any) {
fetch(`/api/users/${friendId}/posts`)
.then((res) => res.json())
.then((data) => {
if (data.posts) {
setFriendsPosts([...friendsPostsData, ...data.posts]);
} else {
console.error("No posts found for friend ID:", friendId);
}
})
.catch((err) => {
console.error("Error fetching friend's posts:", err);
});
}
// Fetch friends' posts
useEffect(() => {
if (isAuthenticated && session?.friends) {
let friendsIds = session.friends.map((friend: any) => friend.id);
// use /api/users/:id to get friend data
friendsIds.forEach((friendId: any) => {
fetch(`/api/users/${friendId}`)
.then((res) => res.json())
.then((data) => {
if (data.user) {
getFriendsPosts(data.user.id);
} else {
console.error("No user data found for friend ID:", friendId);
}
})
.catch((err) => {
console.error("Error fetching friend data:", err);
});
});
}
}, [isAuthenticated, session?.friends]);
return ( return (
<main className="flex flex-col gap-[32px] row-start-2 items-center mt-10 text-white"> <main className="flex flex-col gap-[32px] row-start-2 items-center mt-10 text-white">
@@ -24,7 +65,25 @@ function Mobile() {
<a href="/auth/login?screen_hint=login">Log in</a> <a href="/auth/login?screen_hint=login">Log in</a>
</button> </button>
</div> </div>
) : null} ) : (
<div className="w-full px-6">
<h2 className="text-2xl font-bold text-[color:var(--color-warning-300)] mb-4">
Activity Feed
</h2>
<div className="space-y-6">
{friendsPostsData.map((post, index) => (
<Post
key={index}
post={post}
allowReactions={true} // Allow reactions for friends' posts
onLike={() => console.log("Liked post:", post.id)}
onWarning={() => console.log("Warned post:", post.id)}
onDelete={() => {}} // No delete option for friends' posts
/>
))}
</div>
</div>
)}
</main> </main>
); );
} }
@@ -48,6 +107,6 @@ function Web() {
export default function Home() { export default function Home() {
const { isMobile, isSafari } = useDevice(); const { isMobile, isSafari } = useDevice();
if (isMobile && isSafari) return Mobile(); if (isMobile && isSafari) return <Mobile />;
else return Web(); else return <Web />;
} }

View File

@@ -201,7 +201,6 @@ export default function PostsPage() {
allowReactions={false} allowReactions={false}
key={index} key={index}
post={post} post={post}
userReactions={userReactions[index] || { liked: false, warned: false }}
onLike={() => handleLike(index)} onLike={() => handleLike(index)}
onWarning={() => handleWarning(index)} onWarning={() => handleWarning(index)}
onDelete={() => handleDelete(index)} // Pass the delete handler onDelete={() => handleDelete(index)} // Pass the delete handler

View File

@@ -0,0 +1,42 @@
import { NextResponse } from "next/server";
import { auth0 } from "../../../../../lib/scripts/auth0";
import { db } from "@/lib/scripts/db";
async function authenticateUser() {
const session = await auth0.getSession();
if (!session) {
return NextResponse.json({ message: "No session found" }, { status: 401 });
}
const sessionUser = session.user;
let userData = await db.users.findByEmail(sessionUser.email as string);
if (!userData) return NextResponse.json({ message: "User not found" }, { status: 404 });
return userData != null;
}
export async function GET(req: Request, { params }: any) {
try {
if (!(await authenticateUser())) return;
const { id } = params;
// Find the user by ID
const user = await db.users.findById(id);
if (!user) {
return NextResponse.json({ message: "User not found" }, { status: 404 });
}
// Fetch all posts for the user
const posts = await db.posts.getAllByUserId(id);
if (!posts || posts.length === 0) {
return NextResponse.json({ message: "No posts found for this user" }, { status: 404 });
}
return NextResponse.json({ posts }, { status: 200 });
} catch (error) {
console.error("Error fetching user posts:", error);
return NextResponse.json({ message: "Internal server error" }, { status: 500 });
}
}

View File

@@ -1,22 +1,24 @@
import type { MetadataRoute } from "next"; import type { MetadataRoute } from "next";
export default function manifest(): MetadataRoute.Manifest { export default function manifest(): MetadataRoute.Manifest {
return { return {
name: "Healthify", name: "Drink Happy",
short_name: "Healthify", short_name: "Drink Happy",
description: description: "Track your drinks, earn points, and improve your health with Drink Happy!",
"Healthy APP",
start_url: "/", start_url: "/",
display: "standalone", display: "standalone",
background_color: "#000000", background_color: "#1E293B", // Matches the app's dark theme
theme_color: "#000000", theme_color: "#1E293B", // Matches the app's dark theme
icons: [ icons: [
{ {
src: "/vercel.svg", src: "/cappylogosmall.png",
sizes: "192x192", sizes: "192x192",
type: "image/svg", type: "image/png",
},
{
src: "/cappylogosmall.png",
sizes: "512x512",
type: "image/png",
}, },
], ],
}; };

View File

@@ -1,6 +1,27 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Drinkify", title: "Drink Happy - Health Check & Game",
description: "Drinkify health check app / game", description: "Drink Happy is a fun and engaging app to track your drink choices, earn points, and improve your health!",
keywords: ["Drink Happy", "Health", "Game", "Drink Tracker", "Healthy Lifestyle"],
themeColor: "#1E293B", // Matches the app's dark theme
appleWebApp: {
title: "Drink Happy",
statusBarStyle: "black-translucent",
capable: true,
},
manifest: "/manifest.json",
openGraph: {
title: "Drink Happy - Health Check & Game",
description: "Drink Happy is a fun and engaging app to track your drink choices, earn points, and improve your health!",
siteName: "Drink Happy",
images: [
{
url: "/cappylogosmall.png",
width: 512,
height: 512,
alt: "Drink Happy Logo",
},
],
},
}; };

View File

@@ -14,7 +14,6 @@ interface PostProps {
onLike: () => void; onLike: () => void;
onWarning: () => void; onWarning: () => void;
onDelete: () => void; // Callback for deleting the post onDelete: () => void; // Callback for deleting the post
userReactions: { liked: boolean; warned: boolean };
allowReactions: boolean; // New property to toggle reactions allowReactions: boolean; // New property to toggle reactions
} }
@@ -23,10 +22,12 @@ export default function Post({
onLike, onLike,
onWarning, onWarning,
onDelete, onDelete,
userReactions,
allowReactions, allowReactions,
}: PostProps) { }: PostProps) {
const [userData, setUserData] = useState<{ username: string; avatar: number } | null>({username: "Loading...", avatar: 1}); const [userData, setUserData] = useState<{ username: string; avatar: number } | null>({
username: "Loading...",
avatar: 1,
});
useEffect(() => { useEffect(() => {
// Fetch the username and avatar based on the userId // Fetch the username and avatar based on the userId
@@ -89,30 +90,28 @@ export default function Post({
{/* Post Actions */} {/* Post Actions */}
<div className="flex gap-4 items-center"> <div className="flex gap-4 items-center">
{allowReactions && (
<>
<button <button
onClick={onLike} onClick={onLike}
disabled={!allowReactions} // Disable button if allowReactions is false
className={`px-3 py-1 rounded text-sm ${ className={`px-3 py-1 rounded text-sm ${
userReactions.liked allowReactions
? "bg-success-800" ? "bg-success-600 hover:bg-primary-600 text-white"
: "bg-success-600 hover:bg-primary-600" : "bg-gray-500 text-gray-300 cursor-not-allowed"
} text-white`} }`}
> >
👍 Like ({post.reactions.filter((reaction) => reaction.liked).length}) 👍 Like ({post.reactions.filter((reaction) => reaction.liked).length})
</button> </button>
<button <button
onClick={onWarning} onClick={onWarning}
disabled={!allowReactions} // Disable button if allowReactions is false
className={`px-3 py-1 rounded text-sm ${ className={`px-3 py-1 rounded text-sm ${
userReactions.warned allowReactions
? "bg-red-800" ? "bg-primary-500 hover:bg-red-600 text-white"
: "bg-primary-500 hover:bg-red-600" : "bg-gray-500 text-gray-300 cursor-not-allowed"
} text-white`} }`}
> >
😭 Stop drinking that ({post.reactions.filter((reaction) => reaction.warned).length}) 😭 Stop drinking that ({post.reactions.filter((reaction) => reaction.warned).length})
</button> </button>
</>
)}
<button <button
onClick={onDelete} onClick={onDelete}
className="px-3 py-1 rounded text-sm bg-red-600 hover:bg-red-700 text-white" className="px-3 py-1 rounded text-sm bg-red-600 hover:bg-red-700 text-white"