diff --git a/src/components/bounty/ClaimButton.test.tsx b/src/components/bounty/ClaimButton.test.tsx
index 9c49b61..835cb75 100644
--- a/src/components/bounty/ClaimButton.test.tsx
+++ b/src/components/bounty/ClaimButton.test.tsx
@@ -108,6 +108,51 @@ describe("ClaimButton", () => {
expect(screen.queryByText(/Claimed by:/)).not.toBeInTheDocument();
});
+ describe("the claimant's own view of their claim (#699)", () => {
+ it("shows 'You're working on this' with PR instructions instead of the loser's message", () => {
+ mockAuth({ id: "user-1", stellarAddress: "GSTELLAR" });
+ mockHooks(
+ {},
+ {
+ status: "claimed",
+ bounty: { id: "b1", status: "claimed", claimedById: "user-1", issueNumber: 42 },
+ },
+ );
+ render();
+
+ expect(screen.getByText("You're working on this")).toBeInTheDocument();
+ expect(screen.getByText("Fixes #42")).toBeInTheDocument();
+ expect(screen.queryByText(/This bounty has already been/)).not.toBeInTheDocument();
+ });
+
+ it("still shows the generic already-claimed view to a different signed-in user", () => {
+ mockAuth({ id: "user-2", stellarAddress: "GOTHER" });
+ mockHooks(
+ {},
+ {
+ status: "claimed",
+ bounty: { id: "b1", status: "claimed", claimedById: "user-1", claimedBy: "alice" },
+ },
+ );
+ render();
+
+ expect(screen.getByText(/This bounty has already been/)).toBeInTheDocument();
+ expect(screen.queryByText("You're working on this")).not.toBeInTheDocument();
+ });
+
+ it("shows the generic already-claimed view when signed out", () => {
+ mockAuth(null);
+ mockHooks(
+ {},
+ { status: "claimed", bounty: { id: "b1", status: "claimed", claimedById: "user-1" } },
+ );
+ render();
+
+ expect(screen.getByText(/This bounty has already been/)).toBeInTheDocument();
+ expect(screen.queryByText("You're working on this")).not.toBeInTheDocument();
+ });
+ });
+
it("shows the auto-refresh hint only while polling", () => {
mockHooks({}, { isPolling: true });
render();
diff --git a/src/components/bounty/ClaimButton.tsx b/src/components/bounty/ClaimButton.tsx
index 3e11d4c..f867801 100644
--- a/src/components/bounty/ClaimButton.tsx
+++ b/src/components/bounty/ClaimButton.tsx
@@ -186,6 +186,30 @@ export function ClaimButton({
const needsPayoutWallet = !!user && !user.stellarAddress;
if (status === 'claimed') {
+ // The claimant sees this same view on every later visit too, not just
+ // right after the 5s success notice expires -- "already claimed" /
+ // "Claimed by: ..." reads like they lost a race they actually won, with
+ // no indication of what to do next (#699).
+ const isOwnClaim = !!user && !!bounty?.claimedById && bounty.claimedById === user.id;
+
+ if (isOwnClaim) {
+ return (
+
+
You're working on this
+
+ Open a pull request that says{' '}
+
+ Fixes #{bounty?.issueNumber}
+ {' '}
+ in its description. The reward releases automatically once it's merged.
+
+
+ );
+ }
+
return (