import { ApolloQueryResult } from "apollo-client"; import { DocumentNode } from "graphql"; import gql from "graphql-tag"; import React from "react"; import { Query, QueryResult } from "react-apollo"; import { useIntl } from "react-intl"; import useAppState from "./hooks/useAppState"; import useNotifier from "./hooks/useNotifier"; import { commonMessages } from "./intl"; import { maybe, 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 pushMessage = useNotifier(); const [, dispatchAppState] = useAppState(); const intl = useIntl(); return ( {(queryData: QueryResult) => { if (queryData.error) { if ( !queryData.error.graphQLErrors.every( err => maybe(() => err.extensions.exception.code) === "PermissionDenied" ) ) { pushMessage({ text: intl.formatMessage(commonMessages.somethingWentWrong) }); } } 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 })} ); }} ); }; } export const pageInfoFragment = gql` fragment PageInfoFragment on PageInfo { endCursor hasNextPage hasPreviousPage startCursor } `;