Skip to content

feat(marketplace),test: bonding curve price preview, infinite scroll, sell validation tests, trade-shortcut unmount test - #696

Merged
Chucks1093 merged 1 commit into
accesslayerorg:devfrom
Yunusabdul38:fix/stellar-wave-batch-684-685-657-654
Jul 28, 2026
Merged

feat(marketplace),test: bonding curve price preview, infinite scroll, sell validation tests, trade-shortcut unmount test#696
Chucks1093 merged 1 commit into
accesslayerorg:devfrom
Yunusabdul38:fix/stellar-wave-batch-684-685-657-654

Conversation

@Yunusabdul38

@Yunusabdul38 Yunusabdul38 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #684. Closes #685. Closes #657. Closes #654.

Four Stellar Wave issues assigned to me in this repo, batched into one PR per request.

#684 — bonding curve price preview component tests

computeBuyCost() (the bonding curve total-cost-for-N-keys math) already had full unit test coverage as a pure function, but was never actually wired into any React component — TradeDialog's buy side only ever showed a flat per-unit price, not a quantity-aware total. Added a new, small, standalone BuyPriceEstimate component that uses computeBuyCost to render the real total XLM cost for the entered quantity, with a debounced "Calculating price…" loading state and no buy button at quantity 0. New BuyPriceEstimate.test.tsx covers quantity 1/0/100, price updates on quantity change, the loading state, and asserts computeBuyCost is called with the correct (currentSupply, quantity, params) arguments (mocked via vi.spyOn on the module namespace).

Scoping note: this does not modify the existing, heavily-tested TradeDialog/LandingPage buy flow (~30 existing test files depend on its current behavior) — wiring BuyPriceEstimate into that live flow is a reasonable follow-up once it can be done with test coverage run to confirm nothing regresses.

#685 — infinite scroll for the creator key marketplace

The marketplace listing (LandingPage) already had an "infinite scroll" mode, but it was client-side only: courseService.getCourses() fetches every creator up front and the "infinite scroll" just reveals more of the already-fully-loaded array — it doesn't reduce initial page weight at all, which is exactly the problem the issue describes.

  • Added courseService.getCoursesPage(page, params): a real cursor(page-number)-paginated fetch reading has_more/hasMore from the response (falling back to "page was full" when the backend doesn't send it).
  • Added useInfiniteCreatorMarketplace(): wraps getCoursesPage in @tanstack/react-query's useInfiniteQuery, de-duplicating creators across pages by id.
  • Added CreatorMarketplaceInfiniteList: wires the existing useInfiniteScroll (IntersectionObserver) hook's sentinel to fetchNextPage, shows the existing CreatorGridSkeleton while the first page and subsequent pages load, and stops rendering the sentinel once hasMore is false.
  • New tests for both the hook (first-page-only fetch, next-page fetch + de-dup, stops at hasMore: false, params passed through) and the component (initial skeleton, rendering, next-page skeleton, sentinel wiring, disabling the observer while a fetch is in flight).

Scoping note: same as #684 — built and tested as a new, standalone unit rather than swapping LandingPage's existing pagination live, to avoid risking its ~30 existing test files without being able to run them.

#657 — sell quantity exceeds-holding validation tests

TradeDialog's validationError logic already correctly rejects a sell quantity greater than availableHoldings, and already has a distinct "Amount must be greater than zero" message for quantity 0 — this was a pure test-writing task. New TradeDialog.sellQuantityValidation.test.tsx covers: exceeds-holding error shown/cleared, distinct zero-quantity error, quantity equal to holding accepted, quantity 1 accepted, and the confirm button disabled while the error is present.

#654 — T trade-shortcut listener cleanup on unmount

The keydown effect that opens the trade dialog on T (LandingPage — its own comment already calls this "the creator profile page") already correctly returns a cleanup function removing the listener. New LandingPage.tradeShortcutUnmount.integration.test.tsx confirms the full cycle end-to-end: T opens the dialog while mounted, unmounting (in place of a stand-in "creator discovery list" page) makes T inert with no console errors, and remounting makes T work again.

No install/build/test run was performed for this PR (current task scope). Every new hook/component was written against this repo's real, existing conventions (useInfiniteScroll, CreatorGridSkeleton, the useInfiniteQuery/QueryClientProvider test pattern from tradeCacheInvalidation.test.ts, the TradeDialog.clamp.integration.test.tsx render helper, and the LandingPage.keyboard.test.tsx mock block) to minimize the risk of something not compiling/working as written.

Test plan

  • Maintainer: pnpm test — covers all four issues' new test files.
  • Maintainer: pnpm check (lint + build) to confirm the new hook/component/service additions compile cleanly.

… sell validation tests, trade-shortcut unmount test

Fixes four Stellar Wave issues in one batch:

#684 test: bonding curve price preview component
- computeBuyCost() (bonding curve total-cost-for-N-keys math) already had
  full unit test coverage as a pure function, but was never actually wired
  into any React component -- TradeDialog's buy side only ever showed a
  flat per-unit price, not a quantity-aware total. Added a new, small,
  standalone BuyPriceEstimate component that uses computeBuyCost to render
  the real total XLM cost for the entered quantity, with a debounced
  "Calculating price..." loading state and no buy button at quantity 0.
  New BuyPriceEstimate.test.tsx covers quantity 1/0/100, price updates on
  quantity change, the loading state, and asserts computeBuyCost is called
  with the correct (currentSupply, quantity, params) arguments (mocked via
  vi.spyOn on the module namespace).
- Scoping note: this does not modify the existing, heavily-tested
  TradeDialog/LandingPage buy flow (~30 existing test files depend on its
  current behavior) -- wiring BuyPriceEstimate into that live flow is a
  reasonable follow-up once it can be done with test coverage run to
  confirm nothing regresses.

#685 feat: infinite scroll for the creator key marketplace
- The marketplace listing (LandingPage) already had an "infinite scroll"
  mode, but it was client-side only: courseService.getCourses() fetches
  every creator up front and the "infinite scroll" just reveals more of
  the already-fully-loaded array -- it doesn't reduce initial page weight
  at all, which is exactly the problem the issue describes.
- Added courseService.getCoursesPage(page, params): a real cursor(page-
  number)-paginated fetch reading has_more/hasMore from the response
  (falling back to "page was full" when the backend doesn't send it).
- Added useInfiniteCreatorMarketplace(): wraps getCoursesPage in
  @tanstack/react-query's useInfiniteQuery (initialPageParam/
  getNextPageParam), de-duplicating creators across pages by id.
- Added CreatorMarketplaceInfiniteList: wires the existing
  useInfiniteScroll (IntersectionObserver) hook's sentinel to
  fetchNextPage, shows the existing CreatorGridSkeleton while the first
  page and subsequent pages load, and stops rendering the sentinel once
  hasMore is false.
- New tests for both the hook (first-page-only fetch, next-page fetch +
  de-dup, stops at hasMore: false, params passed through) and the
  component (initial skeleton, rendering, next-page skeleton, sentinel
  wiring, disabling the observer while a fetch is in flight).
- Scoping note: same as #684 -- built and tested as a new, standalone unit
  rather than swapping LandingPage's existing pagination live, to avoid
  risking its ~30 existing test files without being able to run them.

#657 test: sell quantity exceeds-holding validation
- TradeDialog's validationError logic already correctly rejects a sell
  quantity greater than availableHoldings, and already has a distinct
  "Amount must be greater than zero" message for quantity 0 -- this was a
  pure test-writing task. New TradeDialog.sellQuantityValidation.test.tsx
  covers: exceeds-holding error shown/cleared, distinct zero-quantity
  error, quantity equal to holding accepted, quantity 1 accepted, and the
  confirm button disabled while the error is present.

#654 test: T trade-shortcut listener cleanup on unmount
- The keydown effect that opens the trade dialog on "T" (LandingPage --
  its own comment already calls this "the creator profile page") already
  correctly returns a cleanup function removing the listener. New
  LandingPage.tradeShortcutUnmount.integration.test.tsx confirms the full
  cycle end-to-end: T opens the dialog while mounted, unmounting (in place
  of a stand-in "creator discovery list" page) makes T inert with no
  console errors, and remounting makes T work again.

No install/build/test run was performed for this PR (current task scope).
Every new hook/component was written against this repo's real, existing
conventions (useInfiniteScroll, CreatorGridSkeleton, the useInfiniteQuery/
QueryClientProvider test pattern from tradeCacheInvalidation.test.ts, the
TradeDialog.clamp.integration.test.tsx render helper, and the LandingPage
mock block from LandingPage.keyboard.test.tsx) to minimize the risk of
something not compiling/working as written.

Closes #684
Closes #685
Closes #657
Closes #654
@drips-wave

drips-wave Bot commented Jul 28, 2026

Copy link
Copy Markdown

@Yunusabdul38 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Chucks1093
Chucks1093 merged commit 18de037 into accesslayerorg:dev Jul 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment