1
0
Fork 0
forked from OpenNeo/impress
impress/app/javascript/wardrobe-2020/WardrobePage/useSearchResults.js

147 lines
4.2 KiB
JavaScript
Raw Normal View History

import gql from "graphql-tag";
import { useQuery } from "@apollo/client";
import { useDebounce } from "../util";
import { emptySearchQuery } from "./SearchToolbar";
import { itemAppearanceFragment } from "../components/useOutfitAppearance";
import { SEARCH_PER_PAGE } from "./SearchPanel";
/**
* useSearchResults manages the actual querying and state management of search!
*/
export function useSearchResults(
query,
outfitState,
currentPageNumber,
{ skip = false } = {},
) {
const { speciesId, colorId, altStyleId } = outfitState;
// We debounce the search query, so that we don't resend a new query whenever
// the user types anything.
const debouncedQuery = useDebounce(query, 300, {
waitForFirstPause: true,
initialValue: emptySearchQuery,
});
// NOTE: This query should always load ~instantly, from the client cache.
const { data: zoneData } = useQuery(gql`
query SearchPanelZones {
allZones {
id
label
}
}
`);
const allZones = zoneData?.allZones || [];
const filterToZones = query.filterToZoneLabel
? allZones.filter((z) => z.label === query.filterToZoneLabel)
: [];
const filterToZoneIds = filterToZones.map((z) => z.id);
const currentPageIndex = currentPageNumber - 1;
const offset = currentPageIndex * SEARCH_PER_PAGE;
// const filters = buildSearchFilters(/* TODO */);
// const { loading, error, data } = useItemSearch(filters);
// Here's the actual GQL query! At the bottom we have more config than usual!
const {
loading: loadingGQL,
error,
data,
} = useQuery(
gql`
query SearchPanel(
$query: String!
$fitsPet: FitsPetSearchFilter
$itemKind: ItemKindSearchFilter
$currentUserOwnsOrWants: OwnsOrWants
$zoneIds: [ID!]!
$speciesId: ID!
$colorId: ID!
$altStyleId: ID
$offset: Int!
$perPage: Int!
) {
itemSearch: itemSearchV2(
query: $query
fitsPet: $fitsPet
itemKind: $itemKind
currentUserOwnsOrWants: $currentUserOwnsOrWants
zoneIds: $zoneIds
) {
id
numTotalItems
items(offset: $offset, limit: $perPage) {
# TODO: De-dupe this from useOutfitState?
id
name
thumbnailUrl
isNc
isPb
currentUserOwnsThis
currentUserWantsThis
appearanceOn(
speciesId: $speciesId
colorId: $colorId
altStyleId: $altStyleId
) {
# This enables us to quickly show the item when the user clicks it!
...ItemAppearanceForOutfitPreview
# This is used to group items by zone, and to detect conflicts when
# wearing a new item.
layers {
zone {
id
label
}
}
restrictedZones {
id
label
isCommonlyUsedByItems
}
}
}
}
}
${itemAppearanceFragment}
`,
{
variables: {
query: debouncedQuery.value,
fitsPet: { speciesId, colorId, altStyleId },
itemKind: debouncedQuery.filterToItemKind,
currentUserOwnsOrWants: debouncedQuery.filterToCurrentUserOwnsOrWants,
zoneIds: filterToZoneIds,
speciesId,
colorId,
altStyleId,
offset,
perPage: SEARCH_PER_PAGE,
},
context: { sendAuth: true },
skip:
skip ||
(!debouncedQuery.value &&
!debouncedQuery.filterToItemKind &&
!debouncedQuery.filterToZoneLabel &&
!debouncedQuery.filterToCurrentUserOwnsOrWants),
onError: (e) => {
console.error("Error loading search results", e);
},
// Return `numTotalItems` from the GQL cache while waiting for next page!
returnPartialData: true,
},
);
const loading = debouncedQuery !== query || loadingGQL;
const items = data?.itemSearch?.items ?? [];
const numTotalItems = data?.itemSearch?.numTotalItems ?? null;
const numTotalPages = Math.ceil(numTotalItems / SEARCH_PER_PAGE);
return { loading, error, items, numTotalPages };
}