feat(verification): pin evidence directly above each checklist item

The review dialog only showed data on the card; the checklist itself was
just labels+checkboxes. Now each item shows its own evidence right above
the checkbox (bio/species for authenticity, avatar+bio completeness,
ban+warning status for standing, join date/posts/followers for
presence) — double verification so a moderator can't check a box from
memory instead of the actual data.
This commit is contained in:
admin committed 2026-08-12 10:24:06 +02:00
1 parent 3a5b72b0f7
commit 4d34b4cd3d
1 file changed
+63 -15
+63 -15
View File
@@ -102,6 +102,51 @@ export default function AdminVerificationPage() {
const allChecked = Object.values(checklist).every(Boolean);
const missingLabels = CHECKLIST.filter((c) => !checklist[c.key]).map((c) => c.label);
const activeRequest = requests.find((r) => r.id === reviewTarget);
// Repeats the same profile data already shown on the card, but pinned
// directly above the matching checkbox — double verification so nothing
// gets checked off from memory instead of the actual evidence.
function renderEvidence(key: ChecklistKey) {
if (!activeRequest) return null;
const pet = activeRequest.pet;
switch (key) {
case "meetsAuthenticity":
return (
<>
<span className="font-medium text-zinc-300">{pet.name}</span> ·{" "}
{pet.breed?.name ?? pet.species.name}
{pet.bio ? <> — &ldquo;{pet.bio}&rdquo;</> : <> — no bio set</>}
</>
);
case "meetsCompleteProfile":
return (
<>
Avatar {pet.avatarKey ? "✓ set" : "✗ missing"} · Bio {pet.bio ? "✓ set" : "✗ missing"}
</>
);
case "meetsGoodStanding":
return pet.owner.ban ? (
<span className="text-red-400">
Banned{pet.owner.ban.reason ? `: ${pet.owner.ban.reason}` : ""}
</span>
) : pet.owner._count.warnings > 0 ? (
<span className="text-yellow-400">
No ban, but {pet.owner._count.warnings} warning
{pet.owner._count.warnings !== 1 ? "s" : ""}
</span>
) : (
<span className="text-blue-400">No ban, no warnings</span>
);
case "meetsEstablishedPresence":
return (
<>
Joined {new Date(pet.createdAt).toLocaleDateString()} · {pet._count.posts} posts ·{" "}
{pet._count.followers} followers
</>
);
}
}
return (
<div className="space-y-6">
@@ -265,22 +310,25 @@ export default function AdminVerificationPage() {
<DialogTitle>Review request</DialogTitle>
</DialogHeader>
<div className="space-y-3">
<div className="space-y-2">
{CHECKLIST.map((c) => (
<label key={c.key} className="flex items-start gap-3 cursor-pointer">
<input
type="checkbox"
checked={checklist[c.key]}
onChange={(e) =>
setChecklist((prev) => ({ ...prev, [c.key]: e.target.checked }))
}
className="mt-0.5 h-4 w-4 shrink-0 accent-blue-500"
/>
<span>
<span className="block text-sm text-zinc-100">{c.label}</span>
<span className="block text-xs text-zinc-500">{c.hint}</span>
</span>
</label>
<div key={c.key} className="rounded-lg border border-zinc-800 bg-zinc-950/40 p-2.5">
<p className="text-xs text-zinc-400 mb-1.5">{renderEvidence(c.key)}</p>
<label className="flex items-start gap-3 cursor-pointer">
<input
type="checkbox"
checked={checklist[c.key]}
onChange={(e) =>
setChecklist((prev) => ({ ...prev, [c.key]: e.target.checked }))
}
className="mt-0.5 h-4 w-4 shrink-0 accent-blue-500"
/>
<span>
<span className="block text-sm text-zinc-100">{c.label}</span>
<span className="block text-xs text-zinc-500">{c.hint}</span>
</span>
</label>
</div>
))}
</div>