Skip to content

Instantly share code, notes, and snippets.

@zebapy
Last active November 17, 2020 17:09
Show Gist options
  • Save zebapy/5e899cf55ff0828056b718c657bbc29d to your computer and use it in GitHub Desktop.
Save zebapy/5e899cf55ff0828056b718c657bbc29d to your computer and use it in GitHub Desktop.
import { useState } from 'react';
import { useQuery } from '@apollo/client';
import update from 'immutability-helper';
import get from 'lodash/get';
export const usePagerQuery = (
query,
{ variables, updateQuery, itemsPath, countPath, skip }
) => {
const [loadingMore, setLoadingMore] = useState(false);
const { data, loading, fetchMore } = useQuery(query, {
variables,
skip
});
const items = get(data, itemsPath, []);
const total = get(data, countPath, 0);
const count = items.length;
const hasNextPage = count !== total;
const loadMore = async () => {
setLoadingMore(true);
const result = await fetchMore({
query,
variables: {
...variables,
skip: count
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (!fetchMoreResult) {
return previousResult;
}
return update(previousResult, updateQuery(fetchMoreResult));
}
});
setLoadingMore(false);
return result;
};
return {
data,
items,
total,
count,
loading,
loadMore,
hasNextPage,
loadingMore
};
};
import React from 'react';
import PropTypes from 'prop-types';
import { Blankslate, Text, Button, Spinner } from 'components';
import { usePagerQuery } from 'hooks/use-pager-query';
const Pager = ({
query,
variables,
updateQuery,
children,
itemsPath,
countPath,
buttonProps,
showToolbar,
skip,
showNoResultsBlankslate = true,
blankslateProps = {
title: 'No results found',
text: 'Try adjusting filters or searching for something else'
}
}) => {
const {
data,
items,
total,
count,
loading,
loadMore,
loadingMore,
hasNextPage
} = usePagerQuery(query, {
variables,
skip,
itemsPath,
countPath,
updateQuery
});
if (loading) {
return <Spinner size="lg" centered />;
}
if (showNoResultsBlankslate && items && count === 0) {
return <Blankslate {...blankslateProps} />;
}
return (
<div>
{children({
data,
loading,
totalCount: total
})}
{hasNextPage && (
<Text textAlign="center" py={4}>
<Button
kind="primary"
size="lg"
onClick={loadMore}
loading={loadingMore}
label={
loadingMore
? 'Loading more...'
: `Load ${variables.first ? variables.first : ''} more`
}
data-cy="load-more-btn"
{...buttonProps}
/>
</Text>
)}
</div>
);
};
Pager.propTypes = {
buttonProps: PropTypes.object,
children: PropTypes.func.isRequired,
// TODO: change these to use lodash.get and pass a path instead
countPath: PropTypes.string.isRequired,
itemsPath: PropTypes.string.isRequired,
query: PropTypes.object.isRequired,
updateQuery: PropTypes.func,
variables: PropTypes.object
};
export default Pager;
import React from 'react';
import { gql } from '@apollo/client';
import Pager from 'components/Pager';
import Decks from '../components/Decks';
export const decksQuery = gql`
query decksPage(
$orderBy: DeckOrderBy
$skip: Int
$filter: DeckFilter
$first: Int
) {
decks(skip: $skip, filter: $filter, orderBy: $orderBy, first: $first) {
...Decks
}
decksMeta(filter: $filter) {
count
}
}
${Decks.fragments.decks}
`;
const DecksContainer = ({
showTotals,
filter,
orderBy = 'created_at_DESC'
}) => (
<Pager
query={decksQuery}
variables={{
first: 9,
filter,
orderBy
}}
countPath="decksMeta.count"
itemsPath="decks"
updateQuery={data => ({
decks: {
$push: data.decks
}
})}
children={({ data, totalCount }) => (
<Decks
decks={data.decks}
totalCount={totalCount}
showTotals={showTotals}
/>
)}
/>
);
export default DecksContainer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment