import { ApolloQueryResult } from "apollo-client"; import { DocumentNode } from "graphql"; import React from "react"; import { Query, QueryResult } from "react-apollo"; import { useIntl } from "react-intl"; import { handleQueryAuthError } from "./auth"; import useAppState from "./hooks/useAppState"; import useNotifier from "./hooks/useNotifier"; import useUser from "./hooks/useUser"; import { RequireAtLeastOne } from "./misc"; export interface LoadMore { loadMore: ( mergeFunc: (prev: TData, next: TData) => TData, extraVariables: Partial ) => Promise>; } export type TypedQueryResult = QueryResult< TData, TVariables > & LoadMore; export interface TypedQueryInnerProps { children: (result: TypedQueryResult) => React.ReactNode; displayLoader?: boolean; skip?: boolean; variables?: TVariables; } interface QueryProgressProps { loading: boolean; onLoading: () => void; onCompleted: () => void; } class QueryProgress extends React.Component { componentDidMount() { const { loading, onLoading } = this.props; if (loading) { onLoading(); } } componentDidUpdate(prevProps) { const { loading, onLoading, onCompleted } = this.props; if (prevProps.loading !== loading) { if (loading) { onLoading(); } else { onCompleted(); } } } render() { return this.props.children; } } // For some reason Query returns () => Element instead of () => ReactNode export function TypedQuery( query: DocumentNode ): React.FC> { return ({ children, displayLoader, skip, variables }) => { const notify = useNotifier(); const [, dispatchAppState] = useAppState(); const intl = useIntl(); const user = useUser(); return ( handleQueryAuthError( error, notify, user.tokenRefresh, user.logout, intl ) } > {(queryData: QueryResult) => { const loadMore = ( mergeFunc: ( previousResults: TData, fetchMoreResult: TData ) => TData, extraVariables: RequireAtLeastOne ) => queryData.fetchMore({ query, updateQuery: (previousResults, { fetchMoreResult }) => { if (!fetchMoreResult) { return previousResults; } return mergeFunc(previousResults, fetchMoreResult); }, variables: { ...variables, ...extraVariables } }); if (displayLoader) { return ( dispatchAppState({ payload: { value: false }, type: "displayLoader" }) } onLoading={() => dispatchAppState({ payload: { value: true }, type: "displayLoader" }) } > {children({ ...queryData, loadMore })} ); } return ( <> {children({ ...queryData, loadMore })} ); }} ); }; }