-
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
20 changed files
with
1,119 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// components/menu/Menu1.jsx | ||
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 | ||
} | ||
|
||
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, lastName, photoUrl}) => { | ||
|
||
const dispatch = useDispatch(); | ||
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">Buyer</p> | ||
</div> | ||
</div> | ||
<FaUserEdit className="text-2xl text-gray-600 cursor-pointer" onClick={() => dispatch(setActiveMenu("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("pendingpayments"))}> | ||
<div className="absolute top-2 right-2 bg-red-500 text-white text-sm rounded-full w-8 h-8 flex items-center justify-center"> | ||
5 | ||
</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> | ||
|
||
{/* All 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("intransit"))} | ||
> | ||
<div className="absolute top-2 right-2 bg-red-500 text-white text-sm rounded-full w-8 h-8 flex items-center justify-center"> | ||
5 | ||
</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("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("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/dashboard/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,158 @@ | ||
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} | ||
/> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default FeedBack; |
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,98 @@ | ||
import React, { useState } from 'react'; | ||
|
||
interface FeedbackModalProps { | ||
productName: string; | ||
isOpen: boolean; | ||
onClose: () => void; | ||
onSubmit: (feedback: { message: string; image: File | null; rating: number }) => void; | ||
} | ||
|
||
const FeedbackModal: React.FC<FeedbackModalProps> = ({ productName, isOpen, onClose, onSubmit }) => { | ||
const [message, setMessage] = useState(''); | ||
const [image, setImage] = useState<File | null>(null); | ||
const [rating, setRating] = useState(0); | ||
|
||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
if (e.target.files && e.target.files[0]) { | ||
setImage(e.target.files[0]); | ||
} | ||
}; | ||
|
||
const handleSubmit = (e: React.FormEvent) => { | ||
e.preventDefault(); | ||
onSubmit({ message, image, rating }); | ||
onClose(); | ||
}; | ||
|
||
if (!isOpen) return null; | ||
|
||
return ( | ||
<div className="fixed inset-0 flex items-center justify-center z-50 bg-blackColor bg-opacity-50"> | ||
<div className="bg-whiteColor p-6 rounded-lg shadow-md w-full max-w-md"> | ||
<h2 className="text-xl font-bold mb-4">Add Feedback for {productName}</h2> | ||
<form onSubmit={handleSubmit}> | ||
<div className="mb-4"> | ||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="message"> | ||
Feedback Message | ||
</label> | ||
<textarea | ||
id="message" | ||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring focus:border-blue-300" | ||
value={message} | ||
onChange={(e) => setMessage(e.target.value)} | ||
required | ||
></textarea> | ||
</div> | ||
<div className="mb-4"> | ||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="image"> | ||
Upload Image (optional) | ||
</label> | ||
<input | ||
type="file" | ||
id="image" | ||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring focus:border-blue-300" | ||
onChange={handleImageChange} | ||
accept="image/*" | ||
/> | ||
</div> | ||
<div className="mb-4"> | ||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="rating"> | ||
Rating | ||
</label> | ||
<select | ||
id="rating" | ||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring focus:border-blue-300" | ||
value={rating} | ||
onChange={(e) => setRating(Number(e.target.value))} | ||
required | ||
> | ||
<option value={0} disabled>Select rating</option> | ||
{[1, 2, 3, 4, 5].map((rate) => ( | ||
<option key={rate} value={rate}> | ||
{rate} star{rate > 1 ? 's' : ''} | ||
</option> | ||
))} | ||
</select> | ||
</div> | ||
<div className="flex justify-end"> | ||
<button | ||
type="button" | ||
className="bg-gray-500 text-white px-4 py-2 rounded mr-2 hover:bg-gray-700" | ||
onClick={onClose} | ||
> | ||
Cancel | ||
</button> | ||
<button | ||
type="submit" | ||
className="bg-darkGreen text-whiteColor px-4 py-2 rounded hover:bg-greenColor" | ||
> | ||
Submit | ||
</button> | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default FeedbackModal; |
Oops, something went wrong.