Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/app/dashboard/contributor/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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). */}
<h2 className="mt-12 text-xl font-semibold text-slate-900 dark:text-white">
Recommended for you
Open bounties
</h2>
<div className="mt-6 grid gap-4 md:grid-cols-2">
{available.slice(0, 4).map((bounty) => (
Expand Down
36 changes: 21 additions & 15 deletions src/app/dashboard/maintainer/page.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -9,25 +10,24 @@ 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",
};

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");
Expand All @@ -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={
<span className="inline-flex items-center gap-2 rounded-full bg-slate-900 px-4 py-2 text-sm font-medium text-white dark:bg-white dark:text-slate-900">
Create bounty
</span>
// 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).
<Link href="/issues">
<span className="inline-flex items-center gap-2 rounded-full bg-slate-900 px-4 py-2 text-sm font-medium text-white hover:bg-slate-800 dark:bg-white dark:text-slate-900 dark:hover:bg-slate-200">
Create bounty
</span>
</Link>
}
>
{/* Pass statStatus so that a fetchBounties failure renders error states
Expand Down
3 changes: 2 additions & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand Down Expand Up @@ -90,7 +91,7 @@ export default function HomePage() {
<div className="mx-auto max-w-6xl px-6 pb-20 pt-20 text-center">
<span className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3 py-1 text-xs font-medium text-slate-600 shadow-sm dark:border-slate-800 dark:bg-slate-900 dark:text-slate-300">
<span className="h-1.5 w-1.5 rounded-full bg-emerald-500" />
Built for Stellar Mainnet
{STELLAR_NETWORK === "PUBLIC" ? "Built for Stellar Mainnet" : "Built for Stellar (Testnet)"}
</span>
<h1 className="mx-auto mt-6 max-w-3xl text-4xl font-semibold tracking-tight text-slate-900 sm:text-6xl dark:text-white">
Merge code.
Expand Down
Loading