import { StateUpdater, useEffect, useState } from 'preact/hooks' import { createContext } from 'preact' import { prependBaseUrl, server } from './api' import { User } from '../shared/model' type Metadata = { title?: string } export const MetadataContext = createContext({}) export const ServerContext = createContext(false) export const ClientContext = createContext(false) type CurrentUserHook = (onLoaded?: (user: User | null) => void) => [User | null, () => Promise] export const useCurrentUser: CurrentUserHook = onLoaded => { const [user, setUser] = useState(null) const logout = async () => { await server.post('/api/logout') setUser(null) } useEffect(() => { server.get('/api/current-user').then(user => { setUser(user) onLoaded?.(user) }) }, []) return [user, logout] } type RefreshFunction = () => AbortController type HeuristicStateUpdater = StateUpdater type ResourceHookFunction = ( url: string | (() => string), initialValue: T ) => [T, RefreshFunction, HeuristicStateUpdater] export const useResource: ResourceHookFunction = (url, initialValue) => { const [value, setValue] = useState(initialValue) function refresh() { const controller = new AbortController() const realUrl = typeof url === 'function' ? url() : url fetch(prependBaseUrl(realUrl), { signal: controller.signal }) .then(res => { if (res.ok) { return res.json() } else { return initialValue } }) .then(newValue => { setValue(newValue) }) return controller } useEffect(() => { const controller = refresh() return () => { controller.abort() } }, []) return [value, refresh, setValue] } type HeuristicListItemUpdater = (index: number, value: S | ((prevValue: S) => S)) => void export const useListResource = ( url: string | (() => string) ): [T[], RefreshFunction, HeuristicListItemUpdater, HeuristicStateUpdater] => { const [list, refreshList, setListHeuristic] = useResource(url, []) const setItemHeuristic: HeuristicListItemUpdater = (index, newValue) => { setListHeuristic(list => { const newList = [...list] // @ts-ignore newList[index] = typeof newValue === 'function' ? newValue(list[index]) : newValue return newList }) } return [list, refreshList, setItemHeuristic, setListHeuristic] }