misc search ui improvements!

This commit is contained in:
Matt Dunn-Rankin 2020-04-25 02:18:03 -07:00
parent 5e3071db4f
commit 49718a96f7
2 changed files with 43 additions and 6 deletions

View file

@ -30,8 +30,13 @@ function SearchResults({ query, outfitState, dispatchToOutfit }) {
const { speciesId, colorId } = outfitState;
const debouncedQuery = useDebounce(query, 300, { waitForFirstPause: true });
const [isEndOfResults, setIsEndOfResults] = React.useState(false);
const { loading, error, data, fetchMore, variables } = useQuery(
React.useEffect(() => {
setIsEndOfResults(false);
}, [query]);
const { loading, error, data, fetchMore } = useQuery(
gql`
query($query: String!, $speciesId: ID!, $colorId: ID!, $offset: Int!) {
itemSearchToFit(
@ -70,6 +75,12 @@ function SearchResults({ query, outfitState, dispatchToOutfit }) {
variables: { query: debouncedQuery, speciesId, colorId, offset: 0 },
skip: debouncedQuery === null,
notifyOnNetworkStatusChange: true,
onCompleted: (d) => {
const items = d && d.itemSearchToFit && d.itemSearchToFit.items;
if (items && items.length < 30) {
setIsEndOfResults(true);
}
},
}
);
@ -78,13 +89,27 @@ function SearchResults({ query, outfitState, dispatchToOutfit }) {
const items = (result && result.items) || [];
const onScrolledToBottom = React.useCallback(() => {
if (!loading) {
if (!loading && !isEndOfResults) {
fetchMore({
variables: {
offset: items.length,
},
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) return prev;
// Note: This is a bit awkward because, if the results count ends on
// a multiple of 30, the user will see a flash of loading before
// getting told it's actually the end. Ah well :/
//
// We could maybe make this more rigorous later with
// react-virtualized to have a better scrollbar anyway, and then
// we'd need to return the total result count... a bit annoying to
// potentially double the query runtime? We'd need to see how slow it
// actually makes things.
if (fetchMoreResult.itemSearchToFit.items.length < 30) {
setIsEndOfResults(true);
}
return {
...prev,
itemSearchToFit: {
@ -98,7 +123,7 @@ function SearchResults({ query, outfitState, dispatchToOutfit }) {
},
});
}
}, [loading, fetchMore, items.length]);
}, [loading, isEndOfResults, fetchMore, items.length]);
if (resultQuery !== query || (loading && items.length === 0)) {
return (
@ -144,7 +169,7 @@ function SearchResults({ query, outfitState, dispatchToOutfit }) {
);
}
function ScrollTracker({ children, threshold, onScrolledToBottom }) {
function ScrollTracker({ children, query, threshold, onScrolledToBottom }) {
const containerRef = React.useRef();
const scrollParent = React.useRef();
@ -167,7 +192,7 @@ function ScrollTracker({ children, threshold, onScrolledToBottom }) {
return;
}
for (let el = containerRef.current; el.parentNode; el = el.parentNode) {
if (el.scrollHeight > el.clientHeight) {
if (getComputedStyle(el).overflow === "auto") {
scrollParent.current = el;
break;
}

View file

@ -20,6 +20,7 @@ function WardrobePage() {
const { loading, error, outfitState, dispatchToOutfit } = useOutfitState();
const [searchQuery, setSearchQuery] = React.useState("");
const toast = useToast();
const searchContainerRef = React.useRef();
React.useEffect(() => {
if (error) {
@ -34,6 +35,12 @@ function WardrobePage() {
}
}, [error, toast]);
React.useEffect(() => {
if (searchContainerRef.current) {
searchContainerRef.current.scrollTop = 0;
}
}, [searchQuery]);
return (
<Box position="absolute" top="0" bottom="0" left="0" right="0">
<Grid
@ -67,7 +74,12 @@ function WardrobePage() {
</Box>
{searchQuery ? (
<Box gridArea="items" overflow="auto" key="search-panel">
<Box
gridArea="items"
overflow="auto"
key="search-panel"
ref={searchContainerRef}
>
<Box px="5" py="5">
<SearchPanel
query={searchQuery}