Skip to content

PR 9 — Dashboard: /links/[id] detail page #145

@0xdevcollins

Description

@0xdevcollins

Why

After PR #144 ships, clicking a link in the list goes nowhere. Detail page is where merchants see the QR code, get the shareable URL, watch conversion stats, and deactivate. Standard CRUD completion.

Depends on: #144 (PR 8 — the list page that links here).

Scope

One page at `apps/dashboard/src/app/(dashboard)/links/[id]/page.tsx`.

API endpoints (already shipped)

Verb Path Returns
GET `/v1/payment-links/:id` The full `PaymentLink` object
GET `/v1/payment-links/:id/stats` `{ linkId, totalViews, totalPayments, conversionRate, totalRevenue, currency }`
DELETE `/v1/payment-links/:id` Deactivates (sets `active=false`)

What to build

Three vertical sections + a sidebar.

Hero card

  • Big mono `lnk_…` ID
  • Status badge (reuse `LinkStatusBadge`)
  • Big amount + currency, or "Open amount"
  • Description below
  • Two CTAs side-by-side: "Copy URL" (with toast), "Download QR" (the qrCodeUrl is a data:url — trigger a download)

Stats strip (calls /stats)

  • Three tiles: Views · Payments · Conversion rate
  • Conversion rate gets a sparkline if we add a /stats/timeseries endpoint later (out of scope for this PR — show flat number)
  • Total revenue card with the link's currency

Recent payments table (calls /v1/payments?linkId=…)

  • Last 10 payments routed through this link
  • Columns: created, payer (or "—" if anonymous), amount, method (card/bank/crypto), status badge
  • Click a row → /payments/[id] (existing page)
  • "View all payments" link at the bottom filtering /payments by this link

Right sidebar

  • Created at, updated at (relative time + tooltip with full ISO)
  • Single-use vs multi-use chip
  • Expiry: "Never" or "Expires Aug 4" with a tooltip showing the full datetime
  • Hairline rule, then a destructive "Deactivate link" button (only when status === "active") with a confirm dialog

Files to read first

  • `apps/dashboard/src/app/(dashboard)/payments/[id]/page.tsx` — sibling detail page, mirror the layout
  • `apps/dashboard/src/components/links/LinkCard.tsx` — already renders much of the same data
  • `apps/dashboard/src/components/links/LinkStatusBadge.tsx` — reuse as-is

Acceptance criteria

  • `/links/[id]` renders for a valid link the merchant owns
  • 404 when the link belongs to a different merchant (API enforces this — page should show a friendly "not found")
  • Copy URL button copies + toasts confirmation
  • Download QR button triggers a PNG download
  • Stats tile renders (zeros if no payments)
  • Recent payments table renders or shows empty state
  • Deactivate flow: confirm dialog → DELETE → status badge flips to "Deactivated" → button disappears
  • Breadcrumb / back link to `/links`
  • Loading skeleton matches the existing dashboard skeleton style
  • tsc clean, no console errors

Estimated effort

~0.5 day if PR 8's components are in place.

Metadata

Metadata

Labels

Stellar WaveIssues in the Stellar wave programdashboardMerchant Dashboard productenhancementNew feature or requestfrontendFrontend/UI workpayment-linksPayment Links product

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions