diff --git a/src/app/dashboard/contributor/page.tsx b/src/app/dashboard/contributor/page.tsx index bfc89e9..cdcecd6 100644 --- a/src/app/dashboard/contributor/page.tsx +++ b/src/app/dashboard/contributor/page.tsx @@ -217,8 +217,12 @@ export default function ContributorDashboardPage() { /> )} + {/* "available" is every open bounty in whatever order the backend/mock + data returns, sliced to the first 4 — no relevance scoring against + this contributor's history/languages/orgs. "Open bounties" is the + honest label until real personalization exists (#239). */}

- Recommended for you + Open bounties

{available.slice(0, 4).map((bounty) => ( diff --git a/src/app/dashboard/maintainer/page.tsx b/src/app/dashboard/maintainer/page.tsx index 3e6ca6b..52e05d8 100644 --- a/src/app/dashboard/maintainer/page.tsx +++ b/src/app/dashboard/maintainer/page.tsx @@ -1,3 +1,4 @@ +import Link from "next/link"; import { Layers, Clock, Coins, FolderGit2, CheckCircle2 } from "lucide-react"; import { fetchBounties } from "@/lib/api"; import { mockBounties, recentActivity, bountiesCompletedSparkline } from "@/lib/mock-data"; @@ -9,7 +10,6 @@ import { EmptyState } from "@/components/ui/EmptyState"; import { Avatar } from "@/components/ui/Avatar"; import { formatCurrency } from "@/lib/utils"; import { PipelineBoard, ESCROW_LOCKED_EXCLUDED_STATUSES } from "./PipelineBoard"; -import type { Bounty } from "@/types"; export const metadata = { title: "Maintainer Dashboard | MergeFi", @@ -17,17 +17,17 @@ export const metadata = { export default async function MaintainerDashboardPage() { // Maintainer dashboard is a Server Component (no client-side loading state). - // We wrap fetchBounties in a try/catch so that if the fetch fails, the cards - // explicitly show "Error loading data" rather than rendering stale zeros or - // crashing the page render. - let bounties: Bounty[] = []; - let statStatus: "loaded" | "error" = "loaded"; - - try { - bounties = await fetchBounties(mockBounties); - } catch { - statStatus = "error"; - } + // fetchBounties (lib/api.ts) already catches every failure internally and + // resolves to the `fallback` argument instead of rejecting — it can never + // throw, so a try/catch around it here would be dead code. Detect the + // fallback case instead by reference: fetchBounties returns the exact + // fallback array on failure, but always a freshly-mapped array (a new + // reference, even if its contents happened to match) on a real live + // fetch, so this reliably distinguishes "live data" from "backend down, + // showing mockBounties" without changing fetchBounties' shared contract + // (#240). + const bounties = await fetchBounties(mockBounties); + const statStatus: "loaded" | "error" = bounties === mockBounties ? "error" : "loaded"; const needsReview = bounties.filter((b) => b.status === "in_review"); const open = bounties.filter((b) => b.status === "open" || b.status === "funded"); @@ -42,9 +42,15 @@ export default async function MaintainerDashboardPage() { title="Bounty pipeline" subtitle="Create bounties from your GitHub issues and approve completed work. Payout release happens automatically once a linked pull request is merged." action={ - - Create bounty - + // Bounties are created from your GitHub issues (per the subtitle + // above) — /issues is the same destination the contributor and + // sponsor dashboards' equivalent action buttons already link to + // for picking a bounty to work with (#241). + + + Create bounty + + } > {/* Pass statStatus so that a fetchBounties failure renders error states diff --git a/src/app/page.tsx b/src/app/page.tsx index ec2a3dd..c836ad5 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -25,6 +25,7 @@ import { faqs, } from "@/lib/mock-data"; import { formatCurrency } from "@/lib/utils"; +import { STELLAR_NETWORK } from "@/lib/config"; const integrations = [ { icon: Code2, label: "GitHub" }, @@ -90,7 +91,7 @@ export default function HomePage() {
- Built for Stellar Mainnet + {STELLAR_NETWORK === "PUBLIC" ? "Built for Stellar Mainnet" : "Built for Stellar (Testnet)"}

Merge code.