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:
parent
81065fda6a
commit
f8e625afd2
2 changed files with 43 additions and 4 deletions
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue