Skip to content

Commit

Permalink
bookmarkFE: added global state and frontend modifications to implemen…
Browse files Browse the repository at this point in the history
…t the feature (#516)

* bookmark schema and server actions

* added testing API for bookmark

* half baked

* bookmarkFE: added global state and modifications to implement the feature
  • Loading branch information
ShivanshPlays authored Nov 7, 2024
1 parent c5a5afd commit e7c3722
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 54 deletions.
22 changes: 17 additions & 5 deletions scruter-nextjs/actions/user/bookmarks/GETBYUSER_bookmark.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
'use server';

import prismadb from '@/lib/prismadb';
import { Bookmark } from '@prisma/client';
import { Bookmark, Image, Listing } from '@prisma/client';

// Interface for the Bookmark with Listing and Images
export interface BookmarkWithListing extends Bookmark {
listing: Listing & {
images: Image[]; // Assuming images is an array of strings (URLs)
};
}

export async function getBookmarksByUser({
userId,
}: {
userId: string;
}): Promise<{ success: boolean; error?: string; data?: Bookmark[] }> {
}): Promise<{ success: boolean; error?: string; data?: BookmarkWithListing[] }> {
try {
// Fetch bookmarks including related listing data and images
const bookmarks = await prismadb.bookmark.findMany({
where: { userId },
include: {
listing: true, // Include related listing details
listing: {
include: {
images: true, // Include the images field from the listing
},
},
},
});

return { success: true, data: bookmarks };
// console.log(bookmarks)
return { success: true, data: bookmarks as BookmarkWithListing[] };
} catch (error) {
console.error('[GET_BOOKMARKS_BY_USER_ERROR]', error);
return { success: false, error: 'Error fetching bookmarks' };
Expand Down
76 changes: 38 additions & 38 deletions scruter-nextjs/app/(routes)/(mainNavPages)/[userId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { Bookmark, Delete, Edit, Mail, Text, Trash, User } from 'lucide-react';
import { getuserById } from '@/actions/user/userGET';
import toast from 'react-hot-toast';
import { User as UserType } from '@prisma/client';
import { useBookmark } from '@/context/UserBookmarkProvider';

export default function UserProfile() {
const { data: session } = useSession();
const [user, setUser] = useState<UserType | null>(null);
const [bookmarks, setBookmarks] = useState([]);

const { bookmarks, fetchBookmarks, removeFromBookmarks, loading, error } =
useBookmark();

useEffect(() => {
if (session) {
Expand All @@ -29,31 +32,21 @@ export default function UserProfile() {
}
};
fetchUserData();

fetchBookmarks(session.user.id);
}
}, [session]);
}, []);

const dummyBookmarks = [
{
id: '1',
name: 'Spicy Fried Chicken',
price: 25,
description: 'A delicious spicy fried chicken dish',
images: ['/seed/food1a.jpeg'],
},
{
id: '2',
name: 'Pizza',
price: 15,
description: 'A large Pizza',
images: ['/seed/food2a.jpg'],
},
];


console.log(user);
// if(!loading&&bookmarks.length>0){
// console.log('BOOKMARKSSSSSSS' + bookmarks[0].listing);
// }

return (
<div className="flex flex-col items-center py-8 px-4 md:px-10 lg:px-20">
{/* User Info Section */}
{user && (
{user && user.id && (
<>
<Card className="w-full max-w-7xl p-6 mb-8 shadow-md border border-gray-200 rounded-md">
<CardHeader className="flex items-center">
Expand All @@ -76,51 +69,58 @@ export default function UserProfile() {
</div>
</CardHeader>
</Card>
<div className="w-full max-w-7xl">
<h2 className="text-2xl font-bold mb-4 flex items-center">
<Bookmark className="h-6 w-6 text-gray-600 mr-2" />
Bookmarked Listings
</h2>
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
{dummyBookmarks.map(listing => (

{loading && (
<div>Loading Bookmarks....</div>
)}
{!loading && (

<div className="w-full max-w-7xl">
<h2 className="text-2xl font-bold mb-4 flex items-center">
<Bookmark className="h-6 w-6 text-gray-600 mr-2" />
Bookmarked Listings
</h2>
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
{bookmarks.length>0 && bookmarks.map(bookmark => (
<Card
key={listing.id}
key={bookmark.id}
className="shadow-md border border-gray-200 rounded-md"
>
<CardHeader className="p-3">
<CardTitle className="text-lg font-semibold">
{listing.name}
{bookmark.listing.name}
</CardTitle>
<p className="text-sm text-gray-600 truncate">
{listing.description}
{bookmark.listing.description}
</p>
</CardHeader>
<CardContent className="p-3">
<img
src={listing.images[0]}
src={bookmark.listing.images[0].url}
className="h-32 w-full object-cover rounded-md mb-2"
alt={listing.name}
alt={bookmark.listing.name}
/>
<p className="text-gray-700 font-bold">${listing.price}</p>
<p className="text-gray-700 font-bold">${bookmark.listing.price}</p>

{/* Delete Button */}

<button
// onClick={() => deleteBookmark(listing.id)}
onClick={() => removeFromBookmarks(user.id , bookmark.listing.id)}
className="mt-4 bg-red-500 text-white py-1 px-3 rounded-md hover:bg-red-600 transition duration-200"
>
<Trash className="h-5 w-5" />
</button>
</CardContent>
</Card>
))}
</div>
</div>

{dummyBookmarks.length === 0 && (
{bookmarks.length === 0 && (
<p className="text-center text-gray-500 mt-4">
No bookmarks yet.
</p>
)}
</div>
</div>
)}
</>
)}
</div>
Expand Down
4 changes: 3 additions & 1 deletion scruter-nextjs/app/(routes)/(mainNavPages)/food/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import axios from 'axios';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSearch } from '@fortawesome/free-solid-svg-icons'; // Import FontAwesomeIcon
import { GetAllListing, ListingWithImages } from '@/actions/seller/listing';
import { Listing } from '@prisma/client';
import toast, { Toaster } from 'react-hot-toast';
import ListingCardFE from '@/components/listingCardFE';

Expand All @@ -15,6 +14,8 @@ const FoodPage: React.FC = () => {
const [query, setQuery] = useState('');
const [sort, setSort] = useState<"" | "asc" | "desc" | undefined>('');



useEffect(() => {
const fetchData = async () => {
setLoading(true);
Expand Down Expand Up @@ -132,6 +133,7 @@ const FoodPage: React.FC = () => {
) : (
foodItems.map(food => (
<ListingCardFE
id={food.id}
key={food.id}
name={food.name}
price={food.price}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ const ForSalePage: React.FC = () => {
) : (
items.map(item => (
<ListingCardFE
id={item.id}
key={item.id}
name={item.name}
price={item.price}
Expand Down
1 change: 1 addition & 0 deletions scruter-nextjs/app/(routes)/(mainNavPages)/house/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ const HousePage: React.FC = () => {
) : (
houses.map(house => (
<ListingCardFE
id={house.id}
key={house.id}
name={house.name}
price={house.price}
Expand Down
9 changes: 6 additions & 3 deletions scruter-nextjs/app/(routes)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Navbar from '@/components/common/navbar';
import Footer from '@/components/common/footer';
import { BookmarkProvider } from '@/context/UserBookmarkProvider';

export default function RootLayout({
children,
Expand All @@ -8,9 +9,11 @@ export default function RootLayout({
}>) {
return (
<>
<Navbar />
{children}
<Footer />
<BookmarkProvider>
<Navbar />
{children}
<Footer />
</BookmarkProvider>
</>
);
}
53 changes: 46 additions & 7 deletions scruter-nextjs/components/listingCardFE.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';
import React from 'react';

import React, { useEffect, useState } from 'react';
import { Image as ImageInterface } from '@prisma/client';
import {
Carousel,
Expand All @@ -8,22 +9,46 @@ import {
} from '@/components/ui/carousel';
import Image from 'next/image';
import Autoplay from 'embla-carousel-autoplay';
import { Button } from '@/components/ui/button'; // Importing the Button component from Shadcn
import Link from 'next/link';
import { Button } from '@/components/ui/button';
import { useBookmark } from '@/context/UserBookmarkProvider';
import { useSession } from 'next-auth/react';

interface ListingCardProps {
id: string;
name: string;
price: number;
description: string;
images: ImageInterface[];
images: ImageInterface[];
}

const ListingCardFE: React.FC<ListingCardProps> = ({
id,
name,
price,
description,
images,
}) => {
const { addToBookmarks, isBookmarked } = useBookmark();
const session = useSession();
const userId = session.data?.user.id;

// State to track if the listing is bookmarked
const [isAlreadyBookmarked, setIsAlreadyBookmarked] = useState<boolean>(false);

// Check if the listing is bookmarked when the component mounts
useEffect(() => {
const checkBookmarkStatus = async () => {
if (userId) {
const bookmarked = await isBookmarked(userId, id);
setIsAlreadyBookmarked(bookmarked);
}
};

if (userId && id) {
checkBookmarkStatus();
}
}, []); // Only rerun when userId or id changes

return (
<div className="bg-white overflow-hidden shadow-lg rounded-lg">
<Carousel
Expand Down Expand Up @@ -61,9 +86,23 @@ const ListingCardFE: React.FC<ListingCardProps> = ({
<Button variant="outline" className="text-blue-600">
Add
</Button>
<Button variant="outline" className="text-red-600">
Bookmark
</Button>
{userId && session.data?.user.role === 'user' && !isAlreadyBookmarked && (
<Button
onClick={() => {
addToBookmarks(userId, id);
setIsAlreadyBookmarked(true); // Update the state to reflect the bookmark status
}}
variant="outline"
className="text-red-600"
>
Bookmark
</Button>
)}
{userId && session.data?.user.role === 'user' && isAlreadyBookmarked && (
<Button variant="outline" className="text-green-600">
Bookmarked
</Button>
)}
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit e7c3722

Please sign in to comment.