Files
fabdash/frontend/src/components/Projects/ProjectList.jsx

103 lines
4.6 KiB
React
Raw Normal View History

2026-03-05 15:39:21 -06:00
import { useState, useEffect } from 'react'
2026-03-05 12:13:22 -06:00
import ProjectCard from './ProjectCard'
import ProjectModal from './ProjectModal'
import Button from '../UI/Button'
2026-03-05 15:39:21 -06:00
import AgendaPanel from '../Calendar/AgendaPanel'
2026-03-05 12:13:22 -06:00
import useProjectStore from '../../store/useProjectStore'
2026-03-05 15:39:21 -06:00
import useUIStore from '../../store/useUIStore'
2026-03-05 12:13:22 -06:00
import { deleteProject } from '../../api/projects'
2026-03-05 15:39:21 -06:00
export default function ProjectList({ onRegisterNewProject }) {
2026-03-05 16:08:22 -06:00
const { projects, removeProject } = useProjectStore()
const { sidebarTab, setSidebarTab } = useUIStore()
const [showModal, setShowModal] = useState(false)
const [editing, setEditing] = useState(null)
2026-03-05 15:39:21 -06:00
useEffect(() => { onRegisterNewProject?.(() => setShowModal(true)) }, [onRegisterNewProject])
2026-03-05 12:13:22 -06:00
const handleEdit = (p) => { setEditing(p); setShowModal(true) }
const handleDelete = async (p) => {
if (window.confirm(`Delete "${p.name}" and all its deliverables?`)) {
await deleteProject(p.id); removeProject(p.id)
}
}
const handleClose = () => { setShowModal(false); setEditing(null) }
return (
<div className="flex flex-col h-full">
2026-03-05 16:08:22 -06:00
2026-03-05 16:21:00 -06:00
{/* Header — taller to give logo more presence */}
<div className="flex items-center gap-3 px-4 py-4 border-b border-surface-border flex-shrink-0 pl-10">
2026-03-05 16:08:22 -06:00
<img
src="/logo.png"
alt="FabDash logo"
2026-03-05 16:21:00 -06:00
className="w-12 h-12 object-contain rounded flex-shrink-0"
2026-03-05 16:08:22 -06:00
onError={e => { e.target.style.display = 'none' }}
/>
2026-03-05 16:21:00 -06:00
<div className="flex flex-col justify-center min-w-0">
<span className="text-base font-black tracking-widest uppercase leading-none">
<span className="text-gold">FAB</span><span className="text-white">DASH</span>
</span>
2026-03-05 16:08:22 -06:00
</div>
<div className="ml-auto flex-shrink-0">
<Button size="sm" onClick={() => setShowModal(true)}>+ Project</Button>
</div>
2026-03-05 12:13:22 -06:00
</div>
2026-03-05 15:39:21 -06:00
{/* Tab toggle */}
<div className="flex border-b border-surface-border flex-shrink-0">
{[['projects','Projects'],['agenda','Upcoming']].map(([key, label]) => (
<button key={key} onClick={() => setSidebarTab(key)}
className={`flex-1 py-2 text-xs font-semibold transition-colors ${sidebarTab === key ? 'text-gold border-b-2 border-gold' : 'text-text-muted hover:text-text-primary'}`}>
{label}
</button>
))}
</div>
{/* Content */}
<div className="flex-1 overflow-y-auto">
{sidebarTab === 'projects' ? (
<div className="p-3 space-y-2">
{projects.length === 0 ? (
<div className="flex flex-col items-center justify-center py-10 px-4 text-center">
<div className="opacity-20 mb-3">
<svg width="56" height="56" viewBox="0 0 56 56" fill="none">
<rect x="7" y="12" width="42" height="37" rx="3" stroke="#C9A84C" strokeWidth="1.5"/>
<line x1="7" y1="21" x2="49" y2="21" stroke="#C9A84C" strokeWidth="1.5"/>
<circle cx="17" cy="7" r="3.5" stroke="#C9A84C" strokeWidth="1.5"/>
<circle cx="39" cy="7" r="3.5" stroke="#C9A84C" strokeWidth="1.5"/>
<line x1="17" y1="31" x2="39" y2="31" stroke="#C9A84C" strokeWidth="1.5" strokeDasharray="4 2.5"/>
<line x1="17" y1="39" x2="30" y2="39" stroke="#C9A84C" strokeWidth="1.5" strokeDasharray="4 2.5"/>
</svg>
</div>
<p className="text-text-muted text-sm font-medium">No projects yet</p>
<p className="text-text-muted/50 text-xs mt-1">
Press <kbd className="bg-surface-border px-1.5 py-0.5 rounded text-[10px] font-mono">N</kbd> or click + Project
</p>
</div>
) : (
projects.map(p => (
<ProjectCard key={p.id} project={p} onEdit={handleEdit} onDelete={handleDelete} />
))
)}
2026-03-05 12:13:22 -06:00
</div>
2026-03-05 15:39:21 -06:00
) : (
<AgendaPanel />
2026-03-05 12:13:22 -06:00
)}
2026-03-05 15:39:21 -06:00
</div>
2026-03-05 16:08:22 -06:00
{/* Keyboard shortcut legend */}
2026-03-05 15:39:21 -06:00
<div className="flex-shrink-0 border-t border-surface-border px-4 py-2 flex flex-wrap gap-x-3 gap-y-1">
2026-03-05 16:08:22 -06:00
{[['N','New'],['B','Sidebar'],['← →','Navigate'],['T','Today']].map(([key, desc]) => (
2026-03-05 15:39:21 -06:00
<span key={key} className="flex items-center gap-1 text-[10px] text-text-muted/50">
<kbd className="bg-surface-border px-1 py-0.5 rounded text-[9px] font-mono">{key}</kbd>
{desc}
</span>
2026-03-05 12:13:22 -06:00
))}
</div>
2026-03-05 15:39:21 -06:00
2026-03-05 12:13:22 -06:00
<ProjectModal isOpen={showModal} onClose={handleClose} project={editing} />
</div>
)
}