feat(cms): improve catalog, editorial recovery and operations
CI / check (push) Successful in 52s
CI / deploy (push) Successful in 2m10s
CI / publish-container (push) Failing after 1m18s

This commit is contained in:
Simo committed 2026-09-09 19:36:15 +02:00
1 parent 2fead134e6
commit c389c3893d
122 files changed
+8137 -703

No files matched your search

+63 -8
View File
@@ -10,7 +10,7 @@ import { ProfileImage } from "@/components/shared/profile-image";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { SurfaceCard } from "@/components/surface-card";
import { auth } from "@/lib/auth";
import { avatarImageUrl } from "@/lib/format";
import { avatarImageUrl, slugify } from "@/lib/format";
import { loadUserDashboard } from "@/lib/services/user-dashboard";
import CopyReferralButton from "./CopyReferralButton";
import styles from "./dashboard.module.css";
@@ -75,10 +75,11 @@ export default async function MePage({
referralsRows,
friends,
currencyRows,
dashboardEvent,
} = data;
const userSettings = userSettingsRows[0];
const friendCount = Number(friendCountRows[0]?.value ?? 0);
const unreadCount = Number(unreadCountRows[0]?.value ?? 0);
const unreadCount = Number(unreadCountRows?.[0]?.value ?? 0);
const needed = Math.max(1, Number.parseInt(neededRaw ?? "5", 10) || 5);
const rewardAmount = Number.parseInt(rewardAmountRaw ?? "30", 10) || 0;
const rewardCurrency = (
@@ -173,12 +174,20 @@ export default async function MePage({
{ href: "/shop", label: t("shop"), count: 0 },
].map((link) => (
<Link key={link.href} href={link.href} className={styles.shortcut}>
{link.label}
<span>
{link.label}
{link.href === "/messages" && (
<span className={styles.shortcutHint}>
{unreadCountRows === null
? t("messagesUnavailable")
: unreadCount > 0
? t("unread", { count: unreadCount })
: t("messagesCaughtUp")}
</span>
)}
</span>
{link.count > 0 && (
<span
className={styles.count}
title={t("unread", { count: link.count })}
>
<span className={styles.count} aria-hidden="true">
{link.count > 99 ? "99+" : link.count}
</span>
)}
@@ -199,6 +208,48 @@ export default async function MePage({
</SurfaceCard>
))}
</section>
<SurfaceCard
title={t("eventTitle")}
actionHref="/events"
actionLabel={t("allEvents")}
bodyClassName="p-5"
>
{dashboardEvent.unavailable ? (
<p className="muted" role="status">
{t("eventsUnavailable")}
</p>
) : dashboardEvent.event ? (
<div className={styles.event}>
<div className={styles.eventDetails}>
<span className={styles.eventPhase}>
{t(
dashboardEvent.event.phase === "ongoing"
? "eventOngoing"
: "eventUpcoming",
)}
</span>
<h2>{dashboardEvent.event.title}</h2>
<p className="muted">
{dashboardEvent.event.typeName} ·{" "}
<time dateTime={dashboardEvent.event.startsAt.toISOString()}>
{format.dateTime(dashboardEvent.event.startsAt, {
dateStyle: "medium",
timeStyle: "short",
})}
</time>
</p>
</div>
<Link
href={`/events/${slugify(dashboardEvent.event.title)}-${dashboardEvent.event.id}`}
className="btn btn-outline"
>
{t("eventDetails")} →
</Link>
</div>
) : (
<p className="muted">{t("noUpcomingEvents")}</p>
)}
</SurfaceCard>
<div className={styles.columns}>
<div className={styles.stack}>
<SurfaceCard
@@ -236,7 +287,11 @@ export default async function MePage({
bodyClassName="p-5"
>
<p className="muted">{t("roomsHint")}</p>
{recentRooms.length === 0 ? (
{recentRooms === null ? (
<p className="muted" role="status">
{t("roomsUnavailable")}
</p>
) : recentRooms.length === 0 ? (
<p className="muted">{t("noRooms")}</p>
) : (
<div className={styles.rooms}>