diff --git a/src/app/(user)/projects/[id]/page.tsx b/src/app/(user)/projects/[id]/page.tsx
index e577f90..b2715e8 100644
--- a/src/app/(user)/projects/[id]/page.tsx
+++ b/src/app/(user)/projects/[id]/page.tsx
@@ -434,7 +434,7 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
{project.contributors.length > 0 && (
-
+
{project.contributors.length}
diff --git a/src/app/api/projects/route.ts b/src/app/api/projects/route.ts
index 76f839a..f555d18 100644
--- a/src/app/api/projects/route.ts
+++ b/src/app/api/projects/route.ts
@@ -72,6 +72,25 @@ export async function GET(req: Request) {
];
}
+ const session = await getServerSession(authOptions);
+ const userId = session?.user?.id;
+
+ let userLikes: string[] = [];
+ if (userId) {
+ const userProfile = await db.profile.findUnique({
+ where: { userId },
+ select: { id: true }
+ });
+
+ if (userProfile) {
+ const likes = await db.like.findMany({
+ where: { profileId: userProfile.id },
+ select: { projectId: true }
+ });
+ userLikes = likes.map(like => like.projectId);
+ }
+ }
+
const projects = await db.project.findMany({
skip: (page - 1) * limit,
take: limit,
@@ -103,8 +122,14 @@ export async function GET(req: Request) {
},
});
+ const projectsWithLikes = projects.map(project => ({
+ ...project,
+ isLiked: userLikes.includes(project.id)
+ }));
+
+
// Custom sort to ensure Active > Planning > Completed
- const sortedProjects = projects.sort((a, b) => {
+ const sortedProjects = projectsWithLikes.sort((a, b) => {
const statusOrder: Record = {
'Active': 1,
'Planning': 2,
diff --git a/src/components/LikeButton.tsx b/src/components/LikeButton.tsx
index 44a4c65..6e8ac5a 100644
--- a/src/components/LikeButton.tsx
+++ b/src/components/LikeButton.tsx
@@ -1,16 +1,16 @@
"use client";
-import { useState } from 'react';
-import { FaHeart, FaRegHeart } from 'react-icons/fa';
-import { useToast } from '@/components/ui/toast-1';
-import { clsx } from 'clsx';
-import { useSession } from 'next-auth/react';
-import { LoginModal } from './LoginModal';
+import { useState } from "react";
+import { FaHeart, FaRegHeart } from "react-icons/fa";
+import { useToast } from "@/components/ui/toast-1";
+import { clsx } from "clsx";
+import { useSession } from "next-auth/react";
+import { LoginModal } from "./LoginModal";
interface LikeButtonProps {
projectId: string;
isInitiallyLiked: boolean;
- initialLikeCount: number;
+ initialLikeCount: number;
disabled?: boolean;
}
@@ -37,7 +37,7 @@ const LikeButton = ({
if (isLoading || disabled) return;
setIsLoading(true);
-
+
// --- 1. STORE PREVIOUS STATE FOR ROLLBACK ---
const previousLikeState = isLiked;
const previousLikeCount = likeCount;
@@ -45,18 +45,19 @@ const LikeButton = ({
// --- 2. OPTIMISTIC UPDATE ---
// Update both the icon and the count immediately
setIsLiked(!previousLikeState);
- setLikeCount(previousLikeState ? previousLikeCount - 1 : previousLikeCount + 1);
+ setLikeCount(
+ previousLikeState ? previousLikeCount - 1 : previousLikeCount + 1
+ );
try {
// 3. API CALL (same as before)
const response = await fetch(`/api/projects/${projectId}/like`, {
- method: 'POST',
+ method: "POST",
});
if (!response.ok) {
- throw new Error('Failed to update like status');
+ throw new Error("Failed to update like status");
}
-
} catch (error) {
console.error(error);
@@ -64,8 +65,7 @@ const LikeButton = ({
// If the API call fails, revert both states
setIsLiked(previousLikeState);
setLikeCount(previousLikeCount);
- showToast('Failed to update like status', 'error');
-
+ showToast("Failed to update like status", "error");
} finally {
setIsLoading(false);
}
@@ -82,29 +82,27 @@ const LikeButton = ({
onClick={toggleLike}
disabled={isDisabled}
className={clsx(
- 'inline-flex items-center justify-center transition-opacity h-4 w-4', // Added h-4 w-4
+ "inline-flex items-center justify-center transition-opacity h-6 w-6",
{
- 'cursor-not-allowed opacity-70': isDisabled,
- 'cursor-pointer': !isDisabled,
+ "cursor-not-allowed opacity-70": isDisabled,
+ "cursor-pointer": !isDisabled,
}
)}
- aria-label={
- disabled ? 'Login to like' : isLiked ? 'Unlike' : 'Like'
- }
+ aria-label={disabled ? "Login to like" : isLiked ? "Unlike" : "Like"}
>
{isLiked ? (
-
+
) : (
-
+
)}
-
+
{/* Render the likeCount state, which updates instantly */}
- {likeCount}
+ {likeCount}
setLoginOpen(false)} />
>
);
};
-export default LikeButton;
\ No newline at end of file
+export default LikeButton;
diff --git a/src/components/ProjectCard.tsx b/src/components/ProjectCard.tsx
index 6a172e8..6556105 100644
--- a/src/components/ProjectCard.tsx
+++ b/src/components/ProjectCard.tsx
@@ -21,6 +21,7 @@ interface Project {
projectStatus: "Planning" | "Active" | "Completed";
isActive: boolean;
authorId: string;
+ isLiked: boolean;
author: {
id: string;
name: string;
@@ -136,11 +137,13 @@ export default function ProjectCard() {
ref={index === projects.length - 1 ? lastProjectRef : null}
>
{
+ projectId: string; // Add projectId here
title: string;
tagline: string;
description: string;
status: "Planning" | "Active" | "Completed";
- likes: number;
+ initialLikeCount: number;
+ isInitiallyLiked: boolean;
// comments: number;
href: string;
githubUrl?: string; // Optional GitHub URL
@@ -99,13 +102,15 @@ const ProjectCard = React.forwardRef(
tagline,
description,
status,
- likes,
+ initialLikeCount,
+ isInitiallyLiked,
// comments,
href,
githubUrl,
techStack = [],
isAuthenticated,
onViewProject,
+ projectId, // Destructure projectId to prevent it from being passed to the div
...props
},
ref
@@ -121,18 +126,15 @@ const ProjectCard = React.forwardRef(
};
checkMobile();
- window.addEventListener('resize', checkMobile);
+ window.addEventListener("resize", checkMobile);
- return () => window.removeEventListener('resize', checkMobile);
+ return () => window.removeEventListener("resize", checkMobile);
}, []);
// Toggle expansion on mobile
const handleCardClick = (e: React.MouseEvent) => {
// Don't toggle if clicking on links or buttons
- if (
- isMobile &&
- !(e.target as HTMLElement).closest('a, button')
- ) {
+ if (isMobile && !(e.target as HTMLElement).closest("a, button")) {
setIsExpanded(!isExpanded);
}
};
@@ -162,7 +164,6 @@ const ProjectCard = React.forwardRef(
>
{/* Content Container */}
-
{/* Top Section: Status Badge and GitHub Link */}
@@ -240,63 +241,68 @@ const ProjectCard = React.forwardRef
(
{/* Tech Stack Section (shown on hover for desktop, on click for mobile) */}
{techStack.length > 0 && (
-
+
TECH STACK
- {techStack.filter(tech => tech && tech.name).map((tech, index) => (
-
+ {techStack
+ .filter((tech) => tech && tech.name)
+ .map((tech, index) => (
- {tech?.icon || null}
+
+ {tech?.icon || null}
+
+
+ {tech.name}
+
-
- {tech.name}
-
-
- ))}
+ ))}
)}
-
-
);
@@ -304,4 +310,4 @@ const ProjectCard = React.forwardRef(
);
ProjectCard.displayName = "ProjectCard";
-export { ProjectCard };
\ No newline at end of file
+export { ProjectCard };