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;
}