hellth-hub/apps/admin/app/(authed)/aktivitaetsfeed/page.tsx

85 lines
3.9 KiB
TypeScript
Raw Normal View History

"use client";
import Link from "next/link";
import { trpc } from "@/lib/trpc";
function statusLabel(status: string) {
if (status === "accepted") return "übernommen";
if (status === "rejected") return "abgelehnt";
if (status === "pending") return "in Prüfung";
return status;
}
export default function AktivitaetsfeedPage() {
const utils = trpc.useUtils();
const feedQuery = trpc.health.adminActivityFeed.useQuery();
const reviewStoreChange = trpc.health.reviewStoreChangeRequest.useMutation({
onSuccess: async () => {
await utils.health.adminActivityFeed.invalidate();
await utils.health.listStores.invalidate();
},
});
const items = feedQuery.data ?? [];
return (
<div className="mx-auto max-w-5xl space-y-5 pb-24">
<header className="rounded-[2rem] bg-white p-6 shadow-sm ring-1 ring-gray-100">
<p className="text-sm font-black uppercase text-[#0F766E]">Admin</p>
<h1 className="mt-2 text-4xl font-black tracking-normal text-gray-950">Activity Feed</h1>
<p className="mt-2 max-w-2xl text-sm font-semibold text-gray-400">
Eingereichte Rezeptvorschläge, Marktänderungen und weitere prüfpflichtige Aktionen an einem Ort.
</p>
</header>
<section className="rounded-[2rem] bg-white p-5 shadow-sm ring-1 ring-gray-100">
<div className="space-y-3">
{items.map((item) => (
<div key={`${item.type}-${item.id}`} className="rounded-3xl bg-gray-50 p-4">
<div className="flex flex-wrap items-start justify-between gap-3">
<div>
<p className="text-xs font-black uppercase text-[#0F766E]">
{item.type === "recipe_submission" ? "Rezeptvorschlag" : "Marktänderung"}
</p>
<h2 className="mt-1 text-lg font-black text-gray-950">{item.title}</h2>
<p className="mt-1 text-sm font-bold text-gray-400">{item.actorName}{item.actorEmail ? ` · ${item.actorEmail}` : ""}</p>
<p className="mt-1 text-sm font-semibold text-gray-500">{item.detail}</p>
</div>
<div className="text-right">
<span className={`rounded-full px-3 py-1 text-xs font-black ${
item.status === "accepted"
? "bg-emerald-100 text-emerald-700"
: item.status === "rejected"
? "bg-red-100 text-red-700"
: "bg-amber-100 text-amber-700"
}`}>
{statusLabel(item.status)}
</span>
<p className="mt-2 text-xs font-bold text-gray-400">{new Date(item.createdAt).toLocaleString("de-DE")}</p>
</div>
</div>
<div className="mt-3 flex flex-wrap gap-2">
<Link href={item.href} className="rounded-full bg-white px-4 py-2 text-xs font-black text-gray-700">
Öffnen
</Link>
{item.type === "store_change" && item.status === "pending" ? (
<>
<button type="button" onClick={() => reviewStoreChange.mutate({ id: item.id, action: "accept" })} className="rounded-full bg-[#0F766E] px-4 py-2 text-xs font-black text-white">
Übernehmen
</button>
<button type="button" onClick={() => reviewStoreChange.mutate({ id: item.id, action: "reject" })} className="rounded-full bg-red-50 px-4 py-2 text-xs font-black text-red-700">
Ablehnen
</button>
</>
) : null}
</div>
</div>
))}
{!items.length && !feedQuery.isLoading ? (
<p className="rounded-3xl bg-gray-50 p-4 text-sm font-bold text-gray-400">Aktuell gibt es keine Einträge.</p>
) : null}
</div>
</section>
</div>
);
}