import React, { useEffect, useState } from "react"; import { useSessionStorage } from "../hooks/useStorage"; import { useApi } from "./ApiContext"; export interface User { id: string; email: string; is_superuser: boolean; groups: string[]; full_name: string; username: string; permissions: string[]; } interface UserContext { user: User | null | undefined; login: (username: string, password: string) => Promise; logout: () => Promise; changePassword: ( oldPassword: string, newPassword1: string, newPassword2: string, ) => Promise; /** * Horrid name! This is to prevent a flash of loginscreen or ui when getting an already logged in user. */ hasTriedToFetchUser: boolean; } const UserContext = React.createContext(undefined as unknown as UserContext); export const useUser = () => React.useContext(UserContext); export const UserContextProvider: React.FC = ({ children }) => { const api = useApi(); const [user, setUser] = useSessionStorage("bcom-admin.user"); const [hasTriedToFetchUser, setHasTriedToFetchUser] = useState(false); useEffect(() => { const getInitialUser = async () => { if (api == null) return; const user = (await api.getAuthenticatedUser()) ?? undefined; // `undefined` has meaning here! It resets the sessionStorage. setUser(user); setHasTriedToFetchUser(true); }; if (!hasTriedToFetchUser) getInitialUser(); }, [hasTriedToFetchUser, user, api]); const login = async (username: string, password: string) => { const response = await api?.operations["bananas.login:create"].call({ body: { username, password }, }); if (response?.ok) { const user = await response.json(); setUser(user); return user; } else { setUser(undefined); return null; } }; const changePassword = async ( oldPassword: string, newPassword1: string, newPassword2: string, ) => { const response = await api?.operations["bananas.change_password:create"].call({ body: { old_password: oldPassword, new_password1: newPassword1, new_password2: newPassword2, }, }); if (!response?.ok) { throw new Error("Failed to change password"); } }; const logout = async () => { const response = await api?.operations["bananas.logout:create"].call(); if (response?.ok) { setUser(undefined); return; } throw new Error("Could not log out"); }; return ( {children} ); }; export default UserContext;