'use client'; import { useState, useEffect, useRef } from 'react'; import { useRouter } from 'next/navigation'; import { api } from '@/lib/api'; import { useAuthStore } from '@/stores/authStore'; import BottomNav from '@/components/BottomNav'; import Link from 'next/link'; export default function ScanPage() { const [scanning, setScanning] = useState(false); const [manualCode, setManualCode] = useState(''); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [notFound, setNotFound] = useState(false); const [photoLoading, setPhotoLoading] = useState(false); const [result, setResult] = useState(null); const [addedToList, setAddedToList] = useState(false); const [newBadgeBanner, setNewBadgeBanner] = useState([]); const photoInputRef = useRef(null); const { user, hydrate } = useAuthStore(); const router = useRouter(); const scannerRef = useRef(null); const scannerDivRef = useRef(null); useEffect(() => { hydrate(); const token = localStorage.getItem('token'); if (!token) router.push('/login'); }, []); const startScanner = async () => { setScanning(true); setError(''); try { const { Html5Qrcode } = await import('html5-qrcode'); const scanner = new Html5Qrcode('scanner-view'); scannerRef.current = scanner; await scanner.start( { facingMode: 'environment' }, { fps: 10, qrbox: { width: 250, height: 150 } }, (decodedText) => { scanner.stop().catch(() => {}); setScanning(false); handleScan(decodedText); }, () => {} ); } catch { setScanning(false); setError('Não foi possível acessar a câmera.'); } }; const stopScanner = () => { scannerRef.current?.stop().catch(() => {}); setScanning(false); }; const handleScan = async (barcode: string) => { setLoading(true); setError(''); setNotFound(false); setResult(null); setAddedToList(false); try { const data = await api.scan(barcode); setResult(data); if (data.new_badges?.length) { setNewBadgeBanner(data.new_badges); setTimeout(() => setNewBadgeBanner([]), 5000); } } catch (err: any) { if (err.message.includes('não encontrado')) setNotFound(true); else setError(err.message); } finally { setLoading(false); } }; const handlePhoto = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; setPhotoLoading(true); setError(''); setNotFound(false); try { const data = await api.scanPhoto(file); setResult(data); if (data.new_badges?.length) { setNewBadgeBanner(data.new_badges); setTimeout(() => setNewBadgeBanner([]), 5000); } } catch (err: any) { setError(err.message); } finally { setPhotoLoading(false); } }; const handleShare = () => { if (!result) return; const shareUrl = `${window.location.origin}/api/scan/${result.id}/share`; const shareData = { title: `ALETHEIA: ${result.product_name}`, text: `Score: ${result.score}/100 - ${result.summary}`, url: shareUrl }; if (navigator.share) { navigator.share(shareData).catch(() => {}); } else { navigator.clipboard.writeText(shareUrl); alert('Link copiado!'); } }; const handleAddToList = async () => { if (!result) return; try { await api.addToShoppingList(result.product_name || 'Produto', result.barcode); setAddedToList(true); } catch (e) {} }; const getScoreLabel = (s: number) => { if (s >= 90) return { label: 'Excelente', emoji: '🌟', desc: 'Alimento natural e saudável' }; if (s >= 70) return { label: 'Bom', emoji: '✅', desc: 'Saudável, com poucos aditivos' }; if (s >= 50) return { label: 'Regular', emoji: '⚠️', desc: 'Processado, consumir com moderação' }; if (s >= 30) return { label: 'Ruim', emoji: '🔶', desc: 'Ultraprocessado, vários aditivos' }; return { label: 'Péssimo', emoji: '🚫', desc: 'Muito prejudicial à saúde' }; }; const getScoreColor = (score: number) => score >= 71 ? '#10B981' : score >= 51 ? '#EAB308' : score >= 31 ? '#F97316' : '#EF4444'; const getClassColor = (c: string) => c === 'good' ? 'text-green-400' : c === 'warning' ? 'text-yellow-400' : 'text-red-400'; const getClassIcon = (c: string) => c === 'good' ? '🟢' : c === 'warning' ? '🟡' : '🔴'; const guessLevel = (nutrient: string, val: string) => { const num = parseFloat(val) || 0; if (nutrient === 'acucar') return num > 15 ? 'high' : num > 5 ? 'mid' : 'low'; if (nutrient === 'gordura_total' || nutrient === 'gordura_saturada') return num > 10 ? 'high' : num > 3 ? 'mid' : 'low'; if (nutrient === 'sodio') return num > 400 ? 'high' : num > 120 ? 'mid' : 'low'; if (nutrient === 'fibras') return num > 5 ? 'low' : num > 2 ? 'mid' : 'high'; if (nutrient === 'proteinas') return num > 10 ? 'low' : num > 3 ? 'mid' : 'high'; if (nutrient === 'calorias') return num > 300 ? 'high' : num > 150 ? 'mid' : 'low'; return 'mid'; }; const getNutritionBar = (label: string, value: string, level: string) => { const barColor = level === 'low' ? 'bg-green-500' : level === 'mid' ? 'bg-yellow-500' : 'bg-red-500'; const pillColor = level === 'low' ? 'text-green-400 bg-green-500/10' : level === 'mid' ? 'text-yellow-400 bg-yellow-500/10' : 'text-red-400 bg-red-500/10'; const pillText = level === 'low' ? 'Baixo' : level === 'mid' ? 'Médio' : 'Alto'; const width = level === 'low' ? '25%' : level === 'mid' ? '55%' : '85%'; return (
{label}
{value} {pillText}
); }; // Result view if (result) { const color = getScoreColor(result.score); const dashArray = result.score * 3.267 + ' 326.7'; const nutrition = result.nutrition || {}; const recipe = result.recipe; const allergenAlerts = result.allergen_alerts || []; const substitutions = result.substitutions || []; return (
{/* New badge banner */} {newBadgeBanner.length > 0 && (

🏆 Nova conquista: {newBadgeBanner.join(', ')}

)} {/* Allergen Alert Banner */} {allergenAlerts.length > 0 && (

⚠️ ALERTA DE ALÉRGENOS!

{allergenAlerts.map((a: any, i: number) => (

🔴 {a.ingredient} — contém {a.allergy}

))}
)} {/* Score */}

{result.product_name || 'Produto'}

{result.brand &&

{result.brand}

}
{result.score} /100
{getScoreLabel(result.score).emoji} {getScoreLabel(result.score).label}
{/* Summary */}

{result.summary}

{/* Nutrition */} {Object.keys(nutrition).length > 0 && (

📊 Informações Nutricionais

{result.nutrition_verdict &&

{result.nutrition_verdict}

} {nutrition.calorias && getNutritionBar('Calorias', nutrition.calorias, guessLevel('calorias', nutrition.calorias))} {nutrition.acucar && getNutritionBar('Açúcar', nutrition.acucar, guessLevel('acucar', nutrition.acucar))} {nutrition.gordura_total && getNutritionBar('Gordura Total', nutrition.gordura_total, guessLevel('gordura_total', nutrition.gordura_total))} {nutrition.gordura_saturada && getNutritionBar('Gordura Saturada', nutrition.gordura_saturada, guessLevel('gordura_saturada', nutrition.gordura_saturada))} {nutrition.sodio && getNutritionBar('Sódio', nutrition.sodio, guessLevel('sodio', nutrition.sodio))} {nutrition.carboidratos && getNutritionBar('Carboidratos', nutrition.carboidratos, guessLevel('carboidratos', nutrition.carboidratos))} {nutrition.fibras && getNutritionBar('Fibras', nutrition.fibras, guessLevel('fibras', nutrition.fibras))} {nutrition.proteinas && getNutritionBar('Proteínas', nutrition.proteinas, guessLevel('proteinas', nutrition.proteinas))}
)} {/* Positives & Negatives */}
{result.positives?.length > 0 && (

✅ Positivos

{result.positives.map((p: string, i: number) =>

• {p}

)}
)} {result.negatives?.length > 0 && (

❌ Negativos

{result.negatives.map((n: string, i: number) =>

• {n}

)}
)}
{/* Ingredients */} {result.ingredients?.length > 0 && (

📋 Ingredientes

{result.ingredients.map((ing: any, i: number) => (
{ing.is_allergen ? '🚨' : getClassIcon(ing.classification)} {ing.name}{ing.popular_name && ing.popular_name !== ing.name ? ` (${ing.popular_name})` : ''} {ing.is_allergen && ' ⚠️ ALÉRGENO'}

{ing.explanation}

{ing.reason}

))}
)} {/* Substitutions */} {substitutions?.length > 0 && result.score < 50 && (

🔄 Alternativas Mais Saudáveis

{substitutions.map((sub: any, i: number) => (
{sub.name} {sub.estimated_score && ( ~{sub.estimated_score} )}
{sub.brand &&

{sub.brand}

}

{sub.reason}

))}
)} {/* Recipe */} {recipe && (

🍳 {result.score > 70 ? 'Receita com este produto' : 'Alternativa Saudável'}

{recipe.title}

{recipe.description}

{recipe.prep_time && ⏱ {recipe.prep_time}} {recipe.calories && 🔥 {recipe.calories}}
{recipe.ingredients_list && (

Ingredientes:

{recipe.ingredients_list.map((ing: string, i: number) =>

• {ing}

)}
)} {recipe.steps && (

Preparo:

{recipe.steps.map((step: string, i: number) =>

{i + 1}. {step}

)}
)} {recipe.tip &&

💡 {recipe.tip}

}
)} {/* Actions */}
); } return (

Escanear Produto

Aponte a câmera para o código de barras

{error &&
{error}
} {notFound && !photoLoading && (
🔍

Produto não encontrado

Tire uma foto do rótulo e nossa IA analisa.

)} {(photoLoading || loading) && (
{photoLoading ? '📷' : '👁️'}

{photoLoading ? 'Analisando foto...' : 'Analisando produto...'}

)} {!loading && !notFound && !photoLoading && ( <>
{scanning ? (
) : (
)}
ou digite
setManualCode(e.target.value)} className="flex-1 bg-dark-light rounded-xl px-4 py-3 text-white placeholder-gray-500 outline-none focus:ring-2 focus:ring-primary" onKeyDown={e => e.key === 'Enter' && manualCode && handleScan(manualCode)} />

🧪 Teste rápido:

{[ { name: 'Coca-Cola', code: '7894900011517' }, { name: 'Nescau', code: '7891000379691' }, { name: 'Miojo', code: '7891079000212' }, { name: 'Aveia', code: '7894321219820' }, ].map(p => ( ))}
)}
); }