Add external program marketplace#4053
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds public marketplace API routes and shared query/fetch helpers, introduces the external marketplace route and page shell, and updates marketplace-related redirects, layouts, and public-access handling. ChangesMarketplace external browsing
Sequence Diagram(s)sequenceDiagram
participant Browser
participant MarketplaceExternalListPageClient
participant ProgramsRoute as GET /api/marketplace/programs
participant CountsRoute as GET /api/marketplace/programs/counts
participant Parser as parsePublicMarketplaceQuery
participant ProgramsFetcher as getPublicNetworkPrograms
participant CountsFetcher as getNetworkProgramCounts
Browser->>MarketplaceExternalListPageClient: change filters or page
MarketplaceExternalListPageClient->>ProgramsRoute: request program rows
MarketplaceExternalListPageClient->>CountsRoute: request counts
ProgramsRoute->>Parser: normalize query params
ProgramsRoute->>ProgramsFetcher: load marketplace programs
ProgramsFetcher-->>ProgramsRoute: programs
ProgramsRoute-->>MarketplaceExternalListPageClient: JSON response
CountsRoute->>Parser: normalize query params
CountsRoute->>CountsFetcher: load category and reward counts
CountsFetcher-->>CountsRoute: counts
CountsRoute-->>MarketplaceExternalListPageClient: JSON response
MarketplaceExternalListPageClient-->>Browser: updated grid, sidebar, and pagination
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
4ed65dd to
e8f89dd
Compare
Adds public marketplace pages, API routes, middleware rewrites, and sitemap entries for the external marketplace surface.
854c4a5 to
6e4440e
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/page.tsx (1)
32-44: 🩺 Stability & Availability | 🟡 MinorPoint this redirect at the public marketplace host
redirect("/marketplace/${programSlug}")stays onpartners.dub.co, where/marketplaceis an authenticated dashboard route. If this branch should show the public program page, use theapp.dub.comarketplace URL instead.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/app/`(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/page.tsx around lines 32 - 44, The default-group redirect in the apply page is pointing to the authenticated `/marketplace` route on the current host instead of the public marketplace host. Update the redirect in the `apply/page.tsx` branch that handles `partnerGroupSlug === DEFAULT_PARTNER_GROUP.slug` so it sends users to the public `app.dub.co` marketplace URL for the program page, while leaving the `notFound()` and non-default group redirect behavior unchanged.
🧹 Nitpick comments (1)
apps/web/ui/program-marketplace/external/marketplace-external-list-page-client.tsx (1)
244-277: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valuePagination renders one link per page — consider windowing for large catalogs.
Array.from({ length: totalPages }, ...)emits a<Link>for every page. As the marketplace grows,totalPages(=ceil(total / PAGE_SIZE)) can produce a very long, hard-to-use control and many DOM nodes. Consider a windowed/truncated pager (first/last + neighbors + ellipsis) or prev/next controls.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/ui/program-marketplace/external/marketplace-external-list-page-client.tsx` around lines 244 - 277, The pagination rendering in marketplace-external-list-page-client.tsx currently creates one Link per page via Array.from({ length: totalPages }, ...), which will not scale for large catalogs. Update the pagination UI in the relevant pager component to use a windowed/truncated strategy instead of listing every page, such as showing the first/last pages, the current page with neighboring pages, and ellipses or prev/next controls. Keep the existing query-building logic with URLSearchParams and Link, but change the page selection/rendering logic so the number of links stays small as totalPages grows.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/lib/marketplace/parse-public-marketplace-query.ts`:
- Around line 24-33: The current `parsePublicMarketplaceQuery` flow in
`getPublicNetworkProgramsQuerySchema` drops all valid filters when `safeParse`
fails on a single malformed field. Update the parsing logic to validate or
coerce each query param independently, or merge the successfully parsed fields
with defaults so invalid values do not wipe out other valid ones. Keep
`fixedCategory` and `EXTERNAL_MARKETPLACE_PAGE_SIZE` as fallback values, but
preserve any other valid filters from the original input instead of replacing
the whole object.
In
`@apps/web/ui/program-marketplace/external/marketplace-external-apply-button.tsx`:
- Around line 16-20: The href construction in
marketplace-external-apply-button’s apply button is adding an extra slash when
session is present because getMarketplaceProgramHref(programSlug) already
returns a path starting with a slash. Update the href expression in
MarketplaceExternalApplyButton so the session branch concatenates
PARTNERS_DOMAIN directly with getMarketplaceProgramHref(programSlug), while
keeping the non-session apply path unchanged, to avoid generating a double-slash
partners marketplace URL.
---
Outside diff comments:
In
`@apps/web/app/`(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/page.tsx:
- Around line 32-44: The default-group redirect in the apply page is pointing to
the authenticated `/marketplace` route on the current host instead of the public
marketplace host. Update the redirect in the `apply/page.tsx` branch that
handles `partnerGroupSlug === DEFAULT_PARTNER_GROUP.slug` so it sends users to
the public `app.dub.co` marketplace URL for the program page, while leaving the
`notFound()` and non-default group redirect behavior unchanged.
---
Nitpick comments:
In
`@apps/web/ui/program-marketplace/external/marketplace-external-list-page-client.tsx`:
- Around line 244-277: The pagination rendering in
marketplace-external-list-page-client.tsx currently creates one Link per page
via Array.from({ length: totalPages }, ...), which will not scale for large
catalogs. Update the pagination UI in the relevant pager component to use a
windowed/truncated strategy instead of listing every page, such as showing the
first/last pages, the current page with neighboring pages, and ellipses or
prev/next controls. Keep the existing query-building logic with URLSearchParams
and Link, but change the page selection/rendering logic so the number of links
stays small as totalPages grows.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6b44bd6b-9e7b-4102-8532-ca2600229db4
📒 Files selected for processing (29)
apps/web/app/(ee)/api/marketplace/programs/counts/route.tsapps/web/app/(ee)/api/marketplace/programs/route.tsapps/web/app/(ee)/api/network/programs/count/route.tsapps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/page.tsxapps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/apply/success/page.tsxapps/web/app/(ee)/partners.dub.co/(apply)/[programSlug]/(default)/page.tsxapps/web/app/(ee)/partners.dub.co/(dashboard)/marketplace/[[...segments]]/page.tsxapps/web/app/app.dub.co/(dashboard)/layout.tsxapps/web/app/app.dub.co/layout.tsxapps/web/app/app.dub.co/marketplace/[[...segments]]/page.tsxapps/web/app/app.dub.co/marketplace/layout.tsxapps/web/lib/fetchers/get-network-program-counts.tsapps/web/lib/fetchers/get-public-network-programs.tsapps/web/lib/marketplace/parse-public-marketplace-query.tsapps/web/lib/middleware/app.tsapps/web/lib/middleware/utils/app-redirect.tsapps/web/lib/swr/use-workspace.tsapps/web/ui/program-marketplace/external/marketplace-external-apply-button.tsxapps/web/ui/program-marketplace/external/marketplace-external-filters.tsxapps/web/ui/program-marketplace/external/marketplace-external-header.tsxapps/web/ui/program-marketplace/external/marketplace-external-home-page.tsxapps/web/ui/program-marketplace/external/marketplace-external-list-page-client.tsxapps/web/ui/program-marketplace/external/marketplace-external-list-page.tsxapps/web/ui/program-marketplace/external/marketplace-external-program-page.tsxapps/web/ui/program-marketplace/external/marketplace-external-router.tsxapps/web/ui/program-marketplace/external/marketplace-external-shell.tsxapps/web/ui/program-marketplace/pages/marketplace-program-page.tsxapps/web/ui/program-marketplace/program-rewards-display.tsxapps/web/ui/program-marketplace/utils/urls.ts
💤 Files with no reviewable changes (1)
- apps/web/lib/middleware/utils/app-redirect.ts
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/app/app.dub.co/marketplace/[[...segments]]/page.tsx (1)
48-55: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReuse the router’s category parser here.
MarketplaceExternalRouteraccepts category slugs case-insensitively viaslugToCategory(), but this metadata branch does a case-sensitive enum match. A URL like/marketplace/c/SEOwill render the category page and still keep the generic metadata. Use the same helper in both places so routing and metadata stay aligned.Proposed fix
import { getMarketplaceCanonicalUrl, getMarketplacePathFromSegments, + slugToCategory, } from "`@/ui/program-marketplace/utils/urls`"; import { constructMetadata } from "`@dub/utils`"; -import { Category } from "`@prisma/client`"; import { Metadata } from "next"; @@ } else if (segments.length === 2 && segments[0] === "c") { - const category = Object.values(Category).find( - (value) => value.toLowerCase() === segments[1], - ); + const category = slugToCategory(segments[1]); if (category) { const categoryMeta = PROGRAM_CATEGORIES_MAP[category];🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/app/app.dub.co/marketplace/`[[...segments]]/page.tsx around lines 48 - 55, The category metadata lookup in the marketplace page is doing a case-sensitive enum match instead of reusing the router’s category parser, so it can disagree with `MarketplaceExternalRouter` for URLs like `/marketplace/c/SEO`. Update the `page.tsx` category branch to use the same `slugToCategory()` helper used by `MarketplaceExternalRouter`, then derive `categoryMeta` and `label` from that resolved category so routing and metadata stay aligned.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/ui/program-marketplace/marketplace-program-row.tsx`:
- Line 64: Remove the leftover debug logging from marketplace-program-row.tsx:
the console.log in the MarketplaceProgramRow render path is emitting the full
programs payload on every render. Delete this statement so MarketplaceProgramRow
no longer spams logs in either the server-rendered or client-rendered path.
---
Outside diff comments:
In `@apps/web/app/app.dub.co/marketplace/`[[...segments]]/page.tsx:
- Around line 48-55: The category metadata lookup in the marketplace page is
doing a case-sensitive enum match instead of reusing the router’s category
parser, so it can disagree with `MarketplaceExternalRouter` for URLs like
`/marketplace/c/SEO`. Update the `page.tsx` category branch to use the same
`slugToCategory()` helper used by `MarketplaceExternalRouter`, then derive
`categoryMeta` and `label` from that resolved category so routing and metadata
stay aligned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6d106c7d-2b02-43e1-9a5f-eb4ccba351f9
📒 Files selected for processing (8)
apps/web/app/(ee)/partners.dub.co/(dashboard)/marketplace/[[...segments]]/page.tsxapps/web/app/app.dub.co/marketplace/[[...segments]]/page.tsxapps/web/ui/program-marketplace/external/marketplace-external-home-page.tsxapps/web/ui/program-marketplace/home-sections.tsapps/web/ui/program-marketplace/marketplace-program-row.tsxapps/web/ui/program-marketplace/pages/marketplace-home-page.tsxapps/web/ui/program-marketplace/pages/marketplace-program-page.tsxapps/web/ui/program-marketplace/utils/default-exports.ts
💤 Files with no reviewable changes (1)
- apps/web/ui/program-marketplace/pages/marketplace-program-page.tsx
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/ui/program-marketplace/external/marketplace-external-apply-button.tsx (1)
14-26: 🎯 Functional Correctness | 🟠 MajorUse a single interactive element
Buttonrenders a native<button>, so wrapping it in<a target="_blank">creates nested interactive content. Style the anchor directly here instead.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/ui/program-marketplace/external/marketplace-external-apply-button.tsx` around lines 14 - 26, The Apply control in marketplace-external-apply-button.tsx uses nested interactive elements because Button renders a native button inside an anchor. Update the MarketplaceExternalApplyButton component to remove the Button wrapper and style the anchor itself with the same classes so the link remains the only interactive element; keep the existing href logic based on session and programSlug and preserve target="_blank".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In
`@apps/web/ui/program-marketplace/external/marketplace-external-apply-button.tsx`:
- Around line 14-26: The Apply control in marketplace-external-apply-button.tsx
uses nested interactive elements because Button renders a native button inside
an anchor. Update the MarketplaceExternalApplyButton component to remove the
Button wrapper and style the anchor itself with the same classes so the link
remains the only interactive element; keep the existing href logic based on
session and programSlug and preserve target="_blank".
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 46fced09-93f2-496b-8c3f-263df5ade340
📒 Files selected for processing (13)
apps/web/app/app.dub.co/marketplace/[[...segments]]/page.tsxapps/web/ui/program-marketplace/external/marketplace-external-apply-button.tsxapps/web/ui/program-marketplace/external/marketplace-external-header.tsxapps/web/ui/program-marketplace/external/marketplace-external-program-page.tsxapps/web/ui/program-marketplace/featured-program-card.tsxapps/web/ui/program-marketplace/marketplace-program-row.tsxapps/web/ui/program-marketplace/marketplace-router.tsxapps/web/ui/program-marketplace/marketplace-sidebar-filters.tsxapps/web/ui/program-marketplace/pages/marketplace-program-page.tsxapps/web/ui/program-marketplace/program-card.tsxapps/web/ui/program-marketplace/program-marketplace-banner.tsxapps/web/ui/program-marketplace/program-marketplace-card.tsxapps/web/ui/program-marketplace/utils/urls.ts
💤 Files with no reviewable changes (1)
- apps/web/ui/program-marketplace/marketplace-program-row.tsx
✅ Files skipped from review due to trivial changes (1)
- apps/web/ui/program-marketplace/marketplace-sidebar-filters.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/web/ui/program-marketplace/external/marketplace-external-program-page.tsx
- apps/web/app/app.dub.co/marketplace/[[...segments]]/page.tsx
- apps/web/ui/program-marketplace/pages/marketplace-program-page.tsx
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
UI