Merge version_2 into main
Merge version_2 into main
This commit was merged in pull request #5.
This commit is contained in:
@@ -21,12 +21,13 @@ interface CartContextTypeExtended {
|
||||
}
|
||||
|
||||
const CartPageContent = () => {
|
||||
const { cartItems, removeFromCart, updateQuantity, getTotalPrice } = useCart() as CartContextTypeExtended;
|
||||
const { cartItems, removeFromCart, updateQuantity, getTotalPrice } = useCart() as unknown as CartContextTypeExtended;
|
||||
|
||||
const navItems = [
|
||||
{ name: 'Products', id: '/products' },
|
||||
{ name: 'Cart', id: '/cart' },
|
||||
{ name: 'Checkout', id: '/checkout' },
|
||||
{ name: 'Home', id: '/' }
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,185 +4,101 @@ import { ThemeProvider } from '@/providers/themeProvider/ThemeProvider';
|
||||
import NavbarLayoutFloatingOverlay from '@/components/navbar/NavbarLayoutFloatingOverlay/NavbarLayoutFloatingOverlay';
|
||||
import FooterCard from '@/components/sections/footer/FooterCard';
|
||||
import { useCart } from '@/components/cart/CartProvider';
|
||||
import { CreditCard, Truck, Receipt, Facebook, Twitter, Instagram } from 'lucide-react';
|
||||
import React, { useState } from 'react';
|
||||
import { ShoppingBag, CreditCard, Truck, CheckCircle, Facebook, Twitter, Instagram } from 'lucide-react';
|
||||
|
||||
interface CartContextTypeExtended {
|
||||
cartItems: Array<{
|
||||
id: string;
|
||||
imageSrc: string;
|
||||
imageAlt: string;
|
||||
name: string;
|
||||
price: string;
|
||||
quantity: number;
|
||||
}>;
|
||||
removeFromCart: (id: string) => void;
|
||||
updateQuantity: (id: string, quantity: number) => void;
|
||||
getTotalPrice: () => number;
|
||||
}
|
||||
|
||||
interface CheckoutItem {
|
||||
id: string;
|
||||
name: string;
|
||||
price: string;
|
||||
quantity: number;
|
||||
}
|
||||
|
||||
const CheckoutPageContent = () => {
|
||||
const { cartItems, getTotalPrice, clearCart } = useCart();
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
email: '',
|
||||
address: '',
|
||||
city: '',
|
||||
zip: '',
|
||||
cardNumber: '',
|
||||
cardExpiry: '',
|
||||
cardCVC: '',
|
||||
});
|
||||
const [orderConfirmed, setOrderConfirmed] = useState(false);
|
||||
|
||||
const handleChange = (e) => {
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
};
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
// Simulate order processing
|
||||
console.log('Order submitted:', formData, 'Items:', cartItems);
|
||||
setOrderConfirmed(true);
|
||||
clearCart(); // Clear cart after successful order
|
||||
};
|
||||
const { cartItems, getTotalPrice } = useCart() as unknown as CartContextTypeExtended; // Fix 1: Type assertion
|
||||
|
||||
const navItems = [
|
||||
{ name: 'Products', id: '/products' },
|
||||
{ name: 'Cart', id: '/cart' },
|
||||
{ name: 'Checkout', id: '/checkout' },
|
||||
{ name: 'Home', id: '/' }
|
||||
];
|
||||
|
||||
if (orderConfirmed) {
|
||||
return (
|
||||
<>
|
||||
<NavbarLayoutFloatingOverlay
|
||||
navItems={navItems}
|
||||
button={{ text: 'Continue Shopping', href: '/products' }}
|
||||
/>
|
||||
<main className="container mx-auto px-4 py-8 text-center min-h-[calc(100vh-160px)]">
|
||||
<Receipt className="mx-auto text-green-500 mb-4" size={64} />
|
||||
<h1 className="text-4xl font-bold mb-4">Order Confirmed!</h1>
|
||||
<p className="text-lg mb-6">Thank you for your purchase. Your order will be shipped soon.</p>
|
||||
<a href="/products" className="btn-primary px-6 py-3 rounded-md text-lg">Continue Shopping</a>
|
||||
</main>
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterCard
|
||||
logoText="GR Tackle"
|
||||
copyrightText="© 2024 GR Tackle. All rights reserved."
|
||||
socialLinks={[
|
||||
{ icon: Facebook, href: '#', ariaLabel: 'Facebook' },
|
||||
{ icon: Twitter, href: '#', ariaLabel: 'Twitter' },
|
||||
{ icon: Instagram, href: '#', ariaLabel: 'Instagram' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
const handleConfirmCheckout = (items: CheckoutItem[], totalPrice: string) => {
|
||||
// In a real application, this would handle payment processing and order finalization.
|
||||
console.log('Order Confirmed!', { items, totalPrice });
|
||||
alert(`Order placed successfully! Total: $${totalPrice}`);
|
||||
// Redirect to a success page or clear cart
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<NavbarLayoutFloatingOverlay
|
||||
navItems={navItems}
|
||||
button={{ text: 'Return to Cart', href: '/cart' }}
|
||||
button={{ text: 'Cart', href: '/cart' }}
|
||||
/>
|
||||
<main className="container mx-auto px-4 py-8 min-h-[calc(100vh-160px)]">
|
||||
<h1 className="text-3xl font-bold mb-6 flex items-center">
|
||||
<CreditCard className="mr-3" /> Checkout
|
||||
<ShoppingBag className="mr-3" /> Checkout
|
||||
</h1>
|
||||
|
||||
{cartItems.length === 0 ? (
|
||||
<p className="text-lg">Your cart is empty. Please <a href="/products" className="text-primary-cta hover:underline">add items</a> before checking out.</p>
|
||||
<p className="text-lg">Your cart is empty. <a href="/products" className="text-primary-cta hover:underline">Start shopping!</a></p>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold mb-4">Shipping Information</h2>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="Full Name"
|
||||
value={formData.name}
|
||||
onChange={handleChange}
|
||||
className="w-full p-3 border rounded-md"
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
className="w-full p-3 border rounded-md"
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="address"
|
||||
placeholder="Address"
|
||||
value={formData.address}
|
||||
onChange={handleChange}
|
||||
className="w-full p-3 border rounded-md"
|
||||
required
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<input
|
||||
type="text"
|
||||
name="city"
|
||||
placeholder="City"
|
||||
value={formData.city}
|
||||
onChange={handleChange}
|
||||
className="w-full p-3 border rounded-md"
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="zip"
|
||||
placeholder="ZIP Code"
|
||||
value={formData.zip}
|
||||
onChange={handleChange}
|
||||
className="w-full p-3 border rounded-md"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h2 className="text-2xl font-semibold mb-4 pt-6">Payment Information</h2>
|
||||
<input
|
||||
type="text"
|
||||
name="cardNumber"
|
||||
placeholder="Card Number"
|
||||
value={formData.cardNumber}
|
||||
onChange={handleChange}
|
||||
className="w-full p-3 border rounded-md"
|
||||
required
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<input
|
||||
type="text"
|
||||
name="cardExpiry"
|
||||
placeholder="MM/YY"
|
||||
value={formData.cardExpiry}
|
||||
onChange={handleChange}
|
||||
className="w-full p-3 border rounded-md"
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
name="cardCVC"
|
||||
placeholder="CVC"
|
||||
value={formData.cardCVC}
|
||||
onChange={handleChange}
|
||||
className="w-full p-3 border rounded-md"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button type="submit" className="btn-primary w-full px-6 py-3 rounded-md text-lg">Place Order</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
{/* Order Summary */}
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold mb-4">Order Summary</h2>
|
||||
<div className="border rounded-md p-4">
|
||||
<div className="border rounded-md p-4 bg-white shadow-sm">
|
||||
{cartItems.map((item) => (
|
||||
<div key={item.id} className="flex justify-between items-center mb-2">
|
||||
<span>{item.name} (x{item.quantity})</span>
|
||||
<span>${(parseFloat(item.price) * item.quantity).toFixed(2)}</span>
|
||||
<div key={item.id} className="flex justify-between items-center py-2 border-b last:border-b-0">
|
||||
<span className="text-gray-700">{item.name} (x{item.quantity})</span>
|
||||
<span className="font-medium">${(parseFloat(item.price) * item.quantity).toFixed(2)}</span>
|
||||
</div>
|
||||
))}
|
||||
<div className="border-t pt-4 mt-4 flex justify-between items-center font-bold text-xl">
|
||||
<div className="flex justify-between items-center pt-4 text-xl font-bold">
|
||||
<span>Total:</span>
|
||||
<span>${getTotalPrice().toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Payment & Shipping */}
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold mb-4">Payment Information</h2>
|
||||
<div className="border rounded-md p-4 bg-white shadow-sm space-y-4">
|
||||
<p className="flex items-center text-lg"><CreditCard className="mr-2" /> Secure Payment Gateway</p>
|
||||
{/* Placeholder for payment form */}
|
||||
<div className="border-t pt-4">
|
||||
<h3 className="text-xl font-semibold mb-2">Shipping Address</h3>
|
||||
{/* Placeholder for shipping address form */}
|
||||
<p className="text-gray-600 flex items-center"><Truck className="mr-2" /> Estimated delivery: 3-5 business days</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => handleConfirmCheckout(
|
||||
cartItems.map(item => ({ id: item.id, name: item.name, price: item.price, quantity: item.quantity })),
|
||||
getTotalPrice().toFixed(2) // Fix 2: Convert number to string
|
||||
)}
|
||||
className="btn-primary w-full px-6 py-3 rounded-md text-lg flex items-center justify-center"
|
||||
>
|
||||
<CheckCircle className="mr-2" /> Confirm Order
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
|
||||
183
src/app/page.tsx
183
src/app/page.tsx
@@ -1,149 +1,64 @@
|
||||
"use client";
|
||||
'use client';
|
||||
|
||||
import { ThemeProvider } from "@/components/ThemeProvider";
|
||||
import { ThemeProvider } from '@/providers/themeProvider/ThemeProvider';
|
||||
import NavbarLayoutFloatingOverlay from '@/components/navbar/NavbarLayoutFloatingOverlay/NavbarLayoutFloatingOverlay';
|
||||
import FooterBaseReveal from '@/components/sections/footer/FooterBaseReveal';
|
||||
import Image from "next/image";
|
||||
import FooterCard from '@/components/sections/footer/FooterCard';
|
||||
import HeroLogoBillboardSplit from '@/components/sections/hero/HeroLogoBillboardSplit';
|
||||
import { Facebook, Twitter, Instagram } from 'lucide-react';
|
||||
|
||||
export default function Home() {
|
||||
const HomePageContent = () => {
|
||||
const navItems = [
|
||||
{ name: 'Products', id: '/products' },
|
||||
{ name: 'Cart', id: '/cart' },
|
||||
{ name: 'Checkout', id: '/checkout' },
|
||||
{ name: 'Home', id: '/' }
|
||||
];
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
defaultButtonVariant="hover-magnetic"
|
||||
defaultTextAnimation="entrance-slide"
|
||||
borderRadius="rounded"
|
||||
contentWidth="medium"
|
||||
sizing="medium"
|
||||
background="none"
|
||||
cardStyle="solid"
|
||||
primaryButtonStyle="gradient"
|
||||
secondaryButtonStyle="glass"
|
||||
headingFontWeight="semibold"
|
||||
>
|
||||
<>
|
||||
<NavbarLayoutFloatingOverlay
|
||||
navItems={navItems}
|
||||
button={{ text: "Get Started", href: "#" }}
|
||||
brandName="Webild"
|
||||
button={{ text: 'Shop Now', href: '/products' }}
|
||||
/>
|
||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
||||
<div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
|
||||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
||||
Get started by editing
|
||||
<code className="font-mono font-bold">src/app/page.tsx</code>
|
||||
</p>
|
||||
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
|
||||
<a
|
||||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
By{" "}
|
||||
<Image
|
||||
src="/vercel.svg"
|
||||
alt="Vercel Logo"
|
||||
className="dark:invert"
|
||||
width={100}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-full before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-full after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 sm:before:w-[480px] sm:after:w-[240px] before:lg:h-[360px]">
|
||||
<Image
|
||||
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js Logo"
|
||||
width={180}
|
||||
height={37}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-32 grid text-center lg:mb-0 lg:w-full lg:max-w-5xl lg:grid-cols-4 lg:text-left">
|
||||
<a
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className="mb-3 text-2xl font-semibold">
|
||||
Docs{" "}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
||||
Find in-depth information about Next.js features and API.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className="mb-3 text-2xl font-semibold">
|
||||
Learn{" "}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
||||
Learn about Next.js in an interactive course with quizzes!
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className="mb-3 text-2xl font-semibold">
|
||||
Templates{" "}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
||||
Discover and deploy boilerplate example Next.js projects.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className="mb-3 text-2xl font-semibold">
|
||||
Deploy{" "}
|
||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
||||
->
|
||||
</span>
|
||||
</h2>
|
||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroLogoBillboardSplit
|
||||
logoText="GR Tackle"
|
||||
description="Your ultimate destination for premium fishing gear and accessories."
|
||||
background={{ variant: 'radial-gradient' }}
|
||||
buttons={[
|
||||
{ text: 'Shop All Gear', href: '/products' },
|
||||
{ text: 'Learn More', href: '#about' }
|
||||
]}
|
||||
buttonAnimation="opacity"
|
||||
layoutOrder="default"
|
||||
imageSrc="https://assets.webuild.ai/gr-tackle/hero-fishing-lure.jpg"
|
||||
imageAlt="A vibrant fishing lure in clear water"
|
||||
/>
|
||||
</div>
|
||||
<main className="container mx-auto px-4 py-8 min-h-screen">
|
||||
<h1 className="text-4xl font-bold text-center mb-10">Discover Our Products</h1>
|
||||
{/* Placeholder for other homepage sections (e.g., product showcase, features) */}
|
||||
<p className="text-lg text-center">Explore our wide range of high-quality fishing tackle.</p>
|
||||
</main>
|
||||
<FooterBaseReveal
|
||||
columns={[]}
|
||||
copyrightText="Proudly based on the Grand River, Grand Rapids, MI. © 2023 Webild. All rights reserved."
|
||||
ariaLabel="Footer section"
|
||||
/>
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterCard
|
||||
logoText="GR Tackle"
|
||||
copyrightText="© 2024 GR Tackle. All rights reserved."
|
||||
socialLinks={[
|
||||
{ icon: Facebook, href: '#', ariaLabel: 'Facebook' },
|
||||
{ icon: Twitter, href: '#', ariaLabel: 'Twitter' },
|
||||
{ icon: Instagram, href: '#', ariaLabel: 'Instagram' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<ThemeProvider defaultButtonVariant="expand-hover" defaultTextAnimation="entrance-slide" borderRadius="rounded" contentWidth="medium" sizing="medium" background="none" cardStyle="solid" primaryButtonStyle="gradient" secondaryButtonStyle="glass" headingFontWeight="bold">
|
||||
<HomePageContent />
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user