-
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
15 changed files
with
1,023 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// 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"; | ||
|
||
|
||
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 = () => { | ||
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={image} alt="Buyer Profile" className="rounded-full mr-4 w-16 h-16 object-cover" /> | ||
<div> | ||
<h2 className="text-xl font-semibold">NP Leon</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,153 @@ | ||
import React, { useState } from 'react'; | ||
import FeedbackModal from './FeedbackModal'; | ||
|
||
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, 5], | ||
}, | ||
{ | ||
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 = 2; | ||
|
||
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 calculateAverageRating = (ratings: Rating[]): string => { | ||
if (ratings.length === 0) return 'No ratings'; | ||
const sum = ratings.reduce((a, b) => a + b, 0); | ||
return (sum / ratings.length).toFixed(1); | ||
}; | ||
|
||
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 | ||
) | ||
); | ||
}; | ||
|
||
return ( | ||
<div className="max-w-4xl mx-auto bg-gray-50 p-8 rounded-lg shadow-lg"> | ||
<h1 className="text-3xl font-bold mb-8 text-center text-gray-800">Product List</h1> | ||
{currentProducts.map((product) => ( | ||
<div key={product.id} className="mb-8 p-6 bg-white rounded-lg shadow-md border border-gray-200"> | ||
<div className="flex justify-between items-center mb-4"> | ||
<div> | ||
<h2 className="text-2xl font-semibold text-gray-800">{product.name}</h2> | ||
<p className="text-gray-600">Average Rating: {calculateAverageRating(product.ratings)}</p> | ||
</div> | ||
<div className="flex items-center"> | ||
{product.ratings.length === 0 ? ( | ||
<button | ||
onClick={() => handleAddFeedback(product)} | ||
className="bg-blue-600 text-white px-4 py-2 rounded shadow hover:bg-blue-700 transition duration-200" | ||
> | ||
Add Feedback | ||
</button> | ||
) : ( | ||
<div className="flex flex-col space-y-2"> | ||
{product.ratings.map((rating, index) => ( | ||
<div key={index} className="flex justify-between items-center"> | ||
<p className="text-gray-600"> | ||
Feedback {index + 1}: {rating} stars | ||
</p> | ||
<button | ||
onClick={() => handleDeleteFeedback(product.id, index)} | ||
className="text-red-500 hover:text-red-700 transition duration-200" | ||
> | ||
Delete | ||
</button> | ||
</div> | ||
))} | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
))} | ||
<div className="mt-6 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-greenColor text-white' | ||
: 'bg-whiteColor 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.