diff --git a/src/pages/AnalysisDashboard.tsx b/src/pages/AnalysisDashboard.tsx index 771227f..b5c2925 100644 --- a/src/pages/AnalysisDashboard.tsx +++ b/src/pages/AnalysisDashboard.tsx @@ -5,7 +5,6 @@ import GlassCard from '../components/GlassCard'; import StatusTerminal from '../components/StatusTerminal'; import { api } from '../lib/api'; import type { ScanResult } from '../lib/types'; - const BIOMARKER_META = { gill_saturation: { label: 'Gill Saturation', icon: Droplets }, corneal_clarity: { label: 'Corneal Clarity', icon: EyeIcon }, @@ -27,12 +26,14 @@ export default function AnalysisDashboard() { const [error, setError] = useState(''); useEffect(() => { + async function load() { setLoading(true); - setError(''); + setError(""); + try { - const idParam = params.get('id'); - const lastId = sessionStorage.getItem('lastScanId'); + const idParam = params.get("id"); + const lastId = sessionStorage.getItem("lastScanId"); const targetId = idParam || lastId; const res = targetId @@ -41,16 +42,35 @@ export default function AnalysisDashboard() { setScan(res.scan); } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to load scan data.'); + const offlineData = sessionStorage.getItem("offlineScanResult"); + + if (offlineData) { + try { + const parsed = JSON.parse(offlineData); + + if (parsed?.freshness_index != null) { + setScan(parsed); + setLoading(false); + return; + } + } catch (e) { + console.warn("Failed to parse offline scan result", e); + } + } + + setError( + err instanceof Error ? err.message : "Failed to load scan data." + ); } finally { setLoading(false); } } + load(); }, [params]); - // ── Loading state ──────────────────────────────────────────────────────── - if (loading) { + + if (loading) { return (
diff --git a/src/pages/ScannerPage.tsx b/src/pages/ScannerPage.tsx index 58af502..4f5e4e3 100644 --- a/src/pages/ScannerPage.tsx +++ b/src/pages/ScannerPage.tsx @@ -253,6 +253,57 @@ export default function ScannerPage() { stopProgress(100); const freshness = Math.round(fusion.fusedScore * 100); + const offlineScanResult = { + scan_id: "offline-scan", + scan_display_id: "OFFLINE_SCAN", + freshness_index: freshness, + grade: deriveGrade(freshness), + confidence: parseFloat(fusion.confidence), + classification: + fusion.label === "Fresh" + ? "FRESH" + : fusion.label === "Moderate" + ? "FRESH" + : "SPOILED", + is_fresh: fusion.label !== "Spoiled", + uncertain_flag: false, + species: { + common_name: "Unknown Fish", + scientific_name: "N/A", + habitat: "N/A", + tags: [], + weight_estimate_kg: 0, + catch_age_hours: 0, + }, + biomarkers: { + gill_saturation: { + score: freshness, + status: "NOMINAL", + detail: "Offline edge inference", + }, + corneal_clarity: { + score: freshness, + status: "NOMINAL", + detail: "Offline edge inference", + }, + epidermal_tension: { + score: freshness, + status: "NOMINAL", + detail: "Offline edge inference", + }, + }, + recommendations: { + consume_within_hours: 0, + storage_temp: "Unknown", + alert_flags: ["Generated from offline scan"], + }, + }; + + sessionStorage.setItem( + "offlineScanResult", + JSON.stringify(offlineScanResult), + ); + setResult({ label: fusion.label, freshness,