Skip to content

bug: campaign detail pages ignore the route id and always render one hardcoded mock campaign #142

Description

@JamesVictor-O

Problem

Every campaign detail route ignores its own params.id and renders one hardcoded mock campaign, regardless of which campaign was actually clicked.

app/marketplace/[id]/page.tsx:

export default function CampaignDetailPage({ params }: { params: { id: string } }) {
  const campaign = campaignDetailMock;   // params.id is never read

app/dashboard/business/campaigns/[id]/page.tsx:

const campaign = campaignDetail; // always mock for now — params.id ignored

Meanwhile the marketplace grid correctly generates distinct links for each of the 13 campaigns in components/marketplace/marketplace-data.ts (nextgen-wallet, lumen-node, cross-border, ...), via Link href={/marketplace/${campaign.id}} in marketplace-grid.tsx. Every one of those routes currently renders the identical campaignDetailMock object (id: "quantum-wearables"), no matter which card was clicked.

Compounding bug

ApplicationForm's "already applied" check is keyed by campaign-application:${campaignId} in sessionStorage, and campaignId defaults to campaignDetailMock.id (components/marketplace/application-form.tsx:17-21) since the page never passes the real id down. So once a creator applies to any campaign, every other campaign's detail page falsely shows "APPLICATION SUBMITTED!" as if they'd already applied to that one too.

Concrete failure scenario

  1. Creator browses the marketplace, clicks into "NextGen Wallet Launch" — sees the "Quantum Wearables" brief/budget/requirements instead.
  2. Clicks into "Lumen Node Validator" — sees the exact same "Quantum Wearables" content again.
  3. Applies to one campaign. Every other campaign in the marketplace now silently shows as already-applied, blocking legitimate applications to genuinely different campaigns.

Expected behaviour

Look up the campaign by params.id from the same dataset used to build the marketplace/dashboard lists, and 404/redirect on an unknown id. Scope the sessionStorage "already applied" key to the real per-campaign id, not a shared default.

Note: app/dashboard/business/campaigns/[id]/page.tsx also still types params synchronously ({ id: string }) rather than Promise<{ id: string }> — unlike the already-correct app/dashboard/creator/campaigns/[id]/page.tsx, which does async function ... { params: Promise<PageParams> } and await params. The app is on Next.js 16, where dynamic route params are async; align the business page to the same pattern while wiring up the real id lookup, since it's currently only harmless because the page never reads params.id at all.

Files

  • app/marketplace/[id]/page.tsx
  • app/dashboard/business/campaigns/[id]/page.tsx
  • components/marketplace/application-form.tsx — sessionStorage key scoping

Acceptance criteria

  • app/marketplace/[id]/page.tsx renders the campaign matching params.id, not a hardcoded mock
  • app/dashboard/business/campaigns/[id]/page.tsx does the same, and adopts the async params: Promise<{id: string}> pattern already used on the creator side
  • An unknown id shows a proper not-found state instead of falling back to an arbitrary campaign
  • The "already applied" sessionStorage key is scoped per real campaign id — applying to one campaign no longer marks unrelated campaigns as applied

Metadata

Metadata

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignThird CampaignCampaign: Third CampaignbugSomething isn't workingfrontendFrontend UI/UX workpriority: highHigh priority issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions