import { useState, useEffect, useContext } from 'react'
import { useNavigate } from 'react-router-dom'
import { Plus, Search, TrendingUp, DollarSign, Eye, MousePointer, Target, BarChart3 } from 'lucide-react'
import { format } from 'date-fns'
import { AppContext } from '../App'
import { useAuth } from '../contexts/AuthContext'
import { useLanguage } from '../i18n/LanguageContext'
import { api, PLATFORMS } from '../utils/api'
import { PlatformIcons } from '../components/PlatformIcon'
import StatusBadge from '../components/StatusBadge'
import BrandBadge from '../components/BrandBadge'
import BudgetBar from '../components/BudgetBar'
import InteractiveTimeline from '../components/InteractiveTimeline'
import CampaignDetailPanel from '../components/CampaignDetailPanel'
function ROIBadge({ revenue, spent }) {
if (!spent || spent <= 0) return null
const roi = ((revenue - spent) / spent * 100).toFixed(0)
const color = roi >= 0 ? 'text-emerald-600 bg-emerald-50' : 'text-red-600 bg-red-50'
return (
ROI {roi}%
)
}
function MetricCard({ icon: Icon, label, value, color = 'text-text-primary' }) {
return (
)
}
export default function Campaigns() {
const { brands, getBrandName } = useContext(AppContext)
const { lang, currencySymbol } = useLanguage()
const { permissions } = useAuth()
const navigate = useNavigate()
const [campaigns, setCampaigns] = useState([])
const [loading, setLoading] = useState(true)
const [panelCampaign, setPanelCampaign] = useState(null)
const [filters, setFilters] = useState({ brand: '', status: '' })
useEffect(() => { loadCampaigns() }, [])
const loadCampaigns = async () => {
try {
const res = await api.get('/campaigns')
setCampaigns(res.data || res || [])
} catch (err) {
console.error('Failed to load campaigns:', err)
} finally {
setLoading(false)
}
}
const handlePanelSave = async (campaignId, data) => {
if (campaignId) {
await api.patch(`/campaigns/${campaignId}`, data)
} else {
await api.post('/campaigns', data)
}
loadCampaigns()
}
const handlePanelDelete = async (campaignId) => {
await api.delete(`/campaigns/${campaignId}`)
loadCampaigns()
}
const openNew = () => {
setPanelCampaign({ status: 'planning', platforms: [] })
}
const filtered = campaigns.filter(c => {
if (filters.brand && String(c.brandId || c.brand_id) !== filters.brand) return false
if (filters.status && c.status !== filters.status) return false
return true
})
// Aggregate stats
const totalBudget = filtered.reduce((sum, c) => sum + (c.budget || 0), 0)
const totalSpent = filtered.reduce((sum, c) => sum + (c.budgetSpent || c.budget_spent || 0), 0)
const totalImpressions = filtered.reduce((sum, c) => sum + (c.impressions || 0), 0)
const totalClicks = filtered.reduce((sum, c) => sum + (c.clicks || 0), 0)
const totalConversions = filtered.reduce((sum, c) => sum + (c.conversions || 0), 0)
const totalRevenue = filtered.reduce((sum, c) => sum + (c.revenue || 0), 0)
if (loading) {
return (
)
}
return (
{/* Toolbar */}
{permissions?.canCreateCampaigns && (
)}
{/* Summary Cards */}
{(totalBudget > 0 || totalSpent > 0) && (
Budget
{totalBudget.toLocaleString()}
{currencySymbol} total
Spent
{totalSpent.toLocaleString()}
{currencySymbol} spent
Impressions
{totalImpressions.toLocaleString()}
Clicks
{totalClicks.toLocaleString()}
Conversions
{totalConversions.toLocaleString()}
Revenue
{totalRevenue.toLocaleString()}
{currencySymbol}
)}
{/* Timeline */}
({
id: campaign._id || campaign.id,
label: campaign.name,
description: campaign.description,
startDate: campaign.startDate || campaign.start_date || campaign.createdAt,
endDate: campaign.endDate || campaign.end_date,
status: campaign.status,
assigneeName: campaign.brandName || campaign.brand_name,
tags: campaign.platforms || [],
})}
onDateChange={async (campaignId, { startDate, endDate }) => {
try {
await api.patch(`/campaigns/${campaignId}`, { start_date: startDate, end_date: endDate })
} catch (err) {
console.error('Timeline date update failed:', err)
} finally {
loadCampaigns()
}
}}
onItemClick={(campaign) => {
navigate(`/campaigns/${campaign._id || campaign.id}`)
}}
/>
{/* Campaign list */}
All Campaigns
{filtered.length === 0 ? (
No campaigns found
) : (
filtered.map(campaign => {
const spent = campaign.budgetSpent || campaign.budget_spent || 0
const budget = campaign.budget || 0
return (
navigate(`/campaigns/${campaign.id || campaign._id}`)}
className="relative px-5 py-4 hover:bg-surface-secondary cursor-pointer transition-colors"
>
{campaign.name}
{(campaign.brand_id || campaign.brandName) && }
{campaign.description && (
{campaign.description}
)}
{budget > 0 && (
)}
{(campaign.impressions > 0 || campaign.clicks > 0) && (
{campaign.impressions > 0 && 👁 {campaign.impressions.toLocaleString()}}
{campaign.clicks > 0 && 🖱 {campaign.clicks.toLocaleString()}}
{campaign.conversions > 0 && 🎯 {campaign.conversions.toLocaleString()}}
)}
{campaign.startDate && campaign.endDate ? (
<>
{format(new Date(campaign.startDate), 'MMM d')} – {format(new Date(campaign.endDate), 'MMM d, yyyy')}
>
) : '—'}
{campaign.platforms && campaign.platforms.length > 0 && (
)}
)
})
)}
{/* Campaign Panel */}
{panelCampaign && (
setPanelCampaign(null)}
onSave={handlePanelSave}
onDelete={permissions?.canDeleteCampaigns ? handlePanelDelete : null}
brands={brands}
permissions={permissions}
/>
)}
)
}