Skip to main content

Hooks Overview

The React SDK provides hooks for all experience types. Each hook follows a consistent pattern with state management, actions, and automatic event subscriptions.

Available Hooks

HookDescriptionSee Also
useFanfare()Access SDK instanceContext
useFanfareAuth()Authentication state and methodsAuth Hook
useQueue(queueId)Queue operations and stateuseQueue
useDraw(drawId)Draw operations and stateuseDraw
useAuction(auctionId)Auction operations and stateuseAuction
useWaitlist(waitlistId)Waitlist operations and stateuseWaitlist
useTimedRelease(id)Timed release operationsuseTimedRelease
useExperienceJourney(id)Journey orchestrationuseExperienceJourney

Common Hook Pattern

All experience hooks share a consistent interface:
interface UseExperienceHook {
  // Loading state
  isLoading: boolean;

  // Error state
  error: Error | null;

  // Client-friendly status
  status: ClientStatus;

  // Experience-specific state...

  // Actions
  enter: (metadata?: Record<string, unknown>) => Promise<void>;
  leave: () => Promise<void>;
  refreshStatus: () => Promise<void>;
  // Experience-specific actions...
}

useFanfareAuth

Hook for authentication state and methods.
function useFanfareAuth(): {
  isAuthenticated: boolean;
  isGuest: boolean | undefined;
  session: Session | undefined;
  guest: () => Promise<GuestSession>;
  requestOtp: (options: OtpRequest) => Promise<void>;
  verifyOtp: (options: OtpVerify) => Promise<AuthenticatedSession>;
  logout: () => Promise<void>;
};

Usage

import { useFanfareAuth } from "@waitify-io/fanfare-sdk-react";

function AuthComponent() {
  const { isAuthenticated, isGuest, session, guest, requestOtp, verifyOtp, logout } = useFanfareAuth();

  if (!isAuthenticated && !isGuest) {
    return (
      <div>
        <button onClick={guest}>Continue as Guest</button>
        <button onClick={() => requestOtp({ email: "[email protected]" })}>Login with Email</button>
      </div>
    );
  }

  if (isGuest) {
    return (
      <div>
        <p>Guest session: {session?.consumerId}</p>
        <button onClick={() => requestOtp({ email: "[email protected]" })}>Upgrade to Account</button>
      </div>
    );
  }

  return (
    <div>
      <p>Logged in as: {session?.email}</p>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

OTP Flow

function OtpLogin() {
  const { requestOtp, verifyOtp } = useFanfareAuth();
  const [email, setEmail] = useState("");
  const [code, setCode] = useState("");
  const [step, setStep] = useState<"email" | "code">("email");

  const handleRequestOtp = async () => {
    await requestOtp({ email });
    setStep("code");
  };

  const handleVerifyOtp = async () => {
    await verifyOtp({ email, code });
  };

  if (step === "email") {
    return (
      <div>
        <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
        <button onClick={handleRequestOtp}>Send Code</button>
      </div>
    );
  }

  return (
    <div>
      <input value={code} onChange={(e) => setCode(e.target.value)} placeholder="Enter code" />
      <button onClick={handleVerifyOtp}>Verify</button>
    </div>
  );
}

Quick Reference

useQueue

const {
  queue, // Queue details
  status, // QueueConsumerState
  position, // number | null
  isLoading,
  error,
  enter, // () => Promise<QueueEnterResult>
  leave, // () => Promise<void>
} = useQueue("queue_123");

useDraw

const {
  draw, // Draw details
  status, // UseDrawClientStatus
  consumerState, // DrawConsumerState
  isEntered,
  isWinner,
  admissionToken,
  result, // DrawResult | null
  isLoading,
  error,
  enter, // (metadata?) => Promise<DrawConsumerState>
  withdraw, // () => Promise<void>
  refreshStatus, // () => Promise<DrawConsumerState | null>
  checkResult, // () => Promise<DrawResult | null>
} = useDraw("draw_123");

useAuction

const {
  details, // AuctionDetails
  status, // UseAuctionClientStatus
  currentBid, // string | null
  myBid, // string | null
  minNextBid, // string | null
  bidIncrement, // string | null
  reservePrice, // string | null
  reserveMet, // boolean
  bidCount, // number
  bidHistory, // Bid[]
  timeRemaining, // number | null
  isWinning, // boolean
  autoRebidConfig, // AutoRebidConfig | null
  isLoading,
  error,
  enter, // () => Promise<void>
  leave, // () => Promise<void>
  placeBid, // (amount: string) => Promise<BidResult>
  refreshStatus, // () => Promise<AuctionStatus | null>
  refreshHistory, // () => Promise<Bid[]>
  enableAutoRebid, // (maxBid, increment) => void
  disableAutoRebid, // () => void
} = useAuction("auction_123");

useWaitlist

const {
  status, // UseWaitlistClientStatus
  waitlistStatus, // WaitlistStatus | null
  isEntered,
  enteredAt, // Date | null
  isLoading,
  error,
  enter, // () => Promise<WaitlistEntry>
  leave, // () => Promise<void>
  refreshStatus, // () => Promise<WaitlistStatus | null>
} = useWaitlist("waitlist_123", "sequence_456");

useTimedRelease

const {
  timedRelease, // TimedRelease details
  status, // UseTimedReleaseClientStatus
  consumerState, // TimedReleaseConsumerState | null
  endTime, // Date | null
  timeRemaining, // number | null
  isEntered,
  hasCompleted,
  isLoading,
  error,
  enter, // (variantId?) => Promise<TimedReleaseConsumerState>
  leave, // () => Promise<void>
  complete, // () => Promise<void>
  refreshStatus, // () => Promise<TimedReleaseConsumerState | null>
} = useTimedRelease("tr_123");

useExperienceJourney

const {
  journey, // ExperienceJourney | null
  state, // ExperienceJourneyState | null
  status, // ExperienceJourneyStatus
  error, // string | null
  start, // (options?) => Promise<ExperienceJourneyState>
} = useExperienceJourney("exp_123", { autoStart: true });

State Types

Client Status Types

Each hook uses a client-friendly status enum:
// useDraw
type UseDrawClientStatus =
  | "idle"
  | "not_entered"
  | "entered"
  | "won"
  | "completed"
  | "denied"
  | "expired"
  | "loading"
  | "error";

// useAuction
type UseAuctionClientStatus =
  | "idle"
  | "open"
  | "watching"
  | "winning"
  | "outbid"
  | "won"
  | "lost"
  | "ended"
  | "loading"
  | "error";

// useWaitlist
type UseWaitlistClientStatus = "idle" | "available" | "entered" | "loading" | "error";

// useTimedRelease
type UseTimedReleaseClientStatus =
  | "idle"
  | "open"
  | "entered"
  | "completed"
  | "left"
  | "expired"
  | "ended"
  | "loading"
  | "error";

// useExperienceJourney
type ExperienceJourneyStatus =
  | "idle"
  | "entering_experience"
  | "routing_sequence"
  | "needs_authentication"
  | "needs_access_code"
  | "validating_access"
  | "loading_distributions"
  | "entering_waitlist"
  | "waiting"
  | "ready"
  | "no_sequence_available"
  | "error";

Hook Dependencies

Hooks depend on the SDK instance from context:
FanfareProvider
    └── FanfareContext (SDK instance)

            ├── useFanfare() → SDK
            ├── useFanfareAuth() → SDK.auth
            ├── useQueue() → SDK.queues
            ├── useDraw() → SDK.draws
            ├── useAuction() → SDK.auctions
            ├── useWaitlist() → SDK.waitlists
            ├── useTimedRelease() → SDK.timedReleases
            └── useExperienceJourney() → SDK.experiences

Event Subscriptions

Hooks automatically subscribe to relevant SDK events:
// useQueue subscribes to:
// - queue:position-changed
// - queue:admitted

// useDraw subscribes to:
// - draw:entered
// - draw:won
// - draw:lost
// - draw:expired
// - draw:status-updated
// - draw:error

// useAuction subscribes to:
// - auction:entered
// - auction:bid-placed
// - auction:outbid
// - auction:winning
// - auction:won
// - auction:lost
// - auction:left
// - auction:status-updated
// - auction:bid-updated
// - auction:auto-rebid-enabled
// - auction:auto-rebid-disabled
// - auction:error

Cleanup

All hooks properly clean up on unmount:
  • Event subscriptions are removed
  • Polling is stopped (where applicable)
  • Scheduled checks are cancelled
function QueueComponent({ queueId }: { queueId: string }) {
  // When this component unmounts, all subscriptions are cleaned up
  const { enter, leave } = useQueue(queueId);

  return <button onClick={enter}>Enter</button>;
}