-
{entry.name}
+ {entry.handleSlug ? (
+
+ {entry.name}
+
+ ) : (
+
{entry.name}
+ )}
{entry.completed} Punkte-Einträge
diff --git a/apps/admin/app/(authed)/profil/[handle]/page.tsx b/apps/admin/app/(authed)/profil/[handle]/page.tsx
new file mode 100644
index 0000000..de404cb
--- /dev/null
+++ b/apps/admin/app/(authed)/profil/[handle]/page.tsx
@@ -0,0 +1,113 @@
+"use client";
+
+import { FireIcon, SparklesIcon } from "@heroicons/react/24/outline";
+import { useParams } from "next/navigation";
+import { DataPageLayout } from "@/app/_components/data-page-layout";
+import { trpc } from "@/lib/trpc";
+
+export default function PublicProfilePage() {
+ const params = useParams<{ handle: string }>();
+ const handleSlug = decodeURIComponent(params.handle ?? "");
+
+ const profileQuery = trpc.users.publicProfileByHandle.useQuery(
+ { handle: handleSlug },
+ { retry: false },
+ );
+
+ if (profileQuery.isLoading) {
+ return (
+
+ Profil wird geladen …
+
+ );
+ }
+
+ if (profileQuery.isError || !profileQuery.data) {
+ return (
+
+
+ Dieses Profil gibt es nicht oder es ist privat. Nur Mitglieder, die ihr
+ Profil öffentlich geschaltet haben, sind hier sichtbar.
+
+
+ );
+ }
+
+ const profile = profileQuery.data;
+ const initial = (profile.username ?? "?").charAt(0).toUpperCase();
+
+ return (
+
+
+
+ {profile.image ? (
+ // eslint-disable-next-line @next/next/no-img-element
+

+ ) : (
+
+ {initial}
+
+ )}
+
+
+ {profile.username}
+ #{profile.discriminator}
+
+ {profile.bio ? (
+
{profile.bio}
+ ) : (
+
Keine Bio hinterlegt.
+ )}
+
+
+
+
+ }
+ label="Punkte gesamt"
+ value={profile.points.total.toLocaleString("de-DE")}
+ />
+ }
+ label="Punkte (30 Tage)"
+ value={profile.points.last30Days.toLocaleString("de-DE")}
+ />
+ }
+ label="Aktive Tage (7 Tage)"
+ value={`${profile.activeDaysLast7}/7`}
+ />
+
+
+
+ Gesundheitsdaten wie Gewicht, Kalorien und Ziele sind immer privat und
+ werden hier nie angezeigt.
+
+
+
+ );
+}
+
+function StatCard({
+ icon,
+ label,
+ value,
+}: {
+ icon: React.ReactNode;
+ label: string;
+ value: string;
+}) {
+ return (
+
+
+ {icon}
+ {label}
+
+
{value}
+
+ );
+}
diff --git a/packages/api/src/trpc/routers/health/dashboard.ts b/packages/api/src/trpc/routers/health/dashboard.ts
index 3c0beb5..9039ca0 100644
--- a/packages/api/src/trpc/routers/health/dashboard.ts
+++ b/packages/api/src/trpc/routers/health/dashboard.ts
@@ -1,6 +1,7 @@
import { schema } from "@hellth/db";
import { and, eq, isNull } from "drizzle-orm";
import { z } from "zod";
+import { handleToSlug } from "../../../lib/handle";
import { platformProcedure, protectedProcedure, router } from "../../init";
import {
auditHealthMutation,