feat(frontend): connect the frontend to the real GraphQL API #62
+802
−193
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.
Closes #58
What and why
Connects the frontend to the real GraphQL API instead of filtering
frontend/src/mocks/recipes.tsin the browser, so search, category/ratingfiltering, sorting and paging run server-side over the whole dataset (the
assignment's explicit requirement).
frontend/src/graphql/).Its normalized cache covers the assignment's state-management requirement
for server data; the recently-merged Zustand store (Fix/59 fridge recipe matches #60) separately
covers local Fridge UI state - the two don't overlap.
/project2/graphqlto the backend, mirroringdeploy/apache/project2.conf's production proxy, and honorsVITE_GRAPHQL_URLthe same wayIngredientSearch.tsxalready does.recipesquery; a "Loadmore" button pages through
fetchMore, using the server'stotalCountand
hasMore; loading and error states are handled; thearia-liveresult count reads the server's total.
recipe(id)instead of a mocklookup.
RecipeFilter'scategory
<option>values were lowercase ("beef"), but the server doesa case-sensitive array-contains match against Title Case data
(
"Beef") - every category filter would have silently returned zeroresults once connected. Also fixed
"Soup"→"Soup/Stew", the onlyname that actually exists in the dataset.
frontend/src/mocks/recipes.tsremoved; nothing depends on it anymore.Rebased on top of #60 (merged during this PR's development), which
overlapped heavily in the same files (HomePage, recipeFilters, vite.config,
Apache config, CLAUDE.md/README). Resolved conflicts so both land together:
#60's any-ingredient-matches semantics, "Back to Fridge" link and Fridge
persistence are preserved as-is; my Apollo wiring sits underneath them.
HomePage.test.tsxnow covers both concerns (GraphQL loading/error/pagingand the Fridge integration scenarios from #60), and
FridgePage.test.tsx'sone test that mounts the full
<App>now wraps it inMockedProvider.Known gap, tracked separately: "My Fridge" still matches ingredients
client-side against whatever page the server already returned - the
backend has no ingredient filter on
recipes. #60 fixed the matchsemantics (any vs. all) within that constraint; true whole-dataset
ingredient filtering needs a backend change, which I'll file as a
follow-up issue.
How to test
npm run lint && npm run format:check && npm run typecheck && npm test && npm run buildnpm run dev:backend(needs an imported local database, see README"Data") and
npm run dev:frontend, then in the browser:(e.g. "Beef") and confirm results actually narrow down (this is the
bug that's fixed); set a minimum rating; scroll down and click
"Load more" to confirm more results append and the button disappears
once
hasMoreis false.ingredients, directions, fetched live.
npm run ingredients:refresh, unrelated to this PR) → Find recipes →confirm the "matching any of: ..." text and results.
imported dataset (17,698 recipes), both before and after rebasing onto
Fix/59 fridge recipe matches #60.
AI usage
Done together with Claude Code in an interactive session. Claude wrote the
Apollo Client setup, the HomePage/RecipeDetailPage rewiring, the category
bug fix, and the test updates (including resolving the merge conflicts with
#60 and adapting its tests to the new GraphQL-backed HomePage), driven by a
plan reviewed before implementation. The human caught the overlap with #60
mid-session and directed the rebase-after-merge approach; browser
verification (screenshots, manual click-through of search/filter/paging/
Fridge) was done together via the Chrome extension, not just trusted from
the model's claims.
Checklist
states and result count are in the existing
aria-liveregion;category/rating selects and search input unchanged