Skip to content
AppContext.tsx 5.53 KiB
Newer Older
Grant's avatar
Grant committed
import {
Grant's avatar
Grant committed
  PropsWithChildren,
  createContext,
  useContext,
  useEffect,
  useState,
} from "react";
import { AuthSession, ClientConfig, IPosition } from "@sc07-canvas/lib/src/net";
Grant's avatar
Grant committed
import Network from "../lib/network";
import { Spinner } from "@nextui-org/react";
Grant's avatar
Grant committed
import { api } from "../lib/utils";
Grant's avatar
Grant committed

interface IAppContext {
  config?: ClientConfig;
  user?: AuthSession;
Grant's avatar
Grant committed
  connected: boolean;

  canvasPosition?: ICanvasPosition;
  setCanvasPosition: (v: ICanvasPosition) => void;
  cursorPosition?: IPosition;
  setCursorPosition: (v?: IPosition) => void;
  pixels: { available: number };
  undo?: { available: true; expireAt: number };
Grant's avatar
Grant committed

  loadChat: boolean;
  setLoadChat: (v: boolean) => void;

  infoSidebar: boolean;
  setInfoSidebar: (v: boolean) => void;
  settingsSidebar: boolean;
  setSettingsSidebar: (v: boolean) => void;
  pixelWhois?: { x: number; y: number; surrounding: string[][] };
  setPixelWhois: (v: this["pixelWhois"]) => void;
  showKeybinds: boolean;
  setShowKeybinds: (v: boolean) => void;

Grant's avatar
Grant committed
  blankOverlay: IMapOverlay;
  setBlankOverlay: React.Dispatch<React.SetStateAction<IMapOverlay>>;
  heatmapOverlay: IMapOverlay;
  setHeatmapOverlay: React.Dispatch<React.SetStateAction<IMapOverlay>>;

Grant's avatar
Grant committed
  profile?: string; // sub
  setProfile: (v?: string) => void;

  hasAdmin: boolean;
}

interface ICanvasPosition {
  x: number;
  y: number;
  zoom: number;
}

interface IMapOverlay {
  enabled: boolean;

  /**
   * opacity of the overlay
   * 0.0 - 1.0
   */
  opacity: number;

  loading: boolean;
}

Grant's avatar
Grant committed
const appContext = createContext<IAppContext>({} as any);

export const useAppContext = () => useContext(appContext);

export const AppContext = ({ children }: PropsWithChildren) => {
  const [config, setConfig] = useState<ClientConfig>(undefined as any);
  const [auth, setAuth] = useState<AuthSession>();
Grant's avatar
Grant committed
  const [canvasPosition, setCanvasPosition] = useState<ICanvasPosition>();
Grant's avatar
Grant committed
  const [cursorPosition, setCursorPosition] = useState<IPosition>();
  const [connected, setConnected] = useState(false);
Grant's avatar
Grant committed

Grant's avatar
Grant committed
  // --- settings ---
  const [loadChat, _setLoadChat] = useState(false);

Grant's avatar
Grant committed
  const [pixels, setPixels] = useState({ available: 0 });
Grant's avatar
Grant committed
  const [undo, setUndo] = useState<{ available: true; expireAt: number }>();
Grant's avatar
Grant committed

  const [infoSidebar, setInfoSidebar] = useState(false);
  const [settingsSidebar, setSettingsSidebar] = useState(false);
  const [pixelWhois, setPixelWhois] = useState<{
    x: number;
    y: number;
    surrounding: string[][];
  }>();
  const [showKeybinds, setShowKeybinds] = useState(false);
Grant's avatar
Grant committed
  const [blankOverlay, setBlankOverlay] = useState<IMapOverlay>({
    enabled: false,
    opacity: 1,
    loading: false,
  });
  const [heatmapOverlay, setHeatmapOverlay] = useState<IMapOverlay>({
    enabled: false,
    opacity: 1,
    loading: false,
  });
Grant's avatar
Grant committed
  const [profile, setProfile] = useState<string>();

Grant's avatar
Grant committed
  const [hasAdmin, setHasAdmin] = useState(false);

Grant's avatar
Grant committed
  useEffect(() => {
Grant's avatar
Grant committed
    function loadSettings() {
Grant's avatar
Grant committed
      setLoadChat(
        localStorage.getItem("matrix.enable") === null
          ? true
          : localStorage.getItem("matrix.enable") === "true"
      );
Grant's avatar
Grant committed
    function handleConfig(config: ClientConfig) {
      setConfig(config);
    }

    function handleUser(user: AuthSession) {
      setAuth(user);
    }

Grant's avatar
Grant committed
    function handlePixels(pixels: { available: number }) {
      setPixels(pixels);
    }

Grant's avatar
Grant committed
    function handleUndo(
      data: { available: false } | { available: true; expireAt: number }
    ) {
      if (data.available) {
        setUndo({ available: true, expireAt: data.expireAt });
      } else {
        setUndo(undefined);
      }
    }

    function handleConnect() {
      setConnected(true);
    }

    function handleDisconnect() {
      setConnected(false);
    }

Grant's avatar
Grant committed
    api<{}>("/api/admin/check").then(({ status, data }) => {
      if (status === 200) {
        if (data.success) {
          setHasAdmin(true);
        }
      }
    });

Grant's avatar
Grant committed
    Network.on("user", handleUser);
    Network.on("config", handleConfig);
Grant's avatar
Grant committed
    Network.waitFor("pixels").then(([data]) => handlePixels(data));
    Network.on("pixels", handlePixels);
Grant's avatar
Grant committed
    Network.on("undo", handleUndo);
Grant's avatar
Grant committed

    Network.on("connected", handleConnect);
    Network.on("disconnected", handleDisconnect);

Grant's avatar
Grant committed
    Network.socket.connect();

Grant's avatar
Grant committed
    loadSettings();

Grant's avatar
Grant committed
    return () => {
      Network.off("user", handleUser);
      Network.off("config", handleConfig);
Grant's avatar
Grant committed
      Network.off("pixels", handlePixels);
      Network.off("undo", handleUndo);
      Network.off("connected", handleConnect);
      Network.off("disconnected", handleDisconnect);
Grant's avatar
Grant committed
    };
  }, []);

Grant's avatar
Grant committed
  const setLoadChat = (v: boolean) => {
    _setLoadChat(v);
    localStorage.setItem("matrix.enable", v ? "true" : "false");
  };

Grant's avatar
Grant committed
  return (
Grant's avatar
Grant committed
    <appContext.Provider
Grant's avatar
Grant committed
      value={{
        config,
        user: auth,
        canvasPosition,
        setCanvasPosition,
        cursorPosition,
        setCursorPosition,
Grant's avatar
Grant committed
        pixels,
        settingsSidebar,
        setSettingsSidebar,
Grant's avatar
Grant committed
        undo,
Grant's avatar
Grant committed
        loadChat,
        setLoadChat,
Grant's avatar
Grant committed
        hasAdmin,
        showKeybinds,
        setShowKeybinds,
Grant's avatar
Grant committed
        blankOverlay,
        setBlankOverlay,
Grant's avatar
Grant committed
        profile,
        setProfile,
        infoSidebar,
        setInfoSidebar,
Grant's avatar
Grant committed
      }}
Grant's avatar
Grant committed
    >
        <div className="fixed top-0 left-0 w-full h-full z-[49] backdrop-blur-sm bg-black/30 text-white flex items-center justify-center">
          <Spinner label="Loading..." />
        </div>
      )}
      {children}
Grant's avatar
Grant committed
    </appContext.Provider>
  );
};