import { useState, useEffect } from 'react' import { Card } from '@/components/ui/Card' import { Button } from '@/components/ui/Button' import { Badge } from '@/components/ui/Badge' import { Skeleton } from '@/components/ui/Skeleton' import { useAuthStore } from '@/stores/authStore' import { Plus, MoreHorizontal, Calendar, User, Flag, CheckCircle2, Circle, Clock, X, GripVertical, } from 'lucide-react' interface Task { id: string title: string description: string status: 'todo' | 'in_progress' | 'review' | 'done' priority: 'low' | 'medium' | 'high' | 'urgent' assignee?: string due_date?: string tags: string[] created_at: string } interface Project { id: string name: string description: string status: string progress: number tasks: Task[] members: string[] created_at: string } const statusColumns = [ { id: 'todo', label: 'Att göra', icon: Circle, color: 'bg-gray-100' }, { id: 'in_progress', label: 'Pågående', icon: Clock, color: 'bg-blue-50' }, { id: 'review', label: 'Granskning', icon: Flag, color: 'bg-yellow-50' }, { id: 'done', label: 'Klart', icon: CheckCircle2, color: 'bg-green-50' }, ] const priorityColors = { low: 'bg-gray-100 text-gray-700', medium: 'bg-blue-100 text-blue-700', high: 'bg-orange-100 text-orange-700', urgent: 'bg-red-100 text-red-700', } const priorityLabels = { low: 'Låg', medium: 'Medium', high: 'Hög', urgent: 'Akut', } export function ProjectsPage() { const [projects, setProjects] = useState([]) const [selectedProject, setSelectedProject] = useState(null) const [tasks, setTasks] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [showCreateTask, setShowCreateTask] = useState(false) const [showCreateProject, setShowCreateProject] = useState(false) const { token } = useAuthStore() const [newTask, setNewTask] = useState({ title: '', description: '', priority: 'medium' as const, status: 'todo' as const, assignee: '', due_date: '', tags: '', }) const [newProject, setNewProject] = useState({ name: '', description: '', }) const fetchProjects = async () => { setLoading(true) try { const res = await fetch('/api/projects') if (!res.ok) throw new Error('Failed to fetch projects') const data = await res.json() setProjects(data) if (data.length > 0 && !selectedProject) { setSelectedProject(data[0]) fetchTasks(data[0].id) } } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load') } finally { setLoading(false) } } const fetchTasks = async (projectId: string) => { try { const res = await fetch(`/api/issues?project_id=${projectId}`) if (!res.ok) throw new Error('Failed to fetch tasks') const data = await res.json() // Map issues to tasks format const mappedTasks: Task[] = data.map((issue: any) => ({ id: issue.id, title: issue.summary || issue.title || 'Untitled', description: issue.description || '', status: mapIssueStatus(issue.status), priority: mapIssuePriority(issue.priority), assignee: issue.assignee, due_date: issue.due_date, tags: issue.tags || [], created_at: issue.created_at, })) setTasks(mappedTasks) } catch (err) { console.error('Failed to fetch tasks:', err) } } const mapIssueStatus = (status: string): Task['status'] => { switch (status) { case 'backlog': case 'todo': return 'todo' case 'in_progress': return 'in_progress' case 'review': return 'review' case 'done': case 'resolved': case 'closed': return 'done' default: return 'todo' } } const mapIssuePriority = (priority: string): Task['priority'] => { switch (priority) { case 'low': return 'low' case 'medium': return 'medium' case 'high': return 'high' case 'urgent': case 'critical': return 'urgent' default: return 'medium' } } useEffect(() => { fetchProjects() }, []) const createTask = async () => { if (!newTask.title || !selectedProject) return try { const res = await fetch('/api/issues', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ summary: newTask.title, description: newTask.description, priority: newTask.priority, issue_type: 'task', project_id: selectedProject.id, }), }) if (!res.ok) throw new Error('Failed to create') setShowCreateTask(false) setNewTask({ title: '', description: '', priority: 'medium', status: 'todo', assignee: '', due_date: '', tags: '', }) fetchTasks(selectedProject.id) } catch (err) { setError(err instanceof Error ? err.message : 'Failed to create') } } const createProject = async () => { if (!newProject.name) return try { // Projects API might not exist yet, create locally const project: Project = { id: `proj-${Date.now()}`, name: newProject.name, description: newProject.description, status: 'active', progress: 0, tasks: [], members: [], created_at: new Date().toISOString(), } setProjects([...projects, project]) setSelectedProject(project) setShowCreateProject(false) setNewProject({ name: '', description: '' }) } catch (err) { setError(err instanceof Error ? err.message : 'Failed to create') } } const updateTaskStatus = async (taskId: string, newStatus: string) => { try { const res = await fetch(`/api/issues/${taskId}/status`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: newStatus }), }) if (res.ok && selectedProject) { fetchTasks(selectedProject.id) } } catch (err) { console.error('Failed to update:', err) } } const getTasksByStatus = (status: string) => { return tasks.filter((task) => task.status === status) } if (loading) { return (
{Array.from({ length: 4 }).map((_, i) => ( ))}
) } return (
{/* Header */}

Projekt

{selectedProject ? selectedProject.name : 'Välj ett projekt'}

{/* Project Selector */} {projects.length > 0 && (
{projects.map((project) => ( ))}
)} {/* Kanban Board */} {selectedProject && (
{statusColumns.map((column) => { const columnTasks = getTasksByStatus(column.id) const Icon = column.icon return (
{/* Column Header */}
{column.label}
{columnTasks.length}
{/* Tasks */}
{columnTasks.map((task) => (
{ // Show task details modal }} >

{task.title}

{task.description && (

{task.description}

)}
{priorityLabels[task.priority]} {task.assignee && (
{task.assignee}
)}
{task.due_date && (
{new Date(task.due_date).toLocaleDateString('sv-SE')}
)} {/* Quick status change */}
{statusColumns .filter((s) => s.id !== task.status) .map((s) => ( ))}
))} {columnTasks.length === 0 && (
Inga uppgifter
)}
) })}
)} {/* Create Task Modal */} {showCreateTask && selectedProject && (

Ny uppgift

setNewTask({ ...newTask, title: e.target.value }) } className="w-full h-10 px-3 rounded-lg border bg-bg text-sm" placeholder="Vad ska göras?" />