From f8e625afd279c109bf16a779f541b14afc070b84 Mon Sep 17 00:00:00 2001 From: Matchu Date: Wed, 19 Aug 2020 19:05:44 -0700 Subject: [PATCH] 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. --- src/app/WardrobePage/OutfitControls.js | 4 +++ src/app/components/SpeciesColorPicker.js | 43 +++++++++++++++++++++--- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/app/WardrobePage/OutfitControls.js b/src/app/WardrobePage/OutfitControls.js index 48c395b..624a4c7 100644 --- a/src/app/WardrobePage/OutfitControls.js +++ b/src/app/WardrobePage/OutfitControls.js @@ -54,6 +54,9 @@ function OutfitControls({ outfitState, dispatchToOutfit }) { pose: closestPose, }); } 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({ title: `We haven't seen a ${color.name} ${species.name} before! 😓`, status: "warning", @@ -162,6 +165,7 @@ function OutfitControls({ outfitState, dispatchToOutfit }) { colorId={outfitState.colorId} idealPose={outfitState.pose} onChange={onSpeciesColorChange} + stateMustAlwaysBeValid /> diff --git a/src/app/components/SpeciesColorPicker.js b/src/app/components/SpeciesColorPicker.js index 40a74ef..c50706c 100644 --- a/src/app/components/SpeciesColorPicker.js +++ b/src/app/components/SpeciesColorPicker.js @@ -21,6 +21,7 @@ function SpeciesColorPicker({ colorId, idealPose, showPlaceholders = false, + stateMustAlwaysBeValid = false, isDisabled = false, size = "md", dark = false, @@ -120,6 +121,13 @@ function SpeciesColorPicker({ const newColor = allColors.find((c) => c.id === newColorId); const validPoses = getValidPoses(valids, speciesId, newColorId); 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); onChange(species, newColor, isValid, closestPose); }; @@ -130,13 +138,40 @@ function SpeciesColorPicker({ const newSpeciesId = e.target.value; const newSpecies = allSpecies.find((s) => s.id === newSpeciesId); - const color = allColors.find((c) => c.id === colorId); - const validPoses = getValidPoses(valids, newSpeciesId, colorId); - const isValid = validPoses.size > 0; + let color = allColors.find((c) => c.id === colorId); + let validPoses = getValidPoses(valids, newSpeciesId, colorId); + 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); 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 ( Dimensional )} - {allColors.map((color) => ( + {visibleColors.map((color) => (