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

81 lines
2.1 KiB
TypeScript

import { ComponentChildren, createContext, JSX } from 'preact'
import { StateUpdater, useContext, useEffect, useState } from 'preact/hooks'
import { User } from '../../shared/model'
import { prependBaseUrl, server } from '../api'
type UserContextValue = {
ready: boolean
user: User | null
setUser: StateUpdater<User | null>
refreshUser: () => Promise<User | null>
}
const UserContext = createContext<UserContextValue | null>(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<void>
logout: () => Promise<void>
}
// 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<boolean>(false)
const [user, setUser] = useState<User | null>(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 <UserContext.Provider value={{ ready, user, setUser, refreshUser }}>{children}</UserContext.Provider>
}