156 lines
5.6 KiB
TypeScript
156 lines
5.6 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Loader2, TrendingUp } from 'lucide-react';
|
|
import VideoPlayerSection from '@/components/video-player-section';
|
|
import { PageHeader } from '@/components/page-header';
|
|
import { PoweredBy } from '@/components/powered-by';
|
|
import { sessionService } from '@/services/api';
|
|
import { SessionContext, DetectionData, DetectionType } from '@/types';
|
|
import { clearVideoFile } from '@/lib/video-storage';
|
|
import { ROUTES } from '@/utils/routes';
|
|
import { Card } from '@/components/ui/card';
|
|
|
|
export default function ResultsPage() {
|
|
const router = useRouter();
|
|
const [session, setSession] = useState<SessionContext | null>(null);
|
|
const [detectionData] = useState<DetectionData | null>(null);
|
|
const [detectionType] = useState<DetectionType>('pothole-detection');
|
|
const [videoId] = useState<string | null>(null);
|
|
const [videoFile] = useState<File | null>(null);
|
|
const [isLoading] = useState(true);
|
|
const [error] = useState<string | null>(null);
|
|
|
|
// Load session and video data on mount
|
|
useEffect(() => {
|
|
const storedSession = sessionService.loadSession();
|
|
const videoData = sessionService.loadVideoData();
|
|
|
|
if (!sessionService.isSessionValid(storedSession) || !videoData) {
|
|
router.replace(ROUTES.UPLOAD);
|
|
return;
|
|
}
|
|
|
|
// If we have a videoId, redirect to the dynamic results page
|
|
if (videoData.videoId) {
|
|
router.replace(`${ROUTES.RESULTS}/${videoData.videoId}`);
|
|
return;
|
|
}
|
|
|
|
setSession(storedSession);
|
|
}, [router]);
|
|
|
|
const handleNewAnalysis = async () => {
|
|
// Clear video from IndexedDB
|
|
if (videoId) {
|
|
try {
|
|
await clearVideoFile(videoId);
|
|
} catch (err) {
|
|
console.error('Failed to clear video file:', err);
|
|
}
|
|
}
|
|
sessionService.clearSession();
|
|
router.push(ROUTES.UPLOAD);
|
|
};
|
|
|
|
const getTitle = () => {
|
|
if (detectionType === 'pothole-detection') return 'Pothole Detection Results';
|
|
if (detectionType === 'sign-board-detection') return 'Signboard Detection Results';
|
|
return 'Pothole & Signboard Detection Results';
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center">
|
|
<Card className="flex flex-col items-center gap-4 p-8">
|
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
|
<p className="text-sm text-muted-foreground">Loading results...</p>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center">
|
|
<Card className="flex flex-col items-center gap-6 p-8 text-center max-w-md">
|
|
<p className="text-destructive font-medium">{error}</p>
|
|
<Button onClick={handleNewAnalysis}>Start New Analysis</Button>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen">
|
|
<main className="min-h-screen">
|
|
<div className="container mx-auto px-6 py-10 max-w-[1600px]">
|
|
<div className="mb-8">
|
|
<PageHeader
|
|
title={getTitle()}
|
|
description="View your AI-powered road analysis results"
|
|
icon={TrendingUp}
|
|
/>
|
|
</div>
|
|
|
|
{session && (
|
|
<div className="mb-6">
|
|
<Card className="p-0 border shadow-sm overflow-hidden">
|
|
<div className="flex flex-col md:flex-row md:items-center justify-between py-4 px-6 gap-6 bg-card">
|
|
<div className="flex flex-wrap items-center gap-x-12 gap-y-4">
|
|
<div className="flex flex-col">
|
|
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-1.5">
|
|
Project
|
|
</span>
|
|
<span className="text-base font-bold leading-tight">
|
|
{session.projectName}
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col border-l pl-12 border-border/60">
|
|
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-1.5">
|
|
Package
|
|
</span>
|
|
<span className="text-sm font-semibold text-muted-foreground leading-tight">
|
|
{session.packageName}
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-col border-l pl-12 border-border/60">
|
|
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-1.5">
|
|
Segment
|
|
</span>
|
|
<span className="text-sm font-semibold text-muted-foreground leading-tight">
|
|
{session.chainageName}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<Button
|
|
onClick={handleNewAnalysis}
|
|
variant="outline"
|
|
size="sm"
|
|
className="font-semibold px-6 shrink-0 h-9"
|
|
>
|
|
Start New Analysis
|
|
</Button>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
)}
|
|
|
|
{detectionData && videoId && (
|
|
<VideoPlayerSection
|
|
data={detectionData}
|
|
videoId={videoId}
|
|
videoFile={videoFile}
|
|
detectionType={detectionType}
|
|
projectId={session?.projectId || undefined}
|
|
/>
|
|
)}
|
|
<PoweredBy />
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|