Commit graph

222 commits

Author SHA1 Message Date
f7f6f7b82b Remove useRequireLogin, show logged-out message
There was a bug in the new db auth method where `useRequireLogin` was expecting Auth0 logins to work, so it would get caught in an infinite redirect loop.

Rather than trying to figure out how to make `useRequireLogin` work with the new modal UI, I figured we can just delete it (since we only ended up using it once anyway), and add a little message if you happen to end up on the page while logged out. Easy peasy!
2022-08-17 16:11:40 -07:00
db8fe9f3c2 Logout button for new auth mode
Hey hey, logging out works! The server side of this was easy, but I made a few refactors to support it well on the client, like `useLoginActions` becoming just `useLogout` lol, and updating how the nav menu chooses between buttons vs menu because I wanted `<LogoutButton />` to contain some state.

We also did good Apollo cache stuff to update the page after you log in or out! I think some fields that don't derive from `User`, like `Item.currentUserOwnsThis`, are gonna fail to update until you reload the page but like that's fine idk :p

There's a known bug where logging out on the Your Outfits page turns into an infinite loop situation, because it's trying to do Auth0 stuff but the login keeps failing to have any effect because we're in db mode! I'll fix that next.
2022-08-17 16:05:36 -07:00
2dbfaf1557 Support actual login via db?? :0
Yeah cool the login button seems to. work now? And subsequent requests serve user data correctly based on that, and let you edit stuff.

I also tested the following attacks:
- Using the wrong password indeed fails! lol basic one
- Changing the userId or createdAt fields in the cookie causes the auth token to be rejected for an invalid signature.

Tbh that's all that comes to mind… like, you either attack us by tricking the login itself into giving you a token when it shouldn't, or you attack us by tricking the subsequent requests into accepting a token when it shouldn't. Seems like we're covered? 😳🤞

Still need to add logout, but yeah, this is… looking surprisingly feature-parity with our Auth0 integration already lmao. Maybe it'll be ready to launch sooner than expected?
2022-08-17 15:24:17 -07:00
4d0c48ab7c Login form checks the db, and saves a cookie
Okay so one of the trickiest parts of login is done! 🤞 and now we need to make it actually show up in the UI. (and also pressure-test the security a bit, I've only really checked the happy path!)
2022-08-17 00:58:52 -07:00
ce503ea730 Start building a login form, behind a feature flag
Thinking about longevity, I think I wanna cut Auth0 loose, and just go back to using our own auth.

I had figured at the time that I didn't want to integrate with OpenNeo ID's whole mess, and I didn't want to write a whole new auth system, so Auth0 seemed to make things easier.

But now, it's just kinda a lot to be carrying along an external service as a dependency for login, especially when we've got all the stuff in the database right here. I wanna remove architecture pieces! Get it outta here!

And I'll finally build account creation from the 2020 site while I'm at it, which seemed like it was gonna be a bit of a pain with Auth0 and syncing anyway. (I think at the time I was a bit more optimistic about a full transfer from one system to another, but that's much further off than I realized, and this path will be much better for keeping things in sync.)
2022-08-16 17:34:51 -07:00
7015dc3635 [WIP] Add lint exceptions for <img> tags
There are some places where we use <img> tags where I think it's actually just the right thing to do.

`next/image` is good for image optimization, but I don't think it's worth the proxying for Neopets art images that don't actually always have a higher-res version to begin with.

Idk, maybe the species faces could be a decent choice, but right now we're solving it with `srcSet`, and that's fine. Doesn't seem worth migrating, let's just move on with our lives! 😅

I'm still leaving the lint rule on though, because I think it's a helpful reminder. (I don't think it catches `<Box as="img" />` though, which is a shame, because that would be our natural default in this app!)
2021-11-02 00:55:21 -07:00
405b3ded77 [WIP] Fix app images in Next.js
Yeah, cool, now we use the `next/image` tag, and our images are showing up again!

There's still lint errors for using bare img tags in some places, but I'm not sure I really care…
2021-11-02 00:50:39 -07:00
7fd85e5e2a [WIP] Fix bug loading movies
This was a fun journey! Turns out Next 12 is using a new faster JS compiler called SWC, which had a compiler bug that triggered here!

The incorrect looping behavior caused `libraryUrl` to sometimes be `null` by the time the movie promise completes, because `layer` was set to whatever the `last` layer in the list had been. https://github.com/swc-project/swc/issues/2624

Anyway, turns out this code has been through a few refactors, and the `async` function wrapper is extraneous now! So I've just deleted it and inlined its code. Ta da! lol
2021-11-02 00:11:23 -07:00
299561d1e3 Paginate the user outfits page
My main inspiration for doing this is actually our potentially-huge upcoming Vercel bill lol

From inspecting my Honeycomb dashboard, it looks like the main offender for backend CPU time usage is outfit images. And it looks like they come in big spikes, of lots of low usage and then suddenly 1,000 requests in one minute.

My suspicion is that this is from users with many saved outfits loading their outfit page, which previously would show all of them at once.

We do have `loading="lazy"` set, but not all browsers support that yet, and I've had trouble pinning down the exact behavior anyway!

Anyway, paginating makes for a better experience for those huge-list users anyway. We've been meaning to do it, so here we go!

My hope is that this drastically decreases backend CPU hours immediately 🤞 If not, we'll need to investigate in more detail where these outfit image requests are actually coming from!

Note that I added the pagination to the existing `outfits` GraphQL endpoint, rather than creating a new one. I felt comfortable doing this because it requires login anyway, so I'm confident that other clients aren't using it; and because, while this kind of thing often creates a risk of problems with frontend and backend code getting out of sync, I think someone running old frontend code will just see only their first 30 outfits (but no pagination toolbar), and get confused and refresh the page, at which point they'll see all of them. (And I actually _prefer_ that slightly confusing UX, to avoid getting more giant spikes of outfit image requests, lol :p)
2021-11-01 19:33:40 -07:00
33740af5ee Stop passing null value in SpeciesColorPicker
This is a minor change to clear a console warning, and make intended behavior clearer! You're not supposed to pass `null` as a select value, because it's ambiguous about whether you're looking for the first option or to make this an "uncontrolled component".

Here, I now provide a fallback value, which is an explicit string for the placeholder option. I made the string very explicit, to aid in debugging if it somehow leaks out from where it's supposed to be! (But I also added gating in the `onChange` event, just to be extra sure.)
2021-11-01 16:19:17 -07:00
6ce0f59894 Remove stray onChangeHasAnimations prop
This isn't used, so it was getting passed down to the underlying DOM element and triggering a console warning! Remove it.
2021-11-01 16:09:09 -07:00
086ada40f1 Polyfill Promise.any
Resolves Sentry issue IMPRESS-2020-7T
2021-11-01 16:01:05 -07:00
0a5d8f1f74 Add search toolbar to item page
Trickier than it looks, to get the shared UI across pages without disrupting things like focus!
2021-09-30 20:04:50 -07:00
6efd542f49 Wire up the Remove button for item lists
Did some stuff in here for parsing the default list ID too. We skipped that when making the new list index page, but now maybe you could reasonably link to the default list? 🤔 not sure it's a huge deal though
2021-09-30 19:26:09 -07:00
64db3dd1b7 [WIP] UI for item remove button
It's code for a remove button in item lists! When you click it, you see a "TODO" alert.

Not shipping this change until it's wired up!
2021-09-30 18:12:31 -07:00
2bd573690e Add underline to item list description links
Oops, right, a bit of a CSS oversight! Added now!
2021-09-06 14:08:43 -07:00
315744b4f7 Allow pre tag in lists
I noticed someone using `<pre>` for styling, and thought, sure why not!

I haven't added support for the code block indent thing, and I think that's probably fine?
2021-09-06 14:07:05 -07:00
cc9cd5ef28 Rewrite old closet links to use new syntax
A lot of DTI lists use old URLs to anchor-link between lists! Here, we rewrite those URLs to match what DTI 2020 expects, so that they actually correctly jump you across the page and aren't filtered out!
2021-09-06 14:05:36 -07:00
9a68bd1355 Use standard image URLs on Your Outfits page
The old URLs were glitchy because we weren't escaping the `layerUrls` param… and this will let us take better advantage of the same shared caching as other stuff!
2021-09-03 15:37:38 -07:00
781034a568 Oops, don't crash if animation image fails
Whoops, `Promise.race` isn't quite what I wanted here. This meant that, if the image promise _fails_ before the movie _succeeds_, the outfit would crash even though it doesn't need to. (And this was happening too often, due to a bug in /api/assetImage!)

Now, we accept whichever _successful_ result loads first, or reject if they _both_ fail.

I tested this by having /api/assetImage always throw, and confirmed that it crashed the outfit before this change, and no longer does after this change!
2021-09-02 19:09:27 -07:00
f9b4852da1 Handle OFFICIAL_SWF_IS_INCORRECT for pet layers
Marking this glitch on the Yellow Lutari head today, and oops there isn't UI copy for it yet! Added!

Also fixed some bugs in here, like old text about the position of the pose picker relative to the glitch badge, and I noticed while debugging that `layerUsesHTML5` returns a truthy string instead of a boolean which seems error-prone!
2021-08-14 16:46:05 -07:00
2a5ecb688a Improve homepage modeling loading state
Add a skeleton stripe for the modeling data! Won't show up in most cases because we load fast, but it helps things a lot when it does. (Also, will we keep loading fast with the cache changes on this query?)
2021-07-11 18:16:57 -07:00
f2259d6487 Add modeling info to homepage
To make this fast, I had to tweak the GraphQL resolver a bit to run a filtered version of the query for `newestItems` instead of scanning the full database! But yeah, looking good!

I think I'm gonna want to swap out "Fully modeled" for some insight about who it fits
2021-07-11 18:09:29 -07:00
a19c2facbf Detect more animated items
Okay cool, I noticed that "A Warm Winters Night Background" sometimes animates when other things are playing, but the animations aren't _detected_. (Huh, I actually thought we just didn't schedule ticks in that case? But maybe I'm missing something.)

Anyway, some movies don't use the built-in frames construct to animate, and instead use tweens that hook into the timeline and mutate the stage. Okay! Now we detect those.

This _did_ enable the Play/Pause button on some items that don't actually animate in practice, like the "#1 Fan Room Background", which seems to have an animated string of lights in the corner that got layered incorrectly. Maybe we should add a new glitch type, to flag movies that don't actually animate?
2021-07-02 15:40:04 -07:00
dcfcbf9ff7 /api/assetImage can render movies!
Yeah wow huh, that was much less painful than I expected!

I haven't tested this very rigorously, literally just the Floating Negg Faerie Doll: https://images.neopets.com/cp/items/data/000/000/005/5735_a8feda8d08/5735.js
2021-07-02 15:19:11 -07:00
4e31a4bec7 /internal/assetImage can render movies
This is a new page, that I'm gonna use a headless browser to navigate to and screenshot the asset!
2021-07-02 14:36:08 -07:00
2f0d145e49 Move error toast out of OutfitMovieLayer
Doing this for two reasons! One is that I want the movie layer component to be a bit thinner in general - I think we might even want to move the fallback image logic out, too.

The second is that I want the onError for something else soon!
2021-07-02 14:35:27 -07:00
f5e5f16f87 Improve movie cancels and error handling
Oops, my inbox was getting full of uncaught promise rejections of `loadImage`!

I'm pretty sure they're caused when multiple images in a movie fail to load (e.g. network problems), but we fail to cancel them. So, the first failure would be caught as a part of `Promise.all` in `loadMovieLibrary`, but then subsequent failures wouldn't be caught by anything, and would propagate up to the console and to Sentry as uncaught errors.

In this change, we make a number of improvements to cancellation. The most relevant change for this bug is that `loadMovieLibrary` will now automatically cancel all resource promises when it throws an error! But this improved robustness also enabled us to finally offer a simple `cancel()` method on movie library promises, which we now available ourselves of at call sites, too.
2021-06-26 12:04:40 -07:00
0bffaec989 Try moving the glitch badges to the top
Experiment! Let's see if them being more prominent like this is helpful or annoying 😅

I think this is clunkier in the HTML5 Green Happy Path, but worth it for bringing attention in the error cases.

But I feel like we might tweak this over time!
2021-06-24 20:05:31 -07:00
47c40eaf03 Keep prev/next enabled while pages load
Right, cool, yes, this is the thing about partial data; you need to define the loading condition as "relevant data is missing, _and_ loading is still happening".
2021-06-21 13:50:49 -07:00
d025f2ba7a Navigate item search by page number
The page number is a dropdown now! Wowie!
2021-06-21 10:54:31 -07:00
7d1872920c Add page numbers to item search
I'm gonna make this a bit more powerful later, but just for now, the text "Page 1 of 27" shows up!

I also don't like that the page number has to blink out while we load the new stuff; there are multiple solutions, but tbh I think the Apollo Cache should be the one to handle this, and that we can do it by refactoring the query structure a bit!
2021-06-21 10:21:25 -07:00
56c91e900a Better error handling when preloading layers
I'm seeing uncaught promise rejections in `loadImage`? It's hard to know exactly where it's actually coming from, those _should_ be caught?

My guess is that it's coming from canceled images, which are throwing errors even after loading? I don't totally understand how, because looking back, I don't think the `cancel` method was actually called???

Anyway, I fixed it so cancel actually _is_ called, and that we don't throw errors when the canceled image _correctly_ fails to load.

This should be more robust either way, but hopefully it also stops the flow of errors?
2021-06-21 09:34:05 -07:00
7a8c5068a7 Fade from image -> movie, instead of harsh change
We put it on top, then fade it out!
2021-06-20 12:21:11 -07:00
e2aeb90b4b Oops, fix loading state bug on homepage!
Right, when there are zero layers, we shouldn't say we're loading!

This is a consequence of the HACK below. If we didn't short-circuit the effect when length == 0, then we would go through and successfully load 0 layers.
2021-06-20 12:04:07 -07:00
6652e66af1 Show image preview while movie loads
Movies often have a lot of assets, which are more likely to be cache misses, and take script time to render! So the time until the user sees something is often huge.

Here, we start loading our PNG image at the same time. This is a filesize loading increase, but even in slow connections, it's generally worth it as a _sharp_ improvement in time until you get to see something!

One noteworthy UI weakness here is that we don't show _any_ loading indicator while the image is visible and the movie is still loading. This makes sense from a practical standpoint, but could be a problem when a movie takes a particularly long amount of time. I also want to be cognizant of whether the blink-of-content ever gets annoying! (We could make it fade out 🤔)
2021-06-20 11:54:30 -07:00
92001d514a Refactor crossOrigin handling for image loading
In my last change, I didn't try to change the APIs too much, and kept the concept of `crossOrigin` running through `getBestImageUrlForLayer`.

Now, I've moved the `safeImageUrl` call _outside_ `getBestImageUrlForLayer`, by putting it at the call site: We now call `safeImageUrl` from `loadImage` (which needs to know the `crossOrigin` flag anyway!), and at the `img` tag call site.

This simplifies all of the call sites a lot, I think!
2021-06-20 10:54:03 -07:00
c2535f811f Remove proxy for most images
I've noticed that our Fastly proxy adds a surprising amount of latency on cache misses (500-1000ms). And, while our overall hit ratio of 80% is pretty good, most misses happen at inopportune times, like loading items from search.

But now that the Neopets CDN supports HTTPS, we can safely switch back to theirs for *most* image loads. (Some features, like downloads and movies, still require CORS headers, which our proxy is still reponsible for adding.)

This forgoes some minor performance wins (like the Download button now requires separate network requests), and some potential filesize reduction opportunities (like Fastly's auto-gzip which we're today using for SVGs, and eventually using their Image Optimizer for assets), to decrease latency. We could still potentially do something more powerful for low-power connections someday… but for now, with the cache miss latency being *so* heavy, this seems like the clear win for almost certainly *all* users today.
2021-06-20 10:36:41 -07:00
eace28839e Highlight trade matches with pretty shadow
This makes scanning the lists WAY easier imo!
2021-06-19 11:43:51 -07:00
f20c68ea81 Add description to list page
Pulled MarkdownAndSafeHTML into a shared component, and use it on the single list page now too!

I also simplified some of the logic for the item list, because I figure we'll have to give the trade matching stuff its own pass, y'know?
2021-06-18 17:26:21 -07:00
6ae22d171b Fix previews with large source images
Oops, okay, I guess I didn't test the new preview centering stuff with 1200x1200 images, like the Usul's Damask Markings.

Now, I apply a max size to the whole-ass container, and make the parent responsible for centering it.
2021-06-17 15:37:01 -07:00
75ceeba6e2 Bundle CreateJS, instead of loading async
So I finally started looking into the race condition that makes item previews sometimes fail to load, and as expected, it was that we were trying to load the movie before CreateJS had necessarily loaded. Usually the timing worked out, esp after a reload, but not under certain circumstances!

Anyway, I've been wanting for a while to just bundle them instead. That'll help us more eagerly load them when we need them, and not depend on external CDNs, and remove a bunch of loading state!

So yeah, I had to learn how the `easeljs` and `tweenjs` NPM packages did their bundling, and how to use `imports-loader` to let them just register straight onto `window`! But we got there and it's pretty nice tbh!
2021-06-16 18:00:25 -07:00
bb5ec56752 Pause animation when FPS gets too low
Woof, the "Swirl of Power Effect" item tanks my CPU waaay too much

(I bet it's those 7000x7000 PNGs lolol 😬)

Anyway, before thinking about optimizing specific issues, I'm just adding this emergency switch: if we detect FPS < 2 on any layer, we just pause the whole outfit, until the user decides to unpause.
2021-06-16 16:26:24 -07:00
307ab932c8 Add FPS logging to OutfitMovieLayer
This is a precursor to adding an emergency brake if the FPS gets too low lol
2021-06-16 16:06:34 -07:00
25376a8fa8 Register images, to fix movies like Swirl of Power
Oh hey, turns out I was missing a step in movie clip stuff! Images aren't just for sprite sheets, but also sometimes they just want the raw images!

Here, we register them, uwu

Items like "Swirl of Power Effect" and probably others work correctly now!

That said, Swirl of Power takes WAY too much CPU lmao, I want to maybe add some kind of automatic kill switch lol
2021-06-16 15:49:56 -07:00
cf30b25be0 First draft of UserItemListPage
A lot is missing! No descriptions, no support for the "Not in a list" case, no scroll performance windowing, no editing!

But it's a start :3
2021-06-12 04:45:23 -07:00
eaa4fbb575 Improve item page perf by caching valids in client
Okay, so getting the initial render down time for these faces is annoying, though I might come back to it…

But actually, the _worst_ part isn't the _initial_ render, which just kinda gets processed as part of the page navigation, right?

The _worst_ part is that we render it slowly _twice_: once on page load, as we send the `useAllValidPetPoses` fetch request; and then again when the fetch request ~instantly comes back from the network cache.

The fact that this requires a double-render, instead of just rendering with the cached valids data in the first place (like how our GraphQL client does), causes a second and highly-visible render of a slow-to-render UI!

So, here we update `useAllValidPetPoses` to cache its response in JS memory, similar in principle to how Apollo Client does. That way, we can return the valids instantly on the first render, if you already loaded them from the homepage or the wardrobe page or another item page!
2021-06-11 07:37:49 -07:00
07bf555a02 Oops, fix a perf regression in Hi-Res Mode!
Ah oops, because I forgot to set `hiResMode` here in the image preloader, we would preload the PNG, and _then_ load the SVG separately.

This doubled the effective image loading time in Hi-Res Mode!

Now, the image preloader respects hi-res mode, and will preload the SVG in the SVG case, and the PNG in the PNG case.
2021-06-11 05:52:53 -07:00
bed525d3ff Add hi-res mode setting, default off
We're just having too many glitchy SVGs for my taste, esp since TNT seems to just be using PNGs for now?

This change defaults us to using PNGs for users by default, with the option to use SVGs as a new "hi-res mode" setting.

This is our first ever setting, wow!

I'm also envisioning that like, if we get Fastly Image Optimizer set up, this could be a way to tune the quality of the incoming images.

We could also consider a setting to turn off animations altogether—like, just download the PNG instead of the movie, whereas right now we download the movie on the assumption that you might play it at any time.
2021-06-08 08:27:45 -07:00
a0be9942fb Add extra flair to trade matches
I refactor the hide-badge thing into 3 "trade matching modes". Then, the logic for whether to hide specific badges moves into the component, and we use that same flag to decide whether to show the big word "match"!
2021-06-08 01:23:31 -07:00