Show empty PosePicker for Support users

For most users, I want to hide the pose picker if there's not actually anything to pick from.

But I want Support users to be able to open it and use Support mode, to inspect and label Unknown poses!

In this change, I add new UI to show a question mark pose picker button, and a note explaining the empty picker; but only show them for Support users.

I also made a new `useSupport` hook, to replace `useSupportSecret`, now that I have a use case for "is support user?" that doesn't require the secret. Will migrate the rest!
This commit is contained in:
Emi Matchu 2020-08-29 14:49:37 -07:00
parent 5f3b627187
commit 4e923746ce
5 changed files with 76 additions and 6 deletions

View file

@ -23,12 +23,14 @@ import {
} from "../components/useOutfitAppearance"; } from "../components/useOutfitAppearance";
import { OutfitLayers } from "../components/OutfitPreview"; import { OutfitLayers } from "../components/OutfitPreview";
import SupportOnly from "./support/SupportOnly"; import SupportOnly from "./support/SupportOnly";
import useSupport from "./support/useSupport";
import { useLocalStorage } from "../util"; import { useLocalStorage } from "../util";
// From https://twemoji.twitter.com/, thank you! // From https://twemoji.twitter.com/, thank you!
import twemojiSmile from "../../images/twemoji/smile.svg"; import twemojiSmile from "../../images/twemoji/smile.svg";
import twemojiCry from "../../images/twemoji/cry.svg"; import twemojiCry from "../../images/twemoji/cry.svg";
import twemojiSick from "../../images/twemoji/sick.svg"; import twemojiSick from "../../images/twemoji/sick.svg";
import twemojiQuestion from "../../images/twemoji/question.svg";
import twemojiMasc from "../../images/twemoji/masc.svg"; import twemojiMasc from "../../images/twemoji/masc.svg";
import twemojiFem from "../../images/twemoji/fem.svg"; import twemojiFem from "../../images/twemoji/fem.svg";
@ -67,6 +69,7 @@ function PosePicker({
"DTIPosePickerIsInSupportMode", "DTIPosePickerIsInSupportMode",
false false
); );
const { isSupportUser } = useSupport();
// 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.
@ -89,10 +92,12 @@ function PosePicker({
} }
// If there's only one pose anyway, don't bother showing a picker! // If there's only one pose anyway, don't bother showing a picker!
// (Unless we're Support, in which case we want the ability to pop it open to
// inspect and label the Unknown poses!)
const numAvailablePoses = Object.values(poseInfos).filter( const numAvailablePoses = Object.values(poseInfos).filter(
(p) => p.isAvailable (p) => p.isAvailable
).length; ).length;
if (numAvailablePoses <= 1) { if (numAvailablePoses <= 1 && !isSupportUser) {
return null; return null;
} }
@ -147,6 +152,9 @@ function PosePicker({
{getEmotion(pose) === "SICK" && ( {getEmotion(pose) === "SICK" && (
<EmojiImage src={twemojiSick} alt="Choose a pose" /> <EmojiImage src={twemojiSick} alt="Choose a pose" />
)} )}
{getEmotion(pose) === null && (
<EmojiImage src={twemojiQuestion} alt="Choose a pose" />
)}
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<Portal> <Portal>
@ -161,11 +169,28 @@ function PosePicker({
dispatchToOutfit={dispatchToOutfit} dispatchToOutfit={dispatchToOutfit}
/> />
) : ( ) : (
<PosePickerTable <>
poseInfos={poseInfos} <PosePickerTable
onChange={onChange} poseInfos={poseInfos}
checkedInputRef={checkedInputRef} onChange={onChange}
/> checkedInputRef={checkedInputRef}
/>
{numAvailablePoses <= 1 && (
<SupportOnly>
<Box
fontSize="xs"
fontStyle="italic"
textAlign="center"
opacity="0.7"
marginTop="2"
>
The empty picker is hidden for most users!
<br />
You can see it because you're a Support user.
</Box>
</SupportOnly>
)}
</>
)} )}
<SupportOnly> <SupportOnly>
<Box position="absolute" top="5" left="3"> <Box position="absolute" top="5" left="3">

View file

@ -71,6 +71,13 @@ function PosePickerSupport({
) { ) {
id id
} }
unknown: petAppearance(
speciesId: $speciesId
colorId: $colorId
pose: UNKNOWN
) {
id
}
} }
`, `,
{ variables: { speciesId, colorId } } { variables: { speciesId, colorId } }
@ -113,6 +120,7 @@ function PosePickerSupport({
HAPPY_FEM: data.happyFem?.id, HAPPY_FEM: data.happyFem?.id,
SAD_FEM: data.sadFem?.id, SAD_FEM: data.sadFem?.id,
SICK_FEM: data.sickFem?.id, SICK_FEM: data.sickFem?.id,
UNKNOWN: data.unknown?.id,
}; };
const canonicalAppearanceIds = Object.values( const canonicalAppearanceIds = Object.values(
canonicalAppearanceIdsByPose canonicalAppearanceIdsByPose

View file

@ -0,0 +1,29 @@
import * as React from "react";
/**
* useSupport returns the Support secret that the server requires for Support
* actions... if the user has it set. For most users, this returns nothing!
*
* Specifically, we return an object of:
* - isSupportUser: true iff the `supportSecret` is set
* - supportSecret: the secret saved to this device, or null if not set
*
* To become a Support user, you visit /?supportSecret=..., which saves the
* secret to your device.
*
* Note that this hook doesn't check that the secret is *correct*, so it's
* possible that it will return an invalid secret. That's okay, because
* the server checks the provided secret for each Support request.
*/
function useSupport() {
const supportSecret = React.useMemo(
() => localStorage.getItem("supportSecret"),
[]
);
const isSupportUser = supportSecret != null;
return { isSupportUser, supportSecret };
}
export default useSupport;

View file

@ -11,9 +11,16 @@ import * as React from "react";
* Note that this hook doesn't check that the secret is *correct*, so it's * Note that this hook doesn't check that the secret is *correct*, so it's
* possible that it will return an invalid secret. That's okay, because * possible that it will return an invalid secret. That's okay, because
* the server checks the provided secret for each Support request. * the server checks the provided secret for each Support request.
*
* DEPRECATED: Use `useSupport` instead!
*/ */
function useSupportSecret() { function useSupportSecret() {
return React.useMemo(() => localStorage.getItem("supportSecret"), []); return React.useMemo(() => localStorage.getItem("supportSecret"), []);
} }
export function useIsSupportUser() {
const supportSecret = useSupportSecret();
return supportSecret != null;
}
export default useSupportSecret; export default useSupportSecret;

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#CCD6DD" d="M17 27c-1.657 0-3-1.343-3-3v-4c0-1.657 1.343-3 3-3 .603-.006 6-1 6-5 0-2-2-4-5-4-2.441 0-4 2-4 3 0 1.657-1.343 3-3 3s-3-1.343-3-3c0-4.878 4.58-9 10-9 8 0 11 5.982 11 11 0 4.145-2.277 7.313-6.413 8.92-.9.351-1.79.587-2.587.747V24c0 1.657-1.343 3-3 3z"/><circle fill="#CCD6DD" cx="17" cy="32" r="3"/></svg>

After

Width:  |  Height:  |  Size: 388 B