import React, { useState, useMemo } from "react"; import { base44 } from "@/api/base44Client"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { DragDropContext, Draggable } from "@hello-pangea/dnd"; import { Link2, Plus, Users } from "lucide-react"; import TaskCard from "@/components/tasks/TaskCard"; import TaskColumn from "@/components/tasks/TaskColumn"; import TaskDetailModal from "@/components/tasks/TaskDetailModal"; import { useToast } from "@/components/ui/use-toast"; export default function TaskBoard() { const { toast } = useToast(); const queryClient = useQueryClient(); const [createDialog, setCreateDialog] = useState(false); const [selectedTask, setSelectedTask] = useState(null); const [selectedStatus, setSelectedStatus] = useState("pending"); const [newTask, setNewTask] = useState({ task_name: "", description: "", priority: "normal", due_date: "", progress: 0, assigned_members: [] }); const [selectedMembers, setSelectedMembers] = useState([]); const { data: user } = useQuery({ queryKey: ['current-user-taskboard'], queryFn: () => base44.auth.me(), }); const { data: teams = [] } = useQuery({ queryKey: ['teams'], queryFn: () => base44.entities.Team.list(), initialData: [], }); const { data: teamMembers = [] } = useQuery({ queryKey: ['team-members'], queryFn: () => base44.entities.TeamMember.list(), initialData: [], }); const { data: tasks = [] } = useQuery({ queryKey: ['tasks'], queryFn: () => base44.entities.Task.list(), initialData: [], }); const userTeam = teams.find(t => t.owner_id === user?.id) || teams[0]; const teamTasks = tasks.filter(t => t.team_id === userTeam?.id); const currentTeamMembers = teamMembers.filter(m => m.team_id === userTeam?.id); const leadMembers = currentTeamMembers.filter(m => m.role === 'admin' || m.role === 'manager'); const regularMembers = currentTeamMembers.filter(m => m.role === 'member'); // Get unique departments from team members const departments = [...new Set(currentTeamMembers.map(m => m.department).filter(Boolean))]; const tasksByStatus = useMemo(() => ({ pending: teamTasks.filter(t => t.status === 'pending').sort((a, b) => (a.order_index || 0) - (b.order_index || 0)), in_progress: teamTasks.filter(t => t.status === 'in_progress').sort((a, b) => (a.order_index || 0) - (b.order_index || 0)), on_hold: teamTasks.filter(t => t.status === 'on_hold').sort((a, b) => (a.order_index || 0) - (b.order_index || 0)), completed: teamTasks.filter(t => t.status === 'completed').sort((a, b) => (a.order_index || 0) - (b.order_index || 0)), }), [teamTasks]); const overallProgress = useMemo(() => { if (teamTasks.length === 0) return 0; const totalProgress = teamTasks.reduce((sum, t) => sum + (t.progress || 0), 0); return Math.round(totalProgress / teamTasks.length); }, [teamTasks]); const createTaskMutation = useMutation({ mutationFn: (taskData) => base44.entities.Task.create(taskData), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['tasks'] }); setCreateDialog(false); setNewTask({ task_name: "", description: "", priority: "normal", due_date: "", progress: 0, assigned_members: [] }); setSelectedMembers([]); toast({ title: "✅ Task Created", description: "New task added to the board", }); }, }); const updateTaskMutation = useMutation({ mutationFn: ({ id, data }) => base44.entities.Task.update(id, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['tasks'] }); }, }); const handleDragEnd = (result) => { if (!result.destination) return; const { source, destination, draggableId } = result; if (source.droppableId === destination.droppableId && source.index === destination.index) { return; } const task = teamTasks.find(t => t.id === draggableId); if (!task) return; const newStatus = destination.droppableId; updateTaskMutation.mutate({ id: task.id, data: { ...task, status: newStatus, order_index: destination.index } }); }; const handleCreateTask = () => { if (!newTask.task_name.trim()) { toast({ title: "Task name required", variant: "destructive", }); return; } createTaskMutation.mutate({ ...newTask, team_id: userTeam?.id, status: selectedStatus, order_index: tasksByStatus[selectedStatus]?.length || 0, assigned_members: selectedMembers.map(m => ({ member_id: m.id, member_name: m.member_name, avatar_url: m.avatar_url })), assigned_department: selectedMembers.length > 0 && selectedMembers[0].department ? selectedMembers[0].department : null }); }; return (
Create your first task to get started