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
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, |
|
}; |
|
} |