move emotion / gender presentation to outfit state

This commit is contained in:
Matt Dunn-Rankin 2020-05-02 22:20:17 -07:00
parent fae2a579c2
commit a064e5b471
3 changed files with 57 additions and 37 deletions

View file

@ -83,6 +83,7 @@ function OutfitControls({ outfitState, dispatchToOutfit }) {
<Flex flex="1 1 0" align="center" pl="4"> <Flex flex="1 1 0" align="center" pl="4">
<PosePicker <PosePicker
outfitState={outfitState} outfitState={outfitState}
dispatchToOutfit={dispatchToOutfit}
onLockFocus={() => setFocusIsLocked(true)} onLockFocus={() => setFocusIsLocked(true)}
onUnlockFocus={() => setFocusIsLocked(false)} onUnlockFocus={() => setFocusIsLocked(false)}
/> />

View file

@ -25,16 +25,15 @@ import twemojiMasc from "../images/twemoji/masc.svg";
import twemojiFem from "../images/twemoji/fem.svg"; import twemojiFem from "../images/twemoji/fem.svg";
import { OutfitLayers } from "./OutfitPreview"; import { OutfitLayers } from "./OutfitPreview";
function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) { function PosePicker({
outfitState,
dispatchToOutfit,
onLockFocus,
onUnlockFocus,
}) {
const theme = useTheme(); const theme = useTheme();
const { speciesId, colorId } = outfitState;
const { loading, error, poses, selectPose } = usePoses({
speciesId,
colorId,
});
const checkedInputRef = React.useRef(); const checkedInputRef = React.useRef();
const { loading, error, poses } = usePoses(outfitState);
if (loading) { if (loading) {
return null; return null;
@ -52,6 +51,15 @@ function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) {
return null; return null;
} }
const onChange = (e) => {
const [emotion, genderPresentation] = e.target.value.split("-");
dispatchToOutfit({
type: "setPose",
emotion,
genderPresentation,
});
};
return ( return (
<Popover <Popover
placement="bottom-end" placement="bottom-end"
@ -95,16 +103,7 @@ function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) {
</PopoverTrigger> </PopoverTrigger>
<PopoverContent> <PopoverContent>
<Box p="4"> <Box p="4">
<table <table width="100%">
width="100%"
borderSpacing="8px"
onChange={(e) => {
const [emotion, genderPresentation] = e.target.value.split(
"-"
);
selectPose({ emotion, genderPresentation });
}}
>
<thead> <thead>
<tr> <tr>
<th /> <th />
@ -127,21 +126,21 @@ function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) {
<Cell as="td"> <Cell as="td">
<PoseButton <PoseButton
pose={poses.happyMasc} pose={poses.happyMasc}
speciesId={speciesId} onChange={onChange}
inputRef={poses.happyMasc.isSelected && checkedInputRef} inputRef={poses.happyMasc.isSelected && checkedInputRef}
/> />
</Cell> </Cell>
<Cell as="td"> <Cell as="td">
<PoseButton <PoseButton
pose={poses.sadMasc} pose={poses.sadMasc}
speciesId={speciesId} onChange={onChange}
inputRef={poses.sadMasc.isSelected && checkedInputRef} inputRef={poses.sadMasc.isSelected && checkedInputRef}
/> />
</Cell> </Cell>
<Cell as="td"> <Cell as="td">
<PoseButton <PoseButton
pose={poses.sickMasc} pose={poses.sickMasc}
speciesId={speciesId} onChange={onChange}
inputRef={poses.sickMasc.isSelected && checkedInputRef} inputRef={poses.sickMasc.isSelected && checkedInputRef}
/> />
</Cell> </Cell>
@ -153,21 +152,21 @@ function PosePicker({ outfitState, onLockFocus, onUnlockFocus }) {
<Cell as="td"> <Cell as="td">
<PoseButton <PoseButton
pose={poses.happyFem} pose={poses.happyFem}
speciesId={speciesId} onChange={onChange}
inputRef={poses.happyFem.isSelected && checkedInputRef} inputRef={poses.happyFem.isSelected && checkedInputRef}
/> />
</Cell> </Cell>
<Cell as="td"> <Cell as="td">
<PoseButton <PoseButton
pose={poses.sadFem} pose={poses.sadFem}
speciesId={speciesId} onChange={onChange}
inputRef={poses.sadFem.isSelected && checkedInputRef} inputRef={poses.sadFem.isSelected && checkedInputRef}
/> />
</Cell> </Cell>
<Cell as="td"> <Cell as="td">
<PoseButton <PoseButton
pose={poses.sickFem} pose={poses.sickFem}
speciesId={speciesId} onChange={onChange}
inputRef={poses.sickFem.isSelected && checkedInputRef} inputRef={poses.sickFem.isSelected && checkedInputRef}
/> />
</Cell> </Cell>
@ -205,7 +204,7 @@ const GENDER_PRESENTATION_STRINGS = {
FEMININE: "Feminine", FEMININE: "Feminine",
}; };
function PoseButton({ pose, speciesId, inputRef }) { function PoseButton({ pose, onChange, inputRef }) {
const theme = useTheme(); const theme = useTheme();
if (!pose) { if (!pose) {
@ -233,6 +232,7 @@ function PoseButton({ pose, speciesId, inputRef }) {
name="pose" name="pose"
value={`${pose.emotion}-${pose.genderPresentation}`} value={`${pose.emotion}-${pose.genderPresentation}`}
checked={pose.isSelected} checked={pose.isSelected}
onChange={onChange}
ref={inputRef || null} ref={inputRef || null}
/> />
<Box <Box
@ -279,7 +279,8 @@ function PoseButton({ pose, speciesId, inputRef }) {
width="50px" width="50px"
height="50px" height="50px"
transform={ transform={
transformsBySpeciesId[speciesId] || transformsBySpeciesId.default transformsBySpeciesId[pose.speciesId] ||
transformsBySpeciesId.default
} }
> >
<OutfitLayers visibleLayers={getVisibleLayers(pose, [])} /> <OutfitLayers visibleLayers={getVisibleLayers(pose, [])} />
@ -293,11 +294,8 @@ function EmojiImage({ src, "aria-label": ariaLabel }) {
return <Image src={src} aria-label={ariaLabel} width="16px" height="16px" />; return <Image src={src} aria-label={ariaLabel} width="16px" height="16px" />;
} }
function usePoses({ speciesId, colorId }) { function usePoses(outfitState) {
const [selectedPose, selectPose] = React.useState({ const { speciesId, colorId, emotion, genderPresentation } = outfitState;
emotion: "HAPPY",
genderPresentation: "FEMININE",
});
const { loading, error, data } = useQuery( const { loading, error, data } = useQuery(
gql` gql`
@ -320,9 +318,11 @@ function usePoses({ speciesId, colorId }) {
...petAppearances.find( ...petAppearances.find(
(pa) => pa.emotion === e && pa.genderPresentation === gp (pa) => pa.emotion === e && pa.genderPresentation === gp
), ),
speciesId,
isSelected: isSelected:
selectedPose.emotion === e && selectedPose.genderPresentation === gp, outfitState.emotion === e && outfitState.genderPresentation === gp,
}); });
console.log(outfitState.emotion, outfitState.genderPresentation, outfitState);
const poses = { const poses = {
happyMasc: buildPose("HAPPY", "MASCULINE"), happyMasc: buildPose("HAPPY", "MASCULINE"),
@ -333,7 +333,7 @@ function usePoses({ speciesId, colorId }) {
sickFem: buildPose("SICK", "FEMININE"), sickFem: buildPose("SICK", "FEMININE"),
}; };
return { loading, error, poses, selectPose }; return { loading, error, poses };
} }
const transformsBySpeciesId = { const transformsBySpeciesId = {

View file

@ -30,12 +30,14 @@ function useOutfitState() {
"74546", "74546",
"57997", "57997",
]), ]),
speciesId: "24", // Starry speciesId: "24",
colorId: "62", // Zafara colorId: "62",
emotion: "HAPPY",
genderPresentation: "FEMININE",
} }
); );
const { name, speciesId, colorId } = state; const { name, speciesId, colorId, emotion, genderPresentation } = state;
// It's more convenient to manage these as a Set in state, but most callers // It's more convenient to manage these as a Set in state, but most callers
// will find it more convenient to access them as arrays! e.g. for `.map()` // will find it more convenient to access them as arrays! e.g. for `.map()`
@ -94,6 +96,8 @@ function useOutfitState() {
allItemIds, allItemIds,
speciesId, speciesId,
colorId, colorId,
emotion,
genderPresentation,
url, url,
}; };
@ -106,6 +110,8 @@ function useOutfitState() {
name: urlParams.get("name"), name: urlParams.get("name"),
speciesId: urlParams.get("species"), speciesId: urlParams.get("species"),
colorId: urlParams.get("color"), colorId: urlParams.get("color"),
emotion: urlParams.get("emotion"),
genderPresentation: urlParams.get("genderPresentation"),
wornItemIds: urlParams.getAll("objects[]"), wornItemIds: urlParams.getAll("objects[]"),
closetedItemIds: urlParams.getAll("closet[]"), closetedItemIds: urlParams.getAll("closet[]"),
}); });
@ -176,6 +182,9 @@ const outfitStateReducer = (apolloClient) => (baseState, action) => {
wornItemIds.delete(itemId); wornItemIds.delete(itemId);
closetedItemIds.delete(itemId); closetedItemIds.delete(itemId);
}); });
case "setPose":
const { emotion, genderPresentation } = action;
return { ...baseState, emotion, genderPresentation };
case "reset": case "reset":
const { name, speciesId, colorId, wornItemIds, closetedItemIds } = action; const { name, speciesId, colorId, wornItemIds, closetedItemIds } = action;
return { return {
@ -315,12 +324,22 @@ function getZonesAndItems(itemsById, wornItemIds, closetedItemIds) {
} }
function buildOutfitUrl(state) { function buildOutfitUrl(state) {
const { name, speciesId, colorId, wornItemIds, closetedItemIds } = state; const {
name,
speciesId,
colorId,
emotion,
genderPresentation,
wornItemIds,
closetedItemIds,
} = state;
const params = new URLSearchParams(); const params = new URLSearchParams();
params.append("name", name); params.append("name", name);
params.append("species", speciesId); params.append("species", speciesId);
params.append("color", colorId); params.append("color", colorId);
params.append("emotion", emotion);
params.append("genderPresentation", genderPresentation);
for (const itemId of wornItemIds) { for (const itemId of wornItemIds) {
params.append("objects[]", itemId); params.append("objects[]", itemId);
} }