-
-
+
);
+}
+
+export default function CartPage() {
+ return (
+
}>
+
+
+ );
}
\ No newline at end of file
diff --git a/app/stickers/page.tsx b/app/stickers/page.tsx
new file mode 100644
index 0000000..f263286
--- /dev/null
+++ b/app/stickers/page.tsx
@@ -0,0 +1,78 @@
+import { Main } from '@/components/main';
+import { StickerProductCard } from '@/components/stickers/sticker-product-card';
+
+const stickerProducts = [
+ {
+ id: 'sticker-circle',
+ name: 'Circle Sticker Pack',
+ price: 12.99,
+ image: '/images/stickers/circle-sticker.png',
+ description: 'A pack of colorful circular stickers perfect for decoration',
+ colors: ['Red', 'Blue', 'Green', 'Yellow']
+ },
+ {
+ id: 'sticker-star',
+ name: 'Star Sticker Collection',
+ price: 15.99,
+ image: '/images/stickers/star-sticker.png',
+ description: 'Shiny star stickers that glow in the dark',
+ colors: ['Gold', 'Silver', 'Blue', 'Purple']
+ },
+ {
+ id: 'sticker-emoji',
+ name: 'Emoji Sticker Set',
+ price: 10.99,
+ image: '/images/stickers/emoji-sticker.png',
+ description: 'Express yourself with these fun emoji stickers',
+ colors: ['Multi-color']
+ },
+ {
+ id: 'sticker-nature',
+ name: 'Nature Sticker Pack',
+ price: 14.99,
+ image: '/images/stickers/nature-sticker.png',
+ description: 'Beautiful nature-themed stickers with plants and animals',
+ colors: ['Green', 'Brown', 'Multi-color']
+ },
+ {
+ id: 'sticker-geometric',
+ name: 'Geometric Sticker Set',
+ price: 13.99,
+ image: '/images/stickers/geometric-sticker.png',
+ description: 'Modern geometric patterns for a contemporary look',
+ colors: ['Black', 'White', 'Gold', 'Silver']
+ },
+ {
+ id: 'sticker-holographic',
+ name: 'Holographic Sticker Pack',
+ price: 18.99,
+ image: '/images/stickers/holographic-sticker.png',
+ description: 'Shimmering holographic stickers that change colors',
+ colors: ['Rainbow', 'Silver', 'Gold']
+ }
+];
+
+export default function StickersPage() {
+ return (
+
+
+
+
+
+ Stickers Collection
+
+
+ Discover our amazing collection of high-quality stickers
+
+
+
+
+ {stickerProducts.map((product) => (
+
+ ))}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/navigation.tsx b/components/navigation.tsx
index 2566cfc..cde5dc5 100644
--- a/components/navigation.tsx
+++ b/components/navigation.tsx
@@ -56,7 +56,13 @@ export function Navigation() {
key={page}
className="flex items-center text-sm font-medium text-gray-700 hover:text-gray-800"
>
- {page === 'Home' ?
Home : page}
+ {page === 'Home' ? (
+
Home
+ ) : page === 'Stickers' ? (
+
Stickers
+ ) : (
+ page
+ )}
);
})}
diff --git a/components/shopping-cart/order-summary-section.tsx b/components/shopping-cart/order-summary-section.tsx
index 77147cd..34facc0 100644
--- a/components/shopping-cart/order-summary-section.tsx
+++ b/components/shopping-cart/order-summary-section.tsx
@@ -31,20 +31,23 @@ function OrderSummaryFallback({
);
}
-async function OrderSummaryContent({
+function OrderSummaryContent({
showSummerBanner,
freeDelivery,
+ subtotal,
+ itemCount,
}: {
showSummerBanner: boolean;
freeDelivery: boolean;
+ subtotal: number;
+ itemCount: number;
}) {
- const { items } = await getCart();
- const subtotal = items.length * 20; // Assuming $20 per shirt
+ // Calculate discounts and costs
const summerDiscount = showSummerBanner ? subtotal * (20 / 100) * -1 : 0; // 20% discount
- const qualifyingForFreeDelivery = freeDelivery && subtotal > 30;
- const shippingCost = 5;
- const shipping = qualifyingForFreeDelivery ? 0 : shippingCost;
- const total = subtotal + shipping + summerDiscount;
+ const shippingCost = 5.99;
+ const shipping = freeDelivery ? 0 : shippingCost;
+ const tax = subtotal * 0.08; // 8% tax
+ const total = subtotal + shipping + summerDiscount + tax;
return (
@@ -64,10 +67,10 @@ async function OrderSummaryContent({
) : null}
Shipping estimate
- {qualifyingForFreeDelivery ? (
+ {freeDelivery ? (
- {shipping.toFixed(2)} USD
+ {shippingCost.toFixed(2)} USD
{' '}
FREE
@@ -77,6 +80,12 @@ async function OrderSummaryContent({
)}
+
+
Tax
+
+ {tax.toFixed(2)} USD
+
+
Order total
@@ -90,27 +99,23 @@ async function OrderSummaryContent({
export function OrderSummarySection({
showSummerBanner,
freeDelivery,
- proceedToCheckout,
+ subtotal,
+ itemCount,
}: {
showSummerBanner: boolean;
freeDelivery: boolean;
- proceedToCheckout: React.ReactNode;
+ subtotal: number;
+ itemCount: number;
}) {
return (
-
- Order summary
-
- {proceedToCheckout}
-
- }
- >
-
-
-
+
+
+
or{' '}
@@ -122,6 +127,6 @@ export function OrderSummarySection({
-
+
);
}
diff --git a/components/shopping-cart/promo-code-section.tsx b/components/shopping-cart/promo-code-section.tsx
new file mode 100644
index 0000000..b384fc4
--- /dev/null
+++ b/components/shopping-cart/promo-code-section.tsx
@@ -0,0 +1,109 @@
+'use client';
+
+import { useState } from 'react';
+import { toast } from 'sonner';
+
+interface PromoCodeSectionProps {
+ subtotal: number;
+}
+
+const validPromoCodes = {
+ 'SAVE10': { discount: 0.10, description: '10% off' },
+ 'WELCOME20': { discount: 0.20, description: '20% off for new customers' },
+ 'FREESHIP': { discount: 0, description: 'Free shipping', freeShipping: true },
+ 'SUMMER25': { discount: 0.25, description: '25% off summer sale' },
+};
+
+export function PromoCodeSection({ subtotal }: PromoCodeSectionProps) {
+ const [promoCode, setPromoCode] = useState('');
+ const [appliedCode, setAppliedCode] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const handleApplyPromoCode = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (!promoCode.trim()) {
+ toast.error('Please enter a promo code');
+ return;
+ }
+
+ setIsLoading(true);
+
+ // Simulate API call
+ await new Promise(resolve => setTimeout(resolve, 1000));
+
+ const code = promoCode.trim().toUpperCase();
+
+ if (validPromoCodes[code as keyof typeof validPromoCodes]) {
+ setAppliedCode(code);
+ setPromoCode('');
+ toast.success(`Promo code applied: ${validPromoCodes[code as keyof typeof validPromoCodes].description}`);
+ } else {
+ toast.error('Invalid promo code');
+ }
+
+ setIsLoading(false);
+ };
+
+ const handleRemovePromoCode = () => {
+ setAppliedCode(null);
+ toast.success('Promo code removed');
+ };
+
+ return (
+
+
Promo Code
+
+ {appliedCode ? (
+
+
+
+
+
+ {appliedCode}: {validPromoCodes[appliedCode as keyof typeof validPromoCodes].description}
+
+
+
+
+
+ ) : (
+
+ )}
+
+ {/* Promo suggestions */}
+ {!appliedCode && (
+
+
+ Try: SAVE10, WELCOME20, FREESHIP, SUMMER25
+
+
+ )}
+
+ );
+}
\ No newline at end of file
diff --git a/components/shopping-cart/shipping-options-section.tsx b/components/shopping-cart/shipping-options-section.tsx
new file mode 100644
index 0000000..06495c0
--- /dev/null
+++ b/components/shopping-cart/shipping-options-section.tsx
@@ -0,0 +1,156 @@
+'use client';
+
+import { useState } from 'react';
+import { Radio, RadioGroup } from '@headlessui/react';
+import clsx from 'clsx';
+
+interface ShippingOption {
+ id: string;
+ name: string;
+ price: number;
+ description: string;
+ estimatedDays: number;
+ icon: React.ReactNode;
+}
+
+interface ShippingOptionsSectionProps {
+ freeDelivery: boolean;
+}
+
+const shippingOptions: ShippingOption[] = [
+ {
+ id: 'standard',
+ name: 'Standard Shipping',
+ price: 5.99,
+ description: 'Delivered in 5-7 business days',
+ estimatedDays: 7,
+ icon: (
+
+ ),
+ },
+ {
+ id: 'express',
+ name: 'Express Shipping',
+ price: 12.99,
+ description: 'Delivered in 2-3 business days',
+ estimatedDays: 3,
+ icon: (
+
+ ),
+ },
+ {
+ id: 'overnight',
+ name: 'Overnight Shipping',
+ price: 24.99,
+ description: 'Delivered next business day',
+ estimatedDays: 1,
+ icon: (
+
+ ),
+ },
+];
+
+export function ShippingOptionsSection({ freeDelivery }: ShippingOptionsSectionProps) {
+ const [selectedOption, setSelectedOption] = useState(shippingOptions[0]);
+
+ const getShippingPrice = (option: ShippingOption) => {
+ if (freeDelivery && option.id === 'standard') {
+ return 0;
+ }
+ return option.price;
+ };
+
+ const getEstimatedDelivery = (option: ShippingOption) => {
+ const deliveryDate = new Date();
+ deliveryDate.setDate(deliveryDate.getDate() + option.estimatedDays);
+ return deliveryDate.toLocaleDateString('en-US', {
+ month: 'short',
+ day: 'numeric',
+ });
+ };
+
+ return (
+
+
Shipping Options
+
+
+
+ {shippingOptions.map((option) => (
+
+ {({ checked }) => (
+
+
+
+
+
+ {option.icon}
+
+
+
+ {option.name}
+
+
+ {option.description}
+
+
+
+
+
+
+ {getShippingPrice(option) === 0 ? (
+ Free
+ ) : (
+ `$${getShippingPrice(option).toFixed(2)}`
+ )}
+
+
+ by {getEstimatedDelivery(option)}
+
+
+
+ )}
+
+ ))}
+
+
+
+ {freeDelivery && (
+
+
+ 🎉 You qualify for free standard shipping!
+
+
+ )}
+
+ );
+}
\ No newline at end of file
diff --git a/components/stickers/sticker-product-card.tsx b/components/stickers/sticker-product-card.tsx
new file mode 100644
index 0000000..57fb6b2
--- /dev/null
+++ b/components/stickers/sticker-product-card.tsx
@@ -0,0 +1,112 @@
+'use client';
+
+import { useState } from 'react';
+import { useRouter } from 'next/navigation';
+import { track } from '@vercel/analytics';
+import { addToCart } from '@/lib/actions';
+import { toast } from 'sonner';
+import Image from 'next/image';
+
+interface StickerProduct {
+ id: string;
+ name: string;
+ price: number;
+ image: string;
+ description: string;
+ colors: string[];
+}
+
+interface StickerProductCardProps {
+ product: StickerProduct;
+}
+
+export function StickerProductCard({ product }: StickerProductCardProps) {
+ const [isLoading, setIsLoading] = useState(false);
+ const [selectedColor, setSelectedColor] = useState(product.colors[0]);
+ const router = useRouter();
+
+ const handleAddToCart = async () => {
+ setIsLoading(true);
+ track('add_to_cart:clicked', { product_id: product.id });
+
+ try {
+ await addToCart({
+ id: product.id,
+ color: selectedColor,
+ size: 'One Size',
+ quantity: 1
+ });
+
+ toast.success('Added to cart!', {
+ description: `${product.name} has been added to your cart.`,
+ });
+
+ // Optionally redirect to cart
+ // router.push('/cart');
+ } catch (error) {
+ toast.error('Failed to add to cart', {
+ description: 'Please try again later.',
+ });
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+
+
+ {/* Placeholder colored rectangle since we don't have actual sticker images */}
+
+
+
+
+
+
{product.name}
+
${product.price}
+
+
+
{product.description}
+
+ {/* Color Selection */}
+
+
+
+ {product.colors.map((color) => (
+
+ ))}
+
+
+
+ {/* Add to Cart Button */}
+
+
+
+ );
+}
\ No newline at end of file