feat: all project setup

This commit is contained in:
ivannoskov
2025-11-10 12:07:24 +03:00
parent fbfd7719bb
commit b0a9934220
99 changed files with 19597 additions and 0 deletions

186
app/(dashboard)/page.tsx Normal file
View File

@@ -0,0 +1,186 @@
"use client";
// ============================================================================
// Dashboard Home Page
// ============================================================================
import React, { useEffect, useState } from "react";
import { DashboardHeader } from "@/components/layout/dashboard-header";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { analyticsApi } from "@/lib/api";
import {
formatCurrency,
formatNumber,
formatMetric,
formatPercent,
} from "@/lib/utils/format";
import {
BarChart3,
TrendingUp,
Users,
ShoppingCart,
Loader2,
} from "lucide-react";
import type { AnalyticsOverview } from "@/lib/types/api";
export default function DashboardPage() {
const [overview, setOverview] = useState<AnalyticsOverview | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadOverview = async () => {
try {
const data = await analyticsApi.overview();
setOverview(data);
} catch (error) {
console.error("Error loading overview:", error);
} finally {
setLoading(false);
}
};
loadOverview();
}, []);
return (
<>
<DashboardHeader breadcrumbs={[{ label: "Главная" }]} />
<div className="flex flex-1 flex-col gap-4 p-4 pt-0 mt-4">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">
Всего закупов
</CardTitle>
<ShoppingCart className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{loading ? (
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
) : (
<>
<div className="text-2xl font-bold">
{formatNumber(overview?.totalPurchases)}
</div>
<p className="text-xs text-muted-foreground">
{formatNumber(overview?.purchasesChange || 0, true)} за
прошлый месяц
</p>
</>
)}
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">
Подписчиков привлечено
</CardTitle>
<Users className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{loading ? (
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
) : (
<>
<div className="text-2xl font-bold">
{formatNumber(overview?.totalFollowers)}
</div>
<p className="text-xs text-muted-foreground">
{formatNumber(overview?.followersChange || 0, true)} за
прошлый месяц
</p>
</>
)}
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Средний CPF</CardTitle>
<TrendingUp className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{loading ? (
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
) : (
<>
<div className="text-2xl font-bold">
{formatMetric(overview?.averageCpf)}
</div>
<p className="text-xs text-muted-foreground">
{formatPercent(overview?.cpfChange || 0, true)} от прошлого
месяца
</p>
</>
)}
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Средний CPM</CardTitle>
<BarChart3 className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
{loading ? (
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
) : (
<>
<div className="text-2xl font-bold">
{formatMetric(overview?.averageCpm)}
</div>
<p className="text-xs text-muted-foreground">
{formatPercent(overview?.cpmChange || 0, true)} от прошлого
месяца
</p>
</>
)}
</CardContent>
</Card>
</div>
<div className="grid gap-4 md:grid-cols-1">
<Card>
<CardHeader>
<CardTitle>Быстрый старт</CardTitle>
<CardDescription>Начните с основных действий</CardDescription>
</CardHeader>
<CardContent className="space-y-2">
<a
href="/purchases/new"
className="block text-sm text-primary hover:underline"
>
Создать новый закуп
</a>
<a
href="/creatives/new"
className="block text-sm text-primary hover:underline"
>
Создать креатив
</a>
<a
href="/external-channels/import"
className="block text-sm text-primary hover:underline"
>
Импортировать каналы
</a>
<a
href="/analytics"
className="block text-sm text-primary hover:underline"
>
Посмотреть аналитику
</a>
</CardContent>
</Card>
</div>
</div>
</>
);
}