{
  "name": "product-variant-01-block",
  "type": "registry:block",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "badge",
    "https://ui.stackzero.co/r/image-viewer-basic.json",
    "https://ui.stackzero.co/r/price-format-sale.json",
    "https://ui.stackzero.co/r/variant-selector-basic.json",
    "https://ui.stackzero.co/r/quantity-input-basic.json"
  ],
  "files": [
    {
      "type": "registry:block",
      "content": "\"use client\";\n\nimport ImageViewer from \"@/components/commerce-ui/image-viewer-basic\";\nimport PriceFormat_Sale from \"@/components/commerce-ui/price-format-sale\";\nimport QuantityInputBasic from \"@/components/commerce-ui/quantity-input-basic\";\nimport VariantSelectorBasic, {\n  VariantItem as BaseVariantItem,\n} from \"@/components/commerce-ui/variant-selector-basic\";\nimport { Button } from \"@/components/ui/button\";\nimport { Clock } from \"lucide-react\";\nimport { useState } from \"react\";\n\ninterface VariantItem extends BaseVariantItem {\n  price: number;\n  salePrice?: number;\n  imageUrl?: string;\n  isInStock?: boolean;\n  availableQuantity?: number | null;\n}\ninterface VariantSelectionPayload {\n  variantId: string;\n  variantLabel: string;\n  quantity: number;\n  price: number;\n  originalPrice?: number;\n  salePrice?: number;\n  totalPrice: number;\n  isOnSale: boolean;\n}\ninterface ProductVariant01Props {\n  title?: string;\n  description?: string;\n  badge?: string | null;\n  shippingInfo?: string;\n  variants: VariantItem[];\n  defaultImage?: string;\n  initialVariant?: string;\n  variantLabel?: string;\n  onAddToCart?: (payload: VariantSelectionPayload) => void;\n  onBuyNow?: (payload: VariantSelectionPayload) => void;\n  selectedVariant?: string;\n  onVariantChange?: (variant: string) => void;\n  quantity?: number;\n  onQuantityChange?: (quantity: number) => void;\n  isLoading?: boolean;\n  errorMessage?: string | null;\n}\n\nfunction ProductVariant_01({\n  badge = \"New\",\n  defaultImage,\n  description = \"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\",\n  errorMessage = null,\n  initialVariant,\n  isLoading = false,\n  onAddToCart = () => {},\n  onBuyNow = () => {},\n  onQuantityChange,\n  onVariantChange,\n  quantity: controlledQuantity,\n  selectedVariant: controlledVariant,\n  shippingInfo,\n  title = \"Product Variant Title\",\n  variantLabel = \"Variant\",\n  variants,\n}: ProductVariant01Props) {\n  // Ensure variants array is not empty\n  if (!variants.length) {\n    throw new Error(\"At least one variant must be provided\");\n  }\n\n  const defaultInitialVariant = initialVariant || variants[0].value;\n\n  const [internalSelectedVariant, setInternalSelectedVariant] = useState(\n    defaultInitialVariant\n  );\n  const [internalQuantity, setInternalQuantity] = useState(1);\n\n  // Determine if we're in controlled or uncontrolled mode\n  const isVariantControlled = controlledVariant !== undefined;\n  const isQuantityControlled = controlledQuantity !== undefined;\n  const selectedVariantId = isVariantControlled\n    ? controlledVariant\n    : internalSelectedVariant;\n  const quantity = isQuantityControlled ? controlledQuantity : internalQuantity;\n\n  const handleVariantChange = (newVariant: string) => {\n    if (isVariantControlled) {\n      onVariantChange?.(newVariant);\n    } else {\n      setInternalSelectedVariant(newVariant);\n    }\n  };\n\n  const handleQuantityChange = (newQuantity: number) => {\n    if (isQuantityControlled) {\n      onQuantityChange?.(newQuantity);\n    } else {\n      setInternalQuantity(newQuantity);\n    }\n  };\n\n  const selectedVariant =\n    variants.find((v) => v.value === selectedVariantId) || variants[0];\n\n  const currentImage = selectedVariant?.imageUrl || defaultImage;\n  const currentPrice = selectedVariant.price;\n  const currentSalePrice = selectedVariant.salePrice;\n  const isOnSale =\n    currentSalePrice !== undefined && currentSalePrice < currentPrice;\n\n  // Get stock status from the selected variant\n  const isInStock =\n    selectedVariant.isInStock !== undefined ? selectedVariant.isInStock : true; // Default to in stock if not specified\n\n  const availableQuantity = selectedVariant.availableQuantity;\n\n  const effectivePrice = isOnSale ? currentSalePrice : currentPrice;\n\n  const handleAddToCart = () => {\n    onAddToCart({\n      isOnSale: isOnSale,\n      originalPrice: isOnSale ? currentPrice : undefined,\n      price: currentPrice,\n      quantity: quantity,\n      salePrice: isOnSale ? currentSalePrice : undefined,\n      totalPrice: quantity * effectivePrice,\n      variantId: selectedVariantId,\n      variantLabel: selectedVariant?.label || \"\",\n    });\n  };\n\n  const handleBuyNow = () => {\n    onBuyNow({\n      isOnSale: isOnSale,\n      originalPrice: isOnSale ? currentPrice : undefined,\n      price: currentPrice,\n      quantity: quantity,\n      salePrice: isOnSale ? currentSalePrice : undefined,\n      totalPrice: quantity * effectivePrice,\n      variantId: selectedVariantId,\n      variantLabel: selectedVariant?.label || \"\",\n    });\n  };\n\n  if (errorMessage) {\n    return (\n      <div className=\"my-6 rounded-lg border border-red-200 bg-red-50 p-6 text-red-600 dark:border-red-900 dark:bg-red-900/20 dark:text-red-400\">\n        <p className=\"font-medium\">Error loading product</p>\n        <p className=\"text-sm\">{errorMessage}</p>\n      </div>\n    );\n  }\n\n  // Add visual indicator for out of stock items in variant selector\n  const variantsWithStockIndicator = variants.map((variant) => {\n    const isVariantInStock =\n      variant.isInStock !== undefined ? variant.isInStock : true;\n    return {\n      ...variant,\n      disabled: !isVariantInStock,\n      label: variant.label + (isVariantInStock ? \"\" : \" (Out of Stock)\"),\n    };\n  });\n\n  return (\n    <div className=\"my-6 grid max-w-screen-lg grid-cols-1 gap-12 rounded-lg md:grid-cols-2\">\n      <div className=\"relative h-fit w-full overflow-hidden rounded-2xl bg-gradient-to-br from-teal-50 to-cyan-50 p-5 dark:from-teal-950/30 dark:to-cyan-950/30\">\n        {badge && (\n          <span className=\"absolute top-4 left-4 z-10 rounded-full bg-gradient-to-r from-teal-500 to-cyan-600 px-3 py-1.5 text-xs font-bold text-white\">\n            {badge}\n          </span>\n        )}\n        <div className=\"transition-transform duration-500 hover:scale-105\">\n          {isLoading ? (\n            <div className=\"flex h-[300px] items-center justify-center\">\n              <div className=\"h-10 w-10 animate-spin rounded-full border-4 border-teal-200 border-t-teal-600\"></div>\n            </div>\n          ) : (\n            <ImageViewer\n              imageUrl={currentImage || \"\"}\n              classNameThumbnailViewer=\"rounded-lg object-contain h-[300px] mx-auto\"\n            />\n          )}\n        </div>\n      </div>\n\n      <div className=\"flex flex-col gap-6\">\n        {isLoading ? (\n          <div className=\"space-y-4\">\n            <div className=\"h-8 w-3/4 animate-pulse rounded-md bg-gray-200 dark:bg-gray-700\"></div>\n            <div className=\"h-16 animate-pulse rounded-md bg-gray-200 dark:bg-gray-700\"></div>\n            <div className=\"h-8 w-1/3 animate-pulse rounded-md bg-gray-200 dark:bg-gray-700\"></div>\n          </div>\n        ) : (\n          <>\n            <div>\n              <h2 className=\"text-3xl font-bold tracking-tight text-gray-900 dark:text-gray-100\">\n                {title}\n              </h2>\n              <p className=\"mt-3 text-gray-600 dark:text-gray-400\">\n                {description}\n              </p>\n            </div>\n\n            <div className=\"flex flex-wrap items-center gap-2\">\n              <PriceFormat_Sale\n                originalPrice={currentPrice}\n                salePrice={isOnSale ? currentSalePrice : undefined}\n                showSavePercentage\n                className=\"items-baseline\"\n                classNameOriginalPrice=\"text-lg text-gray-500 line-through\"\n                classNameSalePrice=\"text-3xl font-bold text-teal-700 dark:text-teal-400\"\n                classNameSalePercentage=\"bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400 text-xs px-2 py-0.5 rounded-md\"\n              />\n\n              {shippingInfo && (\n                <p className=\"mt-1 inline-flex items-center text-sm text-green-600 dark:text-green-400\">\n                  <Clock className=\"mr-1 h-4 w-4\" />\n                  {shippingInfo}\n                </p>\n              )}\n            </div>\n\n            {isInStock ? (\n              <div className=\"rounded-md bg-green-50 p-3 text-green-800 dark:bg-green-900/20 dark:text-green-300\">\n                <p className=\"text-sm font-bold\">In Stock</p>\n                {availableQuantity !== null &&\n                  availableQuantity !== undefined &&\n                  availableQuantity > 0 && (\n                    <span className=\"mt-1 text-sm font-normal\">\n                      {availableQuantity} units available\n                    </span>\n                  )}\n              </div>\n            ) : (\n              <div className=\"rounded-md bg-amber-50 p-3 text-amber-800 dark:bg-amber-900/20 dark:text-amber-300\">\n                <p className=\"text-sm font-bold\">Currently out of stock</p>\n              </div>\n            )}\n\n            <div className=\"space-y-6\">\n              <div>\n                <label className=\"mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300\">\n                  {variantLabel}\n                </label>\n                <VariantSelectorBasic\n                  value={selectedVariantId}\n                  onValueChange={handleVariantChange}\n                  variants={variantsWithStockIndicator}\n                  className=\"grid-cols-2 sm:grid-cols-2\"\n                  itemClassName=\"bg-gray-50 border-gray-200 hover:border-teal-300 dark:bg-gray-800 dark:border-gray-700\n                                data-[state=checked]:border-teal-500 data-[state=checked]:bg-teal-50 \n                                data-[state=checked]:text-teal-700 dark:data-[state=checked]:bg-gray-700 \n                                dark:data-[state=checked]:border-teal-500 dark:data-[state=checked]:text-teal-300\n                                focus:ring-2 focus:ring-teal-500/50 focus:ring-offset-2 focus:border-teal-400\n                                dark:focus:ring-teal-500/40 dark:focus:ring-offset-gray-900\"\n                />\n              </div>\n            </div>\n\n            <div>\n              <label className=\"mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300\">\n                Quantity\n              </label>\n              <QuantityInputBasic\n                quantity={quantity}\n                onChange={handleQuantityChange}\n                max={\n                  availableQuantity !== null && availableQuantity !== undefined\n                    ? availableQuantity\n                    : undefined\n                }\n                min={1}\n                className=\"max-w-[150px] border-gray-300 dark:border-gray-700\"\n                disabled={!isInStock}\n              />\n            </div>\n\n            <div className=\"mt-2 flex flex-col flex-wrap gap-3 sm:flex-row\">\n              <Button\n                variant=\"outline\"\n                className=\"w-full border-gray-300 bg-white text-gray-800 transition-all duration-200 hover:border-teal-500 hover:bg-teal-50 hover:text-teal-700 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200 dark:hover:border-teal-500 dark:hover:bg-gray-700\"\n                onClick={handleAddToCart}\n                disabled={!isInStock || isLoading}\n              >\n                {isLoading ? \"Loading...\" : \"Add to Cart\"}\n              </Button>\n              <Button\n                className=\"w-full bg-gradient-to-r from-teal-600 to-cyan-600 text-white transition-all hover:from-teal-700 hover:to-cyan-700 disabled:from-gray-400 disabled:to-gray-500\"\n                onClick={handleBuyNow}\n                disabled={!isInStock || isLoading}\n              >\n                {isLoading ? \"Loading...\" : \"Buy Now\"}\n              </Button>\n            </div>\n\n            <div className=\"mt-4 rounded-lg border border-gray-200 p-4 dark:border-gray-800\">\n              <p className=\"font-medium text-gray-900 dark:text-gray-100\">\n                Selected Configuration:\n              </p>\n              <div className=\"mt-2 flex items-center justify-between\">\n                <div className=\"flex items-center gap-2\">\n                  <div className=\"h-3 w-3 rounded-full bg-teal-500\"></div>\n                  <p className=\"text-gray-700 dark:text-gray-300\">\n                    {selectedVariant?.label}\n                  </p>\n                </div>\n                <p className=\"font-medium text-teal-700 dark:text-teal-400\">\n                  {isOnSale ? (\n                    <span>\n                      <span className=\"mr-2 line-through opacity-70\">\n                        ${currentPrice}\n                      </span>\n                      ${currentSalePrice}\n                    </span>\n                  ) : (\n                    `$${currentPrice}`\n                  )}\n                </p>\n              </div>\n              <p className=\"mt-2 text-xs text-gray-500\">\n                {quantity} {quantity > 1 ? \"units\" : \"unit\"} × $\n                {effectivePrice.toFixed(2)} = $\n                {(quantity * effectivePrice).toFixed(2)}\n              </p>\n              <p className=\"mt-1 text-xs text-gray-500\">\n                {isInStock ? \"In Stock\" : \"Out of Stock\"}\n                {isInStock &&\n                  availableQuantity !== null &&\n                  availableQuantity !== undefined &&\n                  ` (${availableQuantity} available)`}\n              </p>\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default ProductVariant_01;\nexport type { ProductVariant01Props, VariantItem, VariantSelectionPayload };\n",
      "path": "/components/commerce-ui/blocks/product-variants/product-variants-01.tsx",
      "target": "components/commerce-ui/product-variants-01.tsx"
    }
  ]
}