"use client"; // ============================================================================ // Purchases List Page // ============================================================================ import React, { useEffect, useState } from "react"; import Link from "next/link"; import { DashboardHeader } from "@/components/layout/dashboard-header"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { purchasesApi, channelsApi } from "@/lib/api"; import { formatNumber, formatMetric, formatCurrency, formatDate, formatPercent, } from "@/lib/utils/format"; import { ShoppingCart, Loader2, AlertCircle, Plus, Search, Filter, Eye, CheckCircle, Clock, Archive, } from "lucide-react"; import type { Purchase, TargetChannel } from "@/lib/types/api"; import { Alert, AlertDescription } from "@/components/ui/alert"; export default function PurchasesPage() { const [purchases, setPurchases] = useState([]); const [channels, setChannels] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [searchQuery, setSearchQuery] = useState(""); const [filterChannel, setFilterChannel] = useState("all"); const [filterStatus, setFilterStatus] = useState("all"); useEffect(() => { loadData(); }, []); const loadData = async () => { try { setLoading(true); const [purchasesRes, channelsRes] = await Promise.all([ purchasesApi.list(), channelsApi.list(), ]); setPurchases(purchasesRes.placements); setChannels(channelsRes.target_channels); } catch (err: any) { setError(err?.error?.message || "Ошибка загрузки данных"); } finally { setLoading(false); } }; const filteredPurchases = purchases.filter((purchase) => { // Поиск const matchesSearch = purchase.external_channel_title .toLowerCase() .includes(searchQuery.toLowerCase()) || purchase.target_channel_title .toLowerCase() .includes(searchQuery.toLowerCase()) || purchase.creative_name.toLowerCase().includes(searchQuery.toLowerCase()); // Фильтр по каналу const matchesChannel = filterChannel === "all" || purchase.target_channel_id === filterChannel; // Фильтр по статусу let matchesStatus = true; if (filterStatus === "archived") { matchesStatus = purchase.status === "archived"; } else if (filterStatus === "active") { matchesStatus = purchase.status === "active"; } return matchesSearch && matchesChannel && matchesStatus; }); // Статистика const stats = { total: purchases.length, active: purchases.filter((p) => p.status === "active").length, archived: purchases.filter((p) => p.status === "archived").length, totalCost: purchases.reduce((sum, p) => sum + (p.cost || 0), 0), totalSubscriptions: purchases.reduce( (sum, p) => sum + p.subscriptions_count, 0 ), }; return ( <>

Закупы

Рекламные размещения во внешних каналах

{error && ( {error} )}
Всего закупов
{formatNumber(stats.total)}

{stats.active} активных, {stats.archived} в архиве

Общие затраты
{formatCurrency(stats.totalCost)}

За все закупы

Подписчиков привлечено
{formatNumber(stats.totalSubscriptions)}

Всего

Фильтры
setSearchQuery(e.target.value)} className="pl-8" />
Найдено: {formatNumber(filteredPurchases.length)}
Список закупов Все рекламные размещения {loading ? (
) : filteredPurchases.length === 0 ? (

{searchQuery || filterChannel !== "all" || filterStatus !== "all" ? "Закупы не найдены" : "Нет закупов"}

{searchQuery || filterChannel !== "all" || filterStatus !== "all" ? "Попробуйте изменить фильтры" : "Создайте первый закуп"}

) : ( Статус Целевой канал Внешний канал Креатив Дата Стоимость Подписки Просмотры {filteredPurchases.map((purchase) => ( {purchase.status === "archived" ? ( Архив ) : ( Активно )} {purchase.target_channel_title} {purchase.external_channel_title} {purchase.creative_name} {formatDate(purchase.placement_date)} {formatCurrency(purchase.cost)} {formatNumber(purchase.subscriptions_count)} {purchase.views_count ? formatNumber(purchase.views_count) : "—"} ))}
)}
); }