import React, { useState, useEffect, useCallback } from 'react'; import { BarChart3, RefreshCw, Clock, AlertTriangle, RotateCcw, PackageX, Award, CheckCircle2, BadgeCheck, Star } from 'lucide-react'; import { HybridBackend } from '../services/backend.ts'; import { PageHeader } from '../components/PageHeader.tsx'; // Área do Laboratório (Fase 5): indicadores derivados da captura + Nota ScoreOdonto. export const LabIndicadoresView: React.FC = () => { const [ind, setInd] = useState(null); const [loading, setLoading] = useState(false); const carregar = useCallback(async () => { setLoading(true); try { setInd(await HybridBackend.getLabIndicadores()); } catch { /* silent */ } finally { setLoading(false); } }, []); useEffect(() => { carregar(); }, [carregar]); const KPI: React.FC<{ titulo: string; valor: string; cor: string; Icon: any; sub?: string }> = ({ titulo, valor, cor, Icon, sub }) => (

{titulo}

{valor}
{sub &&

{sub}

}
); if (loading || !ind) return
; const temNota = ind.nota !== null && ind.nota !== undefined; const notaCor = ind.nota >= 9 ? 'text-green-600' : ind.nota >= 7 ? 'text-teal-600' : ind.nota >= 5 ? 'text-amber-500' : 'text-red-500'; return (
{/* Nota ScoreOdonto */}
{temNota ? ind.nota.toFixed(1) : '—'}

Nota ScoreOdonto

{ind.verificado && Verificado}
{temNota ? (

Sobre {ind.entregues} entrega(s){ind.avaliacoes ? ` · ${ind.satisfacao}★ de ${ind.avaliacoes} avaliações` : ''}. Combina desempenho (atraso/retrabalho/ocorrências) e satisfação da clínica.

) : (

Score em formação — mínimo de {ind.min_os} entregas para gerar a nota.

)}

Como a nota é calculada

Base 10, descontando proporcionalmente: atraso (peso 3), retrabalho/garantia (peso 4) e ocorrências resolvidas (peso 3). Só ocorrências resolvidas (após contraditório) entram — abertas/contestadas não pesam. A nota aparece para as clínicas no marketplace ao escolherem o laboratório.

); };