diff --git a/src/OutfitPreview.js b/src/OutfitPreview.js
index e5c06d6..7d6a5c9 100644
--- a/src/OutfitPreview.js
+++ b/src/OutfitPreview.js
@@ -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 }) {
)}
+
+ setHasFocus(true)}
+ onBlur={() => setHasFocus(false)}
+ onClick={() => setShowResetModal(true)}
+ />
+
+ setShowResetModal(false)}
+ dispatchToOutfit={dispatchToOutfit}
+ />
);
}
diff --git a/src/OutfitResetModal.js b/src/OutfitResetModal.js
new file mode 100644
index 0000000..ba90cdf
--- /dev/null
+++ b/src/OutfitResetModal.js
@@ -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 (
+
+
+
+
+
+
+ );
+}
+
+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;
diff --git a/src/useOutfitState.js b/src/useOutfitState.js
index 9938e7d..164e81a 100644
--- a/src/useOutfitState.js
+++ b/src/useOutfitState.js
@@ -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)}`);
}