Karim Krklec
Obavljene optimizacije
a641ed5
Raw
History Blame Contribute Delete
4.1 kB
import { useState, useEffect } from 'react'
import Navbar from './components/Navbar'
import AnalyzeScreen from './screens/AnalyzeScreen'
import BatchScreen from './screens/BatchScreen'
import SimilarityScreen from './screens/SimilarityScreen'
import DetailScreen from './screens/DetailScreen'
// Hash-based routing — svaki ekran ima vlastiti URL fragment
// Tako browser back/forward gumb rade ispravno
const SCREEN_TO_HASH = {
analyze: '#analyze',
batch: '#batch',
similarity: '#similarity',
detail: '#detail',
}
const HASH_TO_SCREEN = Object.fromEntries(
Object.entries(SCREEN_TO_HASH).map(([k, v]) => [v, k])
)
function getScreenFromHash() {
return HASH_TO_SCREEN[window.location.hash] || 'analyze'
}
export default function App() {
const [screen, setScreen] = useState(getScreenFromHash)
const [detailRow, setDetailRow] = useState(null)
const [serverOk, setServerOk] = useState(null)
// Health check
useEffect(() => {
fetch('/api/health')
.then(r => r.json())
.then(d => setServerOk(d.model_loaded))
.catch(() => setServerOk(false))
}, [])
// Slušamo browser back/forward
useEffect(() => {
const onPop = () => {
const s = getScreenFromHash()
setScreen(s)
// Ako se vraćamo s detail-a, detailRow ostaje — batch zadržava state
}
window.addEventListener('popstate', onPop)
return () => window.removeEventListener('popstate', onPop)
}, [])
// Navigacija — pushState mijenja URL i bilježi u history
const navigate = (s) => {
if (s !== 'batch' && s !== 'detail') setDetailRow(null)
window.history.pushState({ screen: s }, '', SCREEN_TO_HASH[s])
setScreen(s)
}
const openDetail = (row) => {
setDetailRow(row)
window.history.pushState({ screen: 'detail' }, '', '#detail')
setScreen('detail')
}
const backToBatch = () => {
window.history.pushState({ screen: 'batch' }, '', '#batch')
setScreen('batch')
}
return (
<div style={{ minHeight: '100vh', background: '#0A0F1C', position: 'relative' }}>
<div style={{
position: 'fixed', inset: 0, pointerEvents: 'none', zIndex: 0,
background: 'radial-gradient(ellipse 1200px 600px at 50% -10%, rgba(0,212,255,0.08), transparent 60%)',
}}/>
<div style={{ position: 'relative', zIndex: 1 }}>
<Navbar active={screen === 'detail' ? 'batch' : screen} onNavigate={navigate}/>
{serverOk === false && (
<div style={{
background: 'rgba(239,68,68,0.12)', borderBottom: '1px solid rgba(239,68,68,0.25)',
padding: '10px 80px', display: 'flex', alignItems: 'center', gap: 10, fontSize: 13, color: '#EF4444',
}}>
<span></span>
<span>Flask server not reachable — <code style={{ fontFamily: 'JetBrains Mono, monospace', background: 'rgba(239,68,68,0.12)', padding: '2px 6px', borderRadius: 4 }}>python app.py</code></span>
</div>
)}
{serverOk === true && screen === 'analyze' && (
<div style={{
background: 'rgba(16,185,129,0.08)', borderBottom: '1px solid rgba(16,185,129,0.15)',
padding: '8px 80px', display: 'flex', alignItems: 'center', gap: 10, fontSize: 12, color: '#10B981',
}}>
<span style={{ width: 6, height: 6, borderRadius: '50%', background: '#10B981', display: 'inline-block' }}/>
Server connected · Model loaded
</div>
)}
{screen === 'analyze' && <AnalyzeScreen/>}
{screen === 'similarity' && <SimilarityScreen/>}
{/* BatchScreen ostaje montiran dok smo u batch/detail ciklusu */}
<div style={{ display: screen === 'batch' || screen === 'detail' ? 'block' : 'none' }}>
<div style={{ display: screen === 'batch' ? 'block' : 'none' }}>
<BatchScreen onOpenRow={openDetail}/>
</div>
<div style={{ display: screen === 'detail' ? 'block' : 'none' }}>
<DetailScreen row={detailRow} onBack={backToBatch}/>
</div>
</div>
</div>
</div>
)
}