diff --git a/src/app/WardrobePage/SearchFooter.js b/src/app/WardrobePage/SearchFooter.js
index 0ca07da..8c5bbd8 100644
--- a/src/app/WardrobePage/SearchFooter.js
+++ b/src/app/WardrobePage/SearchFooter.js
@@ -4,17 +4,24 @@ import { Box, Flex } from "@chakra-ui/react";
import SearchToolbar from "./SearchToolbar";
import { MajorErrorMessage, TestErrorSender, useLocalStorage } from "../util";
import PaginationToolbar from "../components/PaginationToolbar";
+import { useSearchResults } from "./useSearchResults";
/**
* SearchFooter appears on large screens only, to let you search for new items
* while still keeping the rest of the item screen open!
*/
-function SearchFooter({ searchQuery, onChangeSearchQuery }) {
+function SearchFooter({ searchQuery, onChangeSearchQuery, outfitState }) {
const [canUseSearchFooter, setCanUseSearchFooter] = useLocalStorage(
"DTIFeatureFlagCanUseSearchFooter",
false
);
+ const { items, numTotalPages } = useSearchResults(
+ searchQuery,
+ outfitState,
+ 1
+ );
+
React.useEffect(() => {
if (window.location.search.includes("feature-flag-can-use-search-footer")) {
setCanUseSearchFooter(true);
@@ -27,33 +34,46 @@ function SearchFooter({ searchQuery, onChangeSearchQuery }) {
}
return (
-
-
-
-
-
- Add new items:
-
-
-
-
-
- alert("TODO")}
- buildPageUrl={() => null}
- size="sm"
+
+
+
+
+
+
+ Add new items:
+
+
+
+
+ {numTotalPages != null && (
+
+ alert("TODO")}
+ buildPageUrl={() => null}
+ size="sm"
+ />
+
+ )}
+
+
+
+
+ {items.map((item) => (
+
+ {item.name}
+
+ ))}
-
-
-
+
+
+
);
}
diff --git a/src/app/WardrobePage/SearchPanel.js b/src/app/WardrobePage/SearchPanel.js
index e59b0ca..54adb48 100644
--- a/src/app/WardrobePage/SearchPanel.js
+++ b/src/app/WardrobePage/SearchPanel.js
@@ -1,15 +1,11 @@
import React from "react";
-import gql from "graphql-tag";
import { Box, Text, useColorModeValue, VisuallyHidden } from "@chakra-ui/react";
-import { useQuery } from "@apollo/client";
-import { useDebounce } from "../util";
-import { emptySearchQuery } from "./SearchToolbar";
import Item, { ItemListContainer, ItemListSkeleton } from "./Item";
-import { itemAppearanceFragment } from "../components/useOutfitAppearance";
import PaginationToolbar from "../components/PaginationToolbar";
+import { useSearchResults } from "./useSearchResults";
-const SEARCH_PER_PAGE = 30;
+export const SEARCH_PER_PAGE = 30;
/**
* SearchPanel shows item search results to the user, so they can preview them
@@ -271,133 +267,6 @@ function SearchResultItem({
);
}
-/**
- * useSearchResults manages the actual querying and state management of search!
- */
-function useSearchResults(
- query,
- outfitState,
- currentPageNumber,
- { skip = false } = {}
-) {
- const { speciesId, colorId } = 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!
- $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) {
- # 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 @client
- }
- }
- restrictedZones {
- id
- label @client
- isCommonlyUsedByItems @client
- }
- }
- }
- }
- }
- ${itemAppearanceFragment}
- `,
- {
- variables: {
- query: debouncedQuery.value,
- fitsPet: { speciesId, colorId },
- itemKind: debouncedQuery.filterToItemKind,
- currentUserOwnsOrWants: debouncedQuery.filterToCurrentUserOwnsOrWants,
- zoneIds: filterToZoneIds,
- speciesId,
- colorId,
- 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 };
-}
-
/**
* serializeQuery stably converts a search query object to a string, for easier
* JS comparison.
diff --git a/src/app/WardrobePage/index.js b/src/app/WardrobePage/index.js
index ac26753..5b7151d 100644
--- a/src/app/WardrobePage/index.js
+++ b/src/app/WardrobePage/index.js
@@ -127,6 +127,7 @@ function WardrobePage() {
}
/>
diff --git a/src/app/WardrobePage/useSearchResults.js b/src/app/WardrobePage/useSearchResults.js
new file mode 100644
index 0000000..73107f0
--- /dev/null
+++ b/src/app/WardrobePage/useSearchResults.js
@@ -0,0 +1,133 @@
+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 } = 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!
+ $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) {
+ # 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 @client
+ }
+ }
+ restrictedZones {
+ id
+ label @client
+ isCommonlyUsedByItems @client
+ }
+ }
+ }
+ }
+ }
+ ${itemAppearanceFragment}
+ `,
+ {
+ variables: {
+ query: debouncedQuery.value,
+ fitsPet: { speciesId, colorId },
+ itemKind: debouncedQuery.filterToItemKind,
+ currentUserOwnsOrWants: debouncedQuery.filterToCurrentUserOwnsOrWants,
+ zoneIds: filterToZoneIds,
+ speciesId,
+ colorId,
+ 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 };
+}