i18n observability hub: analytics pages and log tables.
Translate analytics overview/activity/economy plus peak-hours/revenue charts, and audit/chat/commands/trades DataTables (en/nl/it). Includes prior events/polls detail i18n. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
a25008deb5
commit
bcbdca841b
13 files changed
+576
-211
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { ArrowLeftRight } from "lucide-react";
|
||||
import { getLocale, getTranslations } from "next-intl/server";
|
||||
import { redirect } from "next/navigation";
|
||||
import { RevenueChart } from "@/components/admin/revenue-chart";
|
||||
import { StatsCard } from "@/components/admin/stats-card";
|
||||
@@ -41,7 +42,7 @@ async function safeCount(fn: () => Promise<number>): Promise<number> {
|
||||
}
|
||||
}
|
||||
|
||||
async function getEconomyData(): Promise<EconomyData> {
|
||||
async function getEconomyData(locale: string): Promise<EconomyData> {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const todayStart = now - (now % 86400);
|
||||
const weekAgo = now - 7 * 86400;
|
||||
@@ -95,7 +96,7 @@ async function getEconomyData(): Promise<EconomyData> {
|
||||
const dayStart = todayStart - i * 86400;
|
||||
const date = new Date(dayStart * 1000);
|
||||
revenueData.push({
|
||||
label: date.toLocaleDateString("en", { weekday: "short" }),
|
||||
label: date.toLocaleDateString(locale, { weekday: "short" }),
|
||||
credits: 0,
|
||||
points: 0,
|
||||
});
|
||||
@@ -153,33 +154,37 @@ export default async function EconomyPage() {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const data = await getEconomyData();
|
||||
const locale = await getLocale();
|
||||
const t = await getTranslations("pages.admin.analytics.economy");
|
||||
const data = await getEconomyData(locale);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
||||
<StatsCard
|
||||
title="Credits in Circulation"
|
||||
value={data.totalCredits.toLocaleString()}
|
||||
description="Total credits across all users"
|
||||
title={t("creditsInCirculation")}
|
||||
value={data.totalCredits.toLocaleString(locale)}
|
||||
description={t("creditsDescription")}
|
||||
icon={<CurrencyIcon kind="credits" size={16} />}
|
||||
/>
|
||||
<StatsCard
|
||||
title="Pixels in Circulation"
|
||||
value={data.totalPixels.toLocaleString()}
|
||||
description="Total pixels across all users"
|
||||
title={t("pixelsInCirculation")}
|
||||
value={data.totalPixels.toLocaleString(locale)}
|
||||
description={t("pixelsDescription")}
|
||||
icon={<CurrencyIcon kind="pixels" size={16} />}
|
||||
/>
|
||||
<StatsCard
|
||||
title="Points in Circulation"
|
||||
value={data.totalPoints.toLocaleString()}
|
||||
description="Total points across all users"
|
||||
title={t("pointsInCirculation")}
|
||||
value={data.totalPoints.toLocaleString(locale)}
|
||||
description={t("pointsDescription")}
|
||||
icon={<CurrencyIcon kind="diamonds" size={16} />}
|
||||
/>
|
||||
<StatsCard
|
||||
title="Weekly Trades"
|
||||
value={data.weekTrades.toLocaleString()}
|
||||
description={`${data.marketplaceActive} marketplace listings`}
|
||||
title={t("weeklyTrades")}
|
||||
value={data.weekTrades.toLocaleString(locale)}
|
||||
description={t("marketplaceListings", {
|
||||
count: data.marketplaceActive,
|
||||
})}
|
||||
icon={<ArrowLeftRight className="h-4 w-4" />}
|
||||
/>
|
||||
</div>
|
||||
@@ -189,24 +194,24 @@ export default async function EconomyPage() {
|
||||
<div className="grid gap-6 md:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Shop Revenue (7d)</CardTitle>
|
||||
<CardTitle>{t("shopRevenueTitle")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Purchases</span>
|
||||
<span className="text-muted-foreground">{t("purchases")}</span>
|
||||
<span className="font-medium">{data.shopPurchases}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Credits spent</span>
|
||||
<span className="text-muted-foreground">{t("creditsSpent")}</span>
|
||||
<span className="font-medium">
|
||||
{data.shopCreditsSpent.toLocaleString()}
|
||||
{data.shopCreditsSpent.toLocaleString(locale)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Points spent</span>
|
||||
<span className="text-muted-foreground">{t("pointsSpent")}</span>
|
||||
<span className="font-medium">
|
||||
{data.shopPointsSpent.toLocaleString()}
|
||||
{data.shopPointsSpent.toLocaleString(locale)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -214,16 +219,18 @@ export default async function EconomyPage() {
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Marketplace</CardTitle>
|
||||
<CardTitle>{t("marketplaceTitle")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Active listings</span>
|
||||
<span className="text-muted-foreground">
|
||||
{t("activeListings")}
|
||||
</span>
|
||||
<span className="font-medium">{data.marketplaceActive}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Sold (7d)</span>
|
||||
<span className="text-muted-foreground">{t("sold7d")}</span>
|
||||
<span className="font-medium">{data.marketplaceSold}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -231,26 +238,26 @@ export default async function EconomyPage() {
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Currency Distribution</CardTitle>
|
||||
<CardTitle>{t("currencyDistributionTitle")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Credits</span>
|
||||
<span className="text-muted-foreground">{t("credits")}</span>
|
||||
<span className="font-medium">
|
||||
{data.totalCredits.toLocaleString()}
|
||||
{data.totalCredits.toLocaleString(locale)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Pixels</span>
|
||||
<span className="text-muted-foreground">{t("pixels")}</span>
|
||||
<span className="font-medium">
|
||||
{data.totalPixels.toLocaleString()}
|
||||
{data.totalPixels.toLocaleString(locale)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Points</span>
|
||||
<span className="text-muted-foreground">{t("points")}</span>
|
||||
<span className="font-medium">
|
||||
{data.totalPoints.toLocaleString()}
|
||||
{data.totalPoints.toLocaleString(locale)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user