import React, { useState, useEffect, useMemo, useCallback } from 'react'; import { DevMarketingActivity } from '../../types'; import { Megaphone, Users, MessageCircle, Phone, Calendar, ClipboardList, CheckCircle2, MapPin, Plus, Edit, Search, Filter } from 'lucide-react'; import { backendApi } from '../../services/apiClient'; import { MarketingActivityModal } from './MarketingActivityModal'; export const MarketingCampaigns: React.FC = () => { const [activities, setActivities] = useState([]); const [loading, setLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); const [editingActivity, setEditingActivity] = useState(null); const [search, setSearch] = useState(''); const [statusFilter, setStatusFilter] = useState(''); const fetchActivities = useCallback(async () => { try { setLoading(true); const params = statusFilter ? { status: statusFilter } : undefined; const data = await backendApi.getDevelopmentMarketing(params); setActivities(data); } catch (error) { console.error('Error fetching marketing activities:', error); setActivities([]); } finally { setLoading(false); } }, [statusFilter]); useEffect(() => { fetchActivities(); }, [fetchActivities]); const filteredActivities = useMemo(() => { if (!search.trim()) return activities; const q = search.trim().toLowerCase(); return activities.filter(a => (a.address || '').toLowerCase().includes(q) || (a.competitor || '').toLowerCase().includes(q)); }, [activities, search]); const handleCreate = () => { setEditingActivity(null); setIsModalOpen(true); }; const handleEdit = (activity: DevMarketingActivity) => { setEditingActivity(activity); setIsModalOpen(true); }; const handleContacts = () => { alert('В разработке: список контактов по объекту (активисты, председатели).'); }; const handleMeetingsPlan = () => { alert('В разработке: календарь и список запланированных встреч по объекту.'); }; const totals = useMemo(() => { const sum = (arr: DevMarketingActivity[], key: keyof DevMarketingActivity) => arr.reduce((acc, a) => acc + (Number(a[key]) || 0), 0); return { meetings: sum(activities, 'meetingsHeld'), ads: sum(activities, 'adsDistributed'), activists: sum(activities, 'activistsCount'), withMetrics: activities.filter(a => (a.meetingsHeld || 0) > 0 || (a.adsDistributed || 0) > 0 || (a.activistsCount || 0) > 0).length, }; }, [activities]); return (

Работа с активом

setSearch(e.target.value)} className="pl-9 pr-3 py-2 rounded-xl border border-slate-200 text-sm w-48 focus:ring-2 focus:ring-primary-500 outline-none" />
{loading ? (

Загрузка...

) : activities.length === 0 ? (

Нет маркетинговых активностей

Агитация и маркетинг по объектам из воронки и существующим домам.

) : filteredActivities.length === 0 ? (

Нет активностей по фильтру

) : (
{filteredActivities.map(m => (
{/* Status Vertical Line */}

{m.address}

Тек. УК: {m.competitor}

))}
)} {/* Итоги по активностям (реальные данные) */}

Итоги по активностям

{activities.length === 0 ? (

Данные по итогам месяца будут доступны после добавления активностей.

) : (

Встреч проведено

{totals.meetings}

Листовок роздано

{totals.ads}

Активистов

{totals.activists}

Объектов с метриками

{totals.withMetrics} / {activities.length}

)}
{/* Modal */} { setIsModalOpen(false); setEditingActivity(null); }} onSuccess={() => { fetchActivities(); }} activity={editingActivity} />
); }; const MarketingMetric = ({ icon: Icon, value, label, color, bg }: any) => (
{value} {label}
);