Skip to content

Commit f367fdd

Browse files
authored
Merge pull request #89 from udaykiran243/feature/new-arrivals-page
Feature/new arrivals page
2 parents 07c260c + 45ac249 commit f367fdd

3 files changed

Lines changed: 122 additions & 4 deletions

File tree

frontend/src/App.jsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import PrivicyPolicy from './pages/PrivicyPolicy';
2323
import TermsAndServices from './pages/TermsAndServices';
2424
import SizeGuide from './pages/SizeGuide';
2525
import Contributors from './pages/Contributors';
26+
import NewArrivals from './pages/NewArrivals';
2627
import { shopDataContext } from './context/ShopContext';
2728
import ComparisonPanel from './components/ComparisonPanel';
2829
import { RiPriceTag3Line } from "react-icons/ri";
@@ -93,6 +94,16 @@ function App() {
9394
)
9495
}
9596
/>
97+
<Route
98+
path="/new-arrivals"
99+
element={
100+
userData ? (
101+
<NewArrivals />
102+
) : (
103+
<Navigate to="/login" state={{ from: location.pathname }} />
104+
)
105+
}
106+
/>
96107
<Route
97108
path="/product"
98109
element={

frontend/src/components/Footer.jsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,19 @@ function Footer() {
107107
Quick Links
108108
</h3>
109109
<ul className="space-y-3">
110-
{['Home', 'About Us', 'Products', 'Collections', 'New Arrivals', 'Best Sellers'].map((item, index) => (
110+
{[
111+
{ name: 'Home', to: '/' },
112+
{ name: 'About Us', to: '/about' },
113+
{ name: 'Products', to: '/product' },
114+
{ name: 'Collections', to: '/collection' },
115+
{ name: 'New Arrivals', to: '/new-arrivals' },
116+
{ name: 'Best Sellers', to: '/product' }
117+
].map((item, index) => (
111118
<li key={index}>
112-
<a href="#" className="text-sm text-gray-400 hover:text-cyan-400 transition-colors duration-300 flex items-center gap-2 group">
119+
<Link to={item.to} className="text-sm text-gray-400 hover:text-cyan-400 transition-colors duration-300 flex items-center gap-2 group">
113120
<span className="w-1 h-1 bg-cyan-500 rounded-full opacity-0 group-hover:opacity-100 transition-opacity"></span>
114-
{item}
115-
</a>
121+
{item.name}
122+
</Link>
116123
</li>
117124
))}
118125
</ul>

frontend/src/pages/NewArrivals.jsx

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import React, { useContext, useEffect, useState } from 'react';
2+
import { shopDataContext } from '../context/ShopContext';
3+
import Card from '../components/Card';
4+
import Title from '../components/Title';
5+
import { motion } from 'framer-motion';
6+
7+
const NewArrivals = () => {
8+
const { product, compareList, toggleComparePanel, removeFromCompare, toggleCompare } = useContext(shopDataContext);
9+
const [newArrivals, setNewArrivals] = useState([]);
10+
const [isLoading, setIsLoading] = useState(true);
11+
12+
useEffect(() => {
13+
if (product && product.length > 0) {
14+
// Create a copy and reverse to get newest first
15+
const sortedProducts = [...product].reverse();
16+
setNewArrivals(sortedProducts);
17+
setIsLoading(false);
18+
} else {
19+
// If product array is empty, we might be loading or there are no products.
20+
// Since we don't have an explicit loading state from context,
21+
// we'll assume it's loading initially and if it stays empty for a short while,
22+
// we could show "No products found".
23+
// However, usually context fetches on mount.
24+
// Let's just set loading to false if products are still empty after a brief moment
25+
// or rely on the fact that if products are 0, we show empty state or loader.
26+
27+
// For now, let's keep loading true until products arrive, or use a timeout?
28+
// Actually, if ShopContext fetches on mount, product will update.
29+
// If there are genuinely 0 products, this will hang on loading.
30+
// But typically there are products.
31+
32+
const timer = setTimeout(() => {
33+
setIsLoading(false);
34+
}, 2000);
35+
return () => clearTimeout(timer);
36+
}
37+
}, [product]);
38+
39+
// Loading skeleton
40+
if (isLoading) {
41+
return (
42+
<div className="container mx-auto px-4 py-16">
43+
<div className="text-center">
44+
<Title text1="NEW" text2="ARRIVALS" />
45+
<p className="w-3/4 m-auto text-xs sm:text-sm md:text-base text-gray-600 mb-8">
46+
Check out the latest additions to our collection.
47+
</p>
48+
</div>
49+
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 gap-y-6">
50+
{[...Array(8)].map((_, i) => (
51+
<div key={i} className="animate-pulse">
52+
<div className="bg-gray-200 h-64 rounded-lg mb-4"></div>
53+
<div className="h-4 bg-gray-200 rounded w-3/4 mb-2"></div>
54+
<div className="h-4 bg-gray-200 rounded w-1/2"></div>
55+
</div>
56+
))}
57+
</div>
58+
</div>
59+
);
60+
}
61+
62+
return (
63+
<div className="container mx-auto px-4 py-8 border-t pt-16">
64+
<div className="text-center text-2xl mb-8">
65+
<Title text1={'NEW'} text2={'ARRIVALS'}/>
66+
<p className="w-3/4 m-auto text-xs sm:text-sm md:text-base text-gray-600">
67+
Discover our latest products, freshly added to our inventory.
68+
</p>
69+
</div>
70+
71+
{newArrivals.length === 0 ? (
72+
<div className="text-center py-20">
73+
<p className="text-xl text-gray-500">No new arrivals found.</p>
74+
</div>
75+
) : (
76+
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4 gap-y-6">
77+
{newArrivals.map((item, index) => (
78+
<motion.div
79+
key={item._id}
80+
initial={{ opacity: 0, y: 20 }}
81+
animate={{ opacity: 1, y: 0 }}
82+
transition={{ duration: 0.5, delay: index * 0.05 }}
83+
>
84+
<Card
85+
id={item._id}
86+
image={item.image1}
87+
name={item.name}
88+
price={item.price}
89+
onCompare={() => toggleCompare(item)}
90+
isCompared={compareList?.some(p => p._id === item._id)}
91+
/>
92+
</motion.div>
93+
))}
94+
</div>
95+
)}
96+
</div>
97+
);
98+
};
99+
100+
export default NewArrivals;

0 commit comments

Comments
 (0)