LiveDisplayX / src / hooks / useDisplays.ts
useDisplays.ts
Raw
// hooks/useDisplays.ts
"use client";

import useSWR from "swr";
import { mutate } from "swr";
import {
  Display,
  CreateDisplayData,
  UpdateDisplayData,
} from "@/lib/types/types";
import { useAuth } from "@clerk/nextjs";
import { fetcher } from "@/lib/api/displays";

export function useDisplays() {
  const { getToken } = useAuth();

  const swrFetcher = (url: string) => fetcher(url, getToken);

  const {
    data: displays,
    error,
    isLoading,
    isValidating,
  } = useSWR<Display[]>("/api/displays", swrFetcher, {
    revalidateOnFocus: true,
    refreshInterval: 30000, // 30 seconds
    dedupingInterval: 5000, // 5 seconds
  });

  const createDisplay = async (displayData: CreateDisplayData) => {
    try {
      mutate(
        "/api/displays",
        (current: Display[] | undefined) => {
          const newDisplay: Display = {
            id: "temp-id",
            ...displayData,
            authToken: "generating...",
            organizationId: "temp-org",
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
            twitchChannel:
              displayData.mode === "TWITCH"
                ? displayData.twitchChannel || "default_channel"
                : null,
          };
          return current ? [...current, newDisplay] : [newDisplay];
        },
        false
      );

      const newDisplay = await fetcher("/api/displays", getToken, {
        method: "POST",
        body: JSON.stringify(displayData),
      });

      mutate("/api/displays", (current: Display[] | undefined) => {
        return current
          ? current.map((d) => (d.id === "temp-id" ? newDisplay : d))
          : [newDisplay];
      });

      return newDisplay;
    } catch (error) {
      mutate("/api/displays");
      throw error;
    }
  };

  const updateDisplay = async (id: string, updates: UpdateDisplayData) => {
    try {
      // Optimistic update
      mutate(
        "/api/displays",
        (current: Display[] | undefined) => {
          if (!current) return current;
          return current.map((display) =>
            display.id === id ? { ...display, ...updates } : display
          );
        },
        false
      );

      const updatedDisplay = await fetcher(`/api/displays/${id}`, getToken, {
        method: "PUT",
        body: JSON.stringify(updates),
      });

      mutate("/api/displays");
      return updatedDisplay;
    } catch (error) {
      mutate("/api/displays");
      throw error;
    }
  };

  const deleteDisplay = async (id: string) => {
    try {
      // Optimistic update
      mutate(
        "/api/displays",
        (current: Display[] | undefined) => {
          if (!current) return current;
          return current.filter((display) => display.id !== id);
        },
        false
      );

      await fetcher(`/api/displays/${id}`, getToken, {
        method: "DELETE",
      });

      mutate("/api/displays");
    } catch (error) {
      mutate("/api/displays");
      throw error;
    }
  };

  return {
    displays: displays || [],
    isLoading,
    isValidating,
    error,
    createDisplay,
    updateDisplay,
    deleteDisplay,
    refreshDisplays: () => mutate("/api/displays"),
  };
}