import { h, createContext } from 'preact'; import { useRef, useState, useCallback, useEffect, useContext } from 'preact/hooks'; import { API_PREFIX } from './config'; const fetchJSON = async (url, method='GET', data=undefined) => { const res = await fetch(API_PREFIX + url, { method, credentials: 'include', headers: { 'content-type': data && 'application/json' }, body: data && JSON.stringify(data), }); if (res.status !== 200) throw new Error("wrong status"); return res.json(); }; const initialState = { user: null, discussions: [] }; const reducer = async (action, ref) => { switch (action.type) { case 'login': { const { username, password } = action; await fetchJSON('/discdag/login', 'POST', { username, password }); return await reducer({ type: 'refresh' }, ref); } case 'logout': { await fetchJSON('/discdag/logout', 'POST'); return await reducer({ type: 'refresh' }, ref); } case 'refresh': { const { user, discussions } = await fetchJSON('/discdag/list'); return { ...ref.current, user, discussions }; } default: throw new Error('Unexpected action'); } }; const UserContext = createContext({ state: initialState, dispatch: () => { throw new Error("no UserContext Provider!"); }, }); export const UserContainer = ({ children }) => { const ref = useRef(); const [state, setState] = useState(initialState); ref.current = state; const dispatch = useCallback(async (action) => { const nextState = await reducer(action, ref); setState(nextState); }, [ref]); useEffect(() => dispatch({ type: 'refresh' }), []); return ( {children} ); }; export const useUser = () => useContext(UserContext).state; export const useDispatch = () => useContext(UserContext).dispatch; export const useUserCtx = () => useContext(UserContext);