import React, { useState, useEffect, useCallback, useRef } from 'react'; import { GraduationCap, Plus, X, Send, Clock, CheckCircle2, MessageSquare, ChevronDown, ChevronUp, Loader2, User, Camera, ShieldAlert, DollarSign, Info } from 'lucide-react'; import { HybridBackend } from '../services/backend.ts'; import { useToast } from '../contexts/ToastContext.tsx'; // ─── Tipos ──────────────────────────────────────────────────────── interface Tutor { id: string; nome: string; especialidade?: string; bio?: string; preco_base?: number; sla_horas?: number; } interface Mensagem { id: string; request_id: string; autor_tipo: 'CLINICA' | 'TUTOR'; autor_nome?: string; conteudo: string; created_at: string; } interface Solicitacao { id: string; tratamento_id: string; tutor_id: string; tutor_nome?: string; tutor_especialidade?: string; tutor_bio?: string; sla_horas?: number; tipo: string; descricao?: string; paciente_nome?: string; status: string; created_at: string; mensagens?: Mensagem[]; fotos?: { id: string; url: string; slot: string }[]; } // ─── Helpers ────────────────────────────────────────────────────── const TIPO_LABELS: Record = { SEGUNDA_OPINIAO: 'SEGUNDA OPINIÃO', PLANEJAMENTO_COMPLETO: 'PLANEJAMENTO COMPLETO', DISCUSSAO_CASO: 'DISCUSSÃO DE CASO', ALINHADORES: 'ALINHADORES', ORTO_CIRURGICO: 'ORTO-CIRÚRGICO', ENCAMINHAMENTO: 'ENCAMINHAMENTO', }; const STATUS_STYLE: Record = { AGUARDANDO: { cls: 'bg-amber-100 text-amber-700', label: 'AGUARDANDO' }, EM_ANALISE: { cls: 'bg-blue-100 text-blue-700', label: 'EM ANÁLISE' }, RESPONDIDO: { cls: 'bg-green-100 text-green-700', label: 'RESPONDIDO' }, FECHADO: { cls: 'bg-gray-100 text-gray-500', label: 'FECHADO' }, }; // ─── Chat inline ────────────────────────────────────────────────── const TutorChat: React.FC<{ solicitacao: Solicitacao; autorNome: string; onUpdated: () => void; }> = ({ solicitacao, autorNome, onUpdated }) => { const toast = useToast(); const [msgs, setMsgs] = useState(solicitacao.mensagens || []); const [texto, setTexto] = useState(''); const [enviando, setEnviando] = useState(false); const bottomRef = useRef(null); useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [msgs]); const send = async () => { const txt = texto.trim(); if (!txt) return; setEnviando(true); try { const res = await HybridBackend.sendMensagemTutoria(solicitacao.id, txt, 'CLINICA', autorNome); if (!res.success) { toast.error('ERRO AO ENVIAR.'); return; } setMsgs(prev => [...prev, res.mensagem]); setTexto(''); onUpdated(); } catch { toast.error('ERRO AO ENVIAR.'); } finally { setEnviando(false); } }; return (
{msgs.length === 0 ? (

NENHUMA MENSAGEM AINDA — INICIE A CONVERSA

) : msgs.map(m => (
{m.autor_nome && (

{m.autor_nome}

)}

{m.conteudo}

{new Date(m.created_at).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}

))}
{solicitacao.status !== 'FECHADO' && (
setTexto(e.target.value)} onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }} placeholder="MENSAGEM PARA O TUTOR..." className="flex-1 border border-gray-200 rounded-xl px-3 py-2 text-xs font-medium focus:outline-none focus:border-teal-400 uppercase placeholder:normal-case" />
)}
); }; // ─── Card de solicitação ────────────────────────────────────────── const SolicitacaoCard: React.FC<{ sol: Solicitacao; autorNome: string; onUpdated: () => void; }> = ({ sol, autorNome, onUpdated }) => { const [open, setOpen] = useState(false); const [detail, setDetail] = useState(null); const [loadingDetail, setLoadingDetail] = useState(false); const st = STATUS_STYLE[sol.status] || STATUS_STYLE.AGUARDANDO; const loadDetail = useCallback(async () => { if (detail) return; setLoadingDetail(true); try { const res = await HybridBackend.getSolicitacaoTutoria(sol.id); if (res.success) setDetail(res.solicitacao); } catch {} finally { setLoadingDetail(false); } }, [sol.id, detail]); const toggle = () => { if (!open) loadDetail(); setOpen(!open); }; const refreshDetail = async () => { const res = await HybridBackend.getSolicitacaoTutoria(sol.id); if (res.success) setDetail(res.solicitacao); onUpdated(); }; return (
{/* Header clicável */} {/* Expandido */} {open && (
{/* Info do tutor */}
{sol.tutor_especialidade && (

ESPECIALIDADE

{sol.tutor_especialidade}

)} {sol.sla_horas && (

SLA

ATÉ {sol.sla_horas}H

)} {sol.descricao && (

DESCRIÇÃO

{sol.descricao}

)}
{/* Fotos do pacote */} {loadingDetail ? (
) : detail?.fotos && detail.fotos.length > 0 && (

FOTOS INCLUÍDAS ({detail.fotos.length})

{detail.fotos.slice(0, 8).map(f => ( {f.slot} ))} {detail.fotos.length > 8 && (
+{detail.fotos.length - 8}
)}
)} {/* Chat */} {detail && ( )}
)}
); }; // ─── Modal de aceite de responsabilidade ───────────────────────── const TEXTO_RESPONSABILIDADE_DEFAULT = `Ao solicitar esta tutoria, o profissional solicitante declara expressamente que: • É o RESPONSÁVEL LEGAL pelo tratamento do paciente e por todas as decisões clínicas relacionadas. • O parecer emitido pelo tutor tem caráter estritamente CONSULTIVO e NÃO VINCULANTE. • A decisão de executar ou não as recomendações do tutor compete EXCLUSIVAMENTE ao profissional tratante, que deve avaliá-las com base em seu conhecimento clínico e nas condições específicas do paciente. • O tutor NÃO ASSUME qualquer responsabilidade sobre a execução do tratamento, os resultados obtidos ou quaisquer complicações decorrentes da aplicação ou não das recomendações emitidas. • Este termo é um registro formal do entendimento mútuo sobre os limites e a natureza consultiva do serviço de tutoria.`; const AceiteModal: React.FC<{ pacienteNome: string; autorNome: string; textoCustom?: string; onAceitar: (nome: string) => void; onCancelar: () => void; }> = ({ pacienteNome, autorNome, textoCustom, onAceitar, onCancelar }) => { const [nome, setNome] = useState(autorNome); const [aceito, setAceito] = useState(false); const texto = textoCustom || TEXTO_RESPONSABILIDADE_DEFAULT; return (

TERMO DE RESPONSABILIDADE CLÍNICA

PACIENTE: {pacienteNome}

{texto}

setNome(e.target.value.toUpperCase())} className="w-full border border-gray-200 rounded-xl px-3 py-2.5 text-sm font-bold focus:outline-none focus:border-amber-400 uppercase" />
); }; // ─── Modal de nova solicitação ──────────────────────────────────── const NovoModal: React.FC<{ tratamentoId: string; clinicaId?: string; pacienteNome: string; autorNome: string; onClose: () => void; onCreated: () => void; }> = ({ tratamentoId, clinicaId, pacienteNome, autorNome, onClose, onCreated }) => { const toast = useToast(); const [tutores, setTutores] = useState([]); const [tutorId, setTutorId] = useState(''); const [tipo, setTipo] = useState('SEGUNDA_OPINIAO'); const [descricao, setDescricao] = useState(''); const [loading, setLoading] = useState(true); const [salvando, setSalvando] = useState(false); const [showAceite, setShowAceite] = useState(false); const [cfgTexto, setCfgTexto] = useState(''); useEffect(() => { Promise.all([ HybridBackend.getTutores().then(r => { if (r.success) setTutores(r.tutores || []); }), HybridBackend.getAdminTutorConfig().then(r => { if (r.success) setCfgTexto(r.config?.texto_responsabilidade || ''); }), ]).finally(() => setLoading(false)); }, []); const tutorSelecionado = tutores.find(t => t.id === tutorId); const handleSubmitComAceite = async (nomeAceite: string) => { setShowAceite(false); setSalvando(true); try { const res = await HybridBackend.createSolicitacaoTutoria({ tratamento_id: tratamentoId, clinica_id: clinicaId, tutor_id: tutorId, tipo, descricao: descricao.toUpperCase() || undefined, paciente_nome: pacienteNome, aceite_responsabilidade: true, aceite_nome: nomeAceite, aceite_texto_versao: 'v1', }); if (!res.success) { toast.error(res.message || 'ERRO.'); return; } toast.success(`TUTORIA SOLICITADA! ${res.fotos_incluidas} FOTOS INCLUÍDAS NO PACOTE.`); onCreated(); } catch { toast.error('ERRO AO SOLICITAR TUTORIA.'); } finally { setSalvando(false); } }; return ( <>

SOLICITAR TUTORIA

{/* Paciente */}
PACIENTE: {pacienteNome}
{/* Tutor */}
{loading ? (
CARREGANDO TUTORES...
) : tutores.length === 0 ? (

NENHUM TUTOR DISPONÍVEL CADASTRADO.

) : (
{tutores.map(t => ( ))}
)}
{/* Preço estimado */} {tutorSelecionado?.preco_base && (

VALOR DA CONSULTORIA: R$ {Number(tutorSelecionado.preco_base).toLocaleString('pt-BR', { minimumFractionDigits: 2 })}

PAGAMENTO COMBINADO DIRETAMENTE COM O TUTOR APÓS RESPOSTA

)} {/* Tipo */}
{/* Descrição */}