From be816d89c97ea7618c55394706b106c79ee0fb6e Mon Sep 17 00:00:00 2001 From: Matchu Date: Wed, 7 Apr 2021 16:48:41 -0700 Subject: [PATCH 1/7] Waka item page UI! --- src/app/ItemPage.js | 1 + src/app/ItemPageLayout.js | 127 +++++++++++++++++++++++++++++++------- src/app/ItemTradesPage.js | 1 + 3 files changed, 107 insertions(+), 22 deletions(-) diff --git a/src/app/ItemPage.js b/src/app/ItemPage.js index 6b4c165..7384e12 100644 --- a/src/app/ItemPage.js +++ b/src/app/ItemPage.js @@ -74,6 +74,7 @@ export function ItemPageContent({ itemId, isEmbedded }) { thumbnailUrl description createdAt + wakaValueText # For Support users. rarityIndex diff --git a/src/app/ItemPageLayout.js b/src/app/ItemPageLayout.js index 9caad8c..d8c9ee2 100644 --- a/src/app/ItemPageLayout.js +++ b/src/app/ItemPageLayout.js @@ -5,6 +5,7 @@ import { Flex, Popover, PopoverArrow, + PopoverBody, PopoverContent, PopoverTrigger, Portal, @@ -12,10 +13,15 @@ import { Skeleton, Spinner, Tooltip, + useBreakpointValue, useToast, VStack, } from "@chakra-ui/react"; -import { ExternalLinkIcon, ChevronRightIcon } from "@chakra-ui/icons"; +import { + ExternalLinkIcon, + ChevronRightIcon, + QuestionIcon, +} from "@chakra-ui/icons"; import { gql, useMutation } from "@apollo/client"; import { @@ -150,6 +156,42 @@ function ItemPageBadges({ item, isEmbedded }) { Jellyneo + {item.isNc && ( + + {item.wakaValueText && ( + <> + {/* For hover-y devices, use a hover popover over the badge. */} + + + + Waka: {item.wakaValueText} + + + + {/* For touch-y devices, use a tappable help icon. */} + + + Waka: {item.wakaValueText} + + + + + + + + + )} + + )} {!item?.isNc && !item?.isPb && ( ; } -function LinkBadge({ children, href, isEmbedded }) { - return ( - - {children} - { - // We also change the icon to signal whether this will launch in a new - // window or not! - isEmbedded ? : - } - - ); -} +const LinkBadge = React.forwardRef( + ({ children, href, isEmbedded, ...props }, ref) => { + return ( + + {children} + { + // We also change the icon to signal whether this will launch in a new + // window or not! + isEmbedded ? ( + + ) : ( + + ) + } + + ); + } +); const fullDateFormatter = new Intl.DateTimeFormat("en-US", { dateStyle: "long", @@ -380,4 +431,36 @@ function ShortTimestamp({ when }) { ); } +function WakaPopover({ children, ...props }) { + const placement = useBreakpointValue({ base: "bottom", md: "right" }); + + return ( + + {children} + + + + +

+ Waka is a community resource that tracks the approximate value of + NC items, based on real-world trades. +

+ +

+ Other factors, like rarity and popularity, can affect the trade + economy too—and it can change quickly! +

+ +

+ Be sure to take all factors into account for your trades! And + consider asking for a "value check" on the Neoboards if you're not + sure. +

+
+
+
+
+ ); +} + export default ItemPageLayout; diff --git a/src/app/ItemTradesPage.js b/src/app/ItemTradesPage.js index 75c4e5c..5120f98 100644 --- a/src/app/ItemTradesPage.js +++ b/src/app/ItemTradesPage.js @@ -102,6 +102,7 @@ function ItemTradesPage({ thumbnailUrl description createdAt + wakaValueText } } `, From 61e7a38b33b425bba3af969a60116e7a0cf61dbc Mon Sep 17 00:00:00 2001 From: Matchu Date: Wed, 7 Apr 2021 17:25:58 -0700 Subject: [PATCH 2/7] Normalize names for Waka, and log mismatches By printing out this logging data, of item names we have that Waka doesn't, vs item names Waka has that we don't, I was able to solve a lot of them with new code in `normalizeItemName`! Here's the mismatches that are left at time of writing: ``` [Item: Y, Waka: N] No Waka value for NC DTI item "goldenlulumedallion" (43034) [Item: Y, Waka: N] No Waka value for NC DTI item "faelliebirthdaybagsurprise" (51350) [Item: Y, Waka: N] No Waka value for NC DTI item "neopets11thbirthdaycommemorativemysterycapsule" (53448) [Item: Y, Waka: N] No Waka value for NC DTI item "dyeworksblue:iscawig-blue" (70896) [Item: Y, Waka: N] No Waka value for NC DTI item "mysteriousdoorwithlocks" (75601) [Item: Y, Waka: N] No Waka value for NC DTI item "grapefruitnecklace" (77779) [Item: Y, Waka: N] No Waka value for NC DTI item "discofeverbackground" (79250) [Item: Y, Waka: N] No Waka value for NC DTI item "featherflaredshoes" (80047) [Item: Y, Waka: N] No Waka value for NC DTI item "dyeworksredradioactivemutantmarkings" (80441) [Item: N, Waka: Y] No NC DTI data for Waka item "7thbirthdaycakeslice#1" [Item: N, Waka: Y] No NC DTI data for Waka item "7thbirthdaycakeslice#2" [Item: N, Waka: Y] No NC DTI data for Waka item "7thbirthdaycakeslice#3" [Item: N, Waka: Y] No NC DTI data for Waka item "8thbirthdayrainbowcupcake" [Item: N, Waka: Y] No NC DTI data for Waka item "8thbirthdaysparklercupcake" [Item: N, Waka: Y] No NC DTI data for Waka item "8thbirthdaytiedwithabowcupcake" [Item: N, Waka: Y] No NC DTI data for Waka item "babyspringdress" [Item: N, Waka: Y] No NC DTI data for Waka item "butterflydress(fromfaeriefestivalevent)" [Item: N, Waka: Y] No NC DTI data for Waka item "discofever" [Item: N, Waka: Y] No NC DTI data for Waka item "dyeworksblue:iscawig" [Item: N, Waka: Y] No NC DTI data for Waka item "dyeworksred:radioactivemutantmarkings" [Item: N, Waka: Y] No NC DTI data for Waka item "featherflairedshoes" [Item: N, Waka: Y] No NC DTI data for Waka item "festivebooktree" [Item: N, Waka: Y] No NC DTI data for Waka item "floralblackcardigan" [Item: N, Waka: Y] No NC DTI data for Waka item "grapefruitneckace" [Item: N, Waka: Y] No NC DTI data for Waka item "mysteriousdoorwithlocksbackground" [Item: N, Waka: Y] No NC DTI data for Waka item "valiantchampionwings" [Item: N, Waka: Y] No NC DTI data for Waka item "waxcrayonwig" [Item: N, Waka: Y] No NC DTI data for Waka item "youngsophiesdress" ``` --- api/allWakaValues.js | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/api/allWakaValues.js b/api/allWakaValues.js index 5cb9f15..1c50b04 100644 --- a/api/allWakaValues.js +++ b/api/allWakaValues.js @@ -30,6 +30,23 @@ async function handle(req, res) { for (const { name, id } of allNcItemNamesAndIds) { if (name in itemValuesByName) { itemValues[id] = itemValuesByName[name]; + } else { + console.warn( + `[Item: Y, Waka: N] No Waka value for NC DTI item ${JSON.stringify( + name + )} (${id})` + ); + } + } + + const allNcItemNames = new Set(allNcItemNamesAndIds.map(({ name }) => name)); + for (const name of Object.keys(itemValuesByName)) { + if (!allNcItemNames.has(name)) { + console.warn( + `[Item: N, Waka: Y] No NC DTI data for Waka item ${JSON.stringify( + name + )}` + ); } } @@ -56,7 +73,7 @@ async function loadAllNcItemNamesAndIds() { AND item_translations.locale = "en" `); - return rows; + return rows.map(({ id, name }) => ({ id, name: normalizeItemName(name) })); } async function loadWakaValuesByName() { @@ -96,12 +113,27 @@ async function loadWakaValuesByName() { // That's why we set `""` as the default `value`. const itemValuesByName = {}; for (const [itemName, value = ""] of rows) { - itemValuesByName[itemName] = { value }; + const normalizedItemName = normalizeItemName(itemName); + itemValuesByName[normalizedItemName] = { value }; } return itemValuesByName; } +function normalizeItemName(name) { + return ( + name + // Remove all spaces, they're a common source of inconsistency + .replace(/\s+/g, "") + // Lower case, because capitalization is another common source + .toLowerCase() + // Remove diacritics: https://stackoverflow.com/a/37511463/107415 + // Waka has some stray ones in item names, not sure why! + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") + ); +} + export default async (req, res) => { beeline.withTrace({ name: "allWakaValues" }, () => handle(req, res)); }; From 2b93e5cca79c5222c715dec459003bb87e0732be Mon Sep 17 00:00:00 2001 From: Matchu Date: Wed, 7 Apr 2021 17:37:38 -0700 Subject: [PATCH 3/7] Waka tooltip copy edits --- src/app/ItemPageLayout.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/app/ItemPageLayout.js b/src/app/ItemPageLayout.js index d8c9ee2..a8383f6 100644 --- a/src/app/ItemPageLayout.js +++ b/src/app/ItemPageLayout.js @@ -432,10 +432,8 @@ function ShortTimestamp({ when }) { } function WakaPopover({ children, ...props }) { - const placement = useBreakpointValue({ base: "bottom", md: "right" }); - return ( - + {children} @@ -447,14 +445,15 @@ function WakaPopover({ children, ...props }) {

- Other factors, like rarity and popularity, can affect the trade - economy too—and it can change quickly! + It's a super helpful starting point, but it's not the only factor! + Rarity and popularity can affect trade values too, and the trade + economy can change quickly.

- Be sure to take all factors into account for your trades! And - consider asking for a "value check" on the Neoboards if you're not - sure. + Be sure to take all factors into account for your trades, rather + than sticking to just this number! And consider asking for a + "value check" on the Neoboards if you're not sure.

From 45cf9a6f1ffd06fa6220f32044dc909097e3212b Mon Sep 17 00:00:00 2001 From: Matchu Date: Wed, 7 Apr 2021 20:41:53 -0700 Subject: [PATCH 4/7] Use the new Waka item ID field This will help us disambiguate items like Butterfly Dress with a non-unique name, and also some where the real item name is glitchy so using it as a key is not wise lol --- api/allWakaValues.js | 52 ++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/api/allWakaValues.js b/api/allWakaValues.js index 1c50b04..06e1563 100644 --- a/api/allWakaValues.js +++ b/api/allWakaValues.js @@ -14,9 +14,9 @@ import connectToDb from "../src/server/db"; async function handle(req, res) { const allNcItemNamesAndIdsPromise = loadAllNcItemNamesAndIds(); - let itemValuesByName; + let itemValuesByIdOrName; try { - itemValuesByName = await loadWakaValuesByName(); + itemValuesByIdOrName = await loadWakaValuesByIdOrName(); } catch (e) { console.error(e); res.setHeader("Content-Type", "text/plain"); @@ -28,25 +28,10 @@ async function handle(req, res) { const allNcItemNamesAndIds = await allNcItemNamesAndIdsPromise; const itemValues = {}; for (const { name, id } of allNcItemNamesAndIds) { - if (name in itemValuesByName) { - itemValues[id] = itemValuesByName[name]; - } else { - console.warn( - `[Item: Y, Waka: N] No Waka value for NC DTI item ${JSON.stringify( - name - )} (${id})` - ); - } - } - - const allNcItemNames = new Set(allNcItemNamesAndIds.map(({ name }) => name)); - for (const name of Object.keys(itemValuesByName)) { - if (!allNcItemNames.has(name)) { - console.warn( - `[Item: N, Waka: Y] No NC DTI data for Waka item ${JSON.stringify( - name - )}` - ); + if (id in itemValuesByIdOrName) { + itemValues[id] = itemValuesByIdOrName[id]; + } else if (name in itemValuesByIdOrName) { + itemValues[id] = itemValuesByIdOrName[name]; } } @@ -76,7 +61,12 @@ async function loadAllNcItemNamesAndIds() { return rows.map(({ id, name }) => ({ id, name: normalizeItemName(name) })); } -async function loadWakaValuesByName() { +/** + * Load all Waka values from the spreadsheet. Returns an object keyed by ID or + * name - that is, if the item ID is provided in the sheet, we use that as the + * key; or if not, we use the name as the key. + */ +async function loadWakaValuesByIdOrName() { if (!process.env["GOOGLE_API_KEY"]) { throw new Error(`GOOGLE_API_KEY environment variable must be provided`); } @@ -109,15 +99,21 @@ async function loadWakaValuesByName() { // the spreadsheet columns that we don't use on DTI, like Notes. // // NOTE: The Sheets API only returns the first non-empty cells of the row. - // So, when there's no value specified, it only returns one cell. - // That's why we set `""` as the default `value`. - const itemValuesByName = {}; - for (const [itemName, value = ""] of rows) { + // That's why we set `""` as the defaults, in case the value/notes/etc + // aren't provided. + const itemValuesByIdOrName = {}; + for (const [ + itemName, + value = "", + notes = "", + marks = "", + itemId = "", + ] of rows) { const normalizedItemName = normalizeItemName(itemName); - itemValuesByName[normalizedItemName] = { value }; + itemValuesByIdOrName[itemId || normalizedItemName] = { value }; } - return itemValuesByName; + return itemValuesByIdOrName; } function normalizeItemName(name) { From a32bc34171f5629f403eefc3a21b47beca474c47 Mon Sep 17 00:00:00 2001 From: Matchu Date: Wed, 7 Apr 2021 21:46:03 -0700 Subject: [PATCH 5/7] Tweak Waka tooltip copy --- src/app/ItemPageLayout.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/app/ItemPageLayout.js b/src/app/ItemPageLayout.js index a8383f6..3a107be 100644 --- a/src/app/ItemPageLayout.js +++ b/src/app/ItemPageLayout.js @@ -445,15 +445,10 @@ function WakaPopover({ children, ...props }) {

- It's a super helpful starting point, but it's not the only factor! - Rarity and popularity can affect trade values too, and the trade - economy can change quickly. -

- -

- Be sure to take all factors into account for your trades, rather - than sticking to just this number! And consider asking for a - "value check" on the Neoboards if you're not sure. + The Waka Team aims to maintain the accuracy of the guide as fully + as possible, but please remember values are often changing and + with certain difficult-to-find or popular items it doesn't hurt to + make a value check!

From 089654e092638182aa45b11c9b437c4257c2a28e Mon Sep 17 00:00:00 2001 From: Matchu Date: Wed, 7 Apr 2021 22:02:10 -0700 Subject: [PATCH 6/7] Use VERCEL_URL for waka loader if given Oh right, our preview deploy was loading the prod allWakaValues data! Now it uses the VERCEL_URL env variable to request from the current deployment instead. --- src/server/loaders.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/server/loaders.js b/src/server/loaders.js index 0f1b734..88a811f 100644 --- a/src/server/loaders.js +++ b/src/server/loaders.js @@ -608,10 +608,11 @@ const buildItemWakaValueLoader = () => // API would, and avoid putting pressure on our Google Sheets API quotas. // (Some kind of internal memcache or process-level cache would be a more // idiomatic solution in a monolith server environment!) - const url = - process.env.NODE_ENV === "production" - ? "https://impress-2020.openneo.net/api/allWakaValues" - : "http://localhost:3000/api/allWakaValues"; + const url = process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}/api/allWakaValues` + : process.env.NODE_ENV === "production" + ? "https://impress-2020.openneo.net/api/allWakaValues" + : "http://localhost:3000/api/allWakaValues"; const res = await fetch(url); if (!res.ok) { throw new Error( From b92b5696b4651a7a95d3b63a5e8f79eb8af56407 Mon Sep 17 00:00:00 2001 From: Matchu Date: Wed, 7 Apr 2021 22:12:03 -0700 Subject: [PATCH 7/7] Remove unused import --- src/app/ItemPageLayout.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/ItemPageLayout.js b/src/app/ItemPageLayout.js index 3a107be..c0f1068 100644 --- a/src/app/ItemPageLayout.js +++ b/src/app/ItemPageLayout.js @@ -13,7 +13,6 @@ import { Skeleton, Spinner, Tooltip, - useBreakpointValue, useToast, VStack, } from "@chakra-ui/react";