import { ComponentChildren, createContext, JSX } from 'preact' import { StateUpdater, useContext, useEffect, useState } from 'preact/hooks' import { User } from '../../shared/model' import { server } from '../api' import { prependBaseUrl } from '../../shared/utils' type UserContextValue = { ready: boolean user: User | null setUser: StateUpdater refreshUser: () => Promise } const UserContext = createContext(null) type CurrentUserHook = () => [User | null, boolean] export const useCurrentUser: CurrentUserHook = () => { const userContext = useContext(UserContext) if (!userContext) { return [null, false] } const { ready, user } = userContext return [user, ready] } type UserFunctionsHook = () => { login: (username: string) => Promise logout: () => Promise } // TODO: remove login as it is deprecated export const useUserFunctions: UserFunctionsHook = () => { const login = async (username: string) => { await fetch(prependBaseUrl(`/api/login`), { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: username, }), }) await refreshUser() } const userContext = useContext(UserContext) if (!userContext) { return { login, logout: async () => {} } } const { setUser, refreshUser } = userContext const logout = async () => { await server.post('/api/logout') setUser(null) } return { login, logout } } export const UserProvider = ({ children }: { children: ComponentChildren }): JSX.Element => { const [ready, setReady] = useState(false) const [user, setUser] = useState(null) const refreshUser = async () => { const user = await server.get('/api/current-user') setUser(user) setReady(true) return user } // Fetch user when first mounted useEffect(() => { refreshUser() }, []) return {children} }