From dbc416c43ccfcc90adfc723289ef3760500ca525 Mon Sep 17 00:00:00 2001 From: neodk2004 Date: Sun, 4 Oct 2026 15:01:51 +0200 Subject: [PATCH] feat(admin): Tierliste zeigt alle erreichten Raenge found.md: Admin -> Tiere zeigte nur den hoechsten Rang (Cache referralRankId). Die Liste laedt jetzt alle ReferralRankAchievements des Owners (nach Schwelle) und zeigt sie als Symbole, unabhaengig vom Vorteil NAME_BADGE; entzogene Raenge ausgegraut, Tooltip mit 'manuell vergeben' / 'entzogen'. Co-Authored-By: Claude Opus 5.5 --- src/app/p/[secret]/pets/page.tsx | 4 +- .../admin/pets/AchievedRankBadges.tsx | 39 +++++++++++++++++++ src/trpc/routers/pet-admin.ts | 5 +++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/components/admin/pets/AchievedRankBadges.tsx diff --git a/src/app/p/[secret]/pets/page.tsx b/src/app/p/[secret]/pets/page.tsx index 283ddb0..43b4900 100644 --- a/src/app/p/[secret]/pets/page.tsx +++ b/src/app/p/[secret]/pets/page.tsx @@ -9,7 +9,7 @@ import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { PetAvatar } from "@/components/ui/pet-avatar"; -import { ReferralRankBadge } from "@/components/referrals/ReferralRankBadge"; +import { AchievedRankBadges } from "@/components/admin/pets/AchievedRankBadges"; import { PetDetailSheet } from "@/components/admin/pets/PetDetailSheet"; type Filter = "all" | "verified" | "founding" | "ranked" | "bannedOwner"; @@ -135,7 +135,7 @@ export default function AdminPetsPage() { {pet.isVerified && } {pet.isFoundingMember && } - + {pet.species.name} diff --git a/src/components/admin/pets/AchievedRankBadges.tsx b/src/components/admin/pets/AchievedRankBadges.tsx new file mode 100644 index 0000000..4db26a0 --- /dev/null +++ b/src/components/admin/pets/AchievedRankBadges.tsx @@ -0,0 +1,39 @@ +"use client"; + +import { useReferralRanks } from "@/hooks/useReferralRanks"; +import { ReferralIcon } from "@/components/referrals/ReferralRankBadge"; + +type Achievement = { rankId: string; revokedAt: Date | string | null; grantedManually: boolean }; + +/** + * Admin → Tiere: alle Ränge, die der Owner je erreicht hat (found.md — vorher + * nur der höchste). Unabhängig vom Vorteil NAME_BADGE, weil das hier eine + * Übersicht fürs Team ist. Entzogene Ränge bleiben ausgegraut sichtbar. + */ +export function AchievedRankBadges({ achievements }: { achievements: Achievement[] }) { + const { byId } = useReferralRanks(); + const items = achievements.flatMap((achievement) => { + const rank = byId.get(achievement.rankId); + return rank ? [{ achievement, rank }] : []; + }); + if (items.length === 0) return null; + + return ( + + {items.map(({ achievement, rank }) => { + const isRevoked = !!achievement.revokedAt; + const status = isRevoked ? " · entzogen" : achievement.grantedManually ? " · manuell vergeben" : ""; + return ( + + + + ); + })} + + ); +} diff --git a/src/trpc/routers/pet-admin.ts b/src/trpc/routers/pet-admin.ts index b35e115..16c740f 100644 --- a/src/trpc/routers/pet-admin.ts +++ b/src/trpc/routers/pet-admin.ts @@ -97,6 +97,11 @@ export const petAdminRouter = router({ sponsorSince: true, sponsorPeriodEnd: true, ban: { select: { expiresAt: true } }, + // found.md: die Liste zeigt alle erreichten Ränge, nicht nur den höchsten (Cache referralRankId). + rankAchievements: { + select: { rankId: true, revokedAt: true, grantedManually: true }, + orderBy: { rank: { threshold: "asc" } }, + }, }, }, _count: { select: { posts: true, followers: true } },