1const e=`import { tx } from '@/i18n/t'; 2import { Link } from 'react-router-dom'; 3import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; 4import { Badge } from '@/components/ui/badge'; 5import { Button } from '@/components/ui/button'; 6import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; 7import { Skeleton } from '@/components/ui/skeleton'; 8import { GitBranch, MapPin, AlertTriangle, ArrowRight, Building2, Info } from 'lucide-react'; 9import { useIntegratedTerritorialView } from '@/hooks/useIntegratedTerritorialView'; 10import { getIntlLocale } from '@/i18n/dateLocale'; 11 12interface Props { 13 enterpriseDestinationId: string; 14 enterprisePillarScores: Array<{ pillar: string; score: number; severity: string }>; 15 destinationName: string; 16} 17 18const PILLAR_LABELS: Record<string, string> = { 19 RA: 'I-RA · Relações Ambientais', 20 OE: 'I-OE · Organização Estrutural', 21 AO: 'I-AO · Ações Operacionais', 22}; 23 24const SEVERITY_STYLE: Record<string, { color: string; label: string }> = { 25 CRITICO: { color: 'text-severity-critical', label: tx('CrÃtico') }, 26 MODERADO: { color: 'text-severity-moderate', label: tx('Atenção') }, 27 BOM: { color: 'text-severity-good', label: tx('Adequado') }, 28}; 29 30function pct(score: number | undefined) { 31 if (score == null || isNaN(score)) return 'â'; 32 return \`\${Math.round(score * 100)}%\`; 33} 34 35function delta(ent: number | undefined, terr: number | undefined) { 36 if (ent == null || terr == null) return null; 37 return Math.round((ent - terr) * 100); 38} 39 40export function IntegratedTerritorialView({ 41 enterpriseDestinationId, 42 enterprisePillarScores, 43 destinationName, 44}: Props) { 45 const { data, isLoading } = useIntegratedTerritorialView(enterpriseDestinationId, true); 46 47 if (isLoading) { 48 return ( 49 <div className="space-y-4"> 50 <Skeleton className="h-32 w-full" /> 51 <Skeleton className="h-48 w-full" /> 52 </div> 53 ); 54 } 55 56 if (!data?.matched) { 57 const reasonText = 58 data?.reason === 'no_ibge' 59 ? tx('Este empreendimento não tem código IBGE cadastrado â não é possÃvel localizar o municÃpio de referência.') 60 : data?.reason === 'no_assessment' 61 ? tx('Ainda não há nenhum diagnóstico Territorial cadastrado para o municÃpio deste empreendimento.') 62 : 'Existe diagnóstico Territorial para o municÃpio, mas ele ainda não foi calculado.'; 63 return ( 64 <Alert> 65 <Info className="h-4 w-4" /> 66 <AlertTitle>{tx('Visão Integrada indisponÃvel')}</AlertTitle> 67 <AlertDescription className="space-y-2"> 68 <p>{reasonText}</p> 69 <p className="text-sm text-muted-foreground"> 70 {tx("A Visão Integrada cruza o desempenho do empreendimento com o diagnóstico Territorial do municÃpio, ajudando a separar gargalos internos de causas externas (infra pública, segurança, conectividade, sazonalidade do destino).")} 71 </p> 72 </AlertDescription> 73 </Alert> 74 ); 75 } 76 77 const terrPillarMap = new Map( 78 (data.pillarScores || []).map((p) => [p.pillar, p]), 79 ); 80 const entPillarMap = new Map(enterprisePillarScores.map((p) => [p.pillar, p])); 81 82 const criticalTerritorialIssues = (data.issues || []).filter( 83 (i) => i.severity === 'CRITICO', 84 ); 85 86 return ( 87 <div className="space-y-6"> 88 {/* Header card with municipality reference */} 89 <Card className="border-primary/30 bg-primary/5"> 90 <CardHeader> 91 <div className="flex items-start justify-between gap-3 flex-wrap"> 92 <div> 93 <CardTitle className="flex items-center gap-2"> 94 <GitBranch className="h-5 w-5 text-primary" /> 95 {tx('Visão Integrada â Empreendimento à MunicÃpio')} 96 </CardTitle> 97 <CardDescription className="mt-1.5 space-y-0.5"> 98 <span className="flex items-center gap-1.5"> 99 <Building2 className="h-3.5 w-3.5" /> {destinationName} 100 </span> 101 <span className="flex items-center gap-1.5"> 102 <MapPin className="h-3.5 w-3.5" /> 103 {data.destination?.name} {data.destination?.uf ? \`(\${data.destination.uf})\` : ''} 104 {data.assessment?.calculated_at && (
105 <span className="text-xs text-muted-foreground ml-1"> 106 · diagnóstico territorial de{' '} 107 {new Date(data.assessment.calculated_at).toLocaleDateString(getIntlLocale())} 108 </span> 109 )} 110 </span> 111 </CardDescription> 112 </div> 113 <Button asChild variant="outline" size="sm"> 114 <Link to={\`/diagnosticos/\${data.assessment!.id}\`}> 115 {tx('Abrir diagnóstico territorial')} 116 <ArrowRight className="h-3.5 w-3.5 ml-1" /> 117 </Link> 118 </Button> 119 </div> 120 </CardHeader> 121 </Card> 122 123 {/* Pillar-by-pillar comparison */} 124 <Card> 125 <CardHeader> 126 <CardTitle className="text-base">{tx('Comparação por Pilar')}</CardTitle> 127 <CardDescription> 128 {tx("Score do empreendimento vs. score do municÃpio no mesmo pilar sistêmico (RA/OE/AO). Î positivo indica que o empreendimento está acima do entorno.")} 129 </CardDescription> 130 </CardHeader> 131 <CardContent className="space-y-3"> 132 {(['RA', 'OE', 'AO'] as const).map((p) => { 133 const ent = entPillarMap.get(p); 134 const terr = terrPillarMap.get(p); 135 const d = delta(ent?.score, terr?.score); 136 const entSev = ent?.severity ? SEVERITY_STYLE[ent.severity] : null; 137 const terrSev = terr?.severity ? SEVERITY_STYLE[terr.severity] : null; 138 return ( 139 <div 140 key={p} 141 className="grid grid-cols-1 md:grid-cols-[1fr_auto_auto_auto] gap-2 md:items-center p-3 rounded-lg border bg-card" 142 > 143 <div className="font-medium text-sm">{tx(PILLAR_LABELS[p])}</div> 144 <div className="text-sm"> 145 <span className="text-muted-foreground">{tx('Empreend.:')} </span> 146 <span className={\`font-semibold \${entSev?.color ?? ''}\`}> 147 {pct(ent?.score)} {entSev ? \`· \${entSev.label}\` : ''} 148 </span> 149 </div> 150 <div className="text-sm"> 151 <span className="text-muted-foreground">{tx('MunicÃpio:')} </span> 152 <span className={\`font-semibold \${terrSev?.color ?? ''}\`}> 153 {pct(terr?.score)} {terrSev ? \`· \${terrSev.label}\` : ''} 154 </span> 155 </div> 156 <div className="text-sm font-mono"> 157 {d == null ? ( 158 <span className="text-muted-foreground">Î â</span> 159 ) : ( 160 <Badge 161 variant="outline" 162 className={ 163 d > 5 164 ? 'border-severity-good/50 text-severity-good' 165 : d < -5 166 ? 'border-severity-critical/50 text-severity-critical' 167 : 'text-muted-foreground' 168 } 169 > 170 Î {d > 0 ? '+' : ''} 171 {d} pp 172 </Badge> 173 )} 174 </div> 175 </div> 176 ); 177 })} 178 </CardContent> 179 </Card> 180 181 {/* Territorial context alerts */} 182 {criticalTerritorialIssues.length > 0 && ( 183 <Card className="border-severity-critical/30"> 184 <CardHeader> 185 <CardTitle className="text-base flex items-center gap-2"> 186 <AlertTriangle className="h-4 w-4 text-severity-critical" /> 187 {tx('Gargalos crÃticos no municÃpio')} 188 </CardTitle> 189 <CardDescription> 190 {tx("Esses gargalos territoriais podem afetar o desempenho do empreendimento mesmo quando a gestão interna está adequada â considere ações conjuntas com a secretaria de turismo, consórcio ou trade local.")} 191 </CardDescription> 192 </CardHeader> 193 <CardContent className="space-y-2"> 194 {criticalTerritorialIssues.slice(0, 8).map((i) => ( 195 <div 196 key={i.id} 197 className="flex items-start gap-3 p-3 rounded-md bg-severity-critical/5 border border-severity-critical/20" 198 > 199 <Badge variant="outline" className="shrink-0 text-xs"> 200 {i.pillar} 201 </Badge> 202 <div className="text-sm"> 203 <div className="font-medium">{tx(i.title)}</div> 204 {i.description && ( 205 <div className="text-muted-foreground text-xs mt-0.5 line-clamp-2"> 206 {tx(i.description)} 207 </div> 208 )} 209 </div> 210 </div> 211 ))} 212 {criticalTerritorialIssues.length > 8 && ( 213 <div className="text-xs text-muted-foreground text-center pt-1"> 214 + {criticalTerritorialIssues.length - 8} outros gargalos crÃticos no municÃpio 215 </div> 216 )} 217 </CardContent> 218 </Card> 219 )} 220 221 <Alert> 222 <Info className="h-4 w-4" /> 223 <AlertDescription className="text-xs"> 224 {tx("A Visão Integrada é informativa e não altera o cálculo do diagnóstico Empresarial. Use-a para contextualizar gargalos, justificar planos de ação cruzados (interno + territorial) e priorizar projetos junto à governança do destino.")} 225 </AlertDescription> 226 </Alert> 227 </div> 228 ); 229} 230`;export{e as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.