Skip to content
Open
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
2 changes: 2 additions & 0 deletions app/(public)/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import Hero from "@/components/Hero";
import Newsletter from "@/components/Newsletter";
import OurSpecs from "@/components/OurSpec";
import LatestProducts from "@/components/LatestProducts";
import RecommendedProducts from "@/components/RecommendedProducts";

export default function Home() {
return (
<div>
<Hero />
<LatestProducts />
<RecommendedProducts />
<BestSelling />
<OurSpecs />
<Newsletter />
Expand Down
126 changes: 110 additions & 16 deletions app/(public)/shop/page.jsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,136 @@
'use client'
import { Suspense } from "react"
import { Suspense, useState } from "react"
import ProductCard from "@/components/ProductCard"
import { MoveLeftIcon } from "lucide-react"
import { useRouter, useSearchParams } from "next/navigation"
import { useSelector } from "react-redux"

function ShopContent() {
function ShopContent() {

// get query params ?search=abc
const searchParams = useSearchParams()
const search = searchParams.get('search')
const router = useRouter()

const products = useSelector(state => state.product.list)
const [minPrice, setMinPrice] = useState(0)
const [maxPrice, setMaxPrice] = useState(999999)
const [inStockOnly, setInStockOnly] = useState(false)
const [proximity, setProximity] = useState(100)
const [category, setCategory] = useState("all")

const filteredProducts = search
let filteredProducts = search
? products.filter(product =>
product.name.toLowerCase().includes(search.toLowerCase())
)
: products;
: products

filteredProducts = filteredProducts.filter(p =>
p.price >= minPrice &&
p.price <= maxPrice &&
(inStockOnly ? p.inStock === true : true) &&
(category === "all" ? true : p.category === category)
)

return (
<div className="min-h-[70vh] mx-6">
<div className=" max-w-7xl mx-auto">
<h1 onClick={() => router.push('/shop')} className="text-2xl text-slate-500 my-6 flex items-center gap-2 cursor-pointer"> {search && <MoveLeftIcon size={20} />} All <span className="text-slate-700 font-medium">Products</span></h1>
<div className="grid grid-cols-2 sm:flex flex-wrap gap-6 xl:gap-12 mx-auto mb-32">
{filteredProducts.map((product) => <ProductCard key={product.id} product={product} />)}
<div className="max-w-7xl mx-auto flex gap-10">

{/* LEFT: PRODUCT GRID */}
<div className="w-full">
<h1
onClick={() => router.push('/shop')}
className="text-2xl text-slate-500 my-6 flex items-center gap-2 cursor-pointer"
>
{search && <MoveLeftIcon size={20} />}
All <span className="text-slate-700 font-medium">Products</span>
</h1>

<div className="grid grid-cols-2 sm:flex flex-wrap gap-6 xl:gap-12 mb-32">
{filteredProducts.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
</div>

{/* RIGHT: FILTER PANEL - moved further down */}
<div className="w-[260px] xl:block sticky top-[150px] h-fit p-2 border border-slate-200 rounded">
<h2 className="text-lg font-semibold mb-4 text-slate-700">
Filters
</h2>

{/* PRICE FILTER */}
<div className="mb-6">
<h3 className="font-medium text-slate-600">Price</h3>
<div className="flex items-center gap-2 mt-2">
<input
type="number"
className="border p-1 rounded w-full"
placeholder="Min"
value={minPrice}
onChange={(e) => setMinPrice(Number(e.target.value))}
/>
<span>-</span>
<input
type="number"
className="border p-1 rounded w-full"
placeholder="Max"
value={maxPrice}
onChange={(e) => setMaxPrice(Number(e.target.value))}
/>
</div>
</div>

{/* STOCK FILTER */}
<div className="mb-6">
<label className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
checked={inStockOnly}
onChange={() => setInStockOnly(!inStockOnly)}
/>
<span className="text-slate-600">In Stock Only</span>
</label>
</div>

{/* PROXIMITY FILTER */}
<div className="mb-6">
<h3 className="font-medium text-slate-600">Proximity (km)</h3>
<input
type="range"
min="1"
max="100"
value={proximity}
onChange={(e) => setProximity(Number(e.target.value))}
className="w-full mt-2"
/>
<p className="text-sm text-slate-500">{proximity} km</p>
</div>

{/* CATEGORY FILTER */}
<div className="mb-6">
<h3 className="font-medium text-slate-600">Category</h3>
<select
className="border p-2 rounded w-full mt-2"
value={category}
onChange={(e) => setCategory(e.target.value)}
>
<option value="all">All</option>
<option value="watches">Watches</option>
<option value="speakers-headphones">Speakers & Headphones</option>
<option value="home">Home</option>
</select>
</div>

</div>

</div>
</div>
)
}


export default function Shop() {
return (
<Suspense fallback={<div>Loading shop...</div>}>
<ShopContent />
</Suspense>
);
return (
<Suspense fallback={<div>Loading shop...</div>}>
<ShopContent />
</Suspense>
);
}
34 changes: 22 additions & 12 deletions app/store/add-product/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,64 @@ export default function StoreAddProduct() {
description: "",
mrp: 0,
price: 0,
quantity: 1, // Added quantity field
category: "",
})
const [loading, setLoading] = useState(false)


const onChangeHandler = (e) => {
setProductInfo({ ...productInfo, [e.target.name]: e.target.value })
}

const onSubmitHandler = async (e) => {
e.preventDefault()
// Logic to add a product

}


return (
<form onSubmit={e => toast.promise(onSubmitHandler(e), { loading: "Adding Product..." })} className="text-slate-500 mb-28">
<h1 className="text-2xl">Add New <span className="text-slate-800 font-medium">Products</span></h1>
<p className="mt-7">Product Images</p>

<div htmlFor="" className="flex gap-3 mt-4">
<div className="flex gap-3 mt-4">
{Object.keys(images).map((key) => (
<label key={key} htmlFor={`images${key}`}>
<Image width={300} height={300} className='h-15 w-auto border border-slate-200 rounded cursor-pointer' src={images[key] ? URL.createObjectURL(images[key]) : assets.upload_area} alt="" />
<Image
width={300}
height={300}
className='h-15 w-auto border border-slate-200 rounded cursor-pointer'
src={images[key] ? URL.createObjectURL(images[key]) : assets.upload_area}
alt=""
/>
<input type="file" accept='image/*' id={`images${key}`} onChange={e => setImages({ ...images, [key]: e.target.files[0] })} hidden />
</label>
))}
</div>

<label htmlFor="" className="flex flex-col gap-2 my-6 ">
<label className="flex flex-col gap-2 my-6">
Name
<input type="text" name="name" onChange={onChangeHandler} value={productInfo.name} placeholder="Enter product name" className="w-full max-w-sm p-2 px-4 outline-none border border-slate-200 rounded" required />
</label>

<label htmlFor="" className="flex flex-col gap-2 my-6 ">
<label className="flex flex-col gap-2 my-6">
Description
<textarea name="description" onChange={onChangeHandler} value={productInfo.description} placeholder="Enter product description" rows={5} className="w-full max-w-sm p-2 px-4 outline-none border border-slate-200 rounded resize-none" required />
</label>

<div className="flex gap-5">
<label htmlFor="" className="flex flex-col gap-2 ">
<label className="flex flex-col gap-2">
Actual Price ($)
<input type="number" name="mrp" onChange={onChangeHandler} value={productInfo.mrp} placeholder="0" rows={5} className="w-full max-w-45 p-2 px-4 outline-none border border-slate-200 rounded resize-none" required />
<input type="number" name="mrp" onChange={onChangeHandler} value={productInfo.mrp} placeholder="0" className="w-full max-w-45 p-2 px-4 outline-none border border-slate-200 rounded resize-none" required />
</label>
<label htmlFor="" className="flex flex-col gap-2 ">

<label className="flex flex-col gap-2">
Offer Price ($)
<input type="number" name="price" onChange={onChangeHandler} value={productInfo.price} placeholder="0" rows={5} className="w-full max-w-45 p-2 px-4 outline-none border border-slate-200 rounded resize-none" required />
<input type="number" name="price" onChange={onChangeHandler} value={productInfo.price} placeholder="0" className="w-full max-w-45 p-2 px-4 outline-none border border-slate-200 rounded resize-none" required />
</label>

<label className="flex flex-col gap-2">
Quantity
<input type="number" name="quantity" onChange={onChangeHandler} value={productInfo.quantity} placeholder="1" min={1} className="w-full max-w-45 p-2 px-4 outline-none border border-slate-200 rounded resize-none" required />
</label>
</div>

Expand All @@ -77,4 +87,4 @@ export default function StoreAddProduct() {
<button disabled={loading} className="bg-slate-800 text-white px-6 mt-7 py-2 hover:bg-slate-900 rounded transition">Add Product</button>
</form>
)
}
}
Loading