-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[finishes #187943570] buyer dashboard
- Loading branch information
Showing
34 changed files
with
1,698 additions
and
11 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
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,87 @@ | ||
// components/menu/Account.tsx | ||
import { FaUserEdit, FaHourglassHalf } from "react-icons/fa"; | ||
import { FaTruckFast } from "react-icons/fa6"; | ||
import { MdOutlineFeedback } from "react-icons/md"; | ||
import { PiKeyReturn } from "react-icons/pi"; | ||
import { useDispatch } from "react-redux"; | ||
import { setActiveMenu } from "../../redux/slices/buyerDashboard"; | ||
|
||
interface AccountProps { | ||
lastName: string; | ||
photoUrl: string; | ||
firstName: string; | ||
email?: string; | ||
orderss: any[]; | ||
data: any[]; | ||
Role: any | ||
} | ||
|
||
const image: string = 'https://images.unsplash.com/photo-1533636721434-0e2d61030955?q=80&w=1740&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D' | ||
|
||
const Account: React.FC<AccountProps> = ({ firstName, Role, lastName, photoUrl, orderss }) => { | ||
const dispatch = useDispatch(); | ||
const {data}:any = orderss | ||
|
||
return ( | ||
<div className="p-6"> | ||
{/* User Profile Section */} | ||
<div className="flex justify-between items-center bg-white shadow-md p-4 rounded-lg mb-6"> | ||
<div className="flex items-center"> | ||
<img src={photoUrl ? photoUrl : image} alt="profile" className="rounded-full mr-4 w-16 h-16 object-cover" /> | ||
<div> | ||
<h2 className="text-xl font-semibold">{lastName} {firstName}</h2> | ||
<p className="text-gray-600">{Role.name}</p> | ||
</div> | ||
</div> | ||
<FaUserEdit className="text-2xl text-gray-600 cursor-pointer" onClick={() => dispatch(setActiveMenu({ activeMenu: "profile" }))} /> | ||
</div> | ||
|
||
{/* Cards Section */} | ||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 py-10"> | ||
{/* Pending Card */} | ||
<div className="bg-whiteColor cursor-pointer shadow-md p-8 rounded-lg flex flex-col items-center transform transition duration-300 hover:scale-105 relative" | ||
onClick={() => dispatch(setActiveMenu({ activeMenu: "pendingpayments" }))}> | ||
<div className="absolute top-2 right-2 bg-redColor text-whiteColor text-sm rounded-full w-8 h-8 flex items-center justify-center"> | ||
{data.filter((order: { status: string; }) => order.status === 'pending').length} | ||
</div> | ||
<FaHourglassHalf className="text-6xl text-greenColor mb-4 w-full text-center" /> | ||
<div className="text-center"> | ||
<h3 className="text-lg font-semibold">Pending Payments</h3> | ||
</div> | ||
</div> | ||
|
||
{/* In Transit Card */} | ||
<div className="bg-whiteColor cursor-pointer shadow-md p-8 rounded-lg flex flex-col items-center transform transition duration-300 hover:scale-105 relative" | ||
onClick={() => dispatch(setActiveMenu({ activeMenu: "intransit" }))}> | ||
<div className="absolute top-2 right-2 bg-redColor text-whiteColor text-sm rounded-full w-8 h-8 flex items-center justify-center"> | ||
{data.filter((order: { status: string; }) => order.status === 'in-transit').length} | ||
</div> | ||
<FaTruckFast className="text-6xl text-greenColor mb-4 w-full text-center" /> | ||
<div className="text-center"> | ||
<h3 className="text-lg font-semibold">In Transit</h3> | ||
</div> | ||
</div> | ||
|
||
{/* Feedback Card */} | ||
<div className="bg-whiteColor cursor-pointer shadow-md p-8 rounded-lg flex flex-col items-center transform transition duration-300 hover:scale-105 relative" | ||
onClick={() => dispatch(setActiveMenu({ activeMenu: "feedback" }))}> | ||
<MdOutlineFeedback className="text-6xl text-greenColor mb-4 w-full text-center" /> | ||
<div className="text-center"> | ||
<h3 className="text-lg font-semibold">Feedback</h3> | ||
</div> | ||
</div> | ||
|
||
{/* Refund & Return Card */} | ||
<div className="bg-whiteColor cursor-pointer shadow-md p-8 rounded-lg flex flex-col items-center transform transition duration-300 hover:scale-105 relative" | ||
onClick={() => dispatch(setActiveMenu({ activeMenu: "returnrefund" }))}> | ||
<PiKeyReturn className="text-6xl text-greenColor mb-4 w-full text-center" /> | ||
<div className="text-center"> | ||
<h3 className="text-lg font-semibold">Return & Refund</h3> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Account; |
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,34 @@ | ||
import React from 'react'; | ||
import { Navigate } from 'react-router-dom'; | ||
import { useSelector } from 'react-redux'; | ||
import { RootState } from '../../redux/store'; | ||
import AdminLayout from '../../components/admin/AdminLayout'; | ||
import BuyerProfile from '../../pages/BuyerProfile'; | ||
|
||
interface RestrictedRouteProp { | ||
role: 'admin' | 'buyer' | 'seller'; | ||
} | ||
|
||
const BuyerRestrictedRoutes: React.FC<RestrictedRouteProp> = ({ role }) => { | ||
const userRole = useSelector((state: RootState) => state.user.role); | ||
const token = useSelector((state: RootState) => state.user.token); | ||
|
||
// orders | ||
// user profile | ||
|
||
|
||
if (!token || userRole !== role) { | ||
return <Navigate to='/' />; | ||
} | ||
|
||
switch (role) { | ||
case 'admin': | ||
return <AdminLayout />; | ||
case 'buyer': | ||
return <BuyerProfile />; | ||
default: | ||
return <Navigate to='/' />; | ||
} | ||
}; | ||
|
||
export default BuyerRestrictedRoutes; |
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,37 @@ | ||
import React from 'react'; | ||
|
||
interface ConfirmationModalProps { | ||
isOpen: boolean; | ||
onClose: () => void; | ||
onConfirm: () => void; | ||
message: string; | ||
} | ||
|
||
const ConfirmationModal: React.FC<ConfirmationModalProps> = ({ isOpen, onClose, onConfirm, message }) => { | ||
if (!isOpen) return null; | ||
|
||
return ( | ||
<div className="fixed inset-0 flex items-center justify-center bg-blackColor bg-opacity-50"> | ||
<div className="bg-whiteColor p-6 rounded-lg shadow-lg max-w-sm mx-auto"> | ||
<h2 className="text-lg font-semibold mb-4">Confirm Action</h2> | ||
<p className="mb-4">{message}</p> | ||
<div className="flex justify-end gap-4"> | ||
<button | ||
className="px-4 py-2 bg-gray-300 text-gray-800 rounded-md hover:bg-gray-400" | ||
onClick={onClose} | ||
> | ||
Cancel | ||
</button> | ||
<button | ||
className="px-4 py-2 bg-redColor text-whiteColor rounded-md cursor-pointer" | ||
onClick={onConfirm} | ||
> | ||
Confirm | ||
</button> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default ConfirmationModal; |
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,159 @@ | ||
import React, { useState } from 'react'; | ||
import FeedbackModal from './FeedbackModal'; | ||
import { FaStar, FaRegStar } from 'react-icons/fa'; | ||
|
||
type Rating = number; | ||
|
||
interface Product { | ||
id: string; | ||
name: string; | ||
price: string; | ||
manufacturer: string; | ||
ratings: Rating[]; | ||
} | ||
|
||
const productsData: Product[] = [ | ||
{ | ||
id: '1', | ||
name: 'Product 1', | ||
price: '$100', | ||
manufacturer: 'Manufacturer A', | ||
ratings: [], | ||
}, | ||
{ | ||
id: '2', | ||
name: 'Product 2', | ||
price: '$200', | ||
manufacturer: 'Manufacturer B', | ||
ratings: [4], | ||
}, | ||
{ | ||
id: '3', | ||
name: 'Product 3', | ||
price: '$300', | ||
manufacturer: 'Manufacturer C', | ||
ratings: [3], | ||
}, | ||
]; | ||
|
||
const FeedBack: React.FC = () => { | ||
const [products, setProducts] = useState<Product[]>(productsData); | ||
const [modalOpen, setModalOpen] = useState(false); | ||
const [currentProduct, setCurrentProduct] = useState<Product | null>(null); | ||
const [currentPage, setCurrentPage] = useState(1); | ||
const productsPerPage = 3; | ||
|
||
const indexOfLastProduct = currentPage * productsPerPage; | ||
const indexOfFirstProduct = indexOfLastProduct - productsPerPage; | ||
const currentProducts = products.slice(indexOfFirstProduct, indexOfLastProduct); | ||
|
||
const totalPages = Math.ceil(products.length / productsPerPage); | ||
|
||
const paginate = (pageNumber: number) => setCurrentPage(pageNumber); | ||
|
||
const handleAddFeedback = (product: Product) => { | ||
setCurrentProduct(product); | ||
setModalOpen(true); | ||
}; | ||
|
||
const handleModalClose = () => { | ||
setModalOpen(false); | ||
setCurrentProduct(null); | ||
}; | ||
|
||
const handleFeedbackSubmit = (feedback: { message: string; image: File | null; rating: number }) => { | ||
console.log('Feedback submitted for product:', currentProduct?.id); | ||
console.log('Feedback details:', feedback); | ||
}; | ||
|
||
const handleDeleteFeedback = (productId: string, feedbackIndex: number) => { | ||
setProducts((prevProducts) => | ||
prevProducts.map((product) => | ||
product.id === productId | ||
? { | ||
...product, | ||
ratings: product.ratings.filter((_, index) => index !== feedbackIndex), | ||
} | ||
: product | ||
) | ||
); | ||
}; | ||
|
||
const renderStars = (rating: number) => { | ||
const stars = []; | ||
for (let i = 1; i <= 5; i++) { | ||
stars.push(i <= rating ? <FaStar key={i} /> : <FaRegStar key={i} />); | ||
} | ||
return stars; | ||
}; | ||
|
||
return ( | ||
<div className="max-w-4xl p-8 rounded-md shadow-lg"> | ||
<h1 className="text-3xl font-bold mb-8 text-gray-800">Purchased Products</h1> | ||
{currentProducts.map((product, index) => ( | ||
<div | ||
key={product.id} | ||
className={`mb-4 p-2 rounded-md shadow-sm ${index % 2 === 0 ? 'bg-grayColor' : 'bg-whiteColor'}`} | ||
> | ||
<div className="flex justify-between items-center mb-2"> | ||
<div> | ||
<h2 className="text-xl font-semibold text-gray-800">{product.name}</h2> | ||
</div> | ||
<div className="flex items-center"> | ||
{product.ratings.length === 0 ? ( | ||
<button | ||
onClick={() => handleAddFeedback(product)} | ||
className="bg-darkGreen text-whiteColor px-3 py-1 rounded shadow hover:bg-greenColor transition duration-200" | ||
> | ||
Add Feedback | ||
</button> | ||
) : ( | ||
<div className="flex flex-col space-y-1"> | ||
{product.ratings.map((rating, index) => ( | ||
<div key={index} className="flex justify-between items-center gap-4"> | ||
<div className="flex items-center"> | ||
<div className="flex">{renderStars(rating)}</div> | ||
</div> | ||
<button | ||
onClick={() => handleDeleteFeedback(product.id, index)} | ||
className="bg-redColor text-whiteColor px-2 py-1 rounded shadow transition duration-200" | ||
> | ||
Delete | ||
</button> | ||
</div> | ||
))} | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
))} | ||
<div className="mt-4 flex justify-end"> | ||
{Array.from({ length: totalPages }, (_, index) => ( | ||
<button | ||
key={index} | ||
onClick={() => paginate(index + 1)} | ||
className={`mx-1 px-3 py-1 border rounded ${ | ||
currentPage === index + 1 | ||
? 'bg-green-500 text-white' | ||
: 'bg-white border-gray-300 text-gray-800 hover:bg-gray-100' | ||
}`} | ||
> | ||
{index + 1} | ||
</button> | ||
))} | ||
</div> | ||
{currentProduct && ( | ||
<FeedbackModal | ||
productName={currentProduct.name} | ||
isOpen={modalOpen} | ||
onClose={handleModalClose} | ||
onSubmit={handleFeedbackSubmit} | ||
productId={currentProduct.id} | ||
/> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default FeedBack; |
Oops, something went wrong.