Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.fanfare.io/llms.txt

Use this file to discover all available pages before exploring further.

Context Hook

The useFanfare hook provides access to the underlying Fanfare SDK instance within the React context.

useFanfare

function useFanfare(): FanfareSDK;
Returns the initialized FanfareSDK instance.

Basic Usage

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

function MyComponent() {
  const fanfare = useFanfare();

  // Access any SDK module
  const handleEnterQueue = async () => {
    await fanfare.queues.enter("queue_123");
  };

  return <button onClick={handleEnterQueue}>Enter Queue</button>;
}

Error Handling

The hook throws if used outside a FanfareProvider:
function ComponentOutsideProvider() {
  // This will throw:
  // "useFanfare must be used within a FanfareProvider"
  const fanfare = useFanfare();
  return null;
}
Always ensure components using useFanfare are descendants of FanfareProvider:
function App() {
  return (
    <FanfareProvider organizationId="org_xxx" publishableKey="pk_live_xxx">
      <MyComponent /> {/* This works */}
    </FanfareProvider>
  );
}

When to Use useFanfare

Use useFanfare When

  • You need direct access to SDK modules
  • You want to call SDK methods imperatively
  • You’re building custom hooks on top of the SDK
  • You need to access modules not covered by existing hooks

Use Specialized Hooks When

  • You need reactive state (use useQueue, useDraw, etc.)
  • You want automatic event subscription
  • You need loading/error state management
  • You want to leverage the hook patterns

Examples

Direct Module Access

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

function DirectAccess() {
  const fanfare = useFanfare();

  // Access auth module
  const handleLogin = async () => {
    await fanfare.auth.requestOtp({ email: "[email protected]" });
  };

  // Access beacon module
  const trackEvent = () => {
    fanfare.beacon.track({
      event: "button_click",
      properties: { button: "cta" },
    });
  };

  return (
    <div>
      <button onClick={handleLogin}>Login</button>
      <button onClick={trackEvent}>Track</button>
    </div>
  );
}

Subscribing to Events

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

function EventSubscriber() {
  const fanfare = useFanfare();

  useEffect(() => {
    const unsubscribe = fanfare.on("queue:admitted", (data) => {
      console.log("Admitted to queue:", data.queueId);
      // Navigate to checkout
    });

    return () => {
      unsubscribe();
    };
  }, [fanfare]);

  return <div>Listening for admission...</div>;
}

Custom Hook Pattern

import { useCallback, useState, useEffect } from "react";
import { useFanfare } from "@waitify-io/fanfare-sdk-react";
import type { Queue } from "@waitify-io/fanfare-sdk-core";

function useQueueDetails(queueId: string) {
  const fanfare = useFanfare();
  const [queue, setQueue] = useState<Queue | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    let mounted = true;

    async function fetchQueue() {
      try {
        setIsLoading(true);
        const data = await fanfare.queues.get(queueId);
        if (mounted) {
          setQueue(data);
          setError(null);
        }
      } catch (err) {
        if (mounted) {
          setError(err as Error);
        }
      } finally {
        if (mounted) {
          setIsLoading(false);
        }
      }
    }

    fetchQueue();

    return () => {
      mounted = false;
    };
  }, [fanfare, queueId]);

  const refetch = useCallback(async () => {
    const data = await fanfare.queues.get(queueId);
    setQueue(data);
    return data;
  }, [fanfare, queueId]);

  return { queue, isLoading, error, refetch };
}

Building a Multi-Queue Dashboard

import { useEffect, useState } from "react";
import { useFanfare } from "@waitify-io/fanfare-sdk-react";
import type { QueueParticipation } from "@waitify-io/fanfare-sdk-core";

function QueueDashboard() {
  const fanfare = useFanfare();
  const [activeQueues, setActiveQueues] = useState<Record<string, QueueParticipation>>({});

  useEffect(() => {
    // Get initial state
    setActiveQueues(fanfare.queues.getActiveQueues());

    // Subscribe to updates
    const unsubscribes = [
      fanfare.on("queue:entered", () => {
        setActiveQueues(fanfare.queues.getActiveQueues());
      }),
      fanfare.on("queue:left", () => {
        setActiveQueues(fanfare.queues.getActiveQueues());
      }),
      fanfare.on("queue:position-changed", () => {
        setActiveQueues(fanfare.queues.getActiveQueues());
      }),
      fanfare.on("queue:admitted", () => {
        setActiveQueues(fanfare.queues.getActiveQueues());
      }),
    ];

    return () => {
      unsubscribes.forEach((unsub) => unsub());
    };
  }, [fanfare]);

  return (
    <div>
      <h2>Your Active Queues</h2>
      {Object.entries(activeQueues).map(([queueId, participation]) => (
        <div key={queueId}>
          <p>Queue: {queueId}</p>
          <p>Status: {participation.status}</p>
          <p>Position: {participation.position}</p>
        </div>
      ))}
    </div>
  );
}

Accessing Experience Journey

import { useEffect, useRef } from "react";
import { useFanfare } from "@waitify-io/fanfare-sdk-react";
import type { ExperienceJourney } from "@waitify-io/fanfare-sdk-core";

function JourneyComponent({ experienceId }: { experienceId: string }) {
  const fanfare = useFanfare();
  const journeyRef = useRef<ExperienceJourney | null>(null);

  useEffect(() => {
    // Create or get existing journey
    const journey = fanfare.experiences.createJourney(experienceId);
    journeyRef.current = journey;

    // Subscribe to state changes
    const unsubscribe = journey.state.listen((snapshot) => {
      console.log("Journey stage:", snapshot.journeyStage);
      console.log("Sequence stage:", snapshot.sequenceStage);
    });

    return () => {
      unsubscribe();
    };
  }, [fanfare, experienceId]);

  const startJourney = async () => {
    if (journeyRef.current) {
      await journeyRef.current.start();
    }
  };

  return <button onClick={startJourney}>Start Journey</button>;
}

TypeScript

import { useFanfare } from "@waitify-io/fanfare-sdk-react";
import type { FanfareSDK } from "@waitify-io/fanfare-sdk-core";

function TypedComponent() {
  // fanfare is typed as FanfareSDK
  const fanfare: FanfareSDK = useFanfare();

  // All modules are fully typed
  const auth = fanfare.auth; // AuthModule
  const queues = fanfare.queues; // QueueModule
  const draws = fanfare.draws; // DrawModule
  const auctions = fanfare.auctions; // AuctionModule

  return null;
}

Best Practices

1. Use Specialized Hooks When Available

// Prefer this
import { useQueue } from "@waitify-io/fanfare-sdk-react";

function QueueComponent() {
  const { queue, position, enter, leave } = useQueue("queue_123");
  // Automatic state management, event subscriptions, cleanup
}

// Over this (unless you need custom behavior)
import { useFanfare } from "@waitify-io/fanfare-sdk-react";

function QueueComponent() {
  const fanfare = useFanfare();
  // Manual state management required
}

2. Clean Up Event Subscriptions

useEffect(() => {
  const unsubscribes = [fanfare.on("queue:admitted", handleAdmitted), fanfare.on("queue:denied", handleDenied)];

  return () => {
    unsubscribes.forEach((unsub) => unsub());
  };
}, [fanfare]);

3. Handle Async Operations Safely

useEffect(() => {
  let mounted = true;

  async function fetchData() {
    const result = await fanfare.queues.status("queue_123");
    if (mounted) {
      setStatus(result);
    }
  }

  fetchData();

  return () => {
    mounted = false;
  };
}, [fanfare]);