Recover from missing pose data

Previously, if you typed a pet name on the homepage, but its pose wasn't labeled in our database, you'd get a black empty screen. Now, we redirect to the UNKNOWN pose, or whatever exists for us to use!
This commit is contained in:
Emi Matchu 2021-01-28 10:37:04 -08:00
parent 71ec5ddc58
commit be7401d62a

View file

@ -14,6 +14,7 @@ import {
VisuallyHidden, VisuallyHidden,
useColorModeValue, useColorModeValue,
useTheme, useTheme,
useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { loadable } from "../util"; import { loadable } from "../util";
@ -71,6 +72,7 @@ function PosePicker({
false false
); );
const { isSupportUser } = useSupport(); const { isSupportUser } = useSupport();
const toast = useToast();
// Resize the Popover when we toggle support mode, because it probably will // Resize the Popover when we toggle support mode, because it probably will
// affect the content size. // affect the content size.
@ -82,6 +84,52 @@ function PosePicker({
window.dispatchEvent(new Event("resize")); window.dispatchEvent(new Event("resize"));
}, [isInSupportMode]); }, [isInSupportMode]);
// Generally, the app tries to never put us in an invalid pose state. But it
// can happen with direct URL navigation, or pet loading when modeling isn't
// updated! Let's do some recovery.
const selectedPoseIsAvailable = Object.values(poseInfos).some(
(pi) => pi.isSelected && pi.isAvailable
);
const firstAvailablePose = Object.values(poseInfos).find(
(pi) => pi.isAvailable
)?.pose;
React.useEffect(() => {
if (loading) {
return;
}
if (!selectedPoseIsAvailable) {
if (!firstAvailablePose) {
// TODO: I suppose this error would fit better in SpeciesColorPicker!
toast({
status: "error",
title: "Oops, we don't have data for this pet color!",
description:
"If it's new, this might be a modeling issue—try modeling it on " +
"Classic DTI first. Sorry!",
duration: null,
isClosable: true,
});
return;
}
console.warn(
`Pose ${pose} not found for speciesId=${speciesId}, ` +
`colorId=${colorId}. Redirecting to pose ${firstAvailablePose}.`
);
dispatchToOutfit({ type: "setPose", pose: firstAvailablePose });
}
}, [
loading,
selectedPoseIsAvailable,
firstAvailablePose,
speciesId,
colorId,
pose,
toast,
dispatchToOutfit,
]);
if (loading) { if (loading) {
return null; return null;
} }
@ -519,6 +567,13 @@ function usePoses(speciesId, colorId, selectedPose) {
) { ) {
...PetAppearanceForPosePicker ...PetAppearanceForPosePicker
} }
unknown: petAppearance(
speciesId: $speciesId
colorId: $colorId
pose: UNKNOWN
) {
...PetAppearanceForPosePicker
}
} }
fragment PetAppearanceForPosePicker on PetAppearance { fragment PetAppearanceForPosePicker on PetAppearance {
@ -529,7 +584,7 @@ function usePoses(speciesId, colorId, selectedPose) {
} }
${petAppearanceFragment} ${petAppearanceFragment}
`, `,
{ variables: { speciesId, colorId } } { variables: { speciesId, colorId }, onError: (e) => console.error(e) }
); );
const poseInfos = { const poseInfos = {
@ -575,6 +630,12 @@ function usePoses(speciesId, colorId, selectedPose) {
isAvailable: Boolean(data?.unconverted), isAvailable: Boolean(data?.unconverted),
isSelected: selectedPose === "UNCONVERTED", isSelected: selectedPose === "UNCONVERTED",
}, },
unknown: {
...data?.unknown,
pose: "UNKNOWN",
isAvailable: Boolean(data?.unknown),
isSelected: selectedPose === "UNKNOWN",
},
}; };
return { loading, error, poseInfos }; return { loading, error, poseInfos };