8 Commits

Author SHA1 Message Date
e78cf18409 Update src/app/checkout/page.tsx 2026-03-25 07:24:55 +00:00
5959806bf3 Update src/app/checkout/page.tsx 2026-03-25 07:24:30 +00:00
0e26d3a073 Add src/context/CartContext.tsx 2026-03-25 07:23:55 +00:00
28f4f84e0c Add src/app/user/dashboard/page.tsx 2026-03-25 07:23:55 +00:00
2041dd8b8a Add src/app/products/[productId]/page.tsx 2026-03-25 07:23:54 +00:00
6fd75d201e Update src/app/page.tsx 2026-03-25 07:23:54 +00:00
484bffd95d Add src/app/checkout/page.tsx 2026-03-25 07:23:53 +00:00
348f55c5ba Merge version_1 into main
Merge version_1 into main
2026-03-25 07:13:49 +00:00
5 changed files with 586 additions and 1 deletions

305
src/app/checkout/page.tsx Normal file
View File

@@ -0,0 +1,305 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import ReactLenis from "lenis/react";
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import Input from '@/components/form/Input';
import ButtonHoverBubble from '@/components/button/ButtonHoverBubble';
import { useState } from "react";
export default function CheckoutPage() {
const [shippingInfo, setShippingInfo] = useState({
fullName: "", address: "", city: "", state: "", zipCode: "", country: ""
});
const [paymentInfo, setPaymentInfo] = useState({
cardNumber: "", cardName: "", expiryDate: "", cvv: ""
});
const [orderConfirmed, setOrderConfirmed] = useState(false);
const handleShippingChange = (field: string, value: string) => {
setShippingInfo((prev) => ({ ...prev, [field]: value }));
};
const handlePaymentChange = (field: string, value: string) => {
setPaymentInfo((prev) => ({ ...prev, [field]: value }));
};
const handlePlaceOrder = async (e: React.FormEvent) => {
e.preventDefault();
// Simulate API call for order placement
console.log("Placing order with:", shippingInfo, paymentInfo);
// In a real app, you'd send this to an API endpoint
const response = await fetch('/api/checkout', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ shippingInfo, paymentInfo, items: [] }) // Add actual cart items
});
if (response.ok) {
setOrderConfirmed(true);
console.log("Order placed successfully!");
// Optionally clear cart or redirect
} else {
console.error("Order failed:", await response.json());
alert("Order placement failed. Please try again.");
}
};
// Dummy order summary data
const orderItems = [
{ id: "prod-1", name: "Luxury Velocity Runner", price: 12500, quantity: 1 },
{ id: "prod-4", name: "Aura X Wireless Earbuds", price: 8999, quantity: 1 }
];
const subtotal = orderItems.reduce((sum, item) => sum + item.price * item.quantity, 0);
const shippingCost = 500; // Example
const total = subtotal + shippingCost;
if (orderConfirmed) {
return (
<ThemeProvider
defaultButtonVariant="shift-hover"
defaultTextAnimation="reveal-blur"
borderRadius="rounded"
contentWidth="small"
sizing="mediumSizeLargeTitles"
background="blurBottom"
cardStyle="inset"
primaryButtonStyle="double-inset"
secondaryButtonStyle="layered"
headingFontWeight="medium"
>
<ReactLenis root>
<div id="nav" data-section="nav">
<NavbarStyleCentered
navItems={[
{ name: "Home", id: "/" },
{ name: "Shop", id: "/shop" },
{ name: "Categories", id: "/categories" },
{ name: "Wishlist", id: "/wishlist" },
{ name: "About", id: "/about" },
{ name: "Contact", id: "/contact" },
{ name: "Checkout", id: "/checkout" }
]}
button={{ text: "Admin Login", href: "/admin" }}
brandName="SHOEMOB"
/>
</div>
<main className="min-h-screen py-20 flex flex-col items-center justify-center text-center">
<h1 className="text-4xl font-bold mb-4">Order Confirmed!</h1>
<p className="text-xl mb-8">Thank you for your purchase. Your order has been successfully placed.</p>
<ButtonHoverBubble text="Continue Shopping" href="/shop" />
</main>
<div id="footer" data-section="footer">
<FooterBaseReveal
columns={[
{
title: "Shop", items: [
{ label: "Luxury Sneakers", href: "/shop?category=luxury-sneakers" }
]
}
]}
/>
</div>
</ReactLenis>
</ThemeProvider>
);
}
return (
<ThemeProvider
defaultButtonVariant="shift-hover"
defaultTextAnimation="reveal-blur"
borderRadius="rounded"
contentWidth="small"
sizing="mediumSizeLargeTitles"
background="blurBottom"
cardStyle="inset"
primaryButtonStyle="double-inset"
secondaryButtonStyle="layered"
headingFontWeight="medium"
>
<ReactLenis root>
<div id="nav" data-section="nav">
<NavbarStyleCentered
navItems={[
{ name: "Home", id: "/" },
{ name: "Shop", id: "/shop" },
{ name: "Categories", id: "/categories" },
{ name: "Wishlist", id: "/wishlist" },
{ name: "About", id: "/about" },
{ name: "Contact", id: "/contact" },
{ name: "Checkout", id: "/checkout" } // Added checkout link
]}
button={{ text: "Admin Login", href: "/admin" }}
brandName="SHOEMOB"
/>
</div>
<main className="min-h-screen py-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-4xl mx-auto">
<h1 className="text-4xl font-bold text-center mb-12">Checkout</h1>
<form onSubmit={handlePlaceOrder} className="grid md:grid-cols-2 gap-12">
{/* Shipping Information */}
<div className="bg-card p-8 rounded-lg shadow-lg">
<h2 className="text-2xl font-semibold mb-6">Shipping Information</h2>
<div className="grid grid-cols-1 gap-4">
<Input
value={shippingInfo.fullName}
onChange={(val) => handleShippingChange("fullName", val)}
placeholder="Full Name"
required
ariaLabel="Full Name"
/>
<Input
value={shippingInfo.address}
onChange={(val) => handleShippingChange("address", val)}
placeholder="Address"
required
ariaLabel="Address"
/>
<div className="grid grid-cols-2 gap-4">
<Input
value={shippingInfo.city}
onChange={(val) => handleShippingChange("city", val)}
placeholder="City"
required
ariaLabel="City"
/>
<Input
value={shippingInfo.state}
onChange={(val) => handleShippingChange("state", val)}
placeholder="State/Province"
required
ariaLabel="State/Province"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<Input
value={shippingInfo.zipCode}
onChange={(val) => handleShippingChange("zipCode", val)}
placeholder="Zip Code"
required
ariaLabel="Zip Code"
/>
<Input
value={shippingInfo.country}
onChange={(val) => handleShippingChange("country", val)}
placeholder="Country"
required
ariaLabel="Country"
/>
</div>
</div>
</div>
{/* Order Summary & Payment */}
<div className="flex flex-col gap-12">
{/* Order Summary */}
<div className="bg-card p-8 rounded-lg shadow-lg">
<h2 className="text-2xl font-semibold mb-6">Order Summary</h2>
<div className="space-y-4">
{orderItems.map((item) => (
<div key={item.id} className="flex justify-between items-center text-foreground">
<span>{item.name} (x{item.quantity})</span>
<span>{(item.price * item.quantity).toLocaleString()}</span>
</div>
))}
<div className="pt-4 border-t border-accent/20">
<div className="flex justify-between text-foreground">
<span>Subtotal</span>
<span>{subtotal.toLocaleString()}</span>
</div>
<div className="flex justify-between text-foreground">
<span>Shipping</span>
<span>{shippingCost.toLocaleString()}</span>
</div>
<div className="flex justify-between font-bold text-xl mt-4 text-primary-cta">
<span>Total</span>
<span>{total.toLocaleString()}</span>
</div>
</div>
</div>
</div>
{/* Payment Information */}
<div className="bg-card p-8 rounded-lg shadow-lg">
<h2 className="text-2xl font-semibold mb-6">Payment Information</h2>
<div className="grid grid-cols-1 gap-4">
<Input
value={paymentInfo.cardName}
onChange={(val) => handlePaymentChange("cardName", val)}
placeholder="Name on Card"
required
ariaLabel="Name on Card"
/>
<Input
value={paymentInfo.cardNumber}
onChange={(val) => handlePaymentChange("cardNumber", val)}
placeholder="Card Number"
type="text"
required
ariaLabel="Card Number"
/>
<div className="grid grid-cols-2 gap-4">
<Input
value={paymentInfo.expiryDate}
onChange={(val) => handlePaymentChange("expiryDate", val)}
placeholder="MM/YY"
type="text"
// MM/YY pattern
required
ariaLabel="Expiry Date"
/>
<Input
value={paymentInfo.cvv}
onChange={(val) => handlePaymentChange("cvv", val)}
placeholder="CVV"
type="text"
// CVV pattern
required
ariaLabel="CVV"
/>
</div>
</div>
</div>
{/* Place Order Button */}
<div className="text-center">
<ButtonHoverBubble
text="Place Order"
type="submit"
className="w-full"
/>
</div>
</div>
</form>
</div>
</main>
<div id="footer" data-section="footer">
<FooterBaseReveal
columns={[
{
title: "Shop", items: [
{ label: "Luxury Sneakers", href: "/shop?category=luxury-sneakers" }
]
}
]}
/>
</div>
</ReactLenis>
</ThemeProvider>
);
}

View File

@@ -40,6 +40,8 @@ export default function LandingPage() {
name: "About", id: "/about"},
{
name: "Contact", id: "/contact"},
{
name: "My Account", id: "/user/dashboard"}
]}
button={{
text: "Admin Login", href: "/admin"}}
@@ -163,4 +165,4 @@ export default function LandingPage() {
</ReactLenis>
</ThemeProvider>
);
}
}

View File

@@ -0,0 +1,98 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import ReactLenis from "lenis/react";
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
import ProductDetailCard from '@/components/ecommerce/productDetail/ProductDetailCard';
import { Star } from 'lucide-react';
export default function ProductDetailPage({ params }: { params: { productId: string } }) {
// In a real application, you would fetch product data based on params.productId
const productData = {
id: params.productId,
name: "Luxury Velocity Runner", price: "₹12,500", description: "Experience unparalleled comfort and style with our Luxury Velocity Runner. Crafted from premium materials, these sneakers offer superior cushioning and dynamic support for your everyday adventures. Featuring a sleek design and advanced sole technology, they are perfect for both athletic performance and casual wear. Available in multiple sizes and limited-edition colors.", images: [
{ src: "http://img.b2bpic.net/free-photo/view-white-ice-skates-with-cherries-tangerines_23-2150806813.jpg", alt: "Luxury Velocity Runner front view" },
{ src: "http://img.b2bpic.net/free-photo/white-sneakers-with-red-sole-against-white-background_23-2147746592.jpg", alt: "Luxury Velocity Runner side view" },
{ src: "http://img.b2bpic.net/free-photo/pair-white-sneakers_23-2147746591.jpg", alt: "Luxury Velocity Runner top view" }
],
variants: [
{
label: "Size", options: ["US 7", "US 8", "US 9", "US 10", "US 11", "US 12"],
selected: "US 9", onChange: (value: string) => console.log("Selected size:", value)
},
{
label: "Color", options: ["White", "Black", "Grey", "Blue"],
selected: "White", onChange: (value: string) => console.log("Selected color:", value)
}
],
quantity: {
label: "Quantity", options: ["1", "2", "3", "4", "5"],
selected: "1", onChange: (value: string) => console.log("Selected quantity:", value)
},
rating: 4.5,
stock: 15
};
const navItems = [
{ name: "Home", id: "/" },
{ name: "Shop", id: "/products/prod-1" }
];
return (
<ThemeProvider
defaultButtonVariant="shift-hover"
defaultTextAnimation="reveal-blur"
borderRadius="rounded"
contentWidth="small"
sizing="mediumSizeLargeTitles"
background="blurBottom"
cardStyle="inset"
primaryButtonStyle="double-inset"
secondaryButtonStyle="layered"
headingFontWeight="medium"
>
<ReactLenis root>
<div id="nav" data-section="nav">
<NavbarStyleCentered
navItems={navItems}
button={{
text: "Admin Login", href: "/admin"
}}
brandName="SHOEMOB"
/>
</div>
<div id="product-detail" data-section="product-detail">
<ProductDetailCard
layout="page"
name={productData.name}
price={productData.price}
description={`${productData.description} In stock: ${productData.stock} units.`}
images={productData.images}
variants={productData.variants}
quantity={productData.quantity}
showRating={true}
rating={productData.rating}
ratingIcon={Star}
buttons={[
{ text: "Buy Now", onClick: () => alert(`Buying ${productData.name} (ID: ${productData.id})`) }
]}
/>
</div>
<div id="footer" data-section="footer">
<FooterBaseReveal
columns={[
{
title: "Shop", items: [
{ label: "Luxury Sneakers", href: "/products/prod-1" }
]
}
]}
/>
</div>
</ReactLenis>
</ThemeProvider>
);
}

View File

@@ -0,0 +1,74 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import ReactLenis from "lenis/react";
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
export default function UserDashboardPage() {
return (
<ThemeProvider
defaultButtonVariant="shift-hover"
defaultTextAnimation="reveal-blur"
borderRadius="rounded"
contentWidth="small"
sizing="mediumSizeLargeTitles"
background="blurBottom"
cardStyle="inset"
primaryButtonStyle="double-inset"
secondaryButtonStyle="layered"
headingFontWeight="medium"
>
<ReactLenis root>
<div id="nav" data-section="nav">
<NavbarStyleCentered
navItems={[
{ name: "Home", id: "/" },
{ name: "Shop", id: "/shop" },
{ name: "Categories", id: "/categories" },
{ name: "Wishlist", id: "/wishlist" },
{ name: "About", id: "/about" },
{ name: "Contact", id: "/contact" },
{ name: "My Account", id: "/user/dashboard" }
]}
button={{ text: "Admin Login", href: "/admin" }}
brandName="SHOEMOB"
/>
</div>
<main className="container mx-auto px-4 py-16">
<h1 className="text-4xl font-semibold mb-8">My Account & Order History</h1>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<section className="bg-card p-6 rounded-lg shadow-md">
<h2 className="text-2xl font-medium mb-4">Order History</h2>
<p>No orders found. Start shopping today!</p>
{/* Placeholder for order list */}
</section>
<section className="bg-card p-6 rounded-lg shadow-md">
<h2 className="text-2xl font-medium mb-4">Account Details</h2>
<p>Manage your profile, addresses, and payment methods here.</p>
{/* Placeholder for account details */}
</section>
<section className="bg-card p-6 rounded-lg shadow-md md:col-span-2">
<h2 className="text-2xl font-medium mb-4">Order Tracking</h2>
<p>Enter your order number to track your shipment.</p>
{/* Placeholder for tracking input and status */}
</section>
</div>
</main>
<div id="footer" data-section="footer">
<FooterBaseReveal
columns={[
{
title: "Shop", items: [
{ label: "Luxury Sneakers", href: "/shop?category=luxury-sneakers" },
],
},
]}
/>
</div>
</ReactLenis>
</ThemeProvider>
);
}

106
src/context/CartContext.tsx Normal file
View File

@@ -0,0 +1,106 @@
"use client";
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
interface CartItem {
id: string;
name: string;
price: number; // Store price as number for calculations
imageSrc: string;
quantity: number;
}
interface CartContextType {
cartItems: CartItem[];
addToCart: (item: Omit<CartItem, 'quantity'>) => void;
removeFromCart: (id: string) => void;
updateQuantity: (id: string, quantity: number) => void;
clearCart: () => void;
cartTotal: number;
}
const CartContext = createContext<CartContextType | undefined>(undefined);
export const CartProvider = ({ children }: { children: ReactNode }) => {
const [cartItems, setCartItems] = useState<CartItem[]>([]);
useEffect(() => {
// Load cart from localStorage on mount
if (typeof window !== 'undefined') {
const storedCart = localStorage.getItem('cart');
if (storedCart) {
setCartItems(JSON.parse(storedCart));
}
}
}, []);
useEffect(() => {
// Save cart to localStorage whenever it changes
if (typeof window !== 'undefined') {
localStorage.setItem('cart', JSON.stringify(cartItems));
}
}, [cartItems]);
const addToCart = (item: Omit<CartItem, 'quantity'>) => {
setCartItems((prevItems) => {
const existingItem = prevItems.find((cartItem) => cartItem.id === item.id);
if (existingItem) {
return prevItems.map((cartItem) =>
cartItem.id === item.id
? { ...cartItem, quantity: cartItem.quantity + 1 }
: cartItem
);
} else {
return [...prevItems, { ...item, quantity: 1 }];
}
});
};
const removeFromCart = (id: string) => {
setCartItems((prevItems) => prevItems.filter((item) => item.id !== id));
};
const updateQuantity = (id: string, quantity: number) => {
if (quantity <= 0) {
removeFromCart(id);
return;
}
setCartItems((prevItems) =>
prevItems.map((item) =>
item.id === id ? { ...item, quantity: quantity } : item
)
);
};
const clearCart = () => {
setCartItems([]);
};
const cartTotal = cartItems.reduce(
(total, item) => total + item.price * item.quantity,
0
);
return (
<CartContext.Provider
value={{
cartItems,
addToCart,
removeFromCart,
updateQuantity,
clearCart,
cartTotal,
}}
>
{children}
</CartContext.Provider>
);
};
export const useCart = () => {
const context = useContext(CartContext);
if (context === undefined) {
throw new Error('useCart must be used within a CartProvider');
}
return context;
};