move neopets.com loading into server
the client stuff worked locally, but not in prod because you can't request http from https, even with cors set up correctly 😅
This commit is contained in:
parent
b1a60e4e9d
commit
90ad9feb0c
8 changed files with 155 additions and 53 deletions
|
@ -3,3 +3,9 @@
|
|||
* Restore good download behavior: use crossOrigin for everything, and remove cache-buster in the URL we use for canvas
|
||||
* Undo the local linking we did for @chakra-ui/core, react, and react-dom on Matchu's machine 😅
|
||||
* Present invalidated items somewhere on the screen, instead of them just vanishing? :/
|
||||
|
||||
Features:
|
||||
* Outfit sharing
|
||||
* Search by zone
|
||||
* Outfit saving
|
||||
* Use the space better on big screens?
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"graphql": "^15.0.0",
|
||||
"immer": "^6.0.3",
|
||||
"mysql2": "^2.1.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-scripts": "3.4.1",
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import React from "react";
|
||||
import gql from "graphql-tag";
|
||||
import { useQuery } from "@apollo/react-hooks";
|
||||
import {
|
||||
Text,
|
||||
Modal,
|
||||
|
@ -17,24 +19,45 @@ import {
|
|||
|
||||
function OutfitResetModal({ isOpen, onClose, dispatchToOutfit }) {
|
||||
const [petName, setPetName] = React.useState("");
|
||||
const [submittedPetName, submitPetName] = React.useState("");
|
||||
|
||||
const onComplete = ({ custom_pet, object_info_registry }) => {
|
||||
const { loading, error } = useQuery(
|
||||
gql`
|
||||
query($petName: String!) {
|
||||
petOnNeopetsDotCom(petName: $petName) {
|
||||
color {
|
||||
id
|
||||
}
|
||||
species {
|
||||
id
|
||||
}
|
||||
items {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
variables: { petName: submittedPetName },
|
||||
skip: !submittedPetName,
|
||||
fetchPolicy: "network-only",
|
||||
onCompleted: (data) => {
|
||||
if (!data) return;
|
||||
|
||||
const { species, color, items } = data.petOnNeopetsDotCom;
|
||||
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
|
||||
),
|
||||
name: petName,
|
||||
speciesId: species.id,
|
||||
colorId: color.id,
|
||||
wornItemIds: items.map((i) => i.id),
|
||||
closetedItemIds: [],
|
||||
});
|
||||
onClose();
|
||||
setPetName("");
|
||||
};
|
||||
const { loading, error, loadOutfitData } = useLoadOutfitData(
|
||||
petName,
|
||||
onComplete
|
||||
submitPetName("");
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const clearOutfit = () => {
|
||||
|
@ -46,6 +69,7 @@ function OutfitResetModal({ isOpen, onClose, dispatchToOutfit }) {
|
|||
});
|
||||
onClose();
|
||||
setPetName("");
|
||||
submitPetName("");
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -55,7 +79,7 @@ function OutfitResetModal({ isOpen, onClose, dispatchToOutfit }) {
|
|||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
loadOutfitData();
|
||||
submitPetName(petName);
|
||||
}}
|
||||
>
|
||||
<ModalHeader>
|
||||
|
@ -110,38 +134,4 @@ function OutfitResetModal({ isOpen, onClose, dispatchToOutfit }) {
|
|||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -1,5 +1,44 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Pet looks up a pet 1`] = `
|
||||
Object {
|
||||
"petOnNeopetsDotCom": Object {
|
||||
"color": Object {
|
||||
"id": "75",
|
||||
},
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "37229",
|
||||
},
|
||||
Object {
|
||||
"id": "37375",
|
||||
},
|
||||
Object {
|
||||
"id": "38911",
|
||||
},
|
||||
Object {
|
||||
"id": "38912",
|
||||
},
|
||||
Object {
|
||||
"id": "38913",
|
||||
},
|
||||
Object {
|
||||
"id": "43014",
|
||||
},
|
||||
Object {
|
||||
"id": "43397",
|
||||
},
|
||||
Object {
|
||||
"id": "48313",
|
||||
},
|
||||
],
|
||||
"species": Object {
|
||||
"id": "54",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`SpeciesColorPair gets them all 1`] = `
|
||||
Object {
|
||||
"allValidSpeciesColorPairs": Array [
|
||||
|
|
|
@ -2,6 +2,7 @@ const { gql } = require("apollo-server");
|
|||
|
||||
const connectToDb = require("./db");
|
||||
const buildLoaders = require("./loaders");
|
||||
const neopets = require("./neopets");
|
||||
const { capitalize } = require("./util");
|
||||
|
||||
const typeDefs = gql`
|
||||
|
@ -55,6 +56,12 @@ const typeDefs = gql`
|
|||
color: Color!
|
||||
}
|
||||
|
||||
type Outfit {
|
||||
species: Species!
|
||||
color: Color!
|
||||
items: [Item!]!
|
||||
}
|
||||
|
||||
type Query {
|
||||
allColors: [Color!]!
|
||||
allSpecies: [Species!]!
|
||||
|
@ -70,6 +77,8 @@ const typeDefs = gql`
|
|||
limit: Int
|
||||
): ItemSearchResult!
|
||||
petAppearance(speciesId: ID!, colorId: ID!): Appearance
|
||||
|
||||
petOnNeopetsDotCom(petName: String!): Outfit
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -210,6 +219,17 @@ const resolvers = {
|
|||
const swfAssets = await petSwfAssetLoader.load(petState.id);
|
||||
return { layers: swfAssets, restrictedZones: [] };
|
||||
},
|
||||
petOnNeopetsDotCom: async (_, { petName }) => {
|
||||
const petData = await neopets.loadPetData(petName);
|
||||
const outfit = {
|
||||
species: { id: petData.custom_pet.species_id },
|
||||
color: { id: petData.custom_pet.color_id },
|
||||
items: Object.values(petData.object_info_registry).map((o) => ({
|
||||
id: o.obj_info_id,
|
||||
})),
|
||||
};
|
||||
return outfit;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1680,6 +1680,32 @@ describe("SpeciesColorPair", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("Pet", () => {
|
||||
it("looks up a pet", async () => {
|
||||
const res = await query({
|
||||
query: gql`
|
||||
query {
|
||||
petOnNeopetsDotCom(petName: "roopal27") {
|
||||
species {
|
||||
id
|
||||
}
|
||||
color {
|
||||
id
|
||||
}
|
||||
items {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
expect(res).toHaveNoErrors();
|
||||
expect(res.data).toMatchSnapshot();
|
||||
expect(queryFn.mock.calls).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
});
|
||||
|
||||
expect.extend({
|
||||
toHaveNoErrors(res) {
|
||||
if (res.errors) {
|
||||
|
|
20
src/server/neopets.js
Normal file
20
src/server/neopets.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const fetch = require("node-fetch");
|
||||
|
||||
async function loadPetData(petName) {
|
||||
const res = await fetch(
|
||||
`http://www.neopets.com/amfphp/json.php/CustomPetService.getViewerData` +
|
||||
`/${petName}`
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(`neopets.com returned: ${res.statusText}`);
|
||||
}
|
||||
|
||||
const json = await res.json();
|
||||
if (!json.custom_pet) {
|
||||
throw new Error(`missing custom_pet data`);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
module.exports = { loadPetData };
|
|
@ -7905,7 +7905,7 @@ no-case@^3.0.3:
|
|||
lower-case "^2.0.1"
|
||||
tslib "^1.10.0"
|
||||
|
||||
node-fetch@^2.1.2, node-fetch@^2.2.0:
|
||||
node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@^2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||
|
|
Loading…
Reference in a new issue