Skip to content

Commit c6a5a0d

Browse files
TokenBriceclaude
andcommitted
feat(frontend): add inline data correction triggers on detail page and table
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 93289d9 commit c6a5a0d

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

src/app/stablecoin/[id]/client.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"use client";
22

3+
import { useState } from "react";
34
import Image from "next/image";
45
import Link from "next/link";
5-
import { ArrowLeft, ArrowLeftRight } from "lucide-react";
6+
import { ArrowLeft, ArrowLeftRight, Flag } from "lucide-react";
7+
import { FeedbackModal } from "@/components/feedback-modal";
68
import { useSupplyHistory, useStablecoins } from "@/hooks/use-stablecoins";
79
import { useDepegEvents } from "@/hooks/use-depeg-events";
810
import { usePegSummary } from "@/hooks/use-peg-summary";
@@ -56,6 +58,7 @@ interface StablecoinDetailClientProps {
5658
}
5759

5860
export default function StablecoinDetailClient({ id, summary, coin, logoSrc }: StablecoinDetailClientProps) {
61+
const [feedbackOpen, setFeedbackOpen] = useState(false);
5962
const { data: supplyData, isLoading: supplyLoading, isError: supplyError } = useSupplyHistory(id);
6063
const { data: listData, isLoading: listLoading, isError: listError, dataUpdatedAt: listUpdatedAt } = useStablecoins();
6164
const { data: depegData } = useDepegEvents(id);
@@ -240,6 +243,13 @@ export default function StablecoinDetailClient({ id, summary, coin, logoSrc }: S
240243
</span>
241244
)}
242245
</p>
246+
<button
247+
onClick={() => setFeedbackOpen(true)}
248+
className="mt-2 flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors"
249+
>
250+
<Flag className="h-3 w-3" />
251+
Report data issue
252+
</button>
243253
</div>
244254
</div>
245255
</div>
@@ -403,6 +413,15 @@ export default function StablecoinDetailClient({ id, summary, coin, logoSrc }: S
403413
<DepegHistory stablecoinId={id} earliestTrackingDate={earliestTrackingDate} />
404414
</section>
405415
)}
416+
417+
<FeedbackModal
418+
open={feedbackOpen}
419+
onOpenChange={setFeedbackOpen}
420+
defaultType="data-correction"
421+
stablecoinId={coin.id}
422+
stablecoinName={coin.name}
423+
pegValue={coinData.price != null ? `$${coinData.price.toFixed(6)}` : undefined}
424+
/>
406425
</div>
407426
);
408427
}

src/components/stablecoin-table.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
import { Badge } from "@/components/ui/badge";
1515
import { Button } from "@/components/ui/button";
1616
import { Skeleton } from "@/components/ui/skeleton";
17-
import { Download, Columns3 } from "lucide-react";
17+
import { Download, Columns3, Flag } from "lucide-react";
18+
import { FeedbackModal } from "@/components/feedback-modal";
1819
import {
1920
DropdownMenu,
2021
DropdownMenuTrigger,
@@ -293,6 +294,8 @@ export function StablecoinTable({ data, isLoading, activeFilters, logos, pegRate
293294
});
294295
}, [filtered, sort, effectiveSortKey, pegScores, dexLiquidity, reportCards, pegRates, metaById]);
295296

297+
const [feedbackCoin, setFeedbackCoin] = useState<{ id: string; name: string } | null>(null);
298+
296299
// Reset scroll when filters, search, or sort change
297300
const [prev, setPrev] = useState({ filtered, sort });
298301
if (prev.filtered !== filtered || prev.sort !== sort) {
@@ -518,6 +521,7 @@ export function StablecoinTable({ data, isLoading, activeFilters, logos, pegRate
518521
{isVisible("flags") && (
519522
<TableHead className="hidden md:table-cell text-center">Flags</TableHead>
520523
)}
524+
<TableHead className="w-8" />
521525
</TableRow>
522526
</TableHeader>
523527
<TableBody>
@@ -537,7 +541,7 @@ export function StablecoinTable({ data, isLoading, activeFilters, logos, pegRate
537541
return (
538542
<TableRow
539543
key={coin.id}
540-
className="cursor-pointer focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none"
544+
className="group cursor-pointer focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none"
541545
style={{ height: ROW_HEIGHT }}
542546
onClick={() => router.push(`/stablecoin/${coin.id}`)}
543547
onMouseEnter={() => prefetch(coin.id)}
@@ -700,6 +704,16 @@ export function StablecoinTable({ data, isLoading, activeFilters, logos, pegRate
700704
</div>
701705
</TableCell>
702706
)}
707+
<TableCell className="w-8 p-1 text-center">
708+
<button
709+
onClick={(e) => { e.stopPropagation(); setFeedbackCoin({ id: coin.id, name: coin.name }); }}
710+
className="opacity-0 group-hover:opacity-100 rounded p-1 text-muted-foreground hover:text-foreground transition-all"
711+
aria-label={`Report data issue for ${coin.name}`}
712+
title="Report data issue"
713+
>
714+
<Flag className="h-3 w-3" />
715+
</button>
716+
</TableCell>
703717
</TableRow>
704718
);
705719
})}
@@ -742,6 +756,16 @@ export function StablecoinTable({ data, isLoading, activeFilters, logos, pegRate
742756
</span>
743757
</div>
744758
)}
759+
760+
{feedbackCoin && (
761+
<FeedbackModal
762+
open={!!feedbackCoin}
763+
onOpenChange={(open) => { if (!open) setFeedbackCoin(null); }}
764+
defaultType="data-correction"
765+
stablecoinId={feedbackCoin.id}
766+
stablecoinName={feedbackCoin.name}
767+
/>
768+
)}
745769
</div>
746770
);
747771
}

0 commit comments

Comments
 (0)