Skip to content

Commit

Permalink
Color and types changes
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinLatino committed Nov 2, 2024
1 parent 410eb41 commit 1af4f6b
Show file tree
Hide file tree
Showing 2 changed files with 274 additions and 0 deletions.
102 changes: 102 additions & 0 deletions frontend/app/components/ui/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { createContext, useContext, useState, ReactNode } from "react";
import { cn } from "@/lib/utils";
import { X, Menu } from "lucide-react";

interface SidebarContextType {
isOpen: boolean;
toggleSidebar: () => void;
}

const SidebarContext = createContext<SidebarContextType | undefined>(undefined);

export const SidebarProvider = ({ children }: { children: ReactNode }) => {
const [isOpen, setIsOpen] = useState(false);
const toggleSidebar = () => setIsOpen(!isOpen);

return (
<SidebarContext.Provider value={{ isOpen, toggleSidebar }}>
{children}
</SidebarContext.Provider>
);
};

export const useSidebar = () => {
const context = useContext(SidebarContext);
if (!context) {
throw new Error("useSidebar must be used within a SidebarProvider");
}
return context;
};

export const Sidebar = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => {
const { isOpen } = useSidebar();
return (
<div
ref={ref}
className={cn(
"fixed inset-y-0 left-0 z-50 w-64 bg-white shadow-lg transition-transform duration-300",
isOpen ? "translate-x-0" : "-translate-x-full",
className
)}
{...props}
/>
);
}
);
Sidebar.displayName = "Sidebar";

export const SidebarHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("px-4 py-2 border-b flex justify-between items-center", className)} {...props}>
{props.children}
<SidebarClose />
</div>
)
);
SidebarHeader.displayName = "SidebarHeader";

export const SidebarContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex-1 overflow-y-auto p-4", className)} {...props} />
)
);
SidebarContent.displayName = "SidebarContent";

export const SidebarTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
({ className, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<button
ref={ref}
onClick={toggleSidebar}
className={cn("p-2", className)}
{...props}
>
<Menu size={30} className="text-purple-900"/>
<span className="sr-only">Toggle Sidebar</span>
</button>
);
}
);
SidebarTrigger.displayName = "SidebarTrigger";

export const SidebarClose = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
({ className, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<button
ref={ref}
onClick={toggleSidebar}
className={cn("absolute right-4 top-4 opacity-70 hover:opacity-100", className)}
{...props}
>
<X className="h-4 w-4" />
<span className="sr-only">Close Sidebar</span>
</button>
);
}
);
SidebarClose.displayName = "SidebarClose";

// export { SidebarProvider, Sidebar, SidebarHeader, SidebarContent, SidebarTrigger, SidebarClose };
172 changes: 172 additions & 0 deletions frontend/app/marketplace/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
'use client';
import { useState, Dispatch, SetStateAction } from 'react';
import { Slider } from "@/app/components/ui/slider";
import { Checkbox } from "@/app/components/ui/checkbox";
import { Button } from "@/app/components/ui/button";
import { Input } from "@/app/components/ui/input";
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/app/components/ui/card";
import { Sidebar, SidebarContent, SidebarHeader, SidebarProvider, SidebarTrigger } from "@/app/components/ui/sidebar";
import { Search, Menu as HamIcon } from "lucide-react";

interface Product {
id: number;
name: string;
price: number;
category: string;
}

interface SidebarComponentProps {
priceRange: [number, number];
setPriceRange: Dispatch<SetStateAction<[number, number]>>;
selectedCategories: string[];
handleCategoryChange: (category: string) => void;
}

interface HeaderComponentProps {
searchTerm: string;
setSearchTerm: Dispatch<SetStateAction<string>>;
}

interface ProductListProps {
products: Product[];
}

const products: Product[] = [
{ id: 1, name: "Laptop Pro", price: 1299, category: "Electronics" },
{ id: 2, name: "Smartphone X", price: 699, category: "Electronics" },
{ id: 3, name: "Ergonomic Chair", price: 299, category: "Furniture" },
{ id: 4, name: "Coffee Maker", price: 89, category: "Appliances" },
{ id: 5, name: "Running Shoes", price: 129, category: "Sports" },
{ id: 6, name: "Wireless Earbuds", price: 159, category: "Electronics" },
];

export default function Marketplace() {
const [priceRange, setPriceRange] = useState<[number, number]>([0, 1500]);
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
const [searchTerm, setSearchTerm] = useState<string>("");

const handleCategoryChange = (category: string) => {
setSelectedCategories(prev =>
prev.includes(category)
? prev.filter(c => c !== category)
: [...prev, category]
);
};

const filteredProducts = products.filter(product =>
(searchTerm === "" || product.name.toLowerCase().includes(searchTerm.toLowerCase())) &&
(selectedCategories.length === 0 || selectedCategories.includes(product.category)) &&
product.price >= priceRange[0] && product.price <= priceRange[1]
);

return (
<SidebarProvider>
<div className="flex h-screen overflow-hidden">
<SidebarComponent
priceRange={priceRange}
setPriceRange={setPriceRange}
selectedCategories={selectedCategories}
handleCategoryChange={handleCategoryChange}
/>
<div className="flex-1 overflow-auto">
<HeaderComponent searchTerm={searchTerm} setSearchTerm={setSearchTerm} />
<ProductList products={filteredProducts} />
</div>
</div>
</SidebarProvider>
);
}

function SidebarComponent({ priceRange, setPriceRange, selectedCategories, handleCategoryChange }: SidebarComponentProps) {
return (
<Sidebar>
<SidebarHeader className="p-6 border-b">
<h2 className="text-xl font-semibold">Filters</h2>
</SidebarHeader>
<SidebarContent className="p-6">
<div className="space-y-8">
<div>
<h3 className="mb-3 text-lg font-medium">Price range</h3>
<Slider
min={0}
max={1500}
step={10}
value={priceRange}
onValueChange={setPriceRange}
className="mb-4"
/>
<div className="flex justify-between text-lg">
<span>${priceRange[0]}</span>
<span>${priceRange[1]}</span>
</div>
</div>
<div>
<h3 className="mb-3 text-lg font-medium">Categories</h3>
<div className="space-y-3">
{["Electronics", "Furniture", "Appliances", "Sports"].map((category) => (
<div key={category} className="flex items-center">
<Checkbox
id={category}
checked={selectedCategories.includes(category)}
onCheckedChange={() => handleCategoryChange(category)}
/>
<label htmlFor={category} className="ml-3 text-lg">{category}</label>
</div>
))}
</div>
</div>
</div>
</SidebarContent>
</Sidebar>
);
}

function HeaderComponent({ searchTerm, setSearchTerm }: HeaderComponentProps) {
return (
<header className="flex items-center justify-between p-6 border-b">
<SidebarTrigger>
<Button variant="outline" size="icon" className="text-purple-900">
<HamIcon size={50} />
<span className="sr-only">Toggle Sidebar</span>
</Button>
</SidebarTrigger>
<div className="flex items-center space-x-3">
<Input
type="search"
placeholder="Search products..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-80 text-lg"
/>
<Button size="icon" variant="ghost" className="text-purple-900">
<Search className="h-6 w-6" />
<span className="sr-only">Search</span>
</Button>
</div>
</header>
);
}

function ProductList({ products }: ProductListProps) {
return (
<main className="p-8">
<h1 className="text-3xl font-bold mb-8 text-purple-900">Products</h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{products?.map((product) => (
<Card key={product.id}>
<CardHeader>
<CardTitle className="text-purple-900 text-2xl">{product.name}</CardTitle>
</CardHeader>
<CardContent>
<p className="text-gray-500 text-lg">{product.category}</p>
</CardContent>
<CardFooter className="flex justify-between">
<span className="text-xl font-semibold text-purple-900">${product.price}</span>
<Button variant="outline" className="text-purple-900 text-[1.1rem]">Add to cart</Button>
</CardFooter>
</Card>
))}
</div>
</main>
);
}

0 comments on commit 1af4f6b

Please sign in to comment.