From c6894bfea01e08256baaf5c260fe0ef05cc372d3 Mon Sep 17 00:00:00 2001 From: "santasri.pachhal" Date: Thu, 18 Jun 2026 02:23:25 +0530 Subject: [PATCH] feat(video): base of video refactoring --- next-env.d.ts | 2 +- src/app/(modules)/results/[videoId]/page.tsx | 87 ++- .../results/hooks/useVideoResults.ts | 61 ++ src/app/(modules)/results/page.tsx | 144 +---- .../(modules)/results/queries/videoKeys.ts | 8 + src/components/video-player-section.tsx | 526 +++++++----------- src/components/video/detection-logs.tsx | 118 ++-- src/components/video/detection-stats-bar.tsx | 83 --- src/components/video/summary-section.tsx | 141 ----- src/components/video/video-canvas-player.tsx | 141 ----- src/constants/apiRoutes.ts | 2 +- src/constants/detectionModeConfig.ts | 27 - src/hooks/use-cumulative-counts.ts | 63 --- src/hooks/use-frame-detection-map.ts | 112 ---- src/hooks/use-gps-map.ts | 42 -- src/hooks/use-video-detection-loop.ts | 34 -- src/services/api/video.service.ts | 19 +- src/types/analysis.ts | 82 +-- src/types/detection.ts | 46 +- src/utils/canvas-drawing.ts | 106 ---- 20 files changed, 432 insertions(+), 1412 deletions(-) create mode 100644 src/app/(modules)/results/hooks/useVideoResults.ts create mode 100644 src/app/(modules)/results/queries/videoKeys.ts delete mode 100644 src/components/video/detection-stats-bar.tsx delete mode 100644 src/components/video/summary-section.tsx delete mode 100644 src/components/video/video-canvas-player.tsx delete mode 100644 src/hooks/use-cumulative-counts.ts delete mode 100644 src/hooks/use-frame-detection-map.ts delete mode 100644 src/hooks/use-gps-map.ts delete mode 100644 src/hooks/use-video-detection-loop.ts delete mode 100644 src/utils/canvas-drawing.ts diff --git a/next-env.d.ts b/next-env.d.ts index c4b7818..9edff1c 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/dev/types/routes.d.ts"; +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/src/app/(modules)/results/[videoId]/page.tsx b/src/app/(modules)/results/[videoId]/page.tsx index 0661f13..dec6b79 100644 --- a/src/app/(modules)/results/[videoId]/page.tsx +++ b/src/app/(modules)/results/[videoId]/page.tsx @@ -1,74 +1,56 @@ 'use client'; -import { useState, useEffect } from 'react'; +import { useState, useEffect, useMemo } from 'react'; import { useRouter, useParams } from 'next/navigation'; import { Button } from '@/components/ui/button'; import { Loader2, TrendingUp, ArrowUp, ArrowDown } from 'lucide-react'; import VideoPlayerSection from '@/components/video-player-section'; import { PageHeader } from '@/components/page-header'; -import { sessionService, videoService } from '@/services/api'; -import { SessionContext, DetectionData, DetectionType } from '@/types'; -import { getVideoFile, clearVideoFile } from '@/lib/video-storage'; +import { sessionService } from '@/services/api'; +import { SessionContext, CompletedVideoResult, DetectionType } from '@/types'; +import { clearVideoFile } from '@/lib/video-storage'; import { ROUTES } from '@/utils/routes'; import { Card } from '@/components/ui/card'; import { getDetectionModeConfig } from '@/constants/detectionModeConfig'; +import { useVideoResultsQuery } from '../hooks/useVideoResults'; -const API_URL = process.env.NEXT_PUBLIC_API_URL; +const inferDetectionType = (data: CompletedVideoResult): DetectionType => { + if (data.detection_mode) return data.detection_mode as DetectionType; + + const signboards = data.summary?.unique_signboards || 0; + const potholes = data.summary?.unique_potholes || 0; + + if (signboards > 0 && potholes > 0) return 'pot-sign-detection'; + if (signboards > 0) return 'sign-board-detection'; + return 'pothole-detection'; +}; export default function VideoResultsPage() { const router = useRouter(); const { videoId } = useParams() as { videoId: string }; const [session, setSession] = useState(null); - const [detectionData, setDetectionData] = useState( - null, + + const { + data: detectionData, + isLoading, + isError, + error: queryError, + } = useVideoResultsQuery(videoId); + + const detectionType = useMemo( + () => (detectionData ? inferDetectionType(detectionData) : 'pothole-detection'), + [detectionData], ); - const [detectionType, setDetectionType] = - useState('pothole-detection'); - const [videoFile, setVideoFile] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); + + const error = isError + ? queryError instanceof Error + ? queryError.message + : 'Failed to load results' + : null; useEffect(() => { - const storedSession = sessionService.loadSession(); - setSession(storedSession); - - const fetchResults = async () => { - try { - // Fetch detection data from backend - const data = await videoService.getVideoResults(videoId); - setDetectionData(data as any); - - // Try to infer detection type from results if possible - if (data.detection_mode) { - setDetectionType(data.detection_mode); - } else if ( - data.summary?.unique_signboards !== undefined && - data.summary?.unique_signboards > 0 - ) { - setDetectionType('sign-board-detection'); - } else if ( - data.summary?.unique_potholes !== undefined && - data.summary?.unique_potholes > 0 - ) { - setDetectionType('pothole-detection'); - } - - // Retrieve video file from IndexedDB - const storedVideoFile = await getVideoFile(videoId); - if (storedVideoFile) { - setVideoFile(storedVideoFile); - } - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to load results'); - } finally { - setIsLoading(false); - } - }; - - if (videoId) { - fetchResults(); - } - }, [videoId]); + setSession(sessionService.loadSession()); + }, []); const handleNewAnalysis = async () => { if (videoId) { @@ -188,7 +170,6 @@ export default function VideoResultsPage() { diff --git a/src/app/(modules)/results/hooks/useVideoResults.ts b/src/app/(modules)/results/hooks/useVideoResults.ts new file mode 100644 index 0000000..cbde463 --- /dev/null +++ b/src/app/(modules)/results/hooks/useVideoResults.ts @@ -0,0 +1,61 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; + +import { videoService } from '@/services/api'; + +import { videoKeys } from '../queries/videoKeys'; + +/** + * Fetch the completed detection results for a video. + */ +export function useVideoResultsQuery(videoId: string | undefined) { + return useQuery({ + queryKey: videoKeys.result(videoId ?? ''), + queryFn: () => videoService.getVideoResults(videoId as string), + enabled: Boolean(videoId), + }); +} + +/** + * Download the annotated video through the authenticated axios client and + * expose a local object URL that the native `