forked from OpenNeo/impress
Emi Matchu
fc71f5b5a5
I'm not planning to port full Alt Style support over to the 2020 frontend, I really am winding that down, but adding a couple lil API parameters are *by far* the easiest way to get Alt Styles working in the main app because of how it calls the 2020 API. So here we are, just using new parameters for DTI 2020 that I'm gonna deploy to impress-2020 first!
143 lines
4.1 KiB
JavaScript
143 lines
4.1 KiB
JavaScript
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;
|
|
|
|
// 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 };
|
|
}
|