import { useContext, useEffect, useState, useMemo } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { format, isAfter, isBefore, addDays } from 'date-fns'
import { FileText, Megaphone, AlertTriangle, ArrowRight, Clock, Landmark, CheckSquare, FolderKanban } from 'lucide-react'
import { AppContext } from '../App'
import { useAuth } from '../contexts/AuthContext'
import { useLanguage } from '../i18n/LanguageContext'
import { api, PRIORITY_CONFIG } from '../utils/api'
import StatusBadge from '../components/StatusBadge'
import BrandBadge from '../components/BrandBadge'
import DatePresetPicker from '../components/DatePresetPicker'
import { SkeletonDashboard } from '../components/SkeletonLoader'
function getBudgetBarColor(percentage) {
if (percentage > 90) return 'bg-red-500'
if (percentage > 70) return 'bg-amber-500'
return 'bg-emerald-500'
}
function BudgetSummary({ finance }) {
const { t, currencySymbol } = useLanguage()
if (!finance) return null
const totalReceived = finance.totalReceived || 0
const mainAvailable = finance.mainAvailable != null ? finance.mainAvailable : (finance.remaining || 0)
const consumed = totalReceived - mainAvailable
const pct = totalReceived > 0 ? (consumed / totalReceived) * 100 : 0
const barColor = getBudgetBarColor(pct)
return (
{t('dashboard.budgetOverview')}
{t('dashboard.details')}
{totalReceived === 0 ? (
{t('dashboard.noBudgetRecorded')}. {t('dashboard.addBudget')}
) : (
<>
{consumed.toLocaleString()} {currencySymbol} {t('dashboard.spent')}
{totalReceived.toLocaleString()} {currencySymbol} {t('dashboard.received')}
= 0 ? 'text-emerald-600' : 'text-red-600'}`}>
{mainAvailable.toLocaleString()} {currencySymbol} {t('dashboard.remaining')}
>
)}
)
}
function ActiveCampaignsList({ campaigns, finance }) {
const { t, currencySymbol } = useLanguage()
const active = campaigns.filter(c => c.status === 'active')
const campaignData = (finance?.campaigns || []).filter(c => c.status === 'active')
if (active.length === 0) return null
return (
{t('dashboard.activeCampaigns')}
{t('dashboard.viewAll')}
{active.slice(0, 5).map(c => {
const cd = campaignData.find(d => d.id === (c._id || c.id)) || {}
const spent = cd.tracks_spent || 0
const allocated = cd.tracks_allocated || 0
const pct = allocated > 0 ? (spent / allocated) * 100 : 0
const barColor = getBudgetBarColor(pct)
return (
{c.name}
{allocated > 0 && (
{spent.toLocaleString()}
{allocated.toLocaleString()} {currencySymbol}
)}
)
})}
)
}
function MyTasksList({ tasks, currentUserId, navigate, t }) {
const myTasks = useMemo(() => tasks
.filter(task => {
const assignedId = task.assigned_to_id || task.assignedTo
return assignedId === currentUserId && task.status !== 'done'
})
.slice(0, 5), [tasks, currentUserId])
return (
{t('dashboard.myTasks')}
{t('dashboard.viewAll')}
{myTasks.length === 0 ? (
{t('dashboard.allOnTrack')}
) : (
myTasks.map(task => (
))
)}
)
}
function ProjectProgress({ projects, tasks, t }) {
if (!projects || projects.length === 0) return null
const activeProjects = projects
.filter(p => p.status === 'active' || p.status === 'in_progress')
.slice(0, 5)
if (activeProjects.length === 0) return null
return (
{t('dashboard.projectProgress')}
{t('dashboard.viewAll')}
{activeProjects.map(project => {
const projectId = project._id || project.id
const projectTasks = tasks.filter(t => (t.project_id || t.projectId) === projectId)
const doneTasks = projectTasks.filter(t => t.status === 'done').length
const totalTasks = projectTasks.length
const pct = totalTasks > 0 ? (doneTasks / totalTasks) * 100 : 0
return (
{project.name}
{doneTasks}/{totalTasks} {t('tasks.tasks')}
)
})}
)
}
function ActivityFeed({ posts, deadlines, navigate, t }) {
const [tab, setTab] = useState('posts')
const hasPosts = posts.length > 0
const hasDeadlines = deadlines.length > 0
return (
{t('dashboard.viewAll')}
{tab === 'posts' ? (
!hasPosts ? (
{t('dashboard.noPostsYet')}
) : (
posts.slice(0, 6).map(post => (
))
)
) : (
!hasDeadlines ? (
{t('dashboard.noUpcomingDeadlines')}
) : (
deadlines.map(task => (
))
)
)}
)
}
export default function Dashboard() {
const { t, currencySymbol } = useLanguage()
const navigate = useNavigate()
const { currentUser } = useContext(AppContext)
const { hasModule } = useAuth()
const [posts, setPosts] = useState([])
const [campaigns, setCampaigns] = useState([])
const [tasks, setTasks] = useState([])
const [projects, setProjects] = useState([])
const [finance, setFinance] = useState(null)
const [loading, setLoading] = useState(true)
const [dateFrom, setDateFrom] = useState('')
const [dateTo, setDateTo] = useState('')
const [activePreset, setActivePreset] = useState('')
useEffect(() => {
loadData()
}, [])
const loadData = async () => {
try {
const fetches = []
if (hasModule('marketing')) {
fetches.push(api.get('/posts?limit=50&sort=-createdAt').then(r => ({ key: 'posts', data: Array.isArray(r) ? r : [] })))
fetches.push(api.get('/campaigns').then(r => ({ key: 'campaigns', data: Array.isArray(r) ? r : [] })))
}
if (hasModule('projects')) {
fetches.push(api.get('/tasks').then(r => ({ key: 'tasks', data: Array.isArray(r) ? r : [] })))
fetches.push(api.get('/projects').then(r => ({ key: 'projects', data: Array.isArray(r) ? r : [] })))
}
if (hasModule('finance')) {
fetches.push(api.get('/finance/summary').then(r => ({ key: 'finance', data: r || null })))
}
const results = await Promise.allSettled(fetches)
results.forEach(r => {
if (r.status !== 'fulfilled') return
const { key, data } = r.value
if (key === 'posts') setPosts(data)
else if (key === 'campaigns') setCampaigns(data)
else if (key === 'tasks') setTasks(data)
else if (key === 'projects') setProjects(data)
else if (key === 'finance') setFinance(data)
})
} catch (err) {
console.error('Dashboard load error:', err)
} finally {
setLoading(false)
}
}
const filteredPosts = useMemo(() => {
if (!dateFrom && !dateTo) return posts
return posts.filter(p => {
const d = p.scheduled_date || p.scheduledDate
if (!d) return true
if (dateFrom && d < dateFrom) return false
if (dateTo && d > dateTo) return false
return true
})
}, [posts, dateFrom, dateTo])
const filteredTasks = useMemo(() => {
if (!dateFrom && !dateTo) return tasks
return tasks.filter(t => {
const d = t.due_date || t.dueDate
if (!d) return true
if (dateFrom && d < dateFrom) return false
if (dateTo && d > dateTo) return false
return true
})
}, [tasks, dateFrom, dateTo])
const activeCampaigns = campaigns.filter(c => c.status === 'active').length
const overdueTasks = filteredTasks.filter(t =>
t.dueDate && new Date(t.dueDate) < new Date() && t.status !== 'done'
).length
const upcomingDeadlines = useMemo(() => filteredTasks
.filter(t => {
if (!t.dueDate || t.status === 'done') return false
const due = new Date(t.dueDate)
const now = new Date()
return isAfter(due, now) && isBefore(due, addDays(now, 7))
})
.sort((a, b) => new Date(a.dueDate) - new Date(b.dueDate))
.slice(0, 6), [filteredTasks])
// Inline stat values — no card component needed
const stats = []
if (hasModule('marketing')) {
stats.push({ label: t('dashboard.totalPosts'), value: filteredPosts.length, detail: `${filteredPosts.filter(p => p.status === 'published').length} ${t('dashboard.published')}`, icon: FileText, accent: 'text-indigo-600' })
stats.push({ label: t('dashboard.activeCampaigns'), value: activeCampaigns, detail: `${campaigns.length} ${t('dashboard.total')}`, icon: Megaphone, accent: 'text-pink-600' })
}
if (hasModule('projects')) {
stats.push({ label: t('dashboard.overdueTasks'), value: overdueTasks, detail: overdueTasks > 0 ? t('dashboard.needsAttention') : t('dashboard.allOnTrack'), icon: AlertTriangle, accent: overdueTasks > 0 ? 'text-red-600' : 'text-emerald-600' })
}
if (loading) return
return (
{/* Welcome + Date presets */}
{t('dashboard.welcomeBack')}, {currentUser?.name || 'there'}
{ setDateFrom(from); setDateTo(to); setActivePreset(key) }}
onClear={() => { setDateFrom(''); setDateTo(''); setActivePreset('') }}
/>
{/* Stats — compact inline row, no cards */}
{stats.length > 0 && (
{stats.map((s, i) => (
{s.value}
{s.label}
{s.detail}
))}
)}
{/* My Tasks + Project Progress */}
{hasModule('projects') && (
)}
{/* Budget + Active Campaigns */}
{(hasModule('finance') || hasModule('marketing')) && (
{hasModule('finance') &&
}
{hasModule('marketing') && (
)}
)}
{/* Activity — merged posts + deadlines */}
{(hasModule('marketing') || hasModule('projects')) && (
)}
)
}