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",
+ },
+ };
+}