"use client"; import { useState } from "react"; import { Filter, X } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { cn } from "@/lib/utils"; import type { Project, Channel, Creative, CostType, PlacementType, InviteLinkType } from "@/lib/types/api"; interface AnalyticsFiltersModalProps { open: boolean; onOpenChange: (open: boolean) => void; onApply: (filters: PlacementsAnalyticsFilters) => void; projects: Project[]; channels: Channel[]; creatives: Creative[]; initialFilters: PlacementsAnalyticsFilters; } export interface PlacementsAnalyticsFilters { projectIds: string[]; statusList: string[]; placementChannelIds: string[]; creativeIds: string[]; costTypes: CostType[]; placementTypes: PlacementType[]; inviteLinkTypes: InviteLinkType[]; costMin: number | null; costMax: number | null; viewsMin: number | null; viewsMax: number | null; subscriptionsMin: number | null; subscriptionsMax: number | null; cpmMin: number | null; cpmMax: number | null; channelTitleContains: string; creativeNameContains: string; commentContains: string; placementDateFrom: string; placementDateTo: string; } const STATUS_OPTIONS = [ "Без статуса", "Написать", "Ждём ответа", "Согласование условий", "Оплатить", "Оплачено", "Отмена", "Не подходит цена", "Неактуально", "Не отвечает", ]; const COST_TYPE_OPTIONS: { value: CostType; label: string }[] = [ { value: "fixed", label: "Фикс" }, { value: "cpm", label: "CPM" }, ]; const PLACEMENT_TYPE_OPTIONS: { value: PlacementType; label: string }[] = [ { value: "standard", label: "Стандартный" }, { value: "self_promo", label: "Взаимный пиар" }, ]; const INVITE_LINK_TYPE_OPTIONS: { value: InviteLinkType; label: string }[] = [ { value: "public", label: "Открытая" }, { value: "approval", label: "С заявками" }, ]; export function AnalyticsFiltersModal({ open, onOpenChange, onApply, projects, channels, creatives, initialFilters, }: AnalyticsFiltersModalProps) { const [filters, setFilters] = useState(initialFilters); const [activeTab, setActiveTab] = useState<"categories" | "numbers" | "text" | "dates">("categories"); const handleApply = () => { onApply(filters); onOpenChange(false); }; const handleReset = () => { const defaultFilters: PlacementsAnalyticsFilters = { projectIds: [], statusList: [], placementChannelIds: [], creativeIds: [], costTypes: [], placementTypes: [], inviteLinkTypes: [], costMin: null, costMax: null, viewsMin: null, viewsMax: null, subscriptionsMin: null, subscriptionsMax: null, cpmMin: null, cpmMax: null, channelTitleContains: "", creativeNameContains: "", commentContains: "", placementDateFrom: "", placementDateTo: "", }; setFilters(defaultFilters); }; const toggleArrayItem = (arr: T[], item: T): T[] => { return arr.includes(item) ? arr.filter((i) => i !== item) : [...arr, item]; }; const hasActiveFilters = filters.projectIds.length > 0 || filters.statusList.length > 0 || filters.placementChannelIds.length > 0 || filters.creativeIds.length > 0 || filters.costTypes.length > 0 || filters.placementTypes.length > 0 || filters.inviteLinkTypes.length > 0 || filters.costMin !== null || filters.costMax !== null || filters.viewsMin !== null || filters.viewsMax !== null || filters.subscriptionsMin !== null || filters.subscriptionsMax !== null || filters.cpmMin !== null || filters.cpmMax !== null || filters.channelTitleContains || filters.creativeNameContains || filters.commentContains || filters.placementDateFrom || filters.placementDateTo; return ( Фильтры Настройте гибкие фильтры для таблицы размещений
{[ { id: "categories", label: "Категории" }, { id: "numbers", label: "Числовые" }, { id: "text", label: "Текст" }, { id: "dates", label: "Даты" }, ].map((tab) => ( ))}
{activeTab === "categories" && (
{/* Projects - Multi-select */}
{projects.map((project) => ( ))} {projects.length === 0 && (

Нет доступных проектов

)}
{/* Status - Multi-select */}
{STATUS_OPTIONS.map((status) => ( ))}
{/* Channels - Multi-select */}
{channels.map((channel) => ( ))} {channels.length === 0 && (

Нет доступных каналов

)}
{/* Creatives - Multi-select */}
{creatives.map((creative) => ( ))} {creatives.length === 0 && (

Нет доступных креативов

)}
{/* Cost Type - Multi-select */}
{COST_TYPE_OPTIONS.map((opt) => ( ))}
{/* Placement Type - Multi-select */}
{PLACEMENT_TYPE_OPTIONS.map((opt) => ( ))}
{/* Invite Link Type - Multi-select */}
{INVITE_LINK_TYPE_OPTIONS.map((opt) => ( ))}
)} {activeTab === "numbers" && (
{/* Cost range */}
setFilters({ ...filters, costMin: e.target.value ? parseFloat(e.target.value) : null, }) } /> setFilters({ ...filters, costMax: e.target.value ? parseFloat(e.target.value) : null, }) } />
{/* Views range */}
setFilters({ ...filters, viewsMin: e.target.value ? parseInt(e.target.value) : null, }) } /> setFilters({ ...filters, viewsMax: e.target.value ? parseInt(e.target.value) : null, }) } />
{/* Subscriptions range */}
setFilters({ ...filters, subscriptionsMin: e.target.value ? parseInt(e.target.value) : null, }) } /> setFilters({ ...filters, subscriptionsMax: e.target.value ? parseInt(e.target.value) : null, }) } />
{/* CPM range */}
setFilters({ ...filters, cpmMin: e.target.value ? parseFloat(e.target.value) : null, }) } /> setFilters({ ...filters, cpmMax: e.target.value ? parseFloat(e.target.value) : null, }) } />
)} {activeTab === "text" && (
{/* Channel title */}
setFilters({ ...filters, channelTitleContains: e.target.value }) } />
{/* Creative name */}
setFilters({ ...filters, creativeNameContains: e.target.value }) } />
{/* Comment */}
setFilters({ ...filters, commentContains: e.target.value }) } />
)} {activeTab === "dates" && (
{/* Placement date range */}
setFilters({ ...filters, placementDateFrom: e.target.value }) } /> setFilters({ ...filters, placementDateTo: e.target.value }) } />
)}
); }