Skip to content

feat: Leaderboard sharing and embed widget (Closes #613)#788

Open
JosephOladele wants to merge 2 commits into
Samuel1-ona:mainfrom
JosephOladele:feat/leaderboard-sharing-embed
Open

feat: Leaderboard sharing and embed widget (Closes #613)#788
JosephOladele wants to merge 2 commits into
Samuel1-ona:mainfrom
JosephOladele:feat/leaderboard-sharing-embed

Conversation

@JosephOladele

Copy link
Copy Markdown

Summary

Implements leaderboard sharing and an embeddable widget for #613.

All ranking logic flows through a single server-safe module (lib/leaderboard.ts) so the OG image, public page, embed widget, and existing API stay consistent. One next/og route powers both the shareable board image and the personal "share my rank" card.

What's included

  • lib/leaderboard.ts — server-safe ranking core: getRankedLeaderboard (sorts by points desc, standard competition ranking for ties), computeLeaderboardStats, findPlayerRank (case-insensitive), getHuntSummary (graceful title fallback). Covered by 12 unit tests.
  • lib/siteUrl.ts — canonical absolute base-URL helper.
  • app/api/og/leaderboard/[id]/route.tsxnext/og image (1200×630). Board summary by default; personal rank card when ?address= matches a player.
  • app/leaderboard/[id]/page.tsx — public, crawlable leaderboard page with full OG/Twitter metadata via generateMetadata.
  • app/embed/leaderboard/[id]/page.tsx — chrome-less widget intended for cross-origin <iframe> embedding.
  • components/ShareLeaderboard.tsx — "share my rank as image" (address input) + copy-to-clipboard <iframe> embed snippet.
  • next.config.ts — carves /embed/* out of the global X-Frame-Options: DENY so the widget can be framed.

Incidental build fixes

While building this, I found main did not compile or boot. These are pre-existing issues unrelated to the feature, fixed here so the app runs (happy to split into a separate PR if preferred):

  1. package.json — invalid JSON (missing commas) broke npm install.
  2. Added missing @testing-library/dom peer dep (whole test suite was failing to import).
  3. app/layout.tsx — duplicate PageSkeleton / PageTransitionWrapper imports.
  4. app/layout.tsx — missing headers import from next/headers.
  5. app/providers.tsx — missing queryCachePolicy import from @/lib/queryKeys.
  6. components/Header.tsx — undefined MOCK_NOTIFICATIONS reference.

Testing

  • npm test -- lib/__tests__/leaderboard.test.ts → 12 passing.

Follow-ups (not in this PR)

  • CORS + cache headers on app/api/v1/hunts/[id]/leaderboard/route.ts for third-party JSON consumers.
  • middleware.ts CSP frame-ancestors carve-out for /embed/* (next.config handles X-Frame-Options; middleware CSP still needs the matching exception for full cross-origin embedding).

Note for maintainers

package-lock.json was regenerated by npm (the repo's lockfile appeared pnpm-based). Let me know if you'd prefer I revert the lockfile and you regenerate with pnpm.

Closes #613

Adds lib/leaderboard.ts (getRankedLeaderboard, computeLeaderboardStats, findPlayerRank, getHuntSummary) as the single source of truth for rank derivation, plus lib/siteUrl.ts for resolving the canonical absolute base URL. Covered by 12 passing unit tests. Foundation for Samuel1-ona#613 leaderboard sharing and embed widget.
package.json was not valid JSON (missing commas after the test:mutation script and the @stryker-mutator/vitest-runner devDependency), which broke npm install and all test runs. Refreshes package-lock.json accordingly.
@JosephOladele

Copy link
Copy Markdown
Author

Heads up: main currently doesn't compile or boot.
While building this feature I found that main (at commit 2247083, the merge of #772) fails to build and crashes at runtime out of the box. These look unrelated to each other and to my feature. I've included fixes in this PR so the app runs, but I'm flagging them here in case you want to address them separately or are already aware.
What I hit, in the order they surfaced (each one hides the next, since the app crashes before reaching the later file):

package.json is invalid JSON. Missing commas after the test:mutation script entry and after the @stryker-mutator/vitest-runner devDependency. This breaks npm install entirely.
Missing @testing-library/dom. The @testing-library/react package needs it as a peer dependency. Without it the whole Vitest suite fails to import with "Cannot find module '@testing-library/dom'".
app/layout.tsx imports PageSkeleton and PageTransitionWrapper twice each, giving "Identifier 'PageSkeleton' has already been declared".
app/layout.tsx uses await headers() but never imports headers from next/headers, giving "ReferenceError: headers is not defined".
app/providers.tsx references queryCachePolicy.hunts.gcTime but doesn't import queryCachePolicy from @/lib/queryKeys (it's imported correctly in app/page.tsx), giving "ReferenceError: queryCachePolicy is not defined".
components/Header.tsx references MOCK_NOTIFICATIONS which isn't defined or imported anywhere, giving "ReferenceError: MOCK_NOTIFICATIONS is not defined".

Items 5 and 6 look like leftovers from an in progress data layer refactor. I'm happy to pull these fixes into a dedicated "fix: repair broken main build" PR if you'd rather keep them out of the #613 feature PR. Just let me know which you prefer.
It might also be worth checking whether CI runs npm install and a build on PRs, since these would have been caught at merge time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build leaderboard sharing and embed widget

1 participant