diff --git a/src/app/ItemPage.js b/src/app/ItemPage.js index 5d4edfb..78c78db 100644 --- a/src/app/ItemPage.js +++ b/src/app/ItemPage.js @@ -40,7 +40,7 @@ import { itemAppearanceFragment, petAppearanceFragment, } from "./components/useOutfitAppearance"; -import OutfitPreview from "./components/OutfitPreview"; +import { useOutfitPreview } from "./components/OutfitPreview"; import SpeciesColorPicker, { useAllValidPetPoses, getValidPoses, @@ -646,39 +646,28 @@ function ItemPageOutfitPreview({ itemId }) { valids, } = useAllValidPetPoses(); - // 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: cachedData } = 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", - } - ); - const [hasAnimations, setHasAnimations] = React.useState(false); const [isPaused, setIsPaused] = useLocalStorage("DTIOutfitIsPaused", true); + // This is like , but we can use the appearance data, too! + const { appearance, preview } = useOutfitPreview({ + speciesId: petState.speciesId, + colorId: petState.colorId, + pose: petState.pose, + appearanceId: petState.appearanceId, + wornItemIds: [itemId], + isLoading: loadingGQL || loadingValids, + spinnerVariant: "corner", + loadingDelayMs: 200, + engine: "canvas", + onChangeHasAnimations: setHasAnimations, + }); + + // If there's an appearance loaded for this item, but it's empty, then the + // item is incompatible. (There should only be one item appearance: this one!) + const itemAppearance = appearance?.itemAppearances?.[0]; + const isIncompatible = itemAppearance && itemAppearance.layers.length === 0; + const borderColor = useColorModeValue("green.700", "green.400"); const errorColor = useColorModeValue("red.600", "red.400"); @@ -687,12 +676,6 @@ function ItemPageOutfitPreview({ itemId }) { return {error.message}; } - // 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 = cachedData?.item?.appearanceOn?.layers; - const isIncompatible = Array.isArray(layers) && layers.length === 0; - return ( - + {preview} `, but a bit more power! + * + * It takes the same props and returns a `preview` field, which is just like + * `` - but it also returns `appearance` data too, in case you + * want to show some additional UI that uses the appearance data we loaded! + */ +export function useOutfitPreview({ speciesId, colorId, pose, @@ -41,13 +53,14 @@ function OutfitPreview({ spinnerVariant, onChangeHasAnimations = null, }) { - const { loading, error, visibleLayers } = useOutfitAppearance({ + const appearance = useOutfitAppearance({ speciesId, colorId, pose, appearanceId, wornItemIds, }); + const { loading, error, visibleLayers } = appearance; const { loading: loading2, @@ -76,7 +89,7 @@ function OutfitPreview({ ); } - return ( + const preview = ( ); + + return { appearance, preview }; } /** diff --git a/src/app/components/useOutfitAppearance.js b/src/app/components/useOutfitAppearance.js index 1ffa48b..3420b10 100644 --- a/src/app/components/useOutfitAppearance.js +++ b/src/app/components/useOutfitAppearance.js @@ -69,7 +69,7 @@ export default function useOutfitAppearance(outfitState) { ) { items(ids: $wornItemIds) { id - appearanceOn(speciesId: $speciesId, colorId: $colorId) { + appearance: appearanceOn(speciesId: $speciesId, colorId: $colorId) { ...ItemAppearanceForOutfitPreview } } @@ -86,20 +86,25 @@ export default function useOutfitAppearance(outfitState) { } ); + const petAppearance = data1?.petAppearance; + const items = data2?.items; const itemAppearances = React.useMemo( - () => (data2?.items || []).map((i) => i.appearanceOn), - [data2] + () => (items || []).map((i) => i.appearance), + [items] ); const visibleLayers = React.useMemo( - () => getVisibleLayers(data1?.petAppearance, itemAppearances), - [data1, itemAppearances] + () => getVisibleLayers(petAppearance, itemAppearances), + [petAppearance, itemAppearances] ); - const bodyId = data1?.petAppearance?.bodyId; + const bodyId = petAppearance?.bodyId; return { loading: loading1 || loading2, error: error1 || error2, + petAppearance, + items, + itemAppearances, visibleLayers, bodyId, };