2024-02-27 16:49:52 -08:00
|
|
|
import { useDebounce } from "../util";
|
2024-02-25 14:46:27 -08:00
|
|
|
import { useItemSearch } from "../loaders/items";
|
|
|
|
import { emptySearchQuery, searchQueryIsEmpty } from "./SearchToolbar";
|
2023-08-10 15:56:36 -07:00
|
|
|
import { SEARCH_PER_PAGE } from "./SearchPanel";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* useSearchResults manages the actual querying and state management of search!
|
|
|
|
*/
|
|
|
|
export function useSearchResults(
|
|
|
|
query,
|
|
|
|
outfitState,
|
|
|
|
currentPageNumber,
|
2023-10-24 16:45:49 -07:00
|
|
|
{ skip = false } = {},
|
2023-08-10 15:56:36 -07:00
|
|
|
) {
|
2024-02-01 04:57:20 -08:00
|
|
|
const { speciesId, colorId, altStyleId } = outfitState;
|
2023-08-10 15:56:36 -07:00
|
|
|
|
|
|
|
// 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,
|
|
|
|
});
|
|
|
|
|
2024-02-27 16:49:52 -08:00
|
|
|
const { isLoading, error, data } = useItemSearch(
|
2024-02-25 14:46:27 -08:00
|
|
|
{
|
|
|
|
filters: buildSearchFilters(debouncedQuery, outfitState),
|
|
|
|
withAppearancesFor: { speciesId, colorId, altStyleId },
|
2024-02-27 16:49:52 -08:00
|
|
|
page: currentPageNumber,
|
2024-02-25 14:46:27 -08:00
|
|
|
perPage: SEARCH_PER_PAGE,
|
|
|
|
},
|
|
|
|
{
|
2024-02-27 16:49:52 -08:00
|
|
|
enabled: !skip && !searchQueryIsEmpty(debouncedQuery),
|
2024-02-25 14:46:27 -08:00
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2024-02-27 16:49:52 -08:00
|
|
|
const loading = debouncedQuery !== query || isLoading;
|
|
|
|
const items = data?.items ?? [];
|
|
|
|
const numTotalPages = data?.numTotalPages ?? 0;
|
2023-08-10 15:56:36 -07:00
|
|
|
|
|
|
|
return { loading, error, items, numTotalPages };
|
|
|
|
}
|
2024-02-25 14:46:27 -08:00
|
|
|
|
|
|
|
function buildSearchFilters(query, { speciesId, colorId, altStyleId }) {
|
|
|
|
const filters = [];
|
|
|
|
|
2024-05-06 14:58:03 -07:00
|
|
|
// TODO: We're missing quote support, like `background "Dyeworks White"`.
|
|
|
|
// It might be good to, rather than parse this out here and send it as
|
|
|
|
// filters, include a text-based part of the query as well, and have
|
|
|
|
// the server merge them? That'd support text-based `is:nc` etc too.
|
|
|
|
const words = query.value.split(/\s+/);
|
|
|
|
for (const word of words) {
|
|
|
|
filters.push({ key: "name", value: word });
|
2024-02-25 14:46:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (query.filterToItemKind === "NC") {
|
|
|
|
filters.push({ key: "is_nc" });
|
|
|
|
} else if (query.filterToItemKind === "PB") {
|
|
|
|
filters.push({ key: "is_pb" });
|
|
|
|
} else if (query.filterToItemKind === "NP") {
|
|
|
|
filters.push({ key: "is_np" });
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query.filterToZoneLabel != null) {
|
|
|
|
filters.push({
|
|
|
|
key: "occupied_zone_set_name",
|
|
|
|
value: query.filterToZoneLabel,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query.filterToCurrentUserOwnsOrWants === "OWNS") {
|
|
|
|
filters.push({ key: "user_closet_hanger_ownership", value: "true" });
|
|
|
|
} else if (query.filterToCurrentUserOwnsOrWants === "WANTS") {
|
|
|
|
filters.push({ key: "user_closet_hanger_ownership", value: "false" });
|
|
|
|
}
|
|
|
|
|
|
|
|
filters.push({
|
|
|
|
key: "fits",
|
|
|
|
value: { speciesId, colorId, altStyleId },
|
|
|
|
});
|
|
|
|
|
|
|
|
return filters;
|
|
|
|
}
|