"use client"; // ============================================================================ // Purchase Plans Overview Page // ============================================================================ import { useEffect, useState } from "react"; import { useParams, useRouter } from "next/navigation"; import Link from "next/link"; import { Loader2, ClipboardList, ChevronRight, Tv, Calendar, DollarSign, CheckCircle, Clock, XCircle, } from "lucide-react"; import { DashboardHeader } from "@/components/layout/dashboard-header"; import { useWorkspace } from "@/components/providers/workspace-provider"; import { demoAwarePurchasePlanApi } from "@/lib/demo"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import type { Project, PurchasePlanChannel } 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); }; interface ProjectPlanStats { totalChannels: number; plannedChannels: number; completedChannels: number; cancelledChannels: number; totalPlannedCost: number; } // ============================================================================ // Component // ============================================================================ export default function PurchasePlansPage() { const params = useParams(); const router = useRouter(); const workspaceId = params?.workspaceId as string; const { projects, isLoadingProjects } = useWorkspace(); const [projectStats, setProjectStats] = useState>({}); const [loadingStats, setLoadingStats] = useState(true); useEffect(() => { if (projects.length > 0) { loadAllStats(); } else { setLoadingStats(false); } }, [projects, workspaceId]); const loadAllStats = async () => { setLoadingStats(true); const stats: Record = {}; for (const project of projects) { try { const response = await demoAwarePurchasePlanApi.list(workspaceId, project.id, { size: 100 }); const channels = response.items; stats[project.id] = { totalChannels: channels.length, plannedChannels: channels.filter((c) => c.status === "planned").length, completedChannels: channels.filter((c) => c.status === "completed").length, cancelledChannels: channels.filter((c) => c.status === "cancelled").length, totalPlannedCost: channels .filter((c) => c.status === "planned") .reduce((sum, c) => sum + (c.planned_cost || 0), 0), }; } catch (err) { console.error(`Failed to load plan for project ${project.id}:`, err); stats[project.id] = { totalChannels: 0, plannedChannels: 0, completedChannels: 0, cancelledChannels: 0, totalPlannedCost: 0, }; } } setProjectStats(stats); setLoadingStats(false); }; const isLoading = isLoadingProjects || loadingStats; return ( <>

Планы закупок

Управление планами закупок по проектам

{isLoading ? (
) : projects.length === 0 ? (

Нет проектов

Добавьте проект через Telegram бота для создания плана закупок

) : (
{projects.map((project) => { const stats = projectStats[project.id]; return ( router.push(`/dashboard/${workspaceId}/purchase-plans/${project.id}`) } >
{project.title} {project.username && ( @{project.username} )}
{stats ? (
Всего каналов: {stats.totalChannels}
{stats.plannedChannels > 0 && ( {stats.plannedChannels} план. )} {stats.completedChannels > 0 && ( {stats.completedChannels} заверш. )} {stats.cancelledChannels > 0 && ( {stats.cancelledChannels} отмен. )}
{stats.totalPlannedCost > 0 && (
План. бюджет: {formatCurrency(stats.totalPlannedCost)}
)}
) : (
Загрузка...
)}
); })}
)}
); }