"use client"; // ============================================================================ // Creatives Analytics Page // ============================================================================ import { useEffect, useState } from "react"; import { useParams } from "next/navigation"; import Link from "next/link"; import { Loader2, Folder, ArrowUpDown, ArrowUp, ArrowDown, } from "lucide-react"; import { DashboardHeader } from "@/components/layout/dashboard-header"; import { useWorkspace } from "@/components/providers/workspace-provider"; import { demoAwareAnalyticsApi } from "@/lib/demo"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import type { CreativeAnalyticsItem } from "@/lib/types/api"; // ============================================================================ // Helpers // ============================================================================ const formatCurrency = (value: number | null) => { if (value === null) return "—"; return new Intl.NumberFormat("ru-RU", { style: "currency", currency: "RUB", minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(value); }; const formatNumber = (value: number | null) => { if (value === null) return "—"; return new Intl.NumberFormat("ru-RU").format(value); }; // ============================================================================ // Types // ============================================================================ type SortField = | "placements" | "cost" | "subscriptions" | "views" | "cps" | "cpm"; type SortOrder = "asc" | "desc" | null; // ============================================================================ // Component // ============================================================================ export default function CreativesAnalyticsPage() { const params = useParams(); const workspaceId = params?.workspaceId as string; const { getProjectFilterId } = useWorkspace(); const projectFilterId = getProjectFilterId(); const [creatives, setCreatives] = useState([]); const [loading, setLoading] = useState(true); const [sortField, setSortField] = useState("cost"); const [sortOrder, setSortOrder] = useState("desc"); useEffect(() => { loadData(); }, [workspaceId, projectFilterId]); const loadData = async () => { try { setLoading(true); const response = await demoAwareAnalyticsApi.creatives(workspaceId, { project_id: projectFilterId, size: 100, }); setCreatives(response.items); } catch (err) { console.error("Failed to load creatives analytics:", err); } finally { setLoading(false); } }; // Sort handler const handleSort = (field: SortField) => { if (sortField === field) { if (sortOrder === "asc") setSortOrder("desc"); else if (sortOrder === "desc") { setSortField(null); setSortOrder(null); } else setSortOrder("asc"); } else { setSortField(field); setSortOrder("desc"); } }; const getSortIcon = (field: SortField) => { if (sortField !== field) return ; if (sortOrder === "asc") return ; if (sortOrder === "desc") return ; return ; }; // Sort data const sortedCreatives = [...creatives].sort((a, b) => { if (!sortField || !sortOrder) return 0; let aVal = 0; let bVal = 0; switch (sortField) { case "placements": aVal = a.placements_count; bVal = b.placements_count; break; case "cost": aVal = a.total_cost; bVal = b.total_cost; break; case "subscriptions": aVal = a.total_subscriptions; bVal = b.total_subscriptions; break; case "views": aVal = a.total_views; bVal = b.total_views; break; case "cps": aVal = a.avg_cpf ?? 0; bVal = b.avg_cpf ?? 0; break; case "cpm": aVal = a.avg_cpm ?? 0; bVal = b.avg_cpm ?? 0; break; } return sortOrder === "asc" ? aVal - bVal : bVal - aVal; }); return ( <>

Аналитика по креативам

Сравнение эффективности рекламных материалов

{loading ? (
) : sortedCreatives.length === 0 ? (

Нет данных

Создайте размещения для отображения статистики по креативам

) : ( Креативы {sortedCreatives.length} креативов с размещениями Креатив {sortedCreatives.map((creative) => ( {creative.name} {creative.placements_count} {formatCurrency(creative.total_cost)} {formatNumber(creative.total_subscriptions)} {formatNumber(creative.total_views)} {formatCurrency(creative.avg_cpf)} {formatCurrency(creative.avg_cpm)} ))}
)}
); }