species/color picker!

This commit is contained in:
Matt Dunn-Rankin 2020-04-25 04:33:05 -07:00
parent d13420256c
commit 564cdef0ce
8 changed files with 388 additions and 207 deletions

View file

@ -15,6 +15,7 @@ import {
} from "@chakra-ui/core"; } from "@chakra-ui/core";
import { Delay } from "./util"; import { Delay } from "./util";
import SpeciesColorPicker from "./SpeciesColorPicker";
import "./OutfitPreview.css"; import "./OutfitPreview.css";
@ -35,8 +36,9 @@ export const itemAppearanceFragment = gql`
} }
`; `;
function OutfitPreview({ outfitState }) { function OutfitPreview({ outfitState, dispatchToOutfit }) {
const { wornItemIds, speciesId, colorId } = outfitState; const { wornItemIds, speciesId, colorId } = outfitState;
const [hasFocus, setHasFocus] = React.useState(false);
const { loading, error, data } = useQuery( const { loading, error, data } = useQuery(
gql` gql`
@ -122,12 +124,33 @@ function OutfitPreview({ outfitState }) {
</Delay> </Delay>
)} )}
<Box <Box
// Bottom-right in small screens, top-right on large screens // Bottom toolbar on small screens, top on large screens
pos="absolute" pos="absolute"
right="2" left="0"
right="0"
bottom={{ base: "2", lg: "auto" }} bottom={{ base: "2", lg: "auto" }}
top={{ base: "auto", lg: "2" }} top={{ base: "auto", lg: "2" }}
// Grid layout for the content!
display="grid"
gridTemplateAreas={`"space picker download"`}
gridTemplateColumns="minmax(0, 1fr) auto 1fr"
alignItems="center"
> >
<Box gridArea="space"></Box>
<PseudoBox
gridArea="picker"
opacity={hasFocus ? 1 : 0}
_groupHover={{ opacity: 1 }}
transition="opacity 0.2s"
>
<SpeciesColorPicker
outfitState={outfitState}
dispatchToOutfit={dispatchToOutfit}
onFocus={() => setHasFocus(true)}
onBlur={() => setHasFocus(false)}
/>
</PseudoBox>
<Flex gridArea="download" justify="flex-end">
<Tooltip label="Download" placement="left"> <Tooltip label="Download" placement="left">
<IconButton <IconButton
icon="download" icon="download"
@ -138,15 +161,20 @@ function OutfitPreview({ outfitState }) {
href={downloadImageUrl || "javascript:void 0"} href={downloadImageUrl || "javascript:void 0"}
download={(outfitState.name || "Outfit") + ".png"} download={(outfitState.name || "Outfit") + ".png"}
onMouseEnter={prepareDownload} onMouseEnter={prepareDownload}
onFocus={prepareDownload} onFocus={() => {
prepareDownload();
setHasFocus(true);
}}
onBlur={() => setHasFocus(false)}
cursor={!downloadImageUrl && "wait"} cursor={!downloadImageUrl && "wait"}
variant="unstyled" variant="unstyled"
backgroundColor="gray.600" backgroundColor="gray.600"
color="gray.50" color="gray.50"
boxShadow="md"
d="flex" d="flex"
alignItems="center" alignItems="center"
justifyContent="center" justifyContent="center"
opacity="0" opacity={hasFocus ? 1 : 0}
transition="all 0.2s" transition="all 0.2s"
_groupHover={{ _groupHover={{
opacity: 1, opacity: 1,
@ -161,6 +189,7 @@ function OutfitPreview({ outfitState }) {
outline="initial" outline="initial"
/> />
</Tooltip> </Tooltip>
</Flex>
</Box> </Box>
</PseudoBox> </PseudoBox>
); );
@ -218,14 +247,14 @@ function useDownloadableImage(visibleLayers) {
const [preparedForLayerIds, setPreparedForLayerIds] = React.useState([]); const [preparedForLayerIds, setPreparedForLayerIds] = React.useState([]);
const prepareDownload = React.useCallback(async () => { const prepareDownload = React.useCallback(async () => {
setDownloadImageUrl(null);
// Skip if the current image URL is already correct for these layers. // Skip if the current image URL is already correct for these layers.
const layerIds = visibleLayers.map((l) => l.id); const layerIds = visibleLayers.map((l) => l.id);
if (layerIds.join(",") === preparedForLayerIds.join(",")) { if (layerIds.join(",") === preparedForLayerIds.join(",")) {
return; return;
} }
setDownloadImageUrl(null);
const imagePromises = visibleLayers.map( const imagePromises = visibleLayers.map(
(layer) => (layer) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {

144
src/SpeciesColorPicker.js Normal file
View file

@ -0,0 +1,144 @@
import React from "react";
import gql from "graphql-tag";
import { useQuery } from "@apollo/react-hooks";
import { Box, Flex, Select, Text, useToast } from "@chakra-ui/core";
import { Delay } from "./util";
function SpeciesColorPicker({
outfitState,
dispatchToOutfit,
onFocus,
onBlur,
}) {
const toast = useToast();
const { loading, error, data } = useQuery(gql`
query {
allSpecies {
id
name
}
allColors {
id
name
}
allValidSpeciesColorPairs {
species {
id
}
color {
id
}
}
}
`);
const allColors = (data && [...data.allColors]) || [];
allColors.sort((a, b) => a.name.localeCompare(b.name));
const allSpecies = (data && [...data.allSpecies]) || [];
allSpecies.sort((a, b) => a.name.localeCompare(b.name));
const allValidSpeciesColorPairs = React.useMemo(
() =>
new Set(
((data && data.allValidSpeciesColorPairs) || []).map(
(p) => `${p.species.id},${p.color.id}`
)
),
[data]
);
if (loading) {
return (
<Delay ms={5000}>
<Text color="gray.50" textShadow="md">
Loading species/color data
</Text>
</Delay>
);
}
if (error) {
return (
<Text color="gray.50" textShadow="md">
Error loading species/color data.
</Text>
);
}
const onChangeColor = (e) => {
const speciesId = outfitState.speciesId;
const colorId = e.target.value;
const pair = `${speciesId},${colorId}`;
if (allValidSpeciesColorPairs.has(pair)) {
dispatchToOutfit({ type: "changeColor", colorId: e.target.value });
} else {
console.log(pair, Array.from(allValidSpeciesColorPairs));
const species = allSpecies.find((s) => s.id === speciesId);
const color = allColors.find((c) => c.id === colorId);
toast({
title: `We haven't seen a ${color.name} ${species.name} before! 😓`,
status: "warning",
});
}
};
const onChangeSpecies = (e) => {
const colorId = outfitState.colorId;
const speciesId = e.target.value;
const pair = `${speciesId},${colorId}`;
if (allValidSpeciesColorPairs.has(pair)) {
dispatchToOutfit({ type: "changeSpecies", speciesId: e.target.value });
} else {
console.log(pair, Array.from(allValidSpeciesColorPairs));
const species = allSpecies.find((s) => s.id === speciesId);
const color = allColors.find((c) => c.id === colorId);
toast({
title: `We haven't seen a ${color.name} ${species.name} before! 😓`,
});
}
};
return (
<Flex direction="row">
<Select
aria-label="Pet color"
value={outfitState.colorId}
onChange={onChangeColor}
backgroundColor="gray.600"
color="gray.50"
border="none"
boxShadow="md"
onFocus={onFocus}
onBlur={onBlur}
>
{allColors.map((color) => (
<option key={color.id} value={color.id}>
{color.name}
</option>
))}
</Select>
<Box width="8" />
<Select
aria-label="Pet species"
value={outfitState.speciesId}
onChange={onChangeSpecies}
backgroundColor="gray.600"
color="gray.50"
border="none"
boxShadow="md"
onFocus={onFocus}
onBlur={onBlur}
>
{allSpecies.map((species) => (
<option key={species.id} value={species.id}>
{species.name}
</option>
))}
</Select>
</Flex>
);
}
export default SpeciesColorPicker;

View file

@ -65,7 +65,10 @@ function WardrobePage() {
width="100%" width="100%"
> >
<Box gridArea="outfit" backgroundColor="gray.900"> <Box gridArea="outfit" backgroundColor="gray.900">
<OutfitPreview outfitState={outfitState} /> <OutfitPreview
outfitState={outfitState}
dispatchToOutfit={dispatchToOutfit}
/>
</Box> </Box>
<Box gridArea="search" boxShadow="sm"> <Box gridArea="search" boxShadow="sm">
<Box px="5" py="3"> <Box px="5" py="3">

View file

@ -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 { capitalize } = require("./util");
const typeDefs = gql` const typeDefs = gql`
enum LayerImageSize { enum LayerImageSize {
@ -140,7 +141,7 @@ const resolvers = {
Color: { Color: {
name: async (color, _, { colorTranslationLoader }) => { name: async (color, _, { colorTranslationLoader }) => {
const colorTranslation = await colorTranslationLoader.load(color.id); const colorTranslation = await colorTranslationLoader.load(color.id);
return colorTranslation.name; return capitalize(colorTranslation.name);
}, },
}, },
Species: { Species: {
@ -148,7 +149,7 @@ const resolvers = {
const speciesTranslation = await speciesTranslationLoader.load( const speciesTranslation = await speciesTranslationLoader.load(
species.id species.id
); );
return speciesTranslation.name; return capitalize(speciesTranslation.name);
}, },
}, },
Query: { Query: {

View file

@ -769,223 +769,223 @@ describe("Species", () => {
"allSpecies": Array [ "allSpecies": Array [
Object { Object {
"id": "1", "id": "1",
"name": "acara", "name": "Acara",
}, },
Object { Object {
"id": "2", "id": "2",
"name": "aisha", "name": "Aisha",
}, },
Object { Object {
"id": "3", "id": "3",
"name": "blumaroo", "name": "Blumaroo",
}, },
Object { Object {
"id": "4", "id": "4",
"name": "bori", "name": "Bori",
}, },
Object { Object {
"id": "5", "id": "5",
"name": "bruce", "name": "Bruce",
}, },
Object { Object {
"id": "6", "id": "6",
"name": "buzz", "name": "Buzz",
}, },
Object { Object {
"id": "7", "id": "7",
"name": "chia", "name": "Chia",
}, },
Object { Object {
"id": "8", "id": "8",
"name": "chomby", "name": "Chomby",
}, },
Object { Object {
"id": "9", "id": "9",
"name": "cybunny", "name": "Cybunny",
}, },
Object { Object {
"id": "10", "id": "10",
"name": "draik", "name": "Draik",
}, },
Object { Object {
"id": "11", "id": "11",
"name": "elephante", "name": "Elephante",
}, },
Object { Object {
"id": "12", "id": "12",
"name": "eyrie", "name": "Eyrie",
}, },
Object { Object {
"id": "13", "id": "13",
"name": "flotsam", "name": "Flotsam",
}, },
Object { Object {
"id": "14", "id": "14",
"name": "gelert", "name": "Gelert",
}, },
Object { Object {
"id": "15", "id": "15",
"name": "gnorbu", "name": "Gnorbu",
}, },
Object { Object {
"id": "16", "id": "16",
"name": "grarrl", "name": "Grarrl",
}, },
Object { Object {
"id": "17", "id": "17",
"name": "grundo", "name": "Grundo",
}, },
Object { Object {
"id": "18", "id": "18",
"name": "hissi", "name": "Hissi",
}, },
Object { Object {
"id": "19", "id": "19",
"name": "ixi", "name": "Ixi",
}, },
Object { Object {
"id": "20", "id": "20",
"name": "jetsam", "name": "Jetsam",
}, },
Object { Object {
"id": "21", "id": "21",
"name": "jubjub", "name": "Jubjub",
}, },
Object { Object {
"id": "22", "id": "22",
"name": "kacheek", "name": "Kacheek",
}, },
Object { Object {
"id": "23", "id": "23",
"name": "kau", "name": "Kau",
}, },
Object { Object {
"id": "24", "id": "24",
"name": "kiko", "name": "Kiko",
}, },
Object { Object {
"id": "25", "id": "25",
"name": "koi", "name": "Koi",
}, },
Object { Object {
"id": "26", "id": "26",
"name": "korbat", "name": "Korbat",
}, },
Object { Object {
"id": "27", "id": "27",
"name": "kougra", "name": "Kougra",
}, },
Object { Object {
"id": "28", "id": "28",
"name": "krawk", "name": "Krawk",
}, },
Object { Object {
"id": "29", "id": "29",
"name": "kyrii", "name": "Kyrii",
}, },
Object { Object {
"id": "30", "id": "30",
"name": "lenny", "name": "Lenny",
}, },
Object { Object {
"id": "31", "id": "31",
"name": "lupe", "name": "Lupe",
}, },
Object { Object {
"id": "32", "id": "32",
"name": "lutari", "name": "Lutari",
}, },
Object { Object {
"id": "33", "id": "33",
"name": "meerca", "name": "Meerca",
}, },
Object { Object {
"id": "34", "id": "34",
"name": "moehog", "name": "Moehog",
}, },
Object { Object {
"id": "35", "id": "35",
"name": "mynci", "name": "Mynci",
}, },
Object { Object {
"id": "36", "id": "36",
"name": "nimmo", "name": "Nimmo",
}, },
Object { Object {
"id": "37", "id": "37",
"name": "ogrin", "name": "Ogrin",
}, },
Object { Object {
"id": "38", "id": "38",
"name": "peophin", "name": "Peophin",
}, },
Object { Object {
"id": "39", "id": "39",
"name": "poogle", "name": "Poogle",
}, },
Object { Object {
"id": "40", "id": "40",
"name": "pteri", "name": "Pteri",
}, },
Object { Object {
"id": "41", "id": "41",
"name": "quiggle", "name": "Quiggle",
}, },
Object { Object {
"id": "42", "id": "42",
"name": "ruki", "name": "Ruki",
}, },
Object { Object {
"id": "43", "id": "43",
"name": "scorchio", "name": "Scorchio",
}, },
Object { Object {
"id": "44", "id": "44",
"name": "shoyru", "name": "Shoyru",
}, },
Object { Object {
"id": "45", "id": "45",
"name": "skeith", "name": "Skeith",
}, },
Object { Object {
"id": "46", "id": "46",
"name": "techo", "name": "Techo",
}, },
Object { Object {
"id": "47", "id": "47",
"name": "tonu", "name": "Tonu",
}, },
Object { Object {
"id": "48", "id": "48",
"name": "tuskaninny", "name": "Tuskaninny",
}, },
Object { Object {
"id": "49", "id": "49",
"name": "uni", "name": "Uni",
}, },
Object { Object {
"id": "50", "id": "50",
"name": "usul", "name": "Usul",
}, },
Object { Object {
"id": "51", "id": "51",
"name": "wocky", "name": "Wocky",
}, },
Object { Object {
"id": "52", "id": "52",
"name": "xweetok", "name": "Xweetok",
}, },
Object { Object {
"id": "53", "id": "53",
"name": "yurble", "name": "Yurble",
}, },
Object { Object {
"id": "54", "id": "54",
"name": "zafara", "name": "Zafara",
}, },
Object { Object {
"id": "55", "id": "55",
"name": "vandagyre", "name": "Vandagyre",
}, },
], ],
} }
@ -1078,373 +1078,369 @@ describe("Color", () => {
expect(res.data).toMatchInlineSnapshot(` expect(res.data).toMatchInlineSnapshot(`
Object { Object {
"allColors": Array [ "allColors": Array [
Object {
"id": "-1",
"name": "nebula",
},
Object { Object {
"id": "1", "id": "1",
"name": "alien", "name": "Alien",
}, },
Object { Object {
"id": "2", "id": "2",
"name": "apple", "name": "Apple",
}, },
Object { Object {
"id": "3", "id": "3",
"name": "asparagus", "name": "Asparagus",
}, },
Object { Object {
"id": "4", "id": "4",
"name": "aubergine", "name": "Aubergine",
}, },
Object { Object {
"id": "5", "id": "5",
"name": "avocado", "name": "Avocado",
}, },
Object { Object {
"id": "6", "id": "6",
"name": "baby", "name": "Baby",
}, },
Object { Object {
"id": "7", "id": "7",
"name": "biscuit", "name": "Biscuit",
}, },
Object { Object {
"id": "8", "id": "8",
"name": "blue", "name": "Blue",
}, },
Object { Object {
"id": "9", "id": "9",
"name": "blueberry", "name": "Blueberry",
}, },
Object { Object {
"id": "10", "id": "10",
"name": "brown", "name": "Brown",
}, },
Object { Object {
"id": "11", "id": "11",
"name": "camouflage", "name": "Camouflage",
}, },
Object { Object {
"id": "12", "id": "12",
"name": "carrot", "name": "Carrot",
}, },
Object { Object {
"id": "13", "id": "13",
"name": "checkered", "name": "Checkered",
}, },
Object { Object {
"id": "14", "id": "14",
"name": "chocolate", "name": "Chocolate",
}, },
Object { Object {
"id": "15", "id": "15",
"name": "chokato", "name": "Chokato",
}, },
Object { Object {
"id": "16", "id": "16",
"name": "christmas", "name": "Christmas",
}, },
Object { Object {
"id": "17", "id": "17",
"name": "clay", "name": "Clay",
}, },
Object { Object {
"id": "18", "id": "18",
"name": "cloud", "name": "Cloud",
}, },
Object { Object {
"id": "19", "id": "19",
"name": "coconut", "name": "Coconut",
}, },
Object { Object {
"id": "20", "id": "20",
"name": "custard", "name": "Custard",
}, },
Object { Object {
"id": "21", "id": "21",
"name": "darigan", "name": "Darigan",
}, },
Object { Object {
"id": "22", "id": "22",
"name": "desert", "name": "Desert",
}, },
Object { Object {
"id": "23", "id": "23",
"name": "disco", "name": "Disco",
}, },
Object { Object {
"id": "24", "id": "24",
"name": "durian", "name": "Durian",
}, },
Object { Object {
"id": "25", "id": "25",
"name": "electric", "name": "Electric",
}, },
Object { Object {
"id": "26", "id": "26",
"name": "faerie", "name": "Faerie",
}, },
Object { Object {
"id": "27", "id": "27",
"name": "fire", "name": "Fire",
}, },
Object { Object {
"id": "28", "id": "28",
"name": "garlic", "name": "Garlic",
}, },
Object { Object {
"id": "29", "id": "29",
"name": "ghost", "name": "Ghost",
}, },
Object { Object {
"id": "30", "id": "30",
"name": "glowing", "name": "Glowing",
}, },
Object { Object {
"id": "31", "id": "31",
"name": "gold", "name": "Gold",
}, },
Object { Object {
"id": "32", "id": "32",
"name": "gooseberry", "name": "Gooseberry",
}, },
Object { Object {
"id": "33", "id": "33",
"name": "grape", "name": "Grape",
}, },
Object { Object {
"id": "34", "id": "34",
"name": "green", "name": "Green",
}, },
Object { Object {
"id": "35", "id": "35",
"name": "grey", "name": "Grey",
}, },
Object { Object {
"id": "36", "id": "36",
"name": "halloween", "name": "Halloween",
}, },
Object { Object {
"id": "37", "id": "37",
"name": "ice", "name": "Ice",
}, },
Object { Object {
"id": "38", "id": "38",
"name": "invisible", "name": "Invisible",
}, },
Object { Object {
"id": "39", "id": "39",
"name": "island", "name": "Island",
}, },
Object { Object {
"id": "40", "id": "40",
"name": "jelly", "name": "Jelly",
}, },
Object { Object {
"id": "41", "id": "41",
"name": "lemon", "name": "Lemon",
}, },
Object { Object {
"id": "42", "id": "42",
"name": "lime", "name": "Lime",
}, },
Object { Object {
"id": "43", "id": "43",
"name": "mallow", "name": "Mallow",
}, },
Object { Object {
"id": "44", "id": "44",
"name": "maraquan", "name": "Maraquan",
}, },
Object { Object {
"id": "45", "id": "45",
"name": "msp", "name": "Msp",
}, },
Object { Object {
"id": "46", "id": "46",
"name": "mutant", "name": "Mutant",
}, },
Object { Object {
"id": "47", "id": "47",
"name": "orange", "name": "Orange",
}, },
Object { Object {
"id": "48", "id": "48",
"name": "pea", "name": "Pea",
}, },
Object { Object {
"id": "49", "id": "49",
"name": "peach", "name": "Peach",
}, },
Object { Object {
"id": "50", "id": "50",
"name": "pear", "name": "Pear",
}, },
Object { Object {
"id": "51", "id": "51",
"name": "pepper", "name": "Pepper",
}, },
Object { Object {
"id": "52", "id": "52",
"name": "pineapple", "name": "Pineapple",
}, },
Object { Object {
"id": "53", "id": "53",
"name": "pink", "name": "Pink",
}, },
Object { Object {
"id": "54", "id": "54",
"name": "pirate", "name": "Pirate",
}, },
Object { Object {
"id": "55", "id": "55",
"name": "plum", "name": "Plum",
}, },
Object { Object {
"id": "56", "id": "56",
"name": "plushie", "name": "Plushie",
}, },
Object { Object {
"id": "57", "id": "57",
"name": "purple", "name": "Purple",
}, },
Object { Object {
"id": "58", "id": "58",
"name": "quigukiboy", "name": "Quigukiboy",
}, },
Object { Object {
"id": "59", "id": "59",
"name": "quigukigirl", "name": "Quigukigirl",
}, },
Object { Object {
"id": "60", "id": "60",
"name": "rainbow", "name": "Rainbow",
}, },
Object { Object {
"id": "61", "id": "61",
"name": "red", "name": "Red",
}, },
Object { Object {
"id": "62", "id": "62",
"name": "robot", "name": "Robot",
}, },
Object { Object {
"id": "63", "id": "63",
"name": "royalboy", "name": "Royalboy",
}, },
Object { Object {
"id": "64", "id": "64",
"name": "royalgirl", "name": "Royalgirl",
}, },
Object { Object {
"id": "65", "id": "65",
"name": "shadow", "name": "Shadow",
}, },
Object { Object {
"id": "66", "id": "66",
"name": "silver", "name": "Silver",
}, },
Object { Object {
"id": "67", "id": "67",
"name": "sketch", "name": "Sketch",
}, },
Object { Object {
"id": "68", "id": "68",
"name": "skunk", "name": "Skunk",
}, },
Object { Object {
"id": "69", "id": "69",
"name": "snot", "name": "Snot",
}, },
Object { Object {
"id": "70", "id": "70",
"name": "snow", "name": "Snow",
}, },
Object { Object {
"id": "71", "id": "71",
"name": "speckled", "name": "Speckled",
}, },
Object { Object {
"id": "72", "id": "72",
"name": "split", "name": "Split",
}, },
Object { Object {
"id": "73", "id": "73",
"name": "sponge", "name": "Sponge",
}, },
Object { Object {
"id": "74", "id": "74",
"name": "spotted", "name": "Spotted",
}, },
Object { Object {
"id": "75", "id": "75",
"name": "starry", "name": "Starry",
}, },
Object { Object {
"id": "76", "id": "76",
"name": "strawberry", "name": "Strawberry",
}, },
Object { Object {
"id": "77", "id": "77",
"name": "striped", "name": "Striped",
}, },
Object { Object {
"id": "78", "id": "78",
"name": "thornberry", "name": "Thornberry",
}, },
Object { Object {
"id": "79", "id": "79",
"name": "tomato", "name": "Tomato",
}, },
Object { Object {
"id": "80", "id": "80",
"name": "tyrannian", "name": "Tyrannian",
}, },
Object { Object {
"id": "81", "id": "81",
"name": "usuki boy", "name": "Usuki boy",
}, },
Object { Object {
"id": "82", "id": "82",
"name": "usuki girl", "name": "Usuki girl",
}, },
Object { Object {
"id": "83", "id": "83",
"name": "white", "name": "White",
}, },
Object { Object {
"id": "84", "id": "84",
"name": "yellow", "name": "Yellow",
}, },
Object { Object {
"id": "85", "id": "85",
"name": "zombie", "name": "Zombie",
}, },
Object { Object {
"id": "86", "id": "86",
"name": "onion", "name": "Onion",
}, },
Object { Object {
"id": "87", "id": "87",
"name": "magma", "name": "Magma",
}, },
Object { Object {
"id": "88", "id": "88",
"name": "relic", "name": "Relic",
}, },
Object { Object {
"id": "89", "id": "89",
"name": "woodland", "name": "Woodland",
}, },
Object { Object {
"id": "90", "id": "90",
"name": "transparent", "name": "Transparent",
}, },
Object { Object {
"id": "91", "id": "91",
"name": "maractite", "name": "Maractite",
}, },
Object { Object {
"id": "92", "id": "92",
@ -1452,47 +1448,47 @@ describe("Color", () => {
}, },
Object { Object {
"id": "93", "id": "93",
"name": "swamp gas", "name": "Swamp gas",
}, },
Object { Object {
"id": "94", "id": "94",
"name": "water", "name": "Water",
}, },
Object { Object {
"id": "95", "id": "95",
"name": "wraith", "name": "Wraith",
}, },
Object { Object {
"id": "96", "id": "96",
"name": "eventide", "name": "Eventide",
}, },
Object { Object {
"id": "97", "id": "97",
"name": "elderlyboy", "name": "Elderlyboy",
}, },
Object { Object {
"id": "98", "id": "98",
"name": "elderlygirl", "name": "Elderlygirl",
}, },
Object { Object {
"id": "99", "id": "99",
"name": "stealthy", "name": "Stealthy",
}, },
Object { Object {
"id": "100", "id": "100",
"name": "dimensional", "name": "Dimensional",
}, },
Object { Object {
"id": "101", "id": "101",
"name": "agueena", "name": "Agueena",
}, },
Object { Object {
"id": "102", "id": "102",
"name": "pastel", "name": "Pastel",
}, },
Object { Object {
"id": "103", "id": "103",
"name": "ummagine", "name": "Ummagine",
}, },
Object { Object {
"id": "104", "id": "104",
@ -1504,7 +1500,7 @@ describe("Color", () => {
}, },
Object { Object {
"id": "106", "id": "106",
"name": "marble", "name": "Marble",
}, },
Object { Object {
"id": "107", "id": "107",
@ -1536,13 +1532,12 @@ describe("Color", () => {
expect(queryFn.mock.calls).toMatchInlineSnapshot(` expect(queryFn.mock.calls).toMatchInlineSnapshot(`
Array [ Array [
Array [ Array [
"SELECT * FROM colors", "SELECT * FROM colors WHERE prank = 0",
], ],
Array [ Array [
"SELECT * FROM color_translations "SELECT * FROM color_translations
WHERE color_id IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) AND locale = \\"en\\"", WHERE color_id IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) AND locale = \\"en\\"",
Array [ Array [
"-1",
"1", "1",
"2", "2",
"3", "3",

View file

@ -1,7 +1,7 @@
const DataLoader = require("dataloader"); const DataLoader = require("dataloader");
const loadAllColors = (db) => async () => { const loadAllColors = (db) => async () => {
const [rows, _] = await db.execute(`SELECT * FROM colors`); const [rows, _] = await db.execute(`SELECT * FROM colors WHERE prank = 0`);
const entities = rows.map(normalizeRow); const entities = rows.map(normalizeRow);
return entities; return entities;
}; };

5
src/server/util.js Normal file
View file

@ -0,0 +1,5 @@
function capitalize(str) {
return str[0].toUpperCase() + str.slice(1);
}
module.exports = { capitalize };

View file

@ -94,6 +94,10 @@ const outfitStateReducer = (apolloClient) => (baseState, action) => {
switch (action.type) { switch (action.type) {
case "rename": case "rename":
return { ...baseState, name: action.outfitName }; return { ...baseState, name: action.outfitName };
case "changeColor":
return { ...baseState, colorId: action.colorId };
case "changeSpecies":
return { ...baseState, speciesId: action.speciesId };
case "wearItem": case "wearItem":
return produce(baseState, (state) => { return produce(baseState, (state) => {
// A hack to work around https://github.com/immerjs/immer/issues/586 // A hack to work around https://github.com/immerjs/immer/issues/586
@ -143,7 +147,7 @@ const outfitStateReducer = (apolloClient) => (baseState, action) => {
closetedItemIds.delete(itemId); closetedItemIds.delete(itemId);
}); });
default: default:
throw new Error(`unexpected action ${action}`); throw new Error(`unexpected action ${JSON.stringify(action)}`);
} }
}; };