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
|
* 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 😅
|
* 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? :/
|
* 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",
|
"graphql": "^15.0.0",
|
||||||
"immer": "^6.0.3",
|
"immer": "^6.0.3",
|
||||||
"mysql2": "^2.1.0",
|
"mysql2": "^2.1.0",
|
||||||
|
"node-fetch": "^2.6.0",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"react-scripts": "3.4.1",
|
"react-scripts": "3.4.1",
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import gql from "graphql-tag";
|
||||||
|
import { useQuery } from "@apollo/react-hooks";
|
||||||
import {
|
import {
|
||||||
Text,
|
Text,
|
||||||
Modal,
|
Modal,
|
||||||
|
@ -17,24 +19,45 @@ import {
|
||||||
|
|
||||||
function OutfitResetModal({ isOpen, onClose, dispatchToOutfit }) {
|
function OutfitResetModal({ isOpen, onClose, dispatchToOutfit }) {
|
||||||
const [petName, setPetName] = React.useState("");
|
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({
|
dispatchToOutfit({
|
||||||
type: "reset",
|
type: "reset",
|
||||||
name: custom_pet.name,
|
name: petName,
|
||||||
speciesId: custom_pet.species_id,
|
speciesId: species.id,
|
||||||
colorId: custom_pet.color_id,
|
colorId: color.id,
|
||||||
wornItemIds: Object.values(object_info_registry).map(
|
wornItemIds: items.map((i) => i.id),
|
||||||
(o) => o.obj_info_id
|
|
||||||
),
|
|
||||||
closetedItemIds: [],
|
closetedItemIds: [],
|
||||||
});
|
});
|
||||||
onClose();
|
onClose();
|
||||||
setPetName("");
|
setPetName("");
|
||||||
};
|
submitPetName("");
|
||||||
const { loading, error, loadOutfitData } = useLoadOutfitData(
|
},
|
||||||
petName,
|
}
|
||||||
onComplete
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const clearOutfit = () => {
|
const clearOutfit = () => {
|
||||||
|
@ -46,6 +69,7 @@ function OutfitResetModal({ isOpen, onClose, dispatchToOutfit }) {
|
||||||
});
|
});
|
||||||
onClose();
|
onClose();
|
||||||
setPetName("");
|
setPetName("");
|
||||||
|
submitPetName("");
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -55,7 +79,7 @@ function OutfitResetModal({ isOpen, onClose, dispatchToOutfit }) {
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
loadOutfitData();
|
submitPetName(petName);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ModalHeader>
|
<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;
|
export default OutfitResetModal;
|
||||||
|
|
|
@ -1,5 +1,44 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// 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`] = `
|
exports[`SpeciesColorPair gets them all 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"allValidSpeciesColorPairs": Array [
|
"allValidSpeciesColorPairs": Array [
|
||||||
|
|
|
@ -2,6 +2,7 @@ const { gql } = require("apollo-server");
|
||||||
|
|
||||||
const connectToDb = require("./db");
|
const connectToDb = require("./db");
|
||||||
const buildLoaders = require("./loaders");
|
const buildLoaders = require("./loaders");
|
||||||
|
const neopets = require("./neopets");
|
||||||
const { capitalize } = require("./util");
|
const { capitalize } = require("./util");
|
||||||
|
|
||||||
const typeDefs = gql`
|
const typeDefs = gql`
|
||||||
|
@ -55,6 +56,12 @@ const typeDefs = gql`
|
||||||
color: Color!
|
color: Color!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Outfit {
|
||||||
|
species: Species!
|
||||||
|
color: Color!
|
||||||
|
items: [Item!]!
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
allColors: [Color!]!
|
allColors: [Color!]!
|
||||||
allSpecies: [Species!]!
|
allSpecies: [Species!]!
|
||||||
|
@ -70,6 +77,8 @@ const typeDefs = gql`
|
||||||
limit: Int
|
limit: Int
|
||||||
): ItemSearchResult!
|
): ItemSearchResult!
|
||||||
petAppearance(speciesId: ID!, colorId: ID!): Appearance
|
petAppearance(speciesId: ID!, colorId: ID!): Appearance
|
||||||
|
|
||||||
|
petOnNeopetsDotCom(petName: String!): Outfit
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -210,6 +219,17 @@ const resolvers = {
|
||||||
const swfAssets = await petSwfAssetLoader.load(petState.id);
|
const swfAssets = await petSwfAssetLoader.load(petState.id);
|
||||||
return { layers: swfAssets, restrictedZones: [] };
|
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({
|
expect.extend({
|
||||||
toHaveNoErrors(res) {
|
toHaveNoErrors(res) {
|
||||||
if (res.errors) {
|
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"
|
lower-case "^2.0.1"
|
||||||
tslib "^1.10.0"
|
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"
|
version "2.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||||
|
|
Loading…
Reference in a new issue