impress-2020/src/app/WardrobePage.js

190 lines
5 KiB
JavaScript
Raw Normal View History

2020-04-21 20:32:53 -07:00
import React from "react";
import {
Box,
Grid,
2020-04-22 02:39:06 -07:00
Icon,
2020-04-22 01:10:24 -07:00
IconButton,
2020-04-22 02:39:06 -07:00
Input,
InputGroup,
InputLeftElement,
InputRightElement,
useToast,
2020-04-21 20:32:53 -07:00
} from "@chakra-ui/core";
2020-04-25 20:54:18 -07:00
import { Helmet } from "react-helmet";
2020-04-21 20:32:53 -07:00
import ItemsPanel from "./ItemsPanel";
import OutfitPreview from "./OutfitPreview";
2020-04-24 21:17:03 -07:00
import SearchPanel from "./SearchPanel";
import useOutfitState from "./useOutfitState.js";
2020-04-21 20:32:53 -07:00
function WardrobePage() {
2020-04-24 19:16:24 -07:00
const { loading, error, outfitState, dispatchToOutfit } = useOutfitState();
2020-04-22 02:39:06 -07:00
const [searchQuery, setSearchQuery] = React.useState("");
const toast = useToast();
2020-04-25 02:18:03 -07:00
const searchContainerRef = React.useRef();
const searchQueryRef = React.useRef();
const firstSearchResultRef = React.useRef();
2020-04-22 15:24:38 -07:00
React.useEffect(() => {
if (error) {
2020-04-24 21:17:03 -07:00
console.log(error);
2020-04-22 15:24:38 -07:00
toast({
title: "We couldn't load this outfit 😖",
description: "Please reload the page to try again. Sorry!",
status: "error",
isClosable: true,
2020-04-24 21:17:03 -07:00
duration: 999999999,
2020-04-22 15:24:38 -07:00
});
}
}, [error, toast]);
2020-04-25 02:18:03 -07:00
React.useEffect(() => {
if (searchContainerRef.current) {
searchContainerRef.current.scrollTop = 0;
}
}, [searchQuery]);
2020-04-21 20:32:53 -07:00
return (
2020-04-25 20:54:18 -07:00
<>
<Helmet>
<title>
{outfitState.name || "Untitled outfit"} | Dress to Impress
</title>
</Helmet>
<Box position="absolute" top="0" bottom="0" left="0" right="0">
<Grid
// Fullscreen, split into a vertical stack on smaller screens
// or a horizontal stack on larger ones!
templateAreas={{
base: `"outfit"
2020-04-24 17:48:22 -07:00
"search"
"items"`,
2020-04-25 20:54:18 -07:00
lg: `"outfit search"
2020-04-24 17:48:22 -07:00
"outfit items"`,
2020-04-25 20:54:18 -07:00
}}
templateRows={{
base: "minmax(100px, 1fr) auto minmax(300px, 1fr)",
lg: "auto 1fr",
}}
templateColumns={{
base: "100%",
lg: "50% 50%",
}}
height="100%"
width="100%"
>
<Box gridArea="outfit" backgroundColor="gray.900">
<OutfitPreview
outfitState={outfitState}
dispatchToOutfit={dispatchToOutfit}
/>
2020-04-24 00:46:24 -07:00
</Box>
2020-04-25 20:54:18 -07:00
<Box gridArea="search" boxShadow="sm">
<Box px="5" py="3">
<SearchToolbar
2020-04-24 00:46:24 -07:00
query={searchQuery}
2020-04-25 20:54:18 -07:00
queryRef={searchQueryRef}
onChange={setSearchQuery}
onMoveFocusDownToResults={(e) => {
if (firstSearchResultRef.current) {
firstSearchResultRef.current.focus();
e.preventDefault();
}
}}
2020-04-24 00:46:24 -07:00
/>
</Box>
</Box>
2020-04-25 20:54:18 -07:00
{searchQuery ? (
<Box
gridArea="items"
position="relative"
overflow="auto"
key="search-panel"
ref={searchContainerRef}
>
<Box px="4" py="5">
<SearchPanel
query={searchQuery}
outfitState={outfitState}
dispatchToOutfit={dispatchToOutfit}
firstSearchResultRef={firstSearchResultRef}
onMoveFocusUpToQuery={(e) => {
if (searchQueryRef.current) {
searchQueryRef.current.focus();
e.preventDefault();
}
}}
/>
</Box>
</Box>
2020-04-25 20:54:18 -07:00
) : (
<Box
gridArea="items"
position="relative"
overflow="auto"
key="items-panel"
>
<Box px="5" py="5">
<ItemsPanel
loading={loading}
outfitState={outfitState}
dispatchToOutfit={dispatchToOutfit}
/>
</Box>
</Box>
)}
</Grid>
</Box>
</>
2020-04-21 20:32:53 -07:00
);
}
function SearchToolbar({
query,
queryRef,
onChange,
onMoveFocusDownToResults,
}) {
2020-04-22 02:39:06 -07:00
return (
<InputGroup>
<InputLeftElement>
<Icon name="search" color="gray.400" />
</InputLeftElement>
<Input
2020-04-22 03:13:47 -07:00
placeholder="Search for items to add…"
2020-04-22 02:39:06 -07:00
focusBorderColor="green.600"
color="green.800"
value={query}
ref={queryRef}
2020-04-22 02:39:06 -07:00
onChange={(e) => onChange(e.target.value)}
2020-04-22 04:07:34 -07:00
onKeyDown={(e) => {
if (e.key === "Escape") {
onChange("");
e.target.blur();
} else if (e.key === "ArrowDown") {
onMoveFocusDownToResults(e);
2020-04-22 04:07:34 -07:00
}
}}
2020-04-22 02:39:06 -07:00
/>
{query && (
<InputRightElement>
<IconButton
icon="close"
color="gray.400"
variant="ghost"
variantColor="green"
aria-label="Clear search"
onClick={() => onChange("")}
2020-04-25 02:20:23 -07:00
// Big style hacks here!
height="calc(100% - 2px)"
marginRight="2px"
2020-04-22 02:39:06 -07:00
/>
</InputRightElement>
)}
</InputGroup>
);
}
2020-04-21 20:32:53 -07:00
export default WardrobePage;