🏡 index : ~doyle/chartered.git

import React = require("react");
import { useState, useEffect, useContext, createContext } from "react";
import { unauthenticatedEndpoint } from "./util";

export interface AuthContext {
  authKey?: string;
  expires?: Date;
  login: (username: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
}

const authContext = createContext<AuthContext | null>(null);

export function ProvideAuth({ children }: { children: any }) {
  const auth = useProvideAuth();
  return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}

export const useAuth = (): AuthContext | null => {
  return useContext(authContext);
};

function useProvideAuth(): AuthContext {
  const [authKey, setAuthKey] = useState(() => getAuthStorage().authKey);
  const [expires, setExpires] = useState(() => getAuthStorage().expires);

  useEffect(() => {
    localStorage.setItem(
      "charteredAuthentication",
      JSON.stringify({ authKey, expires })
    );
  }, [authKey, expires]);

  const login = async (username: string, password: string) => {
    let res = await fetch(unauthenticatedEndpoint("login"), {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "User-Agent": window.navigator.userAgent,
      },
      body: JSON.stringify({ username, password }),
    });
    let json = await res.json();

    if (json.error) {
      throw new Error(json.error);
    }

    setExpires(new Date(json.expires));
    setAuthKey(json.key);
  };

  const logout = async () => {
    // todo call the service so we can purge the key from the db
    localStorage.removeItem("charteredAuthentication");
    setExpires(null);
    setAuthKey(null);
  };

  return {
    authKey,
    expires,
    login,
    logout,
  };
}

function getAuthStorage() {
  const saved = localStorage.getItem("charteredAuthentication");
  const initial = JSON.parse(saved);
  return {
    authKey: initial?.authKey || null,
    expires: initial?.expires ? new Date(initial.expires) : null,
  };
}