diff --git a/src/app/ItemPage.js b/src/app/ItemPage.js index c673246..6324db5 100644 --- a/src/app/ItemPage.js +++ b/src/app/ItemPage.js @@ -20,6 +20,7 @@ import { ExternalLinkIcon, ChevronRightIcon, StarIcon, + WarningIcon, } from "@chakra-ui/icons"; import gql from "graphql-tag"; import { useQuery } from "@apollo/client"; @@ -33,6 +34,7 @@ import { } from "./components/ItemCard"; import { Delay, Heading1, usePageTitle } from "./util"; import OutfitPreview from "./components/OutfitPreview"; +import SpeciesColorPicker from "./components/SpeciesColorPicker"; function ItemPage() { const { itemId } = useParams(); @@ -432,30 +434,118 @@ function IconCheckbox({ icon, isChecked, ...props }) { } function ItemPageOutfitPreview({ itemId }) { + const idealPose = React.useMemo( + () => (Math.random() > 0.5 ? "HAPPY_FEM" : "HAPPY_MASC"), + [] + ); + const [petState, setPetState] = React.useState({ + speciesId: "1", + colorId: "8", + pose: idealPose, + }); + + // To check whether the item is compatible with this pet, query for the + // appearance, but only against the cache. That way, we don't send a + // redundant network request just for this (the OutfitPreview component will + // handle it!), but we'll get an update once it arrives in the cache. + const { data } = useQuery( + gql` + query ItemPageOutfitPreview_CacheOnly( + $itemId: ID! + $speciesId: ID! + $colorId: ID! + ) { + item(id: $itemId) { + appearanceOn(speciesId: $speciesId, colorId: $colorId) { + layers { + id + } + } + } + } + `, + { + variables: { + itemId, + speciesId: petState.speciesId, + colorId: petState.colorId, + }, + fetchPolicy: "cache-only", + } + ); + + // If the layers are null-y, then we're still loading. Otherwise, if the + // layers are an empty array, then we're incomaptible. Or, if they're a + // non-empty array, then we're compatible! + const layers = data?.item?.appearanceOn?.layers; + const isIncompatible = Array.isArray(layers) && layers.length === 0; + const borderColor = useColorModeValue("green.700", "green.400"); + const errorColor = useColorModeValue("red.600", "red.400"); return ( - - - + + + + + + + + { + setPetState({ + speciesId: species.id, + colorId: color.id, + pose: closestPose, + }); + }} + size="sm" + showPlaceholders + // This is just a UX affordance: while we could handle invalid states + // from a UI perspective, we figure that, if a pet preview is already + // visible and responsive to changes, it feels better to treat the + // changes as atomic and always-valid. + stateMustAlwaysBeValid + /> + + {isIncompatible && ( + + + + )} + - + ); } diff --git a/src/app/components/SpeciesColorPicker.js b/src/app/components/SpeciesColorPicker.js index db869aa..e072b56 100644 --- a/src/app/components/SpeciesColorPicker.js +++ b/src/app/components/SpeciesColorPicker.js @@ -24,7 +24,6 @@ function SpeciesColorPicker({ stateMustAlwaysBeValid = false, isDisabled = false, size = "md", - dark = false, onChange, }) { const { loading: loadingMeta, error: errorMeta, data: meta } = useQuery(gql`