-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #274 from ShivanshPlays/wishlist-frontend
a global wishlist context, a dedicated wishlist page with styling, responsivenessand functionality, and a functional wishlist button on the dishes page
- Loading branch information
Showing
10 changed files
with
304 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
alimento-nextjs/app/(PublicRoutes)/wishlist/components/wishlistItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
"use client"; | ||
import { deleteWishlist } from "@/actions/customer/wishlist/DELETE_wishlist"; | ||
import { DishWithImages } from "@/app/vendor/[vendorId]/page"; | ||
import { Button } from "@/components/ui/button"; | ||
import { useWishlist } from "@/context/customerWishlistProvider"; | ||
import Image from "next/image"; | ||
import { useEffect } from "react"; | ||
import toast from "react-hot-toast"; | ||
|
||
interface wishlistItemProps { | ||
dish: DishWithImages; | ||
dishId: string; | ||
customerId: string; | ||
} | ||
// WishlistItem.js | ||
const WishlistItem: React.FC<wishlistItemProps> = ({ | ||
dish, | ||
dishId, | ||
customerId, | ||
}) => { | ||
const { removeFromWishlists, loading, error } = useWishlist(); | ||
|
||
|
||
return ( | ||
|
||
<div className="border flex items-center justify-center flex-col dark:border-gray-200 max-w-full p-4 rounded-lg shadow-md hover:shadow-lg transition"> | ||
{error? toast.error(error):null} | ||
<Image | ||
width={1000} | ||
height={1000} | ||
src={dish.images[0].url} | ||
alt={dish.name} | ||
className="w-full h-full object-cover rounded border-b" | ||
/> | ||
<h2 className="mt-2 text-xl dark:text-gray-200 font-semibold"> | ||
{dish.name} | ||
</h2> | ||
<p className="text-lg text-gray-600">₹{dish.price}</p> | ||
<div className="mt-4 flex justify-between gap-2"> | ||
<Button | ||
disabled={loading} | ||
onClick={() => { | ||
removeFromWishlists(customerId, dishId); | ||
}} | ||
variant="outline" | ||
className="dark:text-gray-200 dark:hover:bg-[#f8f8f8] dark:hover:text-gray-700" | ||
> | ||
Remove | ||
</Button> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default WishlistItem; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
"use client"; | ||
import { Button } from "@/components/ui/button"; | ||
import { useSession } from "next-auth/react"; | ||
import { useEffect } from "react"; | ||
import { Toaster } from "react-hot-toast"; | ||
import Link from "next/link"; | ||
import { Spinner } from "@/components/ui/spinner"; | ||
import WishlistItem from "./components/wishlistItem"; | ||
import { useWishlist } from "@/context/customerWishlistProvider"; | ||
|
||
const WishlistPage = () => { | ||
const { data: session } = useSession(); | ||
const { Wishlists, fetchWishlists, loading } = useWishlist(); | ||
|
||
useEffect(() => { | ||
if (session?.user?.id) { | ||
fetchWishlists(session.user.id); | ||
} | ||
}, [session]); | ||
|
||
if (loading) { | ||
return <Spinner />; | ||
} | ||
|
||
return ( | ||
<> | ||
<Toaster /> | ||
<div className="h-full dark:bg-DarkGray pb-10"> | ||
<div className="relative flex items-center justify-center h-96 bg-cover bg-center bg-no-repeat mb-20 p-8 bg-[url('/wishlist.jpg')]"> | ||
{/* Overlay */} | ||
<div className="absolute inset-0 bg-black opacity-50"></div> | ||
|
||
{/* Title Text */} | ||
<div className="relative z-10 text-center"> | ||
<h1 className="text-3xl md:text-5xl lg:text-7xl text-white font-extrabold"> | ||
Wish List | ||
</h1> | ||
</div> | ||
</div> | ||
|
||
<div className="mt-5 flex items-center justify-center"> | ||
{Wishlists && Wishlists.length > 0 ? ( | ||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6 px-6 max-w-screen-xl mx-auto"> | ||
{Wishlists.map((item) => ( | ||
item.dish && item.dish.id && ( | ||
<WishlistItem | ||
key={item.id} | ||
dishId={item.dish.id} | ||
customerId={session?.user.id || ""} | ||
dish={item.dish} | ||
/> | ||
) | ||
))} | ||
</div> | ||
) : ( | ||
<div className="text-center text-gray-700 dark:text-gray-500"> | ||
<p className="text-lg">Your wishlist is empty!</p> | ||
<Link href="/shops"> | ||
<Button className="mt-4 px-6 py-3 bg-customTeal text-white dark:bg-Green dark:hover:bg-opacity-80 transition duration-200 transform hover:scale-105"> | ||
Continue Shopping | ||
</Button> | ||
</Link> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export default WishlistPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
"use client"; | ||
|
||
import { createWishlist } from "@/actions/customer/wishlist/CREATE_wishlist"; | ||
import { deleteWishlist } from "@/actions/customer/wishlist/DELETE_wishlist"; | ||
import { checkWishlistExists } from "@/actions/customer/wishlist/EXISTS_wishlist"; | ||
import { getWishlistsBycustomer, WishlistWithDish } from "@/actions/customer/wishlist/GETBYCUSTOMER_wishlist"; | ||
import React, { createContext, useContext, useState, useEffect } from "react"; | ||
|
||
|
||
|
||
type WishlistContextType = { | ||
Wishlists: WishlistWithDish[]; | ||
loading: boolean; | ||
error: string | null; | ||
fetchWishlists: (customerId: string) => Promise<void>; | ||
addToWishlists: (customerId: string, dishId: string) => Promise<void>; | ||
removeFromWishlists: (customerId: string, dishId: string) => Promise<void>; | ||
isWishlisted: (customerId: string, dishId: string) => Promise<boolean>; | ||
}; | ||
|
||
// Create context with an initial value of null | ||
const WishlistContext = createContext<WishlistContextType | null>(null); | ||
|
||
export function WishlistProvider({ children }: { children: React.ReactNode }) { | ||
const [Wishlists, setWishlists] = useState<WishlistWithDish[]>([]); | ||
const [loading, setLoading] = useState<boolean>(false); | ||
const [error, setError] = useState<string | null>(null); | ||
|
||
// Fetch all Wishlists for a specific customer | ||
const fetchWishlists = async (customerId: string) => { | ||
setLoading(true); | ||
setError(null); | ||
try { | ||
const response = await getWishlistsBycustomer({ customerId }); | ||
if (response.success) { | ||
console.log(response.data) | ||
|
||
if(!response.data){ | ||
return | ||
} | ||
setWishlists(response.data); | ||
} else { | ||
setError(response.error || "Unknown error"); | ||
} | ||
} catch (err) { | ||
console.error("[Wishlist_FETCH_ERROR]", err); | ||
setError("Error fetching Wishlists"); | ||
} finally { | ||
setLoading(false); | ||
} | ||
}; | ||
|
||
// Add a Wishlist | ||
const addToWishlists = async (customerId: string, dishId: string) => { | ||
setLoading(true); | ||
setError(null); | ||
try { | ||
const response = await createWishlist({ customerId, dishId }); | ||
if (response.success && response.data) { | ||
setWishlists((prev) => [...prev, response.data as WishlistWithDish]); | ||
} else { | ||
setError(response.error || "Unknown error"); | ||
} | ||
} catch (err) { | ||
console.error("[Wishlist_ADD_ERROR]", err); | ||
setError("Error adding Wishlist"); | ||
} finally { | ||
setLoading(false); | ||
} | ||
}; | ||
|
||
// Remove a Wishlist | ||
const removeFromWishlists = async (customerId: string, dishId: string) => { | ||
setLoading(true); | ||
setError(null); | ||
try { | ||
// console.log(customerId,dishId) | ||
const response = await deleteWishlist({ customerId, dishId }); | ||
if (response.success && response.data) { | ||
setWishlists((prev) => | ||
prev.filter((Wishlist) => Wishlist.dishId !== dishId) | ||
); | ||
} else { | ||
setError(response.error || "Unknown error"); | ||
} | ||
} catch (err) { | ||
console.error("[Wishlist_REMOVE_ERROR]", err); | ||
setError("Error removing Wishlist"); | ||
} finally { | ||
setLoading(false); | ||
} | ||
}; | ||
|
||
// Check if a Wishlist exists | ||
const isWishlisted = async (customerId: string, dishId: string) => { | ||
setLoading(true); | ||
setError(null); | ||
try { | ||
const response = await checkWishlistExists({ customerId, dishId }); | ||
return response.success && response.exists; | ||
} catch (err) { | ||
console.error("[Wishlist_CHECK_ERROR]", err); | ||
setError("Error checking Wishlist"); | ||
return false; | ||
} finally { | ||
setLoading(false); | ||
} | ||
}; | ||
|
||
return ( | ||
<WishlistContext.Provider | ||
value={{ | ||
Wishlists, | ||
loading, | ||
error, | ||
fetchWishlists, | ||
addToWishlists, | ||
removeFromWishlists, | ||
isWishlisted, | ||
}} | ||
> | ||
{children} | ||
</WishlistContext.Provider> | ||
); | ||
} | ||
|
||
// Custom hook for accessing the Wishlist context | ||
export function useWishlist() { | ||
const context = useContext(WishlistContext); | ||
if (!context) { | ||
throw new Error("useWishlist must be used within a WishlistProvider"); | ||
} | ||
return context; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.