diff --git a/src/app/store/[slug]/components/product-card.tsx b/src/app/store/[slug]/components/product-card.tsx index 6671b186..ff9e4064 100644 --- a/src/app/store/[slug]/components/product-card.tsx +++ b/src/app/store/[slug]/components/product-card.tsx @@ -8,6 +8,7 @@ import { Card, CardContent } from "@/components/ui/card"; import { cn } from "@/lib/utils"; import { Loader2 } from "lucide-react"; import { PriceDisplay } from "./price-display"; +import { Skeleton } from "@/components/ui/skeleton"; interface ProductCardProps { product: { @@ -127,3 +128,34 @@ export function ProductCard({ product, storeSlug, className }: ProductCardProps) ); } + +/** + * Product card skeleton loader + * Used for loading states in product grids + */ +export function ProductCardSkeleton({ className }: { className?: string }) { + return ( + + + {/* Image Skeleton */} + + + {/* Product Info Skeleton */} +
+ {/* Category */} + + + {/* Product Name */} +
+ + +
+ + {/* Price */} + +
+
+
+ ); +} + diff --git a/src/app/store/[slug]/components/product-tabs.tsx b/src/app/store/[slug]/components/product-tabs.tsx new file mode 100644 index 00000000..c316f5f7 --- /dev/null +++ b/src/app/store/[slug]/components/product-tabs.tsx @@ -0,0 +1,100 @@ +"use client"; + +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; + +interface ProductTabsProps { + description?: string | null; + specifications: { + sku: string; + barcode?: string | null; + weight?: number | null; + length?: number | null; + width?: number | null; + height?: number | null; + }; + className?: string; +} + +/** + * Product tabs component for product detail page + * Features: Description, Specifications, and Reviews tabs + * Uses shadcn/ui Tabs primitives + */ +export function ProductTabs({ description, specifications, className }: ProductTabsProps) { + return ( + + + + Description + + + Specifications + + + Reviews + + + + +
+ {description ? ( +

+ {description} +

+ ) : ( +

+ No description available for this product. +

+ )} +
+
+ + +
+
+ SKU + {specifications.sku} +
+ {specifications.barcode && ( +
+ Barcode + {specifications.barcode} +
+ )} + {specifications.weight && ( +
+ Weight + {specifications.weight} kg +
+ )} + {(specifications.length && specifications.width && specifications.height) && ( +
+ Dimensions + + {specifications.length} × {specifications.width} × {specifications.height} cm + +
+ )} +
+
+ + +
+

+ No reviews yet. Be the first to review this product! +

+ {/* TODO: Add review form and list when review feature is implemented */} +
+
+
+ ); +} diff --git a/src/app/store/[slug]/products/[productSlug]/page.tsx b/src/app/store/[slug]/products/[productSlug]/page.tsx index 897d2c9b..0c2f8e48 100644 --- a/src/app/store/[slug]/products/[productSlug]/page.tsx +++ b/src/app/store/[slug]/products/[productSlug]/page.tsx @@ -9,8 +9,8 @@ import { StockBadge } from "../../components/stock-badge"; import { VariantSelector } from "../../components/variant-selector"; import { AddToCartButton } from "../../components/add-to-cart-button"; import { ProductGrid } from "../../components/product-grid"; +import { ProductTabs } from "../../components/product-tabs"; import { Badge } from "@/components/ui/badge"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Package, TruckIcon, RefreshCw, ShieldCheck } from "lucide-react"; interface StoreProductPageProps { @@ -61,6 +61,9 @@ export async function generateMetadata({ }; } +// Revalidate this page every 5 minutes (300 seconds) +export const revalidate = 300; + export default async function StoreProductPage({ params }: StoreProductPageProps) { const { slug, productSlug } = await params; @@ -297,65 +300,18 @@ export default async function StoreProductPage({ params }: StoreProductPageProps {/* Product Details Tabs */}
- - - - Description - - - Specifications - - - - -
- {product.description ? ( -

- {product.description} -

- ) : ( -

- No description available for this product. -

- )} -
-
- - -
-
- SKU - {product.sku} -
- {product.barcode && ( -
- Barcode - {product.barcode} -
- )} - {product.weight && ( -
- Weight - {product.weight} kg -
- )} - {(product.length && product.width && product.height) && ( -
- Dimensions - - {product.length} × {product.width} × {product.height} cm - -
- )} -
-
-
+
{/* Related Products */} diff --git a/src/types/storefront-config.ts b/src/types/storefront-config.ts new file mode 100644 index 00000000..fc261840 --- /dev/null +++ b/src/types/storefront-config.ts @@ -0,0 +1,127 @@ +/** + * Storefront Configuration Types + * Shared types for multi-tenant storefront configuration + */ + +export interface HeroConfig { + title: string; + subtitle?: string; + ctaText?: string; + ctaLink?: string; + backgroundImage?: string; + overlayOpacity?: number; +} + +export interface CategoryConfig { + id: string; + name: string; + slug: string; + description?: string; + image?: string; +} + +export interface CategoriesConfig { + enabled: boolean; + title?: string; + subtitle?: string; + categories: CategoryConfig[]; +} + +export interface FeaturedProductsConfig { + enabled: boolean; + title?: string; + subtitle?: string; + limit?: number; +} + +export interface TrustBadge { + icon: string; + title: string; + description: string; +} + +export interface TrustBadgesConfig { + enabled: boolean; + badges: TrustBadge[]; +} + +export interface NewsletterConfig { + enabled: boolean; + title?: string; + subtitle?: string; + placeholder?: string; + buttonText?: string; +} + +export interface StorefrontConfig { + hero: HeroConfig; + categories: CategoriesConfig; + featuredProducts: FeaturedProductsConfig; + trustBadges: TrustBadgesConfig; + newsletter: NewsletterConfig; +} + +/** + * Get default storefront configuration + * @param storeName - Store name for dynamic config + * @param storeDescription - Store description for dynamic config + * @returns Default storefront configuration + */ +export function getDefaultStorefrontConfig( + storeName: string, + storeDescription?: string +): StorefrontConfig { + return { + hero: { + title: `Welcome to ${storeName}`, + subtitle: storeDescription || `Discover amazing products at ${storeName}`, + ctaText: "Shop Now", + ctaLink: "/products", + overlayOpacity: 0.4, + }, + categories: { + enabled: true, + title: "Shop by Category", + subtitle: "Browse our curated collections", + categories: [], + }, + featuredProducts: { + enabled: true, + title: "Featured Products", + subtitle: "Hand-picked items just for you", + limit: 8, + }, + trustBadges: { + enabled: true, + badges: [ + { + icon: "truck", + title: "Free Shipping", + description: "On orders over $50", + }, + { + icon: "refresh", + title: "Easy Returns", + description: "30-day return policy", + }, + { + icon: "shield", + title: "Secure Payment", + description: "100% secure checkout", + }, + { + icon: "headphones", + title: "24/7 Support", + description: "Dedicated customer service", + }, + ], + }, + newsletter: { + enabled: true, + title: "Stay Updated", + subtitle: "Subscribe to our newsletter for exclusive offers and updates", + placeholder: "Enter your email", + buttonText: "Subscribe", + }, + }; +}