import { BrowserFrame } from "@/components/Browser/BrowserFrame"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Progress } from "@/components/ui/progress"; import { Switch } from "@/components/ui/switch"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useState, useMemo, useEffect } from "react"; import { useAuth } from "@/hooks/use-auth"; import { useToast } from "@/hooks/use-toast"; import { Plus, Users, User, Layers, Clock, CheckCircle2, Circle, AlertCircle, Play, Pause, MoreHorizontal, Calendar, Timer, Trash2, FolderKanban, Building2, Briefcase, FileText, Bot, Search, DollarSign, TrendingUp, Target, Zap, ArrowRight, Paperclip, Upload, Loader2, BarChart3, ChevronRight, GripVertical, Star, Flag } from "lucide-react"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator } from "@/components/ui/dropdown-menu"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; interface Project { id: number; name: string; description?: string; type: "internal" | "external" | "compass"; clientId?: number; clientName?: string; compassProjectId?: number; status: string; budget?: number; totalCost?: number; startDate?: string; endDate?: string; } interface Squad { id: number; name: string; description?: string; membersCount?: number; color?: string; productOwnerId?: string; techLeadId?: string; leaderId?: string; } interface Collaborator { id: string; name: string; username: string; email?: string; phone?: string; collaboratorType: string; hourlyRate?: string; skills?: string[]; status?: string; } interface ProjectMember { id: number; projectId: number; userId?: string; collaboratorId?: number; role: "product_owner" | "tech_lead" | "member"; isExternal: boolean; assignedAt: string; userName?: string; userEmail?: string; userHourlyRate?: string; collaboratorName?: string; collaboratorEmail?: string; collaboratorHourlyRate?: string; collaboratorType?: string; } interface ExternalCollaborator { id: number; tenantId: number; name: string; email?: string; phone?: string; type: string; hourlyRate?: string; skills?: string[]; notes?: string; status?: string; } interface Sprint { id: number; projectId?: number; projectName?: string; squadId?: number; name: string; goal?: string; startDate?: string; endDate?: string; status: string; velocity?: number; completedPoints?: number; } interface WorkItem { id: number; projectId?: number; squadId?: number; sprintId?: number; parentId?: number; code?: string; title: string; description?: string; type: string; status: string; priority: string; storyPoints?: number; effortScore?: number; estimatedHours?: number; actualHours?: number; hourlyRate?: number; totalCost?: number; origin?: string; originId?: number; assigneeId?: string; assigneeName?: string; tags?: string[]; attachments?: { id: number; name: string; url: string }[]; } interface Timesheet { id: number; workItemId?: number; workItemTitle?: string; projectId?: number; sprintId?: number; userId: string; userName?: string; date: string; hours: number; description?: string; hourlyRate?: number; totalCost?: number; billable?: boolean; status?: "draft" | "pending" | "approved" | "rejected"; timerStartedAt?: string; approvedById?: string; approvedByName?: string; approvedAt?: string; } interface SquadMember { id: number; squadId: number; userId: string; memberRole?: string; userName?: string; collaboratorType?: string; hourlyRate?: string; } function SquadDetailContent({ squad, collaborators, onUpdate, onAddCollaborator, onDelete, onClose }: { squad: Squad; collaborators: Collaborator[]; onUpdate: (squad: Squad) => void; onAddCollaborator: () => void; onDelete: () => void; onClose: () => void; }) { const [members, setMembers] = useState([]); const [loadingMembers, setLoadingMembers] = useState(true); const [addingMember, setAddingMember] = useState(false); const [selectedMemberId, setSelectedMemberId] = useState(""); const [memberRole, setMemberRole] = useState("member"); const [editName, setEditName] = useState(squad.name); const [editDescription, setEditDescription] = useState(squad.description || ""); const [saving, setSaving] = useState(false); const [confirmDelete, setConfirmDelete] = useState(false); useEffect(() => { fetch(`/api/production/squads/${squad.id}/members`, { credentials: "include" }) .then(r => r.json()) .then(data => { setMembers(Array.isArray(data) ? data : []); setLoadingMembers(false); }) .catch(() => setLoadingMembers(false)); }, [squad.id]); const updateSquadField = async (field: string, value: string | null) => { const res = await fetch(`/api/production/squads/${squad.id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ [field]: value }), credentials: "include", }); if (res.ok) { const updated = await res.json(); onUpdate({ ...squad, ...updated }); } }; const saveChanges = async () => { if (!editName.trim()) return; setSaving(true); const res = await fetch(`/api/production/squads/${squad.id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: editName.trim(), description: editDescription.trim() || null }), credentials: "include", }); if (res.ok) { const updated = await res.json(); onUpdate({ ...squad, ...updated }); } setSaving(false); }; const handleDelete = async () => { await fetch(`/api/production/squads/${squad.id}`, { method: "DELETE", credentials: "include", }); onDelete(); onClose(); }; const addMember = async () => { if (!selectedMemberId) return; setAddingMember(true); const res = await fetch(`/api/production/squads/${squad.id}/members`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ userId: selectedMemberId, memberRole }), credentials: "include", }); if (res.ok) { const newMember = await res.json(); const collab = collaborators.find(c => c.id === selectedMemberId); setMembers([...members, { ...newMember, userName: collab?.name, collaboratorType: collab?.collaboratorType, hourlyRate: collab?.hourlyRate }]); setSelectedMemberId(""); setMemberRole("member"); } setAddingMember(false); }; const removeMember = async (userId: string) => { await fetch(`/api/production/squads/${squad.id}/members/${userId}`, { method: "DELETE", credentials: "include", }); setMembers(members.filter(m => m.userId !== userId)); }; const availableCollabs = collaborators.filter(c => !members.some(m => m.userId === c.id)); if (confirmDelete) { return (

Excluir Squad

Tem certeza que deseja excluir o squad "{squad.name}"? Esta ação não pode ser desfeita.

); } return (
setEditName(e.target.value)} placeholder="Nome do squad" />