93 lines
3.1 KiB
JavaScript
93 lines
3.1 KiB
JavaScript
|
import React from "react";
|
||
|
import { Box, Flex, useBreakpointValue } from "@chakra-ui/react";
|
||
|
import * as Sentry from "@sentry/react";
|
||
|
|
||
|
import ItemsPanel from "./ItemsPanel";
|
||
|
import SearchToolbar, { searchQueryIsEmpty } from "./SearchToolbar";
|
||
|
import SearchPanel from "./SearchPanel";
|
||
|
import { MajorErrorMessage, TestErrorSender, useLocalStorage } from "../util";
|
||
|
|
||
|
/**
|
||
|
* ItemsAndSearchPanels manages the shared layout and state for:
|
||
|
* - ItemsPanel, which shows the items in the outfit now, and
|
||
|
* - SearchPanel, which helps you find new items to add.
|
||
|
*
|
||
|
* These panels don't share a _lot_ of concerns; they're mainly intertwined by
|
||
|
* the fact that they share the SearchToolbar at the top!
|
||
|
*
|
||
|
* We try to keep the search concerns in the search components, by avoiding
|
||
|
* letting any actual _logic_ live at the root here; and instead just
|
||
|
* performing some wiring to help them interact with each other via simple
|
||
|
* state and refs.
|
||
|
*/
|
||
|
function ItemsAndSearchPanels({
|
||
|
loading,
|
||
|
searchQuery,
|
||
|
onChangeSearchQuery,
|
||
|
outfitState,
|
||
|
outfitSaving,
|
||
|
dispatchToOutfit,
|
||
|
}) {
|
||
|
const scrollContainerRef = React.useRef();
|
||
|
const searchQueryRef = React.useRef();
|
||
|
const firstSearchResultRef = React.useRef();
|
||
|
|
||
|
const hasRoomForSearchFooter = useBreakpointValue({ base: false, md: true });
|
||
|
const [canUseSearchFooter] = useLocalStorage(
|
||
|
"DTIFeatureFlagCanUseSearchFooter",
|
||
|
false
|
||
|
);
|
||
|
const isShowingSearchFooter = canUseSearchFooter && hasRoomForSearchFooter;
|
||
|
|
||
|
return (
|
||
|
<Sentry.ErrorBoundary fallback={MajorErrorMessage}>
|
||
|
<TestErrorSender />
|
||
|
<Flex direction="column" height="100%">
|
||
|
{isShowingSearchFooter && <Box height="2" />}
|
||
|
{!isShowingSearchFooter && (
|
||
|
<Box paddingX="5" paddingTop="3" paddingBottom="2" boxShadow="sm">
|
||
|
<SearchToolbar
|
||
|
query={searchQuery}
|
||
|
searchQueryRef={searchQueryRef}
|
||
|
firstSearchResultRef={firstSearchResultRef}
|
||
|
onChange={onChangeSearchQuery}
|
||
|
/>
|
||
|
</Box>
|
||
|
)}
|
||
|
{!isShowingSearchFooter && !searchQueryIsEmpty(searchQuery) ? (
|
||
|
<Box
|
||
|
key="search-panel"
|
||
|
flex="1 0 0"
|
||
|
position="relative"
|
||
|
overflowY="scroll"
|
||
|
ref={scrollContainerRef}
|
||
|
data-test-id="search-panel-scroll-container"
|
||
|
>
|
||
|
<SearchPanel
|
||
|
query={searchQuery}
|
||
|
outfitState={outfitState}
|
||
|
dispatchToOutfit={dispatchToOutfit}
|
||
|
scrollContainerRef={scrollContainerRef}
|
||
|
searchQueryRef={searchQueryRef}
|
||
|
firstSearchResultRef={firstSearchResultRef}
|
||
|
/>
|
||
|
</Box>
|
||
|
) : (
|
||
|
<Box position="relative" overflow="auto" key="items-panel">
|
||
|
<Box px="4" py="2">
|
||
|
<ItemsPanel
|
||
|
loading={loading}
|
||
|
outfitState={outfitState}
|
||
|
outfitSaving={outfitSaving}
|
||
|
dispatchToOutfit={dispatchToOutfit}
|
||
|
/>
|
||
|
</Box>
|
||
|
</Box>
|
||
|
)}
|
||
|
</Flex>
|
||
|
</Sentry.ErrorBoundary>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
export default ItemsAndSearchPanels;
|