hide invalid colors in wardrobe page dropdown

On the homepage, I want to keep the ability to enter invalid species/color pairs, so that you can say "Alien, Aisha" instead of having to pick the Aisha first.

But on the wardrobe page, we were rejecting invalid state changes anyway, so I decided to remove invalid color options from the list. And I added an ability to still switch to any species, and potentially resetting to a basic color automatically to match.
This commit is contained in:
Emi Matchu 2020-08-19 19:05:44 -07:00
parent 81065fda6a
commit f8e625afd2
2 changed files with 43 additions and 4 deletions

View file

@ -54,6 +54,9 @@ function OutfitControls({ outfitState, dispatchToOutfit }) {
pose: closestPose, pose: closestPose,
}); });
} else { } else {
// NOTE: This shouldn't be possible to trigger, because the
// `stateMustAlwaysBeValid` prop should prevent it. But we have
// it as a fallback, just in case!
toast({ toast({
title: `We haven't seen a ${color.name} ${species.name} before! 😓`, title: `We haven't seen a ${color.name} ${species.name} before! 😓`,
status: "warning", status: "warning",
@ -162,6 +165,7 @@ function OutfitControls({ outfitState, dispatchToOutfit }) {
colorId={outfitState.colorId} colorId={outfitState.colorId}
idealPose={outfitState.pose} idealPose={outfitState.pose}
onChange={onSpeciesColorChange} onChange={onSpeciesColorChange}
stateMustAlwaysBeValid
/> />
</DarkMode> </DarkMode>
</Box> </Box>

View file

@ -21,6 +21,7 @@ function SpeciesColorPicker({
colorId, colorId,
idealPose, idealPose,
showPlaceholders = false, showPlaceholders = false,
stateMustAlwaysBeValid = false,
isDisabled = false, isDisabled = false,
size = "md", size = "md",
dark = false, dark = false,
@ -120,6 +121,13 @@ function SpeciesColorPicker({
const newColor = allColors.find((c) => c.id === newColorId); const newColor = allColors.find((c) => c.id === newColorId);
const validPoses = getValidPoses(valids, speciesId, newColorId); const validPoses = getValidPoses(valids, speciesId, newColorId);
const isValid = validPoses.size > 0; const isValid = validPoses.size > 0;
if (stateMustAlwaysBeValid && !isValid) {
// NOTE: This shouldn't happen, because we should hide invalid colors.
console.error(
`Assertion error in SpeciesColorPicker: Entered an invalid state, ` +
`with prop stateMustAlwaysBeValid.`
);
}
const closestPose = getClosestPose(validPoses, idealPose); const closestPose = getClosestPose(validPoses, idealPose);
onChange(species, newColor, isValid, closestPose); onChange(species, newColor, isValid, closestPose);
}; };
@ -130,13 +138,40 @@ function SpeciesColorPicker({
const newSpeciesId = e.target.value; const newSpeciesId = e.target.value;
const newSpecies = allSpecies.find((s) => s.id === newSpeciesId); const newSpecies = allSpecies.find((s) => s.id === newSpeciesId);
const color = allColors.find((c) => c.id === colorId); let color = allColors.find((c) => c.id === colorId);
const validPoses = getValidPoses(valids, newSpeciesId, colorId); let validPoses = getValidPoses(valids, newSpeciesId, colorId);
const isValid = validPoses.size > 0; let isValid = validPoses.size > 0;
if (stateMustAlwaysBeValid && !isValid) {
// If `stateMustAlwaysBeValid`, but the user switches to a species that
// doesn't support this color, that's okay and normal! We'll just switch
// to one of the four basic colors instead.
const basicColorId = ["8", "34", "61", "84"][
Math.floor(Math.random() * 4)
];
const basicColor = allColors.find((c) => c.id === basicColorId);
color = basicColor;
validPoses = getValidPoses(valids, newSpeciesId, color.id);
isValid = true;
}
const closestPose = getClosestPose(validPoses, idealPose); const closestPose = getClosestPose(validPoses, idealPose);
onChange(newSpecies, color, isValid, closestPose); onChange(newSpecies, color, isValid, closestPose);
}; };
// In `stateMustAlwaysBeValid` mode, we hide colors that are invalid on this
// species, so the user can't switch. (We handle species differently: if you
// switch to a new species and the color is invalid, we reset the color. We
// think this matches users' mental hierarchy of species -> color: showing
// supported colors for a species makes sense, but the other way around feels
// confusing and restrictive.)
let visibleColors = allColors;
if (stateMustAlwaysBeValid && valids) {
visibleColors = visibleColors.filter(
(c) => getValidPoses(valids, speciesId, c.id).size > 0
);
}
return ( return (
<Flex direction="row"> <Flex direction="row">
<SpeciesColorSelect <SpeciesColorSelect
@ -153,7 +188,7 @@ function SpeciesColorPicker({
<option>Dimensional</option> <option>Dimensional</option>
</> </>
)} )}
{allColors.map((color) => ( {visibleColors.map((color) => (
<option key={color.id} value={color.id}> <option key={color.id} value={color.id}>
{color.name} {color.name}
</option> </option>