All files / src/components/features/analytics ABTest.tsx

61.53% Statements 64/104
100% Branches 0/0
0% Functions 0/2
61.53% Lines 64/104

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 1051x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                           1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                        
"use client";
 
/**
 * A/B Test Component
 *
 * Renders different content based on A/B test variant assignment.
 */
 
import { type ReactNode } from "react";
import { useABTest } from "@/hooks/useABTest";
 
/**
 * Props for ABTest component
 */
interface ABTestProps {
  /** The name of the experiment */
  experimentName: string;
  /** Variant components to render */
  variants: {
    [key: string]: ReactNode;
  };
  /** Fallback component while loading */
  fallback?: ReactNode;
  /** Component to show when experiment not running or user not in test */
  defaultVariant?: string;
}
 
/**
 * A/B Test Component
 *
 * Renders different content based on the visitor's assigned variant.
 *
 * @example
 * ```tsx
 * <ABTest
 *   experimentName="checkout-button-color"
 *   variants={{
 *     control: <Button variant="primary">Checkout</Button>,
 *     variant_a: <Button variant="success">Complete Order</Button>,
 *     variant_b: <Button variant="warning">Buy Now</Button>,
 *   }}
 *   fallback={<Skeleton className="h-10 w-24" />}
 * />
 * ```
 */
export function ABTest({
  experimentName,
  variants,
  fallback,
  defaultVariant = "control"}: ABTestProps) {
  const { variant, isLoading } = useABTest(experimentName);

  // Show fallback while loading
  if (isLoading) {
    return <>{fallback || variants[defaultVariant] || null}</>;
  }

  // If no variant assigned (experiment not running or user excluded),
  // show default variant
  if (!variant) {
    return <>{variants[defaultVariant] || fallback || null}</>;
  }

  // Show assigned variant or fall back to default
  return <>{variants[variant] || variants[defaultVariant] || fallback || null}</>;
}
 
/**
 * Hook version of ABTest for more control
 *
 * @example
 * ```tsx
 * const { renderVariant, variant, isLoading, trackConversion } = useABTestRender("checkout-cta");
 *
 * return (
 *   <Button onClick={() => { trackConversion(); handleCheckout(); }}>
 *     {renderVariant({
 *       control: "Checkout",
 *       variant_a: "Complete Order",
 *       variant_b: "Buy Now",
 *     })}
 *   </Button>
 * );
 * ```
 */
export function useABTestRender(experimentName: string) {
  const { variant, isLoading, trackConversion } = useABTest(experimentName);

  const renderVariant = <T,>(
    variants: Record<string, T>,
    defaultVariant: string = "control"
  ): T | undefined => {
    if (isLoading || !variant) {
      return variants[defaultVariant];
    }
    return variants[variant] || variants[defaultVariant];
  };

  return {
    renderVariant,
    variant,
    isLoading,
    trackConversion};
}