diff --git a/src/app/HomePage.js b/src/app/HomePage.js index c5ebb95..c752c3b 100644 --- a/src/app/HomePage.js +++ b/src/app/HomePage.js @@ -105,6 +105,8 @@ function StartOutfitForm({ onChange }) { colorId={colorId} idealPose={idealPose} showPlaceholders + colorPlaceholderText="Blue" + speciesPlaceholderText="Acara" onChange={(species, color, isValid, closestPose) => { setSpeciesId(species.id); setColorId(color.id); diff --git a/src/app/ItemPage.js b/src/app/ItemPage.js index 13305ad..bca1e9c 100644 --- a/src/app/ItemPage.js +++ b/src/app/ItemPage.js @@ -443,41 +443,64 @@ function ItemPageOutfitPreview({ itemId }) { [] ); const [petState, setPetState] = React.useState({ - // Start by looking up Acara appearance data. - speciesId: "1", - colorId: "8", - pose: idealPose, + // We'll fill this in once the canonical appearance data arrives. + speciesId: null, + colorId: null, + pose: null, }); // Start by loading the "canonical" pet and item appearance for the outfit // preview. We'll use this to initialize both the preview and the picker. - const { loading, error, data } = useQuery(gql` - query ItemPageOutfitPreview($itemId: ID!) { - item(id: $itemId) { - id - canonicalAppearance { + const { loading, error } = useQuery( + gql` + query ItemPageOutfitPreview($itemId: ID!) { + item(id: $itemId) { id - ...ItemAppearanceFragment - body { + canonicalAppearance { id - canonicalAppearance { + ...ItemAppearanceForOutfitPreview + body { id - ...PetAppearanceFragment + canonicalAppearance { + id + species { + id + } + color { + id + } + pose + + ...PetAppearanceForOutfitPreview + } } } } } - } - ${itemAppearanceFragment} - ${petAppearanceFragment} - `); + ${itemAppearanceFragment} + ${petAppearanceFragment} + `, + { + variables: { itemId }, + onCompleted: (data) => { + const canonicalBody = data?.item?.canonicalAppearance?.body; + const canonicalPetAppearance = canonicalBody?.canonicalAppearance; + + setPetState({ + speciesId: canonicalPetAppearance?.species?.id, + colorId: canonicalPetAppearance?.color?.id, + pose: canonicalPetAppearance?.pose, + }); + }, + } + ); // 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 { cachedData } = useQuery( + const { data: cachedData } = useQuery( gql` query ItemPageOutfitPreview_CacheOnly( $itemId: ID! @@ -500,17 +523,29 @@ function ItemPageOutfitPreview({ itemId }) { colorId: petState.colorId, }, fetchPolicy: "cache-only", + onCompleted: (data) => console.log("data", data), } ); + const borderColor = useColorModeValue("green.700", "green.400"); + const errorColor = useColorModeValue("red.600", "red.400"); + + if (error) { + 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; - - const borderColor = useColorModeValue("green.700", "green.400"); - const errorColor = useColorModeValue("red.600", "red.400"); + console.log( + petState.speciesId, + petState.colorId, + itemId, + layers, + isIncompatible + ); return ( @@ -531,6 +566,7 @@ function ItemPageOutfitPreview({ itemId }) { colorId={petState.colorId} pose={petState.pose} wornItemIds={[itemId]} + isLoading={loading} spinnerVariant="corner" loadingDelayMs={2000} /> diff --git a/src/app/components/OutfitPreview.js b/src/app/components/OutfitPreview.js index d87fdbb..7957baa 100644 --- a/src/app/components/OutfitPreview.js +++ b/src/app/components/OutfitPreview.js @@ -27,6 +27,7 @@ function OutfitPreview({ pose, wornItemIds, appearanceId = null, + isLoading = false, placeholder, loadingDelayMs, spinnerVariant, @@ -57,7 +58,7 @@ function OutfitPreview({ return ( getValidPoses(valids, speciesId, c.id).size > 0 ); @@ -180,13 +187,19 @@ function SpeciesColorPicker({ isDisabled={isDisabled} onChange={onChangeColor} > - {allColors.length === 0 && ( - <> - {/* The default case, and a long name for sizing! */} - - - - )} + { + // If the selected color isn't in the set we have here, show the + // placeholder. (Can happen during loading, or if an invalid color ID + // like null is intentionally provided while the real value loads.) + !visibleColors.some((c) => c.id === colorId) && ( + + ) + } + { + // A long name for sizing! Should appear below the placeholder, out + // of view. + visibleColors.length === 0 && + } {visibleColors.map((color) => ( - - - )} + { + // If the selected species isn't in the set we have here, show the + // placeholder. (Can happen during loading, or if an invalid species + // ID like null is intentionally provided while the real value + // loads.) + !allSpecies.some((s) => s.id === speciesId) && ( + + ) + } + { + // A long name for sizing! Should appear below the placeholder, out + // of view. + allSpecies.length === 0 && + } {allSpecies.map((species) => (