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