diff --git a/src/OutfitPreview.js b/src/OutfitPreview.js
index b26185d2..dce292c1 100644
--- a/src/OutfitPreview.js
+++ b/src/OutfitPreview.js
@@ -8,10 +8,12 @@ import { Delay } from "./util";
import "./OutfitPreview.css";
-function OutfitPreview({ itemIds, speciesId, colorId }) {
+function OutfitPreview({ outfitState }) {
+ const { wornItemIds, speciesId, colorId } = outfitState;
+
const { loading, error, data } = useQuery(
gql`
- query($itemIds: [ID!]!, $speciesId: ID!, $colorId: ID!) {
+ query($wornItemIds: [ID!]!, $speciesId: ID!, $colorId: ID!) {
petAppearance(speciesId: $speciesId, colorId: $colorId) {
layers {
id
@@ -27,7 +29,7 @@ function OutfitPreview({ itemIds, speciesId, colorId }) {
}
}
- items(ids: $itemIds) {
+ items(ids: $wornItemIds) {
id
appearanceOn(speciesId: $speciesId, colorId: $colorId) {
layers {
@@ -47,7 +49,7 @@ function OutfitPreview({ itemIds, speciesId, colorId }) {
}
`,
{
- variables: { itemIds, speciesId, colorId },
+ variables: { wornItemIds, speciesId, colorId },
}
);
diff --git a/src/WardrobePage.js b/src/WardrobePage.js
index f59184c5..6c0ade61 100644
--- a/src/WardrobePage.js
+++ b/src/WardrobePage.js
@@ -19,7 +19,6 @@ import {
useToast,
} from "@chakra-ui/core";
-import { ITEMS } from "./data";
import ItemList, { ItemListSkeleton } from "./ItemList";
import useItemData from "./useItemData";
import useOutfitState from "./useOutfitState.js";
@@ -27,7 +26,7 @@ import OutfitPreview from "./OutfitPreview";
import { Delay } from "./util";
function WardrobePage() {
- const { loading, error, data, dispatch: dispatchToOutfit } = useOutfitState();
+ const { loading, error, outfitState, dispatchToOutfit } = useOutfitState();
const [searchQuery, setSearchQuery] = React.useState("");
const toast = useToast();
@@ -67,11 +66,7 @@ function WardrobePage() {
width="100%"
>
-
+
@@ -83,13 +78,13 @@ function WardrobePage() {
{searchQuery ? (
) : (
)}
@@ -135,8 +130,13 @@ function SearchToolbar({ query, onChange }) {
);
}
-function SearchPanel({ query, wornItemIds, dispatchToOutfit }) {
- const { loading, error, itemsById } = useItemData(ITEMS.map((i) => i.id));
+function SearchPanel({ query, outfitState, dispatchToOutfit }) {
+ const { allItemIds, wornItemIds, speciesId, colorId } = outfitState;
+ const { loading, error, itemsById } = useItemData(
+ allItemIds,
+ speciesId,
+ colorId
+ );
const normalize = (s) => s.toLowerCase();
const results = Object.values(itemsById).filter((item) =>
@@ -172,7 +172,7 @@ function SearchResults({
if (error) {
return (
- We hit an error trying to load your search results
+ We hit an error trying to load your search results{" "}
😓
{" "}
@@ -202,7 +202,9 @@ function SearchResults({
);
}
-function ItemsPanel({ zonesAndItems, loading, dispatchToOutfit }) {
+function ItemsPanel({ outfitState, loading, dispatchToOutfit }) {
+ const { zonesAndItems, wornItemIds } = outfitState;
+
return (
@@ -217,12 +219,14 @@ function ItemsPanel({ zonesAndItems, loading, dispatchToOutfit }) {
))}
{!loading &&
- zonesAndItems.map(({ zoneName, items, wornItemId }) => (
-
- {zoneName}
+ zonesAndItems.map(({ zone, items }) => (
+
+ {zone.label}
i.id)
+ .filter((id) => wornItemIds.includes(id))}
dispatchToOutfit={dispatchToOutfit}
/>
diff --git a/src/data.js b/src/data.js
deleted file mode 100644
index 52d9313d..00000000
--- a/src/data.js
+++ /dev/null
@@ -1,56 +0,0 @@
-export const ITEMS = [
- {
- id: "38913",
- // name: "Zafara Agent Gloves",
- // thumbnailSrc: "http://images.neopets.com/items/clo_zafara_agent_gloves.gif",
- zoneName: "Gloves",
- },
- {
- id: "38911",
- // name: "Zafara Agent Hood",
- // thumbnailSrc: "http://images.neopets.com/items/clo_zafara_agent_hood.gif",
- zoneName: "Hat",
- },
- {
- id: "38912",
- // name: "Zafara Agent Robe",
- // thumbnailSrc: "http://images.neopets.com/items/clo_zafara_agent_robe.gif",
- zoneName: "Jacket",
- },
- {
- id: "37375",
- // name: "Moon and Stars Background",
- // thumbnailSrc: "http://images.neopets.com/items/bg_moonstars.gif",
- zoneName: "Background",
- },
- {
- id: "74166",
- // name: "Altador Forest Background",
- // thumbnailSrc: "http://images.neopets.com/items/bg_ddy18_altadorforest.gif",
- zoneName: "Background",
- },
- {
- id: "48313",
- // name: "Altador Cup Brooch",
- // thumbnailSrc: "http://images.neopets.com/items/clo_altcuplogo_brooch.gif",
- zoneName: "Collar",
- },
- {
- id: "37229",
- // name: "Magic Ball Table",
- // thumbnailSrc: "http://images.neopets.com/items/gif_magicball_table.gif",
- zoneName: "Lower Foreground Item",
- },
- {
- id: "43014",
- // name: "Green Leaf String Lights",
- // thumbnailSrc: "http://images.neopets.com/items/toy_stringlight_illleaf.gif",
- zoneName: "Background Item",
- },
- {
- id: "43397",
- // name: "Jewelled Staff",
- // thumbnailSrc: "http://images.neopets.com/items/mall_staff_jewelled.gif",
- zoneName: "Left-hand item",
- },
-];
diff --git a/src/useItemData.js b/src/useItemData.js
index a1b63f69..a9c1b791 100644
--- a/src/useItemData.js
+++ b/src/useItemData.js
@@ -1,8 +1,6 @@
import gql from "graphql-tag";
import { useQuery } from "@apollo/react-hooks";
-import { ITEMS } from "./data";
-
function useItemData(itemIds, speciesId, colorId) {
const { loading, error, data } = useQuery(
gql`
@@ -12,12 +10,13 @@ function useItemData(itemIds, speciesId, colorId) {
name
thumbnailUrl
- # This is used for wearItem actions, to resolve conflicts. We don't
- # use it directly; we just expect it to be in the cache!
+ # This is used to group items by zone, and to detect conflicts when
+ # wearing a new item.
appearanceOn(speciesId: $speciesId, colorId: $colorId) {
layers {
zone {
id
+ label
}
}
}
@@ -30,11 +29,7 @@ function useItemData(itemIds, speciesId, colorId) {
const items = (data && data.items) || [];
const itemsById = {};
for (const item of items) {
- const hardcodedItem = ITEMS.find((i) => i.id === item.id);
- itemsById[item.id] = {
- ...hardcodedItem,
- ...item,
- };
+ itemsById[item.id] = item;
}
return { loading, error, itemsById };
diff --git a/src/useOutfitState.js b/src/useOutfitState.js
index f3a90c8d..8cee207f 100644
--- a/src/useOutfitState.js
+++ b/src/useOutfitState.js
@@ -9,21 +9,24 @@ enableMapSet();
function useOutfitState() {
const apolloClient = useApolloClient();
- const [state, dispatch] = React.useReducer(outfitStateReducer(apolloClient), {
- wornItemIds: new Set([
- "38913",
- "38911",
- "38912",
- "37375",
- "48313",
- "37229",
- "43014",
- "43397",
- ]),
- closetedItemIds: new Set(["74166"]),
- speciesId: "54", // Starry
- colorId: "75", // Zafara
- });
+ const [state, dispatchToOutfit] = React.useReducer(
+ outfitStateReducer(apolloClient),
+ {
+ wornItemIds: new Set([
+ "38913",
+ "38911",
+ "38912",
+ "37375",
+ "48313",
+ "37229",
+ "43014",
+ "43397",
+ ]),
+ closetedItemIds: new Set(["74166", "68626", "40319"]),
+ speciesId: "54", // Starry
+ colorId: "75", // Zafara
+ }
+ );
const { speciesId, colorId } = state;
@@ -45,16 +48,22 @@ function useOutfitState() {
closetedItemIds
);
- const data = { zonesAndItems, wornItemIds, speciesId, colorId };
+ const outfitState = {
+ zonesAndItems,
+ wornItemIds,
+ allItemIds,
+ speciesId,
+ colorId,
+ };
- return { loading, error, data, dispatch };
+ return { loading, error, outfitState, dispatchToOutfit };
}
const outfitStateReducer = (apolloClient) => (baseState, action) => {
switch (action.type) {
case "wearItem":
return produce(baseState, (state) => {
- const { wornItemIds, closetedItemIds, speciesId, colorId } = state;
+ const { wornItemIds, closetedItemIds } = state;
const { itemId } = action;
// Move the item out of the closet.
@@ -131,6 +140,7 @@ function findItemConflicts(itemIdToAdd, state, apolloClient) {
return conflictingIds;
}
+// TODO: Get this out of here, tbh...
function getZonesAndItems(itemsById, wornItemIds, closetedItemIds) {
const wornItems = wornItemIds.map((id) => itemsById[id]).filter((i) => i);
const closetedItems = closetedItemIds
@@ -138,17 +148,28 @@ function getZonesAndItems(itemsById, wornItemIds, closetedItemIds) {
.filter((i) => i);
const allItems = [...wornItems, ...closetedItems];
- const allZoneNames = [...new Set(allItems.map((item) => item.zoneName))];
- allZoneNames.sort();
+ const zonesById = new Map();
+ const itemsByZoneId = new Map();
+ for (const item of allItems) {
+ for (const layer of item.appearanceOn.layers) {
+ const zoneId = layer.zone.id;
+ zonesById.set(zoneId, layer.zone);
- const zonesAndItems = allZoneNames.map((zoneName) => {
- const items = allItems.filter((item) => item.zoneName === zoneName);
- items.sort((a, b) => a.name.localeCompare(b.name));
- const wornItemId =
- items.map((item) => item.id).find((id) => wornItemIds.includes(id)) ||
- null;
- return { zoneName, items, wornItemId };
- });
+ if (!itemsByZoneId.has(zoneId)) {
+ itemsByZoneId.set(zoneId, []);
+ }
+ itemsByZoneId.get(zoneId).push(item);
+ }
+ }
+
+ const zonesAndItems = Array.from(itemsByZoneId.entries()).map(
+ ([zoneId, items]) => ({
+ zone: zonesById.get(zoneId),
+ items: [...items].sort((a, b) => a.name.localeCompare(b.name)),
+ })
+ );
+
+ zonesAndItems.sort((a, b) => a.zone.label.localeCompare(b.zone.label));
return zonesAndItems;
}