You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

134 lines
3.7 KiB

// Note: Based on https://usehooks.com/useAuth/
import React, { useState, useContext, createContext, ReactFragment } from "react";
import PersonIcon from '@material-ui/icons/Person';
import * as serverApi from '../api';
export interface AuthUser {
id: number,
email: string,
icon: ReactFragment,
}
export interface Auth {
user: AuthUser | null,
signout: () => void,
signin: (email: string, password: string) => Promise<AuthUser>,
signup: (email: string, password: string) => Promise<void>,
};
const authContext = createContext<Auth>({
user: null,
signout: () => { },
signin: (email: string, password: string) => {
throw new Error("Auth object not initialized.");
},
signup: (email: string, password: string) => {
throw new Error("Auth object not initialized.");
},
});
export function ProvideAuth(props: { children: any }) {
const auth = useProvideAuth();
return <authContext.Provider value={auth}>{props.children}</authContext.Provider>;
}
export const useAuth = () => {
return useContext(authContext);
};
function persistAuth(auth: AuthUser | null) {
let s = window.sessionStorage;
if(auth === null) {
s.removeItem('userId');
s.removeItem('userEmail');
return;
}
s.setItem('userId', auth.id.toString());
s.setItem('userEmail', auth.email);
// TODO icon
}
function loadAuth(): AuthUser | null {
let s = window.sessionStorage;
let id = s.getItem('userId');
let email = s.getItem('userEmail');
if (id && email) {
return {
id: parseInt(id),
email: email,
icon: <PersonIcon />
}
}
return null;
}
function useProvideAuth() {
const [user, setUser] = useState<AuthUser | null>(loadAuth());
// TODO: password maybe shouldn't be encoded into the URL.
const signin = (email: string, password: string) => {
return (async () => {
const urlBase = (process.env.REACT_APP_BACKEND || "") + serverApi.LoginEndpoint;
const url = `${urlBase}?username=${encodeURIComponent(email)}&password=${encodeURIComponent(password)}`;
const response = await fetch(url, { method: "POST" });
const json = await response.json();
if (!("userId" in json)) {
throw new Error("No UserID received from login.");
}
const user = {
id: json.userId,
email: email,
icon: <PersonIcon />,
}
setUser(user);
persistAuth(user);
return user;
})();
};
const signup = (email: string, password: string) => {
return (async () => {
const requestOpts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: email,
password: password,
})
};
const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.RegisterUserEndpoint, requestOpts)
if (!response.ok) {
throw new Error("Failed to register user.")
}
})();
};
const signout = () => {
console.log("Signing out.");
setUser(null);
persistAuth(null);
return (async () => {
const url = (process.env.REACT_APP_BACKEND || "") + serverApi.LogoutEndpoint;
const response = await fetch(url, { method: "POST" });
if (!response.ok) {
throw new Error("Failed to log out.");
}
})();
};
// Return the user object and auth methods
return {
user,
signin,
signup,
signout,
};
}