outfit reset from pet name!

This commit is contained in:
Matt Dunn-Rankin 2020-04-25 05:29:27 -07:00
parent aded259f1b
commit 177aedc09d
3 changed files with 160 additions and 0 deletions

View file

@ -15,6 +15,7 @@ import {
} from "@chakra-ui/core";
import { Delay } from "./util";
import OutfitResetModal from "./OutfitResetModal";
import SpeciesColorPicker from "./SpeciesColorPicker";
import "./OutfitPreview.css";
@ -39,6 +40,7 @@ export const itemAppearanceFragment = gql`
function OutfitPreview({ outfitState, dispatchToOutfit }) {
const { wornItemIds, speciesId, colorId } = outfitState;
const [hasFocus, setHasFocus] = React.useState(false);
const [showResetModal, setShowResetModal] = React.useState(false);
const { loading, error, data } = useQuery(
gql`
@ -123,6 +125,25 @@ function OutfitPreview({ outfitState, dispatchToOutfit }) {
</FullScreenCenter>
</Delay>
)}
<Box pos="absolute" left="2" top="2">
<IconButton
icon="arrow-back"
aria-label="Leave this outfit"
variant="unstyled"
d="flex"
alignItems="center"
justifyContent="center"
color="gray.50"
opacity={hasFocus ? 1 : 0}
transition="all 0.2s"
_groupHover={{
opacity: 1,
}}
onFocus={() => setHasFocus(true)}
onBlur={() => setHasFocus(false)}
onClick={() => setShowResetModal(true)}
/>
</Box>
<Box
// Bottom toolbar on small screens, top on large screens
pos="absolute"
@ -191,6 +212,11 @@ function OutfitPreview({ outfitState, dispatchToOutfit }) {
</Tooltip>
</Flex>
</Box>
<OutfitResetModal
isOpen={showResetModal}
onClose={() => setShowResetModal(false)}
dispatchToOutfit={dispatchToOutfit}
/>
</PseudoBox>
);
}

125
src/OutfitResetModal.js Normal file
View file

@ -0,0 +1,125 @@
import React from "react";
import {
Text,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody,
Input,
Button,
ModalFooter,
FormErrorMessage,
FormControl,
} from "@chakra-ui/core";
function OutfitResetModal({ isOpen, onClose, dispatchToOutfit }) {
const [petName, setPetName] = React.useState("");
const onComplete = ({ custom_pet, object_info_registry }) => {
dispatchToOutfit({
type: "reset",
name: custom_pet.name,
speciesId: custom_pet.species_id,
colorId: custom_pet.color_id,
wornItemIds: Object.values(object_info_registry).map(
(o) => o.obj_info_id
),
closetedItemIds: [],
});
onClose();
setPetName("");
};
const { loading, error, loadOutfitData } = useLoadOutfitData(
petName,
onComplete
);
return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<form
onSubmit={(e) => {
e.preventDefault();
loadOutfitData();
}}
>
<ModalHeader>
<Text fontFamily="Delicious">
Want to try your own pet?{" "}
<span role="img" aria-label="(surprise emoji)">
😮
</span>
</Text>
</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Text mb={4}>
Choose a pet from Neopets.com, and we'll pull their outfit data
into here for you to play with!
</Text>
<FormControl isInvalid={error}>
<Input
placeholder="Enter a pet's name…"
value={petName}
onChange={(e) => setPetName(e.target.value)}
autoFocus
/>
{error && (
<FormErrorMessage>
We had trouble loading that pet, sorry{" "}
<span role="img" aria-label="(confounded emoji)">
😖
</span>
</FormErrorMessage>
)}
</FormControl>
</ModalBody>
<ModalFooter>
<Button type="submit" variantColor="green" isLoading={loading}>
Show me!
</Button>
</ModalFooter>
</form>
</ModalContent>
</Modal>
);
}
function useLoadOutfitData(petName, onComplete) {
const [loading, setLoading] = React.useState(false);
const [error, setError] = React.useState(null);
const loadOutfitData = async () => {
setLoading(true);
setError(null);
let json;
try {
const res = await fetch(
`http://www.neopets.com/amfphp/json.php/CustomPetService.getViewerData` +
`/${petName}`
);
if (!res.ok) {
throw new Error(res.statusText);
}
json = await res.json();
if (!json.custom_pet) {
throw new Error(`missing custom_pet data`);
}
} catch (e) {
setLoading(false);
setError(e);
return;
}
setLoading(false);
onComplete(json);
};
return { loading, error, loadOutfitData };
}
export default OutfitResetModal;

View file

@ -146,6 +146,15 @@ const outfitStateReducer = (apolloClient) => (baseState, action) => {
wornItemIds.delete(itemId);
closetedItemIds.delete(itemId);
});
case "reset":
const { name, speciesId, colorId, wornItemIds, closetedItemIds } = action;
return {
name,
speciesId: String(speciesId),
colorId: String(colorId),
wornItemIds: new Set(wornItemIds.map(String)),
closetedItemIds: new Set(closetedItemIds.map(String)),
};
default:
throw new Error(`unexpected action ${JSON.stringify(action)}`);
}