feat: set up Apollo Client in the frontend #80
+1,419
−8
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
The frontend can call the GraphQL API with Apollo Client, with a cache for the search and the token handling from the login. The pages are not changed. Closes #75.
Depends on the login (#71) and the server (#65) for the tokens and the API, but it does not contain their code, so it targets
devand can be merged first or last. Without a running backend the app starts as before.What's in it
src/lib/apollo/with the client, the cache, the authorization link, the session, plain login/refresh/logout requests and the error messages.src/main.tsxwraps the app inApolloProvider.searchCatalogis one list per search, filter and sort (not perfirstorafter). "Load more" adds the next page after the others, a page that arrives twice adds nothing, the first page again starts over, andtotalCountfrom the first page is kept. Elements and vaults are stored once.possibleTypesfor theCatalogIteminterface.Authorization: Bearer <access token>. OnUNAUTHENTICATEDit refreshes once and repeats the request once.Login,RefreshSessionandLogoutnever start a refresh.localStorage(works without storage too). Several refreshes at the same moment share one request, and tabs follow each other throughnavigator.locks, with the token read inside the lock. A refresh token that the server refuses ends the login, a network error keeps it.login(),logout()andrestoreSession()are exported; there is no Google login button yet.describeError()gives a code, a message for the user and whether to try again./graphqland/imagesgo to port 3001 in development, so there is no CORS to set up.VITE_API_URL(default/graphql) sets another address.docs/API.md,docs/AI_USAGE.md.Checked against the running backend
fetchMorefor the next page (5 + 5 gives 10 in the cache withtotalCountkept), a search that is too long (BAD_USER_INPUTwith the server's message), and a protected query without a login (UNAUTHENTICATED). Through Vite:POST /graphqlandGET /images/UB/UB-1.101-a.webpreturn 200.afteris answered from the cache, becauseafteris not part of the key. The next page must be loaded withfetchMore. This is written in the README anddocs/API.md.Testing
tsc -b,npm run buildand the tests pass: 50 passed, 23 skipped (the database tests, no database here). 28 new tests: session (storage, no storage, refresh, refused, network error, sharing one request, the lock), link (header, one refresh and one repeat, three requests at once refresh once, refused refresh, no endless loop, no refresh for the login operations), cache (pages, duplicates, start over, separate lists, one stored element, the interface) and error messages.🤖 Generated with Claude Code