import { BrowserFrame } from "@/components/Browser/BrowserFrame"; import { useState, useEffect } from "react"; import BpmnDiagram from "@/components/BpmnDiagram"; import { useLocation } from "wouter"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { Textarea } from "@/components/ui/textarea"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Slider } from "@/components/ui/slider"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"; import { Checkbox } from "@/components/ui/checkbox"; import { LayoutDashboard, Users, FolderKanban, Target, TrendingUp, FileText, Plus, Trash2, Settings, Loader2, Building2, Phone, Mail, Globe, MapPin, ChevronRight, Calendar, Clock, BarChart3, Briefcase, UserPlus, Search, Filter, MoreVertical, Edit, Eye, CheckCircle, AlertCircle, Compass, Network, ClipboardList, Layers, Menu, X, RefreshCw, FileCheck, HelpCircle, Info, ExternalLink, Download, Lightbulb, Pencil, LayoutGrid, } from "lucide-react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuSeparator, } from "@/components/ui/dropdown-menu"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { toast } from "sonner"; import { ProcessDiagram } from "@/components/ProcessDiagram"; import { RichTextEditor } from "@/components/RichTextEditor"; import { Upload, UserX, Save, CirclePlay } from "lucide-react"; interface CompassStats { clients: number; projects: number; leads: number; opportunities: number; activeProjects: number; openOpportunities: number; } interface PcClient { id: number; tenantId: number; userId: string; name: string; email: string | null; phone: string | null; company: string | null; industry: string | null; website: string | null; address: string | null; notes: string | null; logoUrl: string | null; status: string; createdAt: string; } interface PcProject { id: number; tenantId: number; clientId: number; name: string; description: string | null; projectType: string; status: string; startDate: string | null; dueDate: string | null; priority: number; createdAt: string; } interface PcCrmLead { id: number; name: string; email: string | null; phone: string | null; company: string | null; source: string | null; status: string; createdAt: string; } interface PcCrmOpportunity { id: number; name: string; value: number; probability: number; status: string; expectedCloseDate: string | null; createdAt: string; } interface Tenant { id: number; name: string; slug: string | null; plan: string; status: string; } interface PcCanvasBlock { id: number; projectId: number; blockType: string; level: string; title: string | null; content: string | null; notes: string | null; score: number; synthesis: string | null; } interface PcCanvasQuestion { id: number; blockId: number; question: string; answer: string | null; score: number | null; orderIndex: number; } interface PcCanvasExpectedOutput { id: number; blockId: number; description: string; completed: boolean; orderIndex: number; } interface PcCanvasPdcaLink { id: number; blockId: number; pdcaActionId: number; observation: string | null; } interface PcCanvasSwotLink { id: number; blockId: number; swotItemId: number; } interface PcProcess { id: number; projectId: number; name: string; description: string | null; category: string | null; owner: string | null; status: string; priority: number; diagramNodes?: any[]; diagramEdges?: any[]; diagramViewport?: { x: number; y: number; zoom: number }; } interface PcProcessStep { id: number; processId: number; name: string; description: string | null; responsible: string | null; inputs: string | null; outputs: string | null; systems: string | null; duration: string | null; painPoints: string | null; suggestions: string | null; order: number; } interface PcSwotAnalysis { id: number; projectId: number; name: string; description: string | null; sector: string | null; status: string; } interface PcSwotItem { id: number; swotAnalysisId: number; type: string; title: string | null; description: string; impact: string; impactScore: number; priorityLevel: string; priority: number; actionPlan: string | null; result: string | null; pdcaStatus: string; responsible: string | null; dueDate: string | null; status: string; } interface PcPdcaCycle { id: number; tenantId: number; projectId: number | null; title: string; description: string | null; status: string; priority: string; dueDate: string | null; createdAt: string; } interface PdcaOverviewItem { id: number; source: 'canvas' | 'processes' | 'swot' | 'requirements'; title: string; description: string | null; pdcaStatus: string; pdcaActionPlan: string | null; pdcaResult: string | null; projectId: number; } interface PdcaOverviewStats { total: number; plan: number; do: number; check: number; act: number; done: number; } interface PdcaOverview { items: PdcaOverviewItem[]; stats: { canvas: PdcaOverviewStats; processes: PdcaOverviewStats; swot: PdcaOverviewStats; requirements: PdcaOverviewStats; }; } interface PcPdcaAction { id: number; cycleId: number; phase: string; title: string; description: string | null; responsible: string | null; status: string; dueDate: string | null; } interface PcRequirement { id: number; tenantId: number; projectId: number | null; code: string | null; title: string; description: string | null; type: string; priority: string; status: string; source: string | null; category: string | null; acceptanceCriteria: string | null; createdAt: string; } interface PcTeamMember { id: number; projectId: number; name: string; email: string | null; role: string; createdAt: string; } interface PcProjectFile { id: number; projectId: number; name: string; originalName: string; mimeType: string; size: number; url: string; createdAt: string; } interface PcProjectTask { id: number; projectId: number; title: string; description: string | null; status: string; priority: string; assignedTo: string | null; dueDate: string | null; createdAt: string; } interface PcProjectHistory { id: number; projectId: number; content: string; updatedAt: string; } const PDCA_PHASES = [ { id: "plan", label: "Plan", color: "bg-blue-100 text-blue-800" }, { id: "do", label: "Do", color: "bg-green-100 text-green-800" }, { id: "check", label: "Check", color: "bg-yellow-100 text-yellow-800" }, { id: "act", label: "Act", color: "bg-purple-100 text-purple-800" }, ]; const REQUIREMENT_TYPES = [ { id: "functional", label: "Funcional" }, { id: "non_functional", label: "Não Funcional" }, { id: "business", label: "Negócio" }, { id: "technical", label: "Técnico" }, ]; const REQUIREMENT_STATUS = [ { id: "draft", label: "Rascunho" }, { id: "approved", label: "Aprovado" }, { id: "implemented", label: "Implementado" }, { id: "verified", label: "Verificado" }, { id: "rejected", label: "Rejeitado" }, ]; const CANVAS_BLOCK_TYPES = [ { id: "value_propositions", label: "Proposta de Valor", color: "bg-green-100 border-green-300", description: "Sentido / Propósito" }, { id: "customer_segments", label: "Segmentos de Clientes", color: "bg-orange-100 border-orange-300", description: "Quem recebe nossa transformação" }, { id: "channels", label: "Canais", color: "bg-yellow-100 border-yellow-300", description: "Caminhos / Pontes" }, { id: "customer_relationships", label: "Relacionamento", color: "bg-yellow-100 border-yellow-300", description: "Forma de Amar/Servir" }, { id: "revenue_streams", label: "Fontes de Receita", color: "bg-emerald-100 border-emerald-300", description: "Energia que sustenta o propósito" }, { id: "key_resources", label: "Recursos-Chave", color: "bg-blue-100 border-blue-300", description: "Capacidades / Disposições" }, { id: "key_activities", label: "Atividades-Chave", color: "bg-blue-100 border-blue-300", description: "Ações / Ritmos" }, { id: "key_partners", label: "Parcerias-Chave", color: "bg-purple-100 border-purple-300", description: "Alianças e interdependência" }, { id: "cost_structure", label: "Estrutura de Custos", color: "bg-red-100 border-red-300", description: "Sacrifícios / Investimentos" }, ]; const CANVAS_LEVELS = [ { id: "atual", label: "Atual", description: "Estado atual do negócio - como está hoje" }, { id: "sistemico", label: "Sistêmico", description: "Visão sistêmica e estratégica" }, { id: "intencao", label: "Intenção", description: "O que pretendemos fazer" }, { id: "evidencias", label: "Evidências", description: "O que temos de concreto" }, { id: "transformacao", label: "Transformação", description: "O que queremos mudar" }, ]; const PROCESS_CATEGORIES = [ { id: "operacional", label: "Operacional" }, { id: "comercial", label: "Comercial" }, { id: "administrativo", label: "Administrativo" }, { id: "financeiro", label: "Financeiro" }, ]; const SWOT_SECTORS = [ { id: "general", label: "Geral" }, { id: "comercial", label: "Comercial" }, { id: "operacional", label: "Operacional" }, { id: "financeiro", label: "Financeiro" }, { id: "rh", label: "Recursos Humanos" }, ]; const INDUSTRY_TEMPLATES: Record = { tecnologia: { strengths: ["Inovação e desenvolvimento ágil", "Equipe técnica qualificada", "Escalabilidade de soluções", "Cultura de aprendizado contínuo"], weaknesses: ["Alta rotatividade de talentos", "Dependência de tecnologias específicas", "Custos elevados de P&D", "Documentação técnica deficiente"], opportunities: ["Transformação digital do mercado", "Novos nichos e verticais", "Parcerias estratégicas", "Expansão internacional"], threats: ["Concorrência global intensa", "Mudanças tecnológicas rápidas", "Regulamentações de dados (LGPD)", "Ataques cibernéticos"], }, varejo: { strengths: ["Localização privilegiada", "Conhecimento do cliente local", "Variedade de produtos", "Atendimento personalizado"], weaknesses: ["Margens reduzidas", "Gestão de estoque complexa", "Sazonalidade de vendas", "Alto custo de aluguel"], opportunities: ["E-commerce e omnichannel", "Programas de fidelidade", "Novos canais de venda", "Parcerias com influenciadores"], threats: ["Concorrência online", "Mudanças de hábitos de consumo", "Flutuações econômicas", "Aumento de custos logísticos"], }, servicos: { strengths: ["Expertise especializada", "Relacionamento com clientes", "Flexibilidade de entrega", "Baixo investimento inicial"], weaknesses: ["Dependência de pessoas-chave", "Dificuldade de escalar", "Precificação subjetiva", "Gestão de expectativas"], opportunities: ["Digitalização de serviços", "Novos modelos de assinatura", "Expansão de portfólio", "Certificações e especializações"], threats: ["Commoditização de serviços", "Novos entrantes", "Automação de processos", "Pressão por redução de preços"], }, manufatura: { strengths: ["Capacidade produtiva instalada", "Controle de qualidade", "Economia de escala", "Expertise técnica"], weaknesses: ["Alto custo fixo", "Obsolescência de equipamentos", "Dependência de fornecedores", "Lead time extenso"], opportunities: ["Indústria 4.0 e IoT", "Novos mercados de exportação", "Sustentabilidade e ESG", "Customização em massa"], threats: ["Importação de produtos mais baratos", "Volatilidade de matérias-primas", "Regulamentações ambientais", "Escassez de mão de obra qualificada"], }, saude: { strengths: ["Profissionais qualificados", "Infraestrutura especializada", "Credibilidade institucional", "Demanda constante"], weaknesses: ["Custos operacionais elevados", "Burocracia regulatória", "Gestão de agenda complexa", "Alta dependência de convênios"], opportunities: ["Telemedicina e saúde digital", "Turismo médico", "Novos tratamentos e tecnologias", "Programas preventivos"], threats: ["Mudanças em planos de saúde", "Judicialização", "Novas regulamentações ANVISA", "Concorrência de grandes redes"], }, }; const MODULE_HELP: Record = { canvas: { title: "Canvas BMC Expandido", description: "Diagnóstico estratégico em múltiplos níveis evolutivos para análise completa do modelo de negócio.", tips: [ "Use os níveis Atual e Sistêmico para diagnóstico estratégico", "Cada bloco tem perguntas diagnósticas para avaliação de maturidade", "A maturidade geral mostra o progresso do diagnóstico", ], }, swot: { title: "Análise SWOT", description: "Metodologia estratégica para analisar Forças, Fraquezas, Oportunidades e Ameaças do negócio.", tips: [ "Use templates por indústria para acelerar sua análise", "Cruze forças com oportunidades para criar estratégias ofensivas (SO)", "Identifique ameaças que podem explorar suas fraquezas (WT)", ], }, pdca: { title: "Ciclo PDCA", description: "Metodologia de melhoria contínua em 4 fases: Planejar (Plan), Executar (Do), Verificar (Check), Agir (Act).", tips: [ "Defina métricas claras na fase Plan", "Documente aprendizados na fase Check", "Use Act para padronizar melhorias que funcionaram", ], }, processes: { title: "Mapeamento de Processos", description: "Documentação detalhada dos processos de negócio, incluindo entradas, saídas e pontos de dor.", tips: [ "Identifique os processos críticos primeiro", "Documente os pain points para priorizar melhorias", "Defina responsáveis claros para cada etapa", ], }, }; const statusColors: Record = { backlog: "bg-gray-100 text-gray-800", diagnostico: "bg-blue-100 text-blue-800", andamento: "bg-yellow-100 text-yellow-800", revisao: "bg-purple-100 text-purple-800", concluido: "bg-green-100 text-green-800", active: "bg-green-100 text-green-800", inactive: "bg-gray-100 text-gray-800", prospect: "bg-blue-100 text-blue-800", new: "bg-blue-100 text-blue-800", contacted: "bg-yellow-100 text-yellow-800", qualified: "bg-purple-100 text-purple-800", converted: "bg-green-100 text-green-800", lost: "bg-red-100 text-red-800", open: "bg-blue-100 text-blue-800", won: "bg-green-100 text-green-800", }; const statusLabels: Record = { backlog: "Backlog", diagnostico: "Diagnóstico", andamento: "Em Andamento", revisao: "Revisão", concluido: "Concluído", active: "Ativo", inactive: "Inativo", prospect: "Prospecto", new: "Novo", contacted: "Contatado", qualified: "Qualificado", converted: "Convertido", lost: "Perdido", open: "Aberta", won: "Ganha", }; export default function ProcessCompass() { const [, navigate] = useLocation(); const [activeTab, setActiveTab] = useState("dashboard"); const [projectDetailTab, setProjectDetailTab] = useState("overview"); const [activeValuationSubTab, setActiveValuationSubTab] = useState("overview"); const [showNewClientDialog, setShowNewClientDialog] = useState(false); const [showNewProjectDialog, setShowNewProjectDialog] = useState(false); const [showNewLeadDialog, setShowNewLeadDialog] = useState(false); const [showNewTenantDialog, setShowNewTenantDialog] = useState(false); const [showNewProcessDialog, setShowNewProcessDialog] = useState(false); const [showNewSwotDialog, setShowNewSwotDialog] = useState(false); const [searchTerm, setSearchTerm] = useState(""); const [selectedProjectId, setSelectedProjectId] = useState(null); const [selectedCanvasLevel, setSelectedCanvasLevel] = useState("atual"); const [selectedProcessId, setSelectedProcessId] = useState(null); const [processView, setProcessView] = useState<"steps" | "diagram">("steps"); const [selectedSwotId, setSelectedSwotId] = useState(null); const [editingBlock, setEditingBlock] = useState(null); const [canvasDialogTab, setCanvasDialogTab] = useState("content"); const [newQuestionText, setNewQuestionText] = useState(""); const [newOutputText, setNewOutputText] = useState(""); const [newProcessCategory, setNewProcessCategory] = useState(""); const [newSwotSector, setNewSwotSector] = useState(""); const [sidebarOpen, setSidebarOpen] = useState(false); const [selectedIndustryTemplate, setSelectedIndustryTemplate] = useState(null); const [showModuleHelp, setShowModuleHelp] = useState(null); const [showNewPdcaDialog, setShowNewPdcaDialog] = useState(false); const [showNewRequirementDialog, setShowNewRequirementDialog] = useState(false); const [newReqTitle, setNewReqTitle] = useState(""); const [newReqDescription, setNewReqDescription] = useState(""); const [newReqType, setNewReqType] = useState("functional"); const [newReqPriority, setNewReqPriority] = useState("medium"); const [showValuationProjectDialog, setShowValuationProjectDialog] = useState(false); const [showEditProjectDialog, setShowEditProjectDialog] = useState(false); const [editingProject, setEditingProject] = useState(null); const [showDeleteProjectConfirm, setShowDeleteProjectConfirm] = useState(false); const [projectToDelete, setProjectToDelete] = useState(null); const [selectedPdcaId, setSelectedPdcaId] = useState(null); const [editingSwotItem, setEditingSwotItem] = useState(null); const [swotItemEditTab, setSwotItemEditTab] = useState("details"); const [swotPdcaStatus, setSwotPdcaStatus] = useState("plan"); const [pdcaPhaseFilter, setPdcaPhaseFilter] = useState("all"); const [pdcaSourceFilter, setPdcaSourceFilter] = useState("all"); const [showReportConfigModal, setShowReportConfigModal] = useState(false); const [showProcessDiagramDialog, setShowProcessDiagramDialog] = useState(false); const [diagramProcessId, setDiagramProcessId] = useState(null); const [showTeamMemberDialog, setShowTeamMemberDialog] = useState(false); const [showNewTaskDialog, setShowNewTaskDialog] = useState(false); const [showFileUploadDialog, setShowFileUploadDialog] = useState(false); const [projectHistoryContent, setProjectHistoryContent] = useState(""); const [historyIsSaving, setHistoryIsSaving] = useState(false); const [newMemberRole, setNewMemberRole] = useState(""); const [newTaskPriority, setNewTaskPriority] = useState("medium"); const [showReportEditorDialog, setShowReportEditorDialog] = useState(false); const [editingReport, setEditingReport] = useState(null); const [reportContent, setReportContent] = useState(""); const [reportName, setReportName] = useState(""); const [reportIsSaving, setReportIsSaving] = useState(false); const [reportConfigTemplate, setReportConfigTemplate] = useState("full_diagnostic"); const [reportConfigSections, setReportConfigSections] = useState([ "project_info", "history", "canvas_atual", "swot", "processes", "pdca", "tasks", "requirements" ]); const queryClient = useQueryClient(); const REPORT_SECTIONS = [ { id: "project_info", label: "Informações do Projeto", description: "Dados básicos do projeto e cliente", icon: "building" }, { id: "history", label: "História do Projeto", description: "Contexto, evolução e documentação do projeto", icon: "book" }, { id: "canvas_atual", label: "Canvas BMC - Atual", description: "Business Model Canvas nível Atual (Intenção)", icon: "layout" }, { id: "canvas_sistemico", label: "Canvas BMC - Sistêmico", description: "Business Model Canvas nível Sistêmico", icon: "layout" }, { id: "swot", label: "Análise SWOT", description: "Forças, Fraquezas, Oportunidades e Ameaças", icon: "grid" }, { id: "processes", label: "Processos", description: "Mapeamento de processos de negócio", icon: "workflow" }, { id: "pdca", label: "Plano PDCA Consolidado", description: "Ciclos de melhoria contínua", icon: "refresh" }, { id: "deliverables", label: "Entregas", description: "Entregáveis e marcos do projeto", icon: "package" }, { id: "tasks", label: "Tarefas", description: "Atividades e responsáveis", icon: "check" }, { id: "requirements", label: "Requisitos ERP", description: "Requisitos de aderência ao ERP", icon: "database" }, ]; const toggleReportSection = (sectionId: string) => { setReportConfigSections(prev => prev.includes(sectionId) ? prev.filter(s => s !== sectionId) : [...prev, sectionId] ); }; const { data: stats, isLoading: statsLoading } = useQuery({ queryKey: ["/api/compass/stats"], }); const { data: tenants = [], isLoading: tenantsLoading } = useQuery({ queryKey: ["/api/compass/tenants"], }); const { data: clients = [], isLoading: clientsLoading } = useQuery({ queryKey: ["/api/compass/clients"], }); const { data: projects = [], isLoading: projectsLoading } = useQuery({ queryKey: ["/api/compass/projects"], }); const { data: canvasBlocks = [] } = useQuery({ queryKey: ["/api/compass/projects", selectedProjectId, "canvas"], queryFn: async () => { if (!selectedProjectId) return []; const res = await fetch(`/api/compass/projects/${selectedProjectId}/canvas`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedProjectId, }); const { data: canvasQuestions = [] } = useQuery({ queryKey: ["/api/compass/canvas", editingBlock?.id, "questions"], queryFn: async () => { if (!editingBlock?.id) return []; const res = await fetch(`/api/compass/canvas/${editingBlock.id}/questions`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!editingBlock?.id, }); const { data: canvasOutputs = [] } = useQuery({ queryKey: ["/api/compass/canvas", editingBlock?.id, "outputs"], queryFn: async () => { if (!editingBlock?.id) return []; const res = await fetch(`/api/compass/canvas/${editingBlock.id}/outputs`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!editingBlock?.id, }); const { data: canvasPdcaLinks = [] } = useQuery({ queryKey: ["/api/compass/canvas", editingBlock?.id, "pdca"], queryFn: async () => { if (!editingBlock?.id) return []; const res = await fetch(`/api/compass/canvas/${editingBlock.id}/pdca`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!editingBlock?.id, }); const { data: canvasSwotLinks = [] } = useQuery({ queryKey: ["/api/compass/canvas", editingBlock?.id, "swot"], queryFn: async () => { if (!editingBlock?.id) return []; const res = await fetch(`/api/compass/canvas/${editingBlock.id}/swot`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!editingBlock?.id, }); const { data: processes = [] } = useQuery({ queryKey: ["/api/compass/projects", selectedProjectId, "processes"], queryFn: async () => { if (!selectedProjectId) return []; const res = await fetch(`/api/compass/projects/${selectedProjectId}/processes`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedProjectId, }); const { data: processSteps = [] } = useQuery({ queryKey: ["/api/compass/processes", selectedProcessId, "steps"], queryFn: async () => { if (!selectedProcessId) return []; const res = await fetch(`/api/compass/processes/${selectedProcessId}/steps`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedProcessId, }); const { data: swotAnalyses = [] } = useQuery({ queryKey: ["/api/compass/projects", selectedProjectId, "swot"], queryFn: async () => { if (!selectedProjectId) return []; const res = await fetch(`/api/compass/projects/${selectedProjectId}/swot`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedProjectId, }); const { data: swotItems = [] } = useQuery({ queryKey: ["/api/compass/swot", selectedSwotId, "items"], queryFn: async () => { if (!selectedSwotId) return []; const res = await fetch(`/api/compass/swot/${selectedSwotId}/items`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedSwotId, }); const { data: pdcaCycles = [] } = useQuery({ queryKey: ["/api/compass/pdca", selectedProjectId], queryFn: async () => { const url = selectedProjectId ? `/api/compass/pdca?projectId=${selectedProjectId}` : `/api/compass/pdca`; const res = await fetch(url, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, }); const { data: pdcaOverview } = useQuery({ queryKey: ["/api/compass/pdca/overview", selectedProjectId], queryFn: async () => { if (!selectedProjectId) return { items: [], stats: { canvas: { total: 0, plan: 0, do: 0, check: 0, act: 0, done: 0 }, processes: { total: 0, plan: 0, do: 0, check: 0, act: 0, done: 0 }, swot: { total: 0, plan: 0, do: 0, check: 0, act: 0, done: 0 }, requirements: { total: 0, plan: 0, do: 0, check: 0, act: 0, done: 0 } } }; const res = await fetch(`/api/compass/pdca/overview/${selectedProjectId}`, { credentials: "include" }); if (!res.ok) return { items: [], stats: { canvas: { total: 0, plan: 0, do: 0, check: 0, act: 0, done: 0 }, processes: { total: 0, plan: 0, do: 0, check: 0, act: 0, done: 0 }, swot: { total: 0, plan: 0, do: 0, check: 0, act: 0, done: 0 }, requirements: { total: 0, plan: 0, do: 0, check: 0, act: 0, done: 0 } } }; return res.json(); }, enabled: !!selectedProjectId, }); // Valuation-specific queries for the integrated tab const selectedProject = projects.find((p) => p.id === selectedProjectId); const { data: valuationSectorAnalysis } = useQuery({ queryKey: ["/api/valuation/projects", selectedProjectId, "sector-analysis"], queryFn: async () => { const res = await fetch(`/api/valuation/projects/${selectedProjectId}/sector-analysis`); return res.json(); }, enabled: !!selectedProjectId && selectedProject?.projectType === "valuation", }); const { data: valuationChecklist = [] } = useQuery({ queryKey: ["/api/valuation/projects", selectedProjectId, "checklist"], queryFn: async () => { const res = await fetch(`/api/valuation/projects/${selectedProjectId}/checklist`); return res.json(); }, enabled: !!selectedProjectId && selectedProject?.projectType === "valuation", }); const { data: valuationCanvasBlocks = [] } = useQuery({ queryKey: ["/api/valuation/projects", selectedProjectId, "valuation-canvas"], queryFn: async () => { const res = await fetch(`/api/valuation/projects/${selectedProjectId}/canvas`); return res.json(); }, enabled: !!selectedProjectId && selectedProject?.projectType === "valuation", }); const { data: generatedReports = [] } = useQuery({ queryKey: ["/api/compass/generated-reports", selectedProjectId], queryFn: async () => { const res = await fetch(`/api/compass/generated-reports?projectId=${selectedProjectId}`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedProjectId, }); const { data: projectTeamMembers = [] } = useQuery({ queryKey: ["/api/compass/projects", selectedProjectId, "team"], queryFn: async () => { if (!selectedProjectId) return []; const res = await fetch(`/api/compass/projects/${selectedProjectId}/team`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedProjectId, }); const { data: projectTasks = [] } = useQuery({ queryKey: ["/api/compass/projects", selectedProjectId, "tasks"], queryFn: async () => { if (!selectedProjectId) return []; const res = await fetch(`/api/compass/projects/${selectedProjectId}/tasks`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedProjectId, }); const { data: projectFiles = [] } = useQuery({ queryKey: ["/api/compass/projects", selectedProjectId, "files"], queryFn: async () => { if (!selectedProjectId) return []; const res = await fetch(`/api/compass/projects/${selectedProjectId}/files`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedProjectId, }); const { data: projectHistory } = useQuery({ queryKey: ["/api/compass/projects", selectedProjectId, "history"], queryFn: async () => { if (!selectedProjectId) return null; const res = await fetch(`/api/compass/projects/${selectedProjectId}/history`, { credentials: "include" }); if (!res.ok) return null; return res.json(); }, enabled: !!selectedProjectId, }); useEffect(() => { if (projectHistory?.content) { setProjectHistoryContent(projectHistory.content); } else { setProjectHistoryContent(""); } }, [projectHistory]); const generateReportMutation = useMutation({ mutationFn: async ({ projectId, name, templateType, format, sections }: { projectId: number; name: string; templateType: string; format: string; sections?: string[] }) => { const res = await fetch("/api/compass/generated-reports", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ projectId, name, reportType: templateType, format, status: "pending", sections }), }); if (!res.ok) throw new Error("Falha ao criar relatório"); const report = await res.json(); const generateRes = await fetch(`/api/compass/generated-reports/${report.id}/generate`, { method: "POST", credentials: "include", }); return generateRes.json(); }, onSuccess: (data) => { queryClient.invalidateQueries({ queryKey: ["/api/compass/generated-reports"] }); toast.success("Relatório gerado com sucesso!"); if (data && data.content) { setEditingReport(data); setReportName(data.name || ""); setReportContent(data.content || ""); setShowReportEditorDialog(true); } }, onError: () => { toast.error("Erro ao gerar relatório"); }, }); const handleQuickReport = (templateType: string) => { if (!selectedProjectId) return; const templateNames: Record = { executive_summary: "Sumário Executivo", full_diagnostic: "Diagnóstico Completo", swot_report: "Análise SWOT", }; const project = projects.find(p => p.id === selectedProjectId); const reportName = `${templateNames[templateType] || templateType} - ${project?.name || "Projeto"}`; generateReportMutation.mutate({ projectId: selectedProjectId, name: reportName, templateType, format: "pdf" }); }; const openReportEditor = async (report: any) => { setEditingReport(report); setReportName(report.name || ""); setReportContent(report.content || ""); setShowReportEditorDialog(true); }; const saveReportContent = async () => { if (!editingReport) return; setReportIsSaving(true); try { const res = await fetch(`/api/compass/generated-reports/${editingReport.id}/content`, { method: "PATCH", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ content: reportContent, name: reportName }), }); if (!res.ok) throw new Error("Falha ao salvar"); queryClient.invalidateQueries({ queryKey: ["/api/compass/generated-reports"] }); toast.success("Relatório salvo com sucesso!"); } catch (error) { toast.error("Erro ao salvar relatório"); } finally { setReportIsSaving(false); } }; const exportReportAsPDF = async () => { if (!reportContent) return; const printWindow = window.open("", "_blank"); if (printWindow) { printWindow.document.write(` ${reportName} ${reportContent} `); printWindow.document.close(); setTimeout(() => printWindow.print(), 500); } }; const initializeValuationChecklistMutation = useMutation({ mutationFn: async () => { const segment = selectedProject?.name?.includes("Indústria") ? "industry" : selectedProject?.name?.includes("Serviços") ? "services" : selectedProject?.name?.includes("Varejo") ? "retail" : selectedProject?.name?.includes("Tecnologia") ? "technology" : "general"; const res = await fetch(`/api/valuation/projects/${selectedProjectId}/checklist/initialize`, { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ segment }), }); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/valuation/projects", selectedProjectId, "checklist"] }); }, }); const VALUATION_CANVAS_BLOCKS = [ { id: "customer_segments", label: "Segmentos de Clientes", description: "Para quem criamos valor?" }, { id: "value_proposition", label: "Proposta de Valor", description: "Que valor entregamos?" }, { id: "channels", label: "Canais", description: "Como alcançamos nossos clientes?" }, { id: "customer_relationships", label: "Relacionamento", description: "Como nos relacionamos?" }, { id: "revenue_streams", label: "Fontes de Receita", description: "Como geramos receita?" }, { id: "key_resources", label: "Recursos Principais", description: "Quais recursos são essenciais?" }, { id: "key_activities", label: "Atividades Principais", description: "O que fazemos de mais importante?" }, { id: "key_partnerships", label: "Parcerias Principais", description: "Quem são nossos parceiros?" }, { id: "cost_structure", label: "Estrutura de Custos", description: "Quais são nossos custos?" }, ]; const getValuationBlockData = (blockType: string) => { if (!Array.isArray(valuationCanvasBlocks)) return undefined; return valuationCanvasBlocks.find((b: any) => b.blockType === blockType); }; const getValuationScoreLevel = (score: number) => { if (score >= 80) return { label: "Excelente", color: "text-emerald-600" }; if (score >= 60) return { label: "Bom", color: "text-blue-600" }; if (score >= 40) return { label: "Intermediário", color: "text-yellow-600" }; return { label: "Inicial", color: "text-red-600" }; }; const { data: pdcaActions = [] } = useQuery({ queryKey: ["/api/compass/pdca", selectedPdcaId, "actions"], queryFn: async () => { if (!selectedPdcaId) return []; const res = await fetch(`/api/compass/pdca/${selectedPdcaId}/actions`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedPdcaId, }); const { data: requirements = [] } = useQuery({ queryKey: ["/api/compass/requirements", selectedProjectId], queryFn: async () => { const url = selectedProjectId ? `/api/compass/requirements?projectId=${selectedProjectId}` : `/api/compass/requirements`; const res = await fetch(url, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, }); const createTenantMutation = useMutation({ mutationFn: async (data: { name: string; slug?: string }) => { const res = await fetch("/api/compass/tenants", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar organização"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/tenants"] }); queryClient.invalidateQueries({ queryKey: ["/api/compass/stats"] }); setShowNewTenantDialog(false); }, }); const { data: crmPartners = [] } = useQuery({ queryKey: ["/api/crm/partners"], queryFn: async () => { const res = await fetch("/api/crm/partners", { credentials: "include" }); if (!res.ok) return []; return res.json(); }, }); const createClientMutation = useMutation({ mutationFn: async (data: any) => { const res = await fetch("/api/crm/clients", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar cliente"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/clients"] }); queryClient.invalidateQueries({ queryKey: ["/api/crm/clients"] }); queryClient.invalidateQueries({ queryKey: ["/api/compass/stats"] }); setShowNewClientDialog(false); }, }); const createProjectMutation = useMutation({ mutationFn: async (data: { name: string; clientId: number; description?: string; status?: string; projectType?: string }) => { const res = await fetch("/api/compass/projects", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar projeto"); return res.json(); }, onSuccess: (createdProject: PcProject) => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects"] }); queryClient.invalidateQueries({ queryKey: ["/api/compass/stats"] }); setShowNewProjectDialog(false); setSelectedProjectId(createdProject.id); setProjectDetailTab("overview"); setActiveTab("project-detail"); }, }); const updateProjectMutation = useMutation({ mutationFn: async (data: { id: number; name?: string; description?: string; status?: string }) => { const res = await fetch(`/api/compass/projects/${data.id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao atualizar projeto"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects"] }); toast.success("Projeto atualizado com sucesso"); }, }); const deleteProjectMutation = useMutation({ mutationFn: async (projectId: number) => { const res = await fetch(`/api/compass/projects/${projectId}`, { method: "DELETE", credentials: "include", }); if (!res.ok) throw new Error("Falha ao excluir projeto"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects"] }); queryClient.invalidateQueries({ queryKey: ["/api/compass/stats"] }); toast.success("Projeto excluído com sucesso"); }, }); const createLeadMutation = useMutation({ mutationFn: async (data: { name: string; email?: string; phone?: string; company?: string; source?: string }) => { const res = await fetch("/api/compass/crm/leads", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar lead"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/crm/leads"] }); queryClient.invalidateQueries({ queryKey: ["/api/compass/stats"] }); setShowNewLeadDialog(false); }, }); const upsertCanvasBlockMutation = useMutation({ mutationFn: async (data: { id?: number; blockType: string; level: string; title?: string; content?: string; notes?: string; score?: number; synthesis?: string }) => { if (data.id) { const res = await fetch(`/api/compass/canvas/${data.id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao atualizar bloco"); return res.json(); } else { const res = await fetch(`/api/compass/projects/${selectedProjectId}/canvas`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar bloco"); return res.json(); } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "canvas"] }); setEditingBlock(null); }, }); const addCanvasQuestionMutation = useMutation({ mutationFn: async (data: { question: string; orderIndex: number }) => { if (!editingBlock?.id) throw new Error("Bloco não selecionado"); const res = await fetch(`/api/compass/canvas/${editingBlock.id}/questions`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar pergunta"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/canvas", editingBlock?.id, "questions"] }); setNewQuestionText(""); }, }); const updateCanvasQuestionMutation = useMutation({ mutationFn: async (data: { id: number; answer?: string; score?: number }) => { const res = await fetch(`/api/compass/canvas/questions/${data.id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ answer: data.answer, score: data.score }), credentials: "include", }); if (!res.ok) throw new Error("Falha ao atualizar pergunta"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/canvas", editingBlock?.id, "questions"] }); }, }); const deleteCanvasQuestionMutation = useMutation({ mutationFn: async (id: number) => { const res = await fetch(`/api/compass/canvas/questions/${id}`, { method: "DELETE", credentials: "include", }); if (!res.ok) throw new Error("Falha ao excluir pergunta"); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/canvas", editingBlock?.id, "questions"] }); }, }); const addCanvasOutputMutation = useMutation({ mutationFn: async (data: { description: string; orderIndex: number }) => { if (!editingBlock?.id) throw new Error("Bloco não selecionado"); const res = await fetch(`/api/compass/canvas/${editingBlock.id}/outputs`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar saída"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/canvas", editingBlock?.id, "outputs"] }); setNewOutputText(""); }, }); const deleteCanvasOutputMutation = useMutation({ mutationFn: async (id: number) => { const res = await fetch(`/api/compass/canvas/outputs/${id}`, { method: "DELETE", credentials: "include", }); if (!res.ok) throw new Error("Falha ao excluir saída"); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/canvas", editingBlock?.id, "outputs"] }); }, }); const addTeamMemberMutation = useMutation({ mutationFn: async (data: { name: string; email?: string; role: string }) => { if (!selectedProjectId) throw new Error("Projeto não selecionado"); const res = await fetch(`/api/compass/projects/${selectedProjectId}/team`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao adicionar membro"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "team"] }); setShowTeamMemberDialog(false); toast.success("Membro adicionado com sucesso"); }, onError: () => { toast.error("Erro ao adicionar membro"); }, }); const removeTeamMemberMutation = useMutation({ mutationFn: async (id: number) => { const res = await fetch(`/api/compass/team/${id}`, { method: "DELETE", credentials: "include", }); if (!res.ok) throw new Error("Falha ao remover membro"); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "team"] }); toast.success("Membro removido"); }, }); const addProjectTaskMutation = useMutation({ mutationFn: async (data: { title: string; description?: string; priority: string; assignedTo?: string; dueDate?: string }) => { if (!selectedProjectId) throw new Error("Projeto não selecionado"); const res = await fetch(`/api/compass/projects/${selectedProjectId}/tasks`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar tarefa"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "tasks"] }); setShowNewTaskDialog(false); toast.success("Tarefa criada com sucesso"); }, onError: () => { toast.error("Erro ao criar tarefa"); }, }); const updateProjectTaskMutation = useMutation({ mutationFn: async ({ id, data }: { id: number; data: Partial }) => { const res = await fetch(`/api/compass/tasks/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao atualizar tarefa"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "tasks"] }); }, }); const uploadProjectFileMutation = useMutation({ mutationFn: async (file: File) => { if (!selectedProjectId) throw new Error("Projeto não selecionado"); const formData = new FormData(); formData.append("file", file); const res = await fetch(`/api/compass/projects/${selectedProjectId}/files`, { method: "POST", body: formData, credentials: "include", }); if (!res.ok) throw new Error("Falha ao fazer upload"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "files"] }); setShowFileUploadDialog(false); toast.success("Arquivo enviado com sucesso"); }, onError: () => { toast.error("Erro ao enviar arquivo"); }, }); const deleteProjectFileMutation = useMutation({ mutationFn: async (id: number) => { const res = await fetch(`/api/compass/files/${id}`, { method: "DELETE", credentials: "include", }); if (!res.ok) throw new Error("Falha ao excluir arquivo"); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "files"] }); toast.success("Arquivo excluído"); }, }); const saveProjectHistoryMutation = useMutation({ mutationFn: async (content: string) => { if (!selectedProjectId) throw new Error("Projeto não selecionado"); const res = await fetch(`/api/compass/projects/${selectedProjectId}/history`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content }), credentials: "include", }); if (!res.ok) throw new Error("Falha ao salvar histórico"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "history"] }); toast.success("Histórico salvo com sucesso"); setHistoryIsSaving(false); }, onError: () => { toast.error("Erro ao salvar histórico"); setHistoryIsSaving(false); }, }); const createProcessMutation = useMutation({ mutationFn: async (data: { name: string; description?: string; category?: string; owner?: string }) => { const res = await fetch(`/api/compass/projects/${selectedProjectId}/processes`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar processo"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "processes"] }); setShowNewProcessDialog(false); }, }); const createSwotAnalysisMutation = useMutation({ mutationFn: async (data: { name: string; description?: string; sector?: string }) => { const res = await fetch(`/api/compass/projects/${selectedProjectId}/swot`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar análise SWOT"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/projects", selectedProjectId, "swot"] }); setShowNewSwotDialog(false); }, }); const createSwotItemMutation = useMutation({ mutationFn: async (data: { type: string; description: string; impact?: string; actionPlan?: string }) => { const res = await fetch(`/api/compass/swot/${selectedSwotId}/items`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar item SWOT"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/swot", selectedSwotId, "items"] }); }, }); const updateSwotItemMutation = useMutation({ mutationFn: async ({ id, data }: { id: number; data: Partial }) => { const res = await fetch(`/api/compass/swot-items/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao atualizar item SWOT"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/swot", selectedSwotId, "items"] }); setEditingSwotItem(null); toast.success("Item SWOT atualizado com sucesso"); }, onError: (error: Error) => { toast.error(`Erro ao atualizar: ${error.message}`); }, }); const deleteSwotItemMutation = useMutation({ mutationFn: async (id: number) => { const res = await fetch(`/api/compass/swot-items/${id}`, { method: "DELETE", credentials: "include", }); if (!res.ok) throw new Error("Falha ao excluir item SWOT"); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/swot", selectedSwotId, "items"] }); toast.success("Item SWOT excluído com sucesso"); }, onError: (error: Error) => { toast.error(`Erro ao excluir: ${error.message}`); }, }); const createPdcaCycleMutation = useMutation({ mutationFn: async (data: { title: string; description?: string; projectId?: number; priority?: string }) => { const res = await fetch("/api/compass/pdca", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar ciclo PDCA"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/pdca"] }); setShowNewPdcaDialog(false); }, }); const createPdcaActionMutation = useMutation({ mutationFn: async (data: { phase: string; title: string; description?: string; responsible?: string }) => { const res = await fetch(`/api/compass/pdca/${selectedPdcaId}/actions`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar ação PDCA"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/pdca", selectedPdcaId, "actions"] }); }, }); const createRequirementMutation = useMutation({ mutationFn: async (data: { title: string; description?: string; type?: string; priority?: string; projectId?: number }) => { const res = await fetch("/api/compass/requirements", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Falha ao criar requisito"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/compass/requirements"] }); setShowNewRequirementDialog(false); setNewReqTitle(""); setNewReqDescription(""); setNewReqType("functional"); setNewReqPriority("medium"); }, }); const filteredClients = clients.filter(c => c.name.toLowerCase().includes(searchTerm.toLowerCase()) || c.company?.toLowerCase().includes(searchTerm.toLowerCase()) ); const filteredProjects = projects.filter(p => p.name.toLowerCase().includes(searchTerm.toLowerCase()) ); const renderDashboard = () => (
Clientes
{stats?.clients || 0}

clientes cadastrados

Projetos
{stats?.projects || 0}

{stats?.activeProjects || 0} em andamento

Leads
{stats?.leads || 0}

leads no funil

Oportunidades
{stats?.opportunities || 0}

{stats?.openOpportunities || 0} abertas

Projetos Recentes {projectsLoading ? (
) : projects.length === 0 ? (

Nenhum projeto ainda

) : (
{projects.slice(0, 5).map(project => (
{ setSelectedProjectId(project.id); setProjectDetailTab("overview"); setActiveTab("project-detail"); }} >

{project.name}

{project.projectType && project.projectType !== "consultoria" && ( {project.projectType === "valuation" ? "Valuation" : project.projectType === "programacao" ? "Dev" : project.projectType} )}

{clients.find(c => c.id === project.clientId)?.name || "Cliente"}

{statusLabels[project.status] || project.status}
))}
)}
CRM e Vendas

Gerencie leads, oportunidades e clientes

{/* Integration Links Section */} Integrações e Ferramentas Acesse módulos complementares do Arcádia {tenants.length === 0 && (

Configure sua Organização

Para começar a usar o Process Compass, você precisa criar uma organização (consultoria) primeiro.

)}
); const renderClients = () => (
setSearchTerm(e.target.value)} data-testid="search-clients" />
{clientsLoading ? (
) : filteredClients.length === 0 ? (

Nenhum cliente encontrado

{searchTerm ? "Tente uma busca diferente" : "Adicione seu primeiro cliente para começar"}

{!searchTerm && ( )}
) : (
{filteredClients.map(client => (
{client.name} {client.company && ( {client.company} )}
Ver Detalhes Editar Excluir
{client.email && (
{client.email}
)} {client.phone && (
{client.phone}
)} {client.industry && (
{client.industry}
)}
{statusLabels[client.status] || client.status} {projects.filter(p => p.clientId === client.id).length} projetos
))}
)}
); const renderProjects = () => (
setSearchTerm(e.target.value)} data-testid="search-projects" />
{projectsLoading ? (
) : filteredProjects.length === 0 ? (

Nenhum projeto encontrado

{clients.length === 0 ? "Adicione um cliente primeiro para criar projetos" : searchTerm ? "Tente uma busca diferente" : "Crie seu primeiro projeto de consultoria"}

{clients.length > 0 && !searchTerm && ( )}
) : (
{filteredProjects.map(project => { const client = clients.find(c => c.id === project.clientId); return ( { setSelectedProjectId(project.id); setProjectDetailTab("overview"); setActiveTab("project-detail"); }} >

{project.name}

{project.projectType && project.projectType !== "consultoria" && ( {project.projectType === "valuation" ? "Valuation" : project.projectType === "programacao" ? "Dev" : project.projectType} )}

{client?.name || "Cliente"}

{project.description && (

{project.description}

)}
{statusLabels[project.status] || project.status} e.stopPropagation()}> { setSelectedProjectId(project.id); setActiveTab("canvas"); }}> Canvas { setSelectedProjectId(project.id); setActiveTab("processes"); }}> Processos { setSelectedProjectId(project.id); setActiveTab("swot"); }}> SWOT { setSelectedProjectId(project.id); setActiveTab("pdca"); }}> PDCA { setEditingProject(project); setShowEditProjectDialog(true); }}> Editar { setProjectToDelete(project); setShowDeleteProjectConfirm(true); }} > Excluir
{(project.startDate || project.dueDate) && (
{project.startDate && ( Início: {new Date(project.startDate).toLocaleDateString('pt-BR')} )} {project.dueDate && ( Prazo: {new Date(project.dueDate).toLocaleDateString('pt-BR')} )}
)}
); })}
)}
); const renderProjectDetail = () => { const project = projects.find(p => p.id === selectedProjectId); if (!project) return null; const client = clients.find(c => c.id === project.clientId); const projectCanvasBlocks = canvasBlocks.filter(b => b.projectId === selectedProjectId); const projectProcesses = processes.filter(p => p.projectId === selectedProjectId); return (
{/* Header */}

{project.name}

{statusLabels[project.status] || project.status} {project.projectType && project.projectType !== "consultoria" && ( {project.projectType === "valuation" ? "Valuation" : project.projectType === "programacao" ? "Dev" : project.projectType} )}

{client?.name || "Cliente"}

{/* Stats Cards */}

{projectCanvasBlocks.length}

Blocos Canvas

{projectProcesses.length}

Processos

0

Tarefas

{project.dueDate ? new Date(project.dueDate).toLocaleDateString('pt-BR') : "Sem prazo"}

Data limite

{/* Tabs */} Visão Geral História Equipe Canvas Processos Tarefas Arquivos Relatórios {project.projectType === "valuation" && ( Valuation )} Sobre o Projeto

{project.description || "Nenhuma descrição adicionada"}

{project.startDate ? new Date(project.startDate).toLocaleDateString('pt-BR') : "Não definida"}

{project.dueDate ? new Date(project.dueDate).toLocaleDateString('pt-BR') : "Não definida"}

História do Projeto

Documente a história, evolução e decisões importantes do projeto. Use formatação rica, adicione imagens, links e vídeos.

Equipe do Projeto {projectTeamMembers.length === 0 ? (

Nenhum membro na equipe

Adicione membros para gerenciar a equipe do projeto

) : (
{projectTeamMembers.map(member => (

{member.name}

{member.role}

{member.email && ( {member.email} )}
))}
)}
{CANVAS_LEVELS.map(level => ( ))}
{CANVAS_BLOCK_TYPES.map(blockType => { const block = projectCanvasBlocks.find(b => b.blockType === blockType.id && b.level === selectedCanvasLevel); return ( { if (block) { setEditingBlock(block); } else { setEditingBlock({ id: 0, projectId: selectedProjectId!, blockType: blockType.id, level: selectedCanvasLevel, title: null, content: null, notes: null, score: 0, synthesis: null }); } }} data-testid={`canvas-block-${blockType.id}`} > {blockType.label} {block ? (
{block.title &&

{block.title}

}

{block.content || "Clique para adicionar"}

{block.score}%
) : (

Clique para adicionar

)} ); })}
Processos {projectProcesses.length === 0 ? (

Nenhum processo mapeado

Comece a mapear os processos do projeto

) : (
{projectProcesses.map(process => (

{process.name}

{process.category || "Sem categoria"}

{process.status}
))}
)}
Tarefas {projectTasks.length === 0 ? (

Nenhuma tarefa

Adicione tarefas para acompanhar o progresso

) : (
{projectTasks.map(task => (
{ updateProjectTaskMutation.mutate({ id: task.id, data: { status: checked ? "completed" : "pending" } }); }} data-testid={`checkbox-task-${task.id}`} />

{task.title}

{task.description && (

{task.description}

)}
{task.priority === "high" ? "Alta" : task.priority === "medium" ? "Média" : "Baixa"} {task.assignedTo && ( {task.assignedTo} )} {task.dueDate && ( {new Date(task.dueDate).toLocaleDateString('pt-BR')} )}
))}
)}
Arquivos {projectFiles.length === 0 ? (

Nenhum arquivo

Faça upload de arquivos relacionados ao projeto

) : (
{projectFiles.map(file => (

{file.originalName}

{(file.size / 1024).toFixed(1)} KB - {new Date(file.createdAt).toLocaleDateString('pt-BR')}

))}
)}
Relatórios do Projeto
handleQuickReport("executive_summary")}>

Sumário Executivo

Visão geral rápida

handleQuickReport("full_diagnostic")}>

Diagnóstico Completo

Todos os dados

handleQuickReport("swot_report")}>

Análise SWOT

Forças e fraquezas

Relatórios Gerados

{!generatedReports?.length ? (

Nenhum relatório gerado ainda

Clique em "Gerar Relatório" para criar um novo

) : (
{generatedReports.map((report: any) => (

{report.name}

{new Date(report.createdAt).toLocaleDateString('pt-BR')} - {report.format?.toUpperCase()}

{report.status === "completed" && report.fileUrl && ( )} {report.status === "generating" && ( Gerando... )} {report.status === "failed" && ( Falhou )}
))}
)}
{project.projectType === "valuation" && (
Visão Geral Checklist Análise Setorial

Checklist

{Array.isArray(valuationChecklist) ? valuationChecklist.filter((c: any) => c.status === "completed").length : 0}/{Array.isArray(valuationChecklist) ? valuationChecklist.length : 0}

itens completos

Score Setorial

{valuationSectorAnalysis?.latest?.overallScore || "--"}%

{valuationSectorAnalysis?.latest?.overallScore ? getValuationScoreLevel(valuationSectorAnalysis.latest.overallScore).label : "Não calculado"}

navigate("/canvas")}>

Canvas

Abrir

Módulo Centralizado

Checklist de Coleta de Dados {(!Array.isArray(valuationChecklist) || valuationChecklist.length === 0) && ( )} {!Array.isArray(valuationChecklist) || valuationChecklist.length === 0 ? (

Clique em "Inicializar Checklist" para começar

) : (
Progresso {valuationChecklist.filter((c: any) => c.status === "completed").length} de {valuationChecklist.length}
c.status === "completed").length / valuationChecklist.length) * 100}%` }} />
)} Análise Setorial {valuationSectorAnalysis?.latest ? (
{valuationSectorAnalysis.latest.overallScore}%

{getValuationScoreLevel(valuationSectorAnalysis.latest.overallScore).label}

Score geral da análise setorial

) : (

Análise setorial não realizada

)}
)}
); }; const handleNavClick = (tab: string) => { setActiveTab(tab); setSidebarOpen(false); }; const renderSidebar = () => (
Process Compass

FERRAMENTAS

); return (
{/* Mobile sidebar overlay */} {sidebarOpen && (
setSidebarOpen(false)} /> )} {/* Sidebar - hidden on mobile, slide-in when open */}
{renderSidebar()}
{/* Mobile header */}
Process Compass
{activeTab === "dashboard" && renderDashboard()} {activeTab === "clients" && renderClients()} {activeTab === "projects" && renderProjects()} {activeTab === "project-detail" && renderProjectDetail()} {activeTab === "canvas" && (
Dica: {MODULE_HELP.canvas.tips[0]}

Canvas de Diagnóstico

Business Model Canvas expandido

{MODULE_HELP.canvas.title}

{MODULE_HELP.canvas.description}

{!selectedProjectId ? (

Selecione um Projeto

Escolha um projeto acima para acessar o Business Model Canvas.

) : ( <>
{CANVAS_LEVELS.map(level => ( ))}
{CANVAS_BLOCK_TYPES.map(blockType => { const block = canvasBlocks.find(b => b.blockType === blockType.id && b.level === selectedCanvasLevel); return ( { if (block) { setEditingBlock(block); } else { setEditingBlock({ id: 0, projectId: selectedProjectId, blockType: blockType.id, level: selectedCanvasLevel, title: null, content: null, notes: null, score: 0, synthesis: null }); } }} data-testid={`canvas-block-${blockType.id}`} >
{block ? ( block.score > 70 ? (
) : block.score > 30 ? (
) : (
) ) : (
)} {blockType.label}
{block && (block as any).questionsCount > 0 && ( {(block as any).answeredCount || 0}/{(block as any).questionsCount} )}

{blockType.description || ""}

{block ? (
{block.title &&

{block.title}

}

{block.content || "Clique para adicionar"}

70 ? "bg-green-500" : block.score > 30 ? "bg-yellow-500" : "bg-red-500" }`} style={{ width: `${block.score}%` }} />
) : (

Clique para adicionar

)} ); })}
)} { if (!open) { setEditingBlock(null); setCanvasDialogTab("content"); setNewQuestionText(""); setNewOutputText(""); } }}> {CANVAS_BLOCK_TYPES.find(b => b.id === editingBlock?.blockType)?.label} - {CANVAS_LEVELS.find(l => l.id === editingBlock?.level)?.label} {(() => { const questionsWithScores = canvasQuestions.filter(q => q.score !== null); const avgScore = questionsWithScores.length > 0 ? Math.round(questionsWithScores.reduce((sum, q) => sum + (q.score || 0), 0) / questionsWithScores.length * 10) : 0; return (
Maturidade ({questionsWithScores.length}/{canvasQuestions.length} perguntas)
{avgScore}%
Saídas
{canvasOutputs.filter(o => o.completed).length}/{canvasOutputs.length}
); })()} Conteúdo Diagnóstico ({canvasQuestions.length}) Saídas ({canvasOutputs.length})
{ e.preventDefault(); const formData = new FormData(e.currentTarget); upsertCanvasBlockMutation.mutate({ id: editingBlock?.id || undefined, blockType: editingBlock?.blockType || "", level: editingBlock?.level || "", title: formData.get("title") as string, content: formData.get("content") as string, notes: formData.get("notes") as string, synthesis: formData.get("synthesis") as string, score: parseInt(formData.get("score") as string) || 0, }); }}>