Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented Flash Sale Page with Filter and Quick Buy features #932

Merged
merged 6 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions frontend/src/AgroShopAI/components/Pages/components/Filter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React, { useState } from "react";

export default function Filter({ onFilterChange }) {
const [name, setName] = useState("");
const [brand, setBrand] = useState("");
const [priceRange, setPriceRange] = useState({ min: 0, max: 10000 });
const [timeLeft, setTimeLeft] = useState("");

const handleFilterChange = () => {
const filterCriteria = {
name,
brand,
priceRange,
timeLeft,
};
console.log("Filter criteria:", filterCriteria); // Debugging step

// Call onFilterChange with the filter criteria
onFilterChange(filterCriteria);
};

return (
<div className="bg-white shadow-lg rounded-lg p-6 mb-8">
<h2 className="text-2xl font-semibold text-center text-green-800 mb-4">
Filter Products
</h2>
<div className="flex flex-col gap-4">
<input
type="text"
placeholder="Search by name"
value={name}
onChange={(e) => setName(e.target.value)}
className="border rounded p-2"
/>
<input
type="text"
placeholder="Search by brand"
value={brand}
onChange={(e) => setBrand(e.target.value)}
className="border rounded p-2"
/>
<div className="flex gap-2">
<input
type="number"
placeholder="Min price"
value={priceRange.min}
onChange={(e) =>
setPriceRange({ ...priceRange, min: Number(e.target.value) })
}
className="border rounded p-2 w-full"
/>
<input
type="number"
placeholder="Max price"
value={priceRange.max}
onChange={(e) =>
setPriceRange({ ...priceRange, max: Number(e.target.value) })
}
className="border rounded p-2 w-full"
/>
</div>
<input
type="number"
placeholder="Time left in hours"
value={timeLeft}
onChange={(e) => setTimeLeft(e.target.value)}
className="border rounded p-2"
/>
<button
onClick={handleFilterChange}
className="bg-green-600 text-white py-2 px-4 rounded hover:bg-green-700 transition duration-300"
>
Apply Filters
</button>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

import React from "react";

export default function FlashSaleHeader({ timeLeft }) {
function formatTime(time) {
return time < 10 ? `0${time}` : time;
}

return (
<div className="bg-gradient-to-r from-red-500 to-yellow-500 shadow-lg rounded-lg p-8 mb-8 text-white">
<h2 className="text-3xl font-extrabold text-center text-white mb-4 animate-pulse">
🕒 Flash Sale Ends In:
</h2>
<div className="text-6xl font-extrabold text-center tracking-wider flex items-center justify-center gap-2">
<span className="bg-white text-red-600 p-4 rounded-md shadow-lg animate-bounce">
{formatTime(timeLeft.hours)}
</span>
<span className="text-4xl">:</span>
<span className="bg-white text-red-600 p-4 rounded-md shadow-lg animate-bounce">
{formatTime(timeLeft.minutes)}
</span>
<span className="text-4xl">:</span>
<span className="bg-white text-red-600 p-4 rounded-md shadow-lg animate-bounce">
{formatTime(timeLeft.seconds)}
</span>
</div>
<p className="text-center text-lg mt-4 font-semibold animate-pulse">
Hurry up! Amazing deals await!
</p>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

import React, { useState, useEffect } from "react";

export default function ProductCard({ product, onQuickBuy }) {
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft(product.endTime));

useEffect(() => {
const timer = setInterval(() => {
setTimeLeft(calculateTimeLeft(product.endTime));
}, 1000);

return () => clearInterval(timer);
}, [product.endTime]);

function calculateTimeLeft(endTime) {
const total = Date.parse(endTime) - Date.now();
const seconds = Math.floor((total / 1000) % 60);
const minutes = Math.floor((total / 1000 / 60) % 60);
const hours = Math.floor((total / (1000 * 60 * 60)) % 24);

return { total, hours, minutes, seconds };
}

function calculateDiscount(original, discounted) {
return Math.round(((original - discounted) / original) * 100);
}

function formatTime(time) {
return time < 10 ? `0${time}` : time;
}

return (
<div className="bg-white shadow-md rounded-lg overflow-hidden">
<img
src={product.image}
alt={product.name}
width={400}
height={400}
className="w-full h-48 object-cover"
/>
<div className="p-4">
<h3 className="text-xl font-semibold mb-2">{product.name}</h3>
<p className="text-gray-600 mb-2">{product.brand}</p>
<div className="flex justify-between items-center mb-2">
<span className="text-2xl font-bold text-green-600">
${product.discountedPrice.toFixed(2)}
</span>
<span className="text-lg text-gray-500 line-through">
${product.originalPrice.toFixed(2)}
</span>
</div>
<div className="bg-red-100 text-red-800 text-sm font-semibold px-2 py-1 rounded mb-2">
{calculateDiscount(product.originalPrice, product.discountedPrice)}% OFF
</div>
<div className="text-sm text-gray-600 mb-4">
Ends in: {formatTime(timeLeft.hours)}:
{formatTime(timeLeft.minutes)}:
{formatTime(timeLeft.seconds)}
</div>
<button
onClick={() => onQuickBuy(product)}
className="w-full bg-green-600 text-white py-2 px-4 rounded hover:bg-green-700 transition duration-300"
>
Quick Buy
</button>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

import React from "react";
import ProductCard from "./ProductCard";

export default function ProductList({ products, onQuickBuy }) {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{products.map((product) => (
<ProductCard key={product.id} product={product} onQuickBuy={onQuickBuy} />
))}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// QuickBuyModal.js
import React from "react";

export default function QuickBuyModal({ product, onClose }) {
if (!product) return null;

return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4">
<div className="bg-white rounded-lg p-8 max-w-md w-full">
<h2 className="text-2xl font-bold mb-4">Quick Buy</h2>
<p className="mb-4">
You are about to buy: <strong>{product.name}</strong> for $
{product.discountedPrice.toFixed(2)}
</p>
<button
onClick={onClose}
className="bg-green-600 text-white py-2 px-4 rounded hover:bg-green-700 transition duration-300"
>
Confirm Purchase
</button>
</div>
</div>
);
}
Loading
Loading