Skip to content

Commit

Permalink
Merge pull request #126 from 202306-NEA-DZ-FEW/119-create-my-listings…
Browse files Browse the repository at this point in the history
…-page

Create my listings page
  • Loading branch information
samiba6 committed Nov 20, 2023
2 parents afe58f6 + 94b0491 commit 220f675
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 41 deletions.
2 changes: 1 addition & 1 deletion src/components/ProfileDropdown/ProfileDropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function ProfileDropdown() {
</li>
<li>
<Link
href='#'
href='/mylistings'
className='text-[#7874F2] font-semibold hover:text-grey'
>
Listings
Expand Down
82 changes: 42 additions & 40 deletions src/components/SideBar/SideBar.jsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,42 @@
// Sidebar.jsx

import React, { useEffect, useState } from "react";
import Link from "next/link";
import firebase from "firebase/app";
import "firebase/firestore";
import { collection, doc, getDoc } from "firebase/firestore";
import { db } from "../../util/firebase.js";
import { MdOutlineKeyboardDoubleArrowLeft } from "react-icons/md";
import { FiEdit3 } from "react-icons/fi";
import { BiLogOut } from "react-icons/bi";
import { BsClipboard2Fill, BsFillBoxSeamFill } from "react-icons/bs";
import {
MdKeyboardDoubleArrowLeft,
MdOutlineKeyboardDoubleArrowLeft,
} from "react-icons/md";
import { RxDoubleArrowLeft, RxDoubleArrowRight } from "react-icons/rx";
import { BiLogOut } from "react-icons/bi";
import { doc, getDoc } from "firebase/firestore";
import { useAuth } from "@/context/AuthContext.js";
import { useRouter } from "next/router.js";
import { ToastContainer, toast } from "react-toastify";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { db } from "../../util/firebase.js";
import Image from "next/image.js";

const SideBar = () => {
const Sidebar = () => {
const [selectedLink, setSelectedLink] = useState(null);
const [userInfo, setUserInfo] = useState(null);
const [collapsed, setCollapsed] = useState(false);
const { logout } = useAuth();
const { currentUser, logout } = useAuth();
const route = useRouter();

useEffect(() => {
const fetchUserInfo = async () => {
const userId = "e43JDIG05abGPsH43xEKBNsD49e2";
const userInfoRef = doc(
db,
"userinfo",
"e43JDIG05abGPsH43xEKBNsD49e2"
);
const userInfoSnapshot = await getDoc(userInfoRef);
if (currentUser) {
const userId = currentUser.uid;
const userInfoRef = doc(db, "userinfo", userId);
const userInfoSnapshot = await getDoc(userInfoRef);

if (userInfoSnapshot.exists()) {
const userInfoData = userInfoSnapshot.data();
setUserInfo(userInfoData);
if (userInfoSnapshot.exists()) {
const userInfoData = userInfoSnapshot.data();
setUserInfo(userInfoData);
}
}
};

fetchUserInfo();
}, []);
}, [currentUser]);

const handleLinkClick = (link) => {
if (collapsed) {
Expand All @@ -48,13 +45,13 @@ const SideBar = () => {
setSelectedLink(link);
}
};
// logout function

const handleLogout = async () => {
try {
await logout();
route.push("/signin");
} catch (error) {
toast.error("Failed to log out");
console.error("Failed to log out", error);
}
};

Expand Down Expand Up @@ -92,21 +89,24 @@ const SideBar = () => {
/>

<div className='flex flex-col items-center mt-20 mb-4 space-y-4'>
<img
src={userInfo ? userInfo.photo : ""}
alt='User'
<Image
src={currentUser.photoURL || "/images/profile.jpg"}
alt='profile-pic'
width={80}
height={80}
className='w-25 h-25 rounded-full mb-2'
/>
{!collapsed && userInfo && (
<div className='text-center'>
<h2 className='text-xl text-[#585785] font-bold mb-1'>{`${userInfo.name} ${userInfo.surname}`}</h2>
<p className='text-[#585785] mb-2'>{userInfo.email}</p>
<p className='text-[#585785] mb-4'>{`${userInfo.address.city}, ${userInfo.address.country}`}</p>
<h2 className='text-xl text-[#585785] font-bold mb-1'>{`${userInfo?.name} ${userInfo?.surname}`}</h2>
<p className='text-[#585785] mb-2'>{userInfo?.email}</p>
<p className='text-[#585785] mb-4'>{`${userInfo?.address?.city}, ${userInfo?.address?.country}`}</p>
</div>
)}
</div>
<div className='flex flex-col items-center space-y-10'>
<div
<Link
href='/editprofile'
className={`flex items-center text-[#585785] text-2xl cursor-pointer font-semibold p-3 rounded-lg ${
selectedLink === "EditProfile" ? "bg-[#90EEE1]" : ""
}`}
Expand All @@ -118,8 +118,9 @@ const SideBar = () => {
{!collapsed && (
<span className='hidden sm:inline'>Edit Profile</span>
)}
</div>
<div
</Link>
<Link
href='/mylistings'
className={`flex items-center text-[#585785] text-2xl cursor-pointer font-semibold p-3 rounded-lg ${
selectedLink === "MyListings" ? "bg-[#90EEE1]" : ""
}`}
Expand All @@ -131,9 +132,10 @@ const SideBar = () => {
{!collapsed && (
<span className='hidden sm:inline'>My Listings</span>
)}
</div>
<div
className={`flex items-center text-[#585785] text-2xl cursor-pointer font-semibold ${
</Link>
<Link
href='/myorders'
className={`flex items-center text-[#585785] text-2xl cursor-pointer font-semibold p-3 rounded-lg ${
selectedLink === "MyOrders" ? "bg-[#90EEE1]" : ""
}`}
onClick={() => handleLinkClick("MyOrders")}
Expand All @@ -144,7 +146,7 @@ const SideBar = () => {
{!collapsed && (
<span className='hidden sm:inline'>My Orders</span>
)}
</div>
</Link>
</div>
{!collapsed && (
<div className='mt-auto mb-4'>
Expand All @@ -162,4 +164,4 @@ const SideBar = () => {
);
};

export default SideBar;
export default Sidebar;
90 changes: 90 additions & 0 deletions src/components/listingcard/ListingCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import Image from "next/image";
import Link from "next/link";
import React from "react";
import { FaTrash } from "react-icons/fa";
import { useState } from "react";
import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { deleteDoc, doc } from "firebase/firestore";
import { db } from "@/util/firebase";

function ListingCard({ product }) {
const [isDeleting, setIsDeleting] = useState(false);

const handleDelete = async () => {
const confirmDelete = window.confirm(
"Are you sure you want to delete this product?"
);

if (confirmDelete) {
try {
setIsDeleting(true);

const productRef = doc(db, "products", product.id);
await deleteDoc(productRef);

toast.success("Product deleted successfully!");
} catch (error) {
console.error("Error deleting product:", error);
toast.error(`Failed to delete product: ${error.message}`);
} finally {
setIsDeleting(false);
}
}
};

return (
<div className='w-56 bg-white shadow-md rounded-xl duration-500 hover:shadow-xl'>
<Link href='/'>
<div className='relative border-b-2 border-gray-300'>
<Image
src={product?.pictures[1]}
height={364}
width={288}
alt='Product'
className='h-64 w-56 object-cover rounded-t-xl'
loading='lazy'
/>
<div className='absolute top-0 m-2 left-0 rounded-full '>
<p
className={`${
product?.type === "sale"
? "bg-[#1B96EF]"
: "bg-[#FF8A57]"
} rounded-full px-2 p-1 text-[12px] font-bold capitalize tracking-wide text-white sm:py-1 sm:px-3`}
>
{product?.type}
</p>
</div>
</div>
</Link>
<div className='px-4 py-3 w-56'>
<div className='flex justify-between'>
<span className='text-gray-400 mr-3 uppercase text-xs'>
{product?.category}
</span>
<span className='text-gray-400 ml-3 capitalize font-semibold text-xs'>
{product?.condition}
</span>
</div>
<Link href='/'>
<p className='text-lg font-bold mt-2 text-black truncate block capitalize'>
{product?.title}
</p>
</Link>
<div className='flex items-center'>
<p className='text-lg font-semibold text-black cursor-auto my-3'>
{product?.price}$
</p>
<div className='ml-auto'>
<button onClick={handleDelete} className='text-red-500'>
<FaTrash />
</button>
</div>
</div>
</div>
</div>
);
}

export default ListingCard;
14 changes: 14 additions & 0 deletions src/components/listingcard/__test__/ListingCard.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import renderer from "react-test-renderer";

import ListingCard from "../ListingCard";

jest.mock("../../../util/firebase", () => {
return {
initializeApp: jest.fn(),
};
});

it("renders correctly", () => {
const tree = renderer.create(<ListingCard />).toJSON();
expect(tree).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders correctly 1`] = `
<div
className="w-56 bg-white shadow-md rounded-xl duration-500 hover:shadow-xl"
>
<a
href="/"
onClick={[Function]}
onMouseEnter={[Function]}
onTouchStart={[Function]}
>
<div
className="relative border-b-2 border-gray-300"
>
<img
alt="Product"
className="h-64 w-56 object-cover rounded-t-xl"
data-nimg="1"
decoding="async"
height={364}
loading="lazy"
onError={[Function]}
onLoad={[Function]}
src=""
style={
Object {
"color": "transparent",
}
}
width={288}
/>
<div
className="absolute top-0 m-2 left-0 rounded-full "
>
<p
className="bg-[#FF8A57] rounded-full px-2 p-1 text-[12px] font-bold capitalize tracking-wide text-white sm:py-1 sm:px-3"
/>
</div>
</div>
</a>
<div
className="px-4 py-3 w-56"
>
<div
className="flex justify-between"
>
<span
className="text-gray-400 mr-3 uppercase text-xs"
/>
<span
className="text-gray-400 ml-3 capitalize font-semibold text-xs"
/>
</div>
<a
href="/"
onClick={[Function]}
onMouseEnter={[Function]}
onTouchStart={[Function]}
>
<p
className="text-lg font-bold mt-2 text-black truncate block capitalize"
/>
</a>
<div
className="flex items-center"
>
<p
className="text-lg font-semibold text-black cursor-auto my-3"
>
$
</p>
<div
className="ml-auto"
>
<button
className="text-red-500"
onClick={[Function]}
>
<svg
fill="currentColor"
height="1em"
stroke="currentColor"
strokeWidth="0"
style={
Object {
"color": undefined,
}
}
viewBox="0 0 448 512"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16zM53.2 467a48 48 0 0 0 47.9 45h245.8a48 48 0 0 0 47.9-45L416 128H32z"
/>
</svg>
</button>
</div>
</div>
</div>
</div>
`;
Loading

0 comments on commit 220f675

Please sign in to comment.