diff --git a/src/app/ItemPage.js b/src/app/ItemPage.js index bcaf877..54b96c7 100644 --- a/src/app/ItemPage.js +++ b/src/app/ItemPage.js @@ -40,7 +40,11 @@ import { petAppearanceFragment, } from "./components/useOutfitAppearance"; import OutfitPreview from "./components/OutfitPreview"; -import SpeciesColorPicker from "./components/SpeciesColorPicker"; +import SpeciesColorPicker, { + useAllValidPetPoses, + getValidPoses, + getClosestPose, +} from "./components/SpeciesColorPicker"; import useCurrentUser from "./components/useCurrentUser"; import { useLocalStorage } from "./util"; @@ -515,7 +519,7 @@ function ItemPageOutfitPreview({ itemId }) { // query after this loads, because our Apollo cache can't detect the // shared item appearance. (For standard colors though, our logic to // cover standard-color switches works for this preloading too.) - const { loading, error, data } = useQuery( + const { loading: loadingGQL, error: errorGQL, data } = useQuery( gql` query ItemPageOutfitPreview($itemId: ID!) { item(id: $itemId) { @@ -581,6 +585,13 @@ function ItemPageOutfitPreview({ itemId }) { ); const couldProbablyModelMoreData = !isProbablySpeciesSpecific; + // TODO: Does this double-trigger the HTTP request with SpeciesColorPicker? + const { + loading: loadingValids, + error: errorValids, + 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 @@ -617,6 +628,7 @@ function ItemPageOutfitPreview({ itemId }) { const borderColor = useColorModeValue("green.700", "green.400"); const errorColor = useColorModeValue("red.600", "red.400"); + const error = errorGQL || errorValids; if (error) { return {error.message}; } @@ -648,7 +660,7 @@ function ItemPageOutfitPreview({ itemId }) { pose={petState.pose} appearanceId={petState.appearanceId} wornItemIds={[itemId]} - isLoading={loading} + isLoading={loadingGQL || loadingValids} spinnerVariant="corner" loadingDelayMs={2000} engine="canvas" @@ -717,15 +729,17 @@ function ItemPageOutfitPreview({ itemId }) { selectedColorId={petState.colorId} compatibleBodies={compatibleBodies} couldProbablyModelMoreData={couldProbablyModelMoreData} - onChange={({ speciesId, colorId }) => + onChange={({ speciesId, colorId }) => { + const validPoses = getValidPoses(valids, speciesId, colorId); + const pose = getClosestPose(validPoses, idealPose); setPetState({ speciesId, colorId, - pose: idealPose, + pose, appearanceId: null, - }) - } - isLoading={loading} + }); + }} + isLoading={loadingGQL || loadingValids} /> @@ -900,7 +914,7 @@ function SpeciesFacesPicker({ > - Error loading this color's thumbnail images. + Error loading this color's pet photos.
Check your connection and try again.
diff --git a/src/app/components/SpeciesColorPicker.js b/src/app/components/SpeciesColorPicker.js index 2172167..ca651b2 100644 --- a/src/app/components/SpeciesColorPicker.js +++ b/src/app/components/SpeciesColorPicker.js @@ -44,15 +44,12 @@ function SpeciesColorPicker({ } } `); + const { loading: loadingValids, error: errorValids, - data: validsBuffer, - } = useFetch("/api/validPetPoses", { responseType: "arrayBuffer" }); - const valids = React.useMemo( - () => validsBuffer && new DataView(validsBuffer), - [validsBuffer] - ); + valids, + } = useAllValidPetPoses(); const allColors = (meta && [...meta.allColors]) || []; allColors.sort((a, b) => a.name.localeCompare(b.name)); @@ -309,6 +306,20 @@ const SpeciesColorSelect = ({ ); }; +export function useAllValidPetPoses() { + const { loading, error, data: validsBuffer } = useFetch( + "/api/validPetPoses", + { responseType: "arrayBuffer" } + ); + + const valids = React.useMemo( + () => validsBuffer && new DataView(validsBuffer), + [validsBuffer] + ); + + return { loading, error, valids }; +} + function getPairByte(valids, speciesId, colorId) { // Reading a bit table, owo! const speciesIndex = speciesId - 1; @@ -331,7 +342,7 @@ function pairIsValid(valids, speciesId, colorId) { return getPairByte(valids, speciesId, colorId) !== 0; } -function getValidPoses(valids, speciesId, colorId) { +export function getValidPoses(valids, speciesId, colorId) { const pairByte = getPairByte(valids, speciesId, colorId); const validPoses = new Set(); @@ -347,7 +358,7 @@ function getValidPoses(valids, speciesId, colorId) { return validPoses; } -function getClosestPose(validPoses, idealPose) { +export function getClosestPose(validPoses, idealPose) { return closestPosesInOrder[idealPose].find((p) => validPoses.has(p)) || null; }