import { useEffect, useReducer } from 'react'; import type { RocQueryResult as RocClientQueryResult } from 'rest-on-couch-client'; import { useRoc } from '../contexts/roc.js'; export type RocQueryResult = RocClientQueryResult<[string, string], T>; interface RocQueryState { loading: boolean; error: null | Error; result: null | Array>; } type RocQueryHookResult = RocQueryState; type RocQueryAction = | { type: 'SET_RESULT'; value: Array> } | { type: 'ERROR'; value: Error } | { type: 'LOAD' }; function rocQueryReducer( state: RocQueryState, action: RocQueryAction, ): RocQueryState { switch (action.type) { case 'LOAD': return { ...state, error: null, loading: true, }; case 'SET_RESULT': return { loading: false, error: null, result: action.value, }; case 'ERROR': return { loading: false, error: action.value, result: null }; default: throw new Error('unreachable'); } } interface RocQueryHookOptions { mine?: boolean; } export function useRocQuery( viewName: string, options: RocQueryHookOptions = {}, ): RocQueryHookResult { const { mine = false } = options; const roc = useRoc(); const [state, dispatch] = useReducer, [RocQueryAction]>( rocQueryReducer, { loading: true, error: null, result: null, }, ); useEffect(() => { dispatch({ type: 'LOAD' }); const query = roc.getQuery<[string, string], T>(viewName, { mine }); query .fetch() .then((result) => dispatch({ type: 'SET_RESULT', value: result })) .catch((err: unknown) => { dispatch({ type: 'ERROR', value: err as Error }); }); }, [roc, viewName, mine]); return state; }