import { useEffect, useRef, useCallback, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Upload, Glasses, CheckCircle, XCircle, Loader2, Box, Package } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { useModelStore } from '@/stores/useModelStore'; import { toast } from 'sonner'; import { getSupportedExtension, convertToGLB, ACCEPTED_EXTENSIONS } from '@/lib/convertToGLB'; import { convertIFCtoGLB } from '@/lib/convertIFC'; import { CloudLoader } from '@/components/CloudLoader'; const Index = () => { const navigate = useNavigate(); const fileInputRef = useRef(null); const [loadingDemoIFC, setLoadingDemoIFC] = useState(false); const [loadingDemoCotovelo, setLoadingDemoCotovelo] = useState(false); const [converting, setConverting] = useState(false); const { model, setModel, xrSupported, setXrSupported } = useModelStore(); useEffect(() => { if (navigator.xr) { navigator.xr.isSessionSupported('immersive-ar').then(setXrSupported).catch(() => setXrSupported(false)); } else { setXrSupported(false); } }, [setXrSupported]); const handleFileUpload = useCallback(async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; const ext = getSupportedExtension(file.name); if (!ext) { toast.error('Formato inválido. Selecione um arquivo .GLB, .OBJ, .STL ou .IFC'); return; } if (ext === 'glb') { const url = URL.createObjectURL(file); setModel({ fileName: file.name, fileSize: file.size, url }); toast.success(`Modelo "${file.name}" carregado com sucesso!`); return; } // Convert OBJ/STL/IFC to GLB setConverting(true); try { const buffer = await file.arrayBuffer(); let result; if (ext === 'ifc') { result = await convertIFCtoGLB(buffer, file.name); } else { result = await convertToGLB(buffer, ext, file.name); } const url = URL.createObjectURL(result.blob); setModel({ fileName: result.fileName, fileSize: result.fileSize, url }); toast.success(`"${file.name}" convertido para GLB e carregado!`); } catch (err) { console.error(err); toast.error(`Falha ao converter "${file.name}"`); } finally { setConverting(false); } }, [setModel]); // Carregar da Nuvem agora é encapsulado em const handleLoadDemoIFC = useCallback(async () => { setLoadingDemoIFC(true); try { const response = await fetch('/models/demo250hp.ifc'); const buffer = await response.arrayBuffer(); const result = await convertIFCtoGLB(buffer, 'demo250hp.ifc'); const url = URL.createObjectURL(result.blob); setModel({ fileName: result.fileName, fileSize: result.fileSize, url }); toast.success('Modelo demo "250 HP" (IFC) carregado!'); } catch (err) { console.error(err); toast.error('Falha ao converter modelo demo IFC'); } finally { setLoadingDemoIFC(false); } }, [setModel]); const handleLoadDemoCotovelo = useCallback(async () => { setLoadingDemoCotovelo(true); try { const response = await fetch('/models/B126-COTOVELO.ifc'); const buffer = await response.arrayBuffer(); const result = await convertIFCtoGLB(buffer, 'B126-COTOVELO.ifc'); const url = URL.createObjectURL(result.blob); setModel({ fileName: result.fileName, fileSize: result.fileSize, url }); toast.success('Modelo demo "B126 Cotovelo" (IFC) carregado!'); } catch (err) { console.error(err); toast.error('Falha ao converter modelo demo Cotovelo'); } finally { setLoadingDemoCotovelo(false); } }, [setModel]); const handleEnterViewer = () => { if (!model) { toast.error('Importe um modelo GLB primeiro'); return; } navigate('/viewer'); }; return (
{/* Logo area */}

TrackSteelXR

Inspeção de Qualidade Industrial

{/* Main card */}
{/* Import button */} {/* Demo buttons */}
{model &&

{model.fileName}

{(model.fileSize / (1024 * 1024)).toFixed(2)} MB

} {/* Enter viewer */} {/* XR Status */}
{xrSupported === null ? <> Verificando suporte WebXR… : xrSupported ? <> WebXR Compatível — Passthrough disponível : <> WebXR não disponível neste navegador }
{/* Footer */}

TrackSteelXR v1.0 — Q.C. Inspection

); }; export default Index;