fix(marketplace): fetch campaign data by ID instead of using mock data - #159
fix(marketplace): fetch campaign data by ID instead of using mock data#159SudiptaPaul-31 wants to merge 5 commits into
Conversation
|
@SudiptaPaul-31 is attempting to deploy a commit to the victorjames408gmailcom's projects Team on Vercel. A member of the Team first needs to authorize it. |
JamesVictor-O
left a comment
There was a problem hiding this comment.
❌ Request Changes
Verified locally (build + a real next start run, not just reading the diff) — the PR's core goal ("fetch campaign data by ID instead of mock data") doesn't actually work yet. Both campaign-detail routes 404 for every real, navigable id.
Bug 1: Marketplace detail page — params never awaited (Next.js 16)
app/marketplace/[id]/page.tsx still types params as { id: string } and reads params.id synchronously in both generateMetadata and the page component. On Next.js 16 (this repo's version), params is a Promise, so params.id is undefined and findCampaignById(undefined) always returns null.
Reproduced: curl localhost:PORT/marketplace/nextgen-wallet (a real id from marketplaceCampaigns) renders the "Campaign Not Found" metadata/notFound page, for every campaign.
The business-dashboard counterpart (app/dashboard/business/campaigns/[id]/page.tsx) in this same PR correctly uses the async pattern (params: Promise<PageParams> + await params) — the marketplace page needs the same treatment:
export default async function CampaignDetailPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const marketplaceCampaign = findCampaignById(id);
...(and the same in generateMetadata).
Bug 2: Business detail page — id literal typo
getBusinessCampaignDetailById only matches campaignDetail.id, which is "cyberpunk-rebrand-q4". But the actual list that links into this page (campaigns-list-data.ts) uses ids cyberpunk-rebrand, stellar-fitness, nft-gallery, defi-education — none of which match. Clicking any campaign from /dashboard/business/campaigns 404s.
Reproduced: curl localhost:PORT/dashboard/business/campaigns/cyberpunk-rebrand (the id actually linked from the list) renders the not-found page; only the unlisted cyberpunk-rebrand-q4 id works.
Why this passed build/typecheck
Both are runtime logic bugs, not type errors — tsc --noEmit and next build are clean, which is presumably why the "Build successful" checkmark in the PR description didn't catch them. Manual click-through of the actual pages would surface both immediately.
What's solid
The sessionStorage-per-campaign scoping fix and the notFound() handling pattern are correct and worth keeping — this is fixable without redesigning the approach, just needs the await params fix and either correcting the mock id or wiring getBusinessCampaignDetailById to look up from campaignsList instead of the single hardcoded campaignDetail.
Happy to re-review once pushed.
JamesVictor-O
left a comment
There was a problem hiding this comment.
Thanks for tackling the mock-data bug — the id-based lookup, notFound() handling, and per-campaign sessionStorage scoping in application-form.tsx all look correct and match the PR description.
Bug found in the new fallback path (components/dashboard/business/campaign-detail-data.ts):
export function buildCampaignDetailFromListItem(id: string, name: string, status: string): CampaignDetail {
return {
...
status: status as CampaignDetailStatus,status is cast without validation. campaignsList (campaigns-list-data.ts) includes items with status "under-review", which is not a member of CampaignDetailStatus ("active" | "paused" | "draft" | "completed").
This isn't a rare edge case — campaignDetail.id ("cyberpunk-rebrand-q4") doesn't match any id in campaignsList ("cyberpunk-rebrand", "stellar-fitness", "nft-gallery", "defi-education"), so getBusinessCampaignDetailById always misses and every real navigation from the campaigns table (campaigns-table.tsx:118, href={/dashboard/business/campaigns/${campaign.id}}) hits this fallback.
Concretely: clicking into "Stellar Fitness App Promo" (status "under-review") renders a broken badge — campaign-detail-header.tsx does statusStyles[campaign.status] / statusLabels[campaign.status], both Record<CampaignDetailStatus, string> with no "under-review" key, so you get an empty label and a literal "undefined" token appended to the badge's class list.
Suggested fix: map "under-review" → "paused" (or add "under-review" to CampaignDetailStatus plus the style/label maps) inside buildCampaignDetailFromListItem, rather than casting an unvalidated string.
Once that's addressed this looks good to merge.
…nto fix-bug-campaign
…uilder - Replace unsafe 'as CampaignDetailStatus' cast with explicit status map - Map 'under-review' status from campaigns list to 'paused' for UI consistency - Add default fallback to 'draft' for unmapped statuses (defensive) - Fixes broken badge rendering when clicking campaigns with non-standard status - Ensures proper UI display for all campaign statuses without TypeScript errors Resolves: Status rendering broken for 'under-review' campaigns in business dashboard
Problem
Solution
Implemented proper campaign lookup by id with 404 handling and per-campaign sessionStorage scoping.
closes #142
Changes
Marketplace Detail Page (
apps/frontend/app/marketplace/[id]/page.tsx)params.idusingfindCampaignById()notFound()for invalid idscampaign.idto ApplicationFormBusiness Campaign Detail Page (
apps/frontend/app/dashboard/business/campaigns/[id]/page.tsx)params: Promise<PageParams>const { id } = await paramsgetBusinessCampaignDetailById(id)notFound()for invalid idsApplication Form (
apps/frontend/components/marketplace/application-form.tsx)campaignIdto required prop (was optional with default)campaignDetailMockimportcampaign-application:{campaignId}contentFormatspropLookup Functions
findCampaignById()inmarketplace-data.ts— find from 13-item campaigns listgetCampaignDetailById()incampaign-detail-data.ts— marketplace detail lookupgetBusinessCampaignDetailById()inbusiness/campaign-detail-data.ts— business detail lookupResults
✅ Each campaign renders with correct params-based id
✅ Business page uses Next.js 16 async params pattern
✅ Invalid ids show proper 404 page
✅ Application tracking scoped per campaign — applying to one no longer marks others as applied
✅ Build successful with no TypeScript errors
Files Modified
apps/frontend/app/marketplace/[id]/page.tsxapps/frontend/app/dashboard/business/campaigns/[id]/page.tsxapps/frontend/components/marketplace/application-form.tsxapps/frontend/components/marketplace/marketplace-data.tsapps/frontend/components/marketplace/campaign-detail-data.tsapps/frontend/components/dashboard/business/campaign-detail-data.ts