import { useState, useEffect, useContext } from 'react'
import { useNavigate } from 'react-router-dom'
import { Plus, Search, FolderKanban, LayoutGrid, GanttChart } from 'lucide-react'
import { AppContext } from '../App'
import { api } from '../utils/api'
import { useAuth } from '../contexts/AuthContext'
import ProjectCard from '../components/ProjectCard'
import Modal from '../components/Modal'
import InteractiveTimeline from '../components/InteractiveTimeline'
import { SkeletonCard } from '../components/SkeletonLoader'
const EMPTY_PROJECT = {
name: '', description: '', brand_id: '', status: 'active',
owner_id: '', start_date: '', due_date: '',
}
export default function Projects() {
const navigate = useNavigate()
const { teamMembers, brands } = useContext(AppContext)
const { permissions } = useAuth()
const [projects, setProjects] = useState([])
const [loading, setLoading] = useState(true)
const [showModal, setShowModal] = useState(false)
const [formData, setFormData] = useState(EMPTY_PROJECT)
const [searchTerm, setSearchTerm] = useState('')
const [view, setView] = useState('timeline') // 'grid' | 'timeline'
useEffect(() => { loadProjects() }, [])
const loadProjects = async () => {
try {
const res = await api.get('/projects')
setProjects(res.data || res || [])
} catch (err) {
console.error('Failed to load projects:', err)
} finally {
setLoading(false)
}
}
const handleCreate = async () => {
try {
const data = {
name: formData.name,
description: formData.description,
brand_id: formData.brand_id ? Number(formData.brand_id) : null,
owner_id: formData.owner_id ? Number(formData.owner_id) : null,
status: formData.status,
start_date: formData.start_date || null,
due_date: formData.due_date || null,
}
await api.post('/projects', data)
setShowModal(false)
setFormData(EMPTY_PROJECT)
loadProjects()
} catch (err) {
console.error('Create failed:', err)
}
}
const filtered = projects.filter(p => {
if (searchTerm && !p.name?.toLowerCase().includes(searchTerm.toLowerCase())) return false
return true
})
if (loading) {
return (
{[...Array(6)].map((_, i) => )}
)
}
return (
{/* Toolbar */}
setSearchTerm(e.target.value)}
className="w-full pl-10 pr-4 py-2 text-sm border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-primary/20 focus:border-brand-primary bg-white"
/>
{/* View switcher */}
{[
{ id: 'grid', icon: LayoutGrid, label: 'Grid' },
{ id: 'timeline', icon: GanttChart, label: 'Timeline' },
].map(v => (
))}
{permissions?.canCreateProjects && (
)}
{/* Content */}
{filtered.length === 0 ? (
No projects yet
Create your first project to start organizing work
) : view === 'grid' ? (
{filtered.map(project => (
))}
) : (
({
id: project._id || project.id,
label: project.name,
description: project.description,
startDate: project.startDate || project.start_date || project.createdAt,
endDate: project.dueDate || project.due_date,
status: project.status,
priority: project.priority,
assigneeName: project.ownerName || project.owner_name,
thumbnailUrl: project.thumbnail_url || project.thumbnailUrl,
tags: [project.status, project.priority].filter(Boolean),
})}
onDateChange={async (projectId, { startDate, endDate }) => {
try {
await api.patch(`/projects/${projectId}`, { start_date: startDate, due_date: endDate })
} catch (err) {
console.error('Timeline date update failed:', err)
} finally {
loadProjects()
}
}}
onItemClick={(project) => {
navigate(`/projects/${project._id || project.id}`)
}}
/>
)}
{/* Create Modal */}
setShowModal(false)} title="Create New Project" size="md">
setFormData(f => ({ ...f, name: e.target.value }))}
className="w-full px-3 py-2 text-sm border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-primary/20 focus:border-brand-primary"
placeholder="Project name"
/>
setFormData(f => ({ ...f, due_date: e.target.value }))}
className="w-full px-3 py-2 text-sm border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-primary/20 focus:border-brand-primary"
/>
)
}