From 42624cae94b21e5d6f14fe5149164c6b9c35fbc1 Mon Sep 17 00:00:00 2001 From: "santasri.pachhal" Date: Wed, 18 Mar 2026 19:39:13 +0530 Subject: [PATCH] refactor: remove unused files --- public/avatars/profile.jpg | Bin 0 -> 31014 bytes src/app/(modules)/dashboard/page.tsx | 158 ++++----- src/components/app-sidebar.tsx | 181 +++++----- .../dashboard/compact-project-selector.tsx | 77 ---- .../dashboard/gradient-stats-card.tsx | 54 --- src/components/nav-main.tsx | 73 ---- src/components/nav-projects.tsx | 89 ----- src/components/team-switcher.tsx | 89 ----- src/components/ui/item.tsx | 193 ---------- src/components/upload-section.tsx | 334 ------------------ 10 files changed, 156 insertions(+), 1092 deletions(-) create mode 100644 public/avatars/profile.jpg delete mode 100644 src/components/dashboard/compact-project-selector.tsx delete mode 100644 src/components/dashboard/gradient-stats-card.tsx delete mode 100644 src/components/nav-main.tsx delete mode 100644 src/components/nav-projects.tsx delete mode 100644 src/components/team-switcher.tsx delete mode 100644 src/components/ui/item.tsx delete mode 100644 src/components/upload-section.tsx diff --git a/public/avatars/profile.jpg b/public/avatars/profile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c3d559066adede109d11fea7560cf26a363454d1 GIT binary patch literal 31014 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 0 || chnPothole > 0 || @@ -146,9 +147,9 @@ function calculateStats(summary: ProjectSummary | null): DetectionStats { chnDamagedRoadMarking > 0 || chnGoodSignboard > 0 ) { - const shortName = - chnName.length > 20 ? chnName.substring(0, 20) + "..." : chnName; - chainageData.push({ // Changed 'locationData.push' to 'chainageData.push' + const shortName = chnName.length > 20 ? chnName.substring(0, 20) + '...' : chnName; + chainageData.push({ + // Changed 'locationData.push' to 'chainageData.push' name: shortName, defected_sign_board: chnDefectedSignboard, pothole: chnPothole, @@ -167,10 +168,7 @@ function calculateStats(summary: ProjectSummary | null): DetectionStats { } total_road_damage = - total_defected_sign_board + - total_pothole + - total_road_crack + - total_damaged_road_marking; + total_defected_sign_board + total_pothole + total_road_crack + total_damaged_road_marking; return { totalDefectedSignboard: total_defected_sign_board, @@ -186,12 +184,8 @@ function calculateStats(summary: ProjectSummary | null): DetectionStats { export default function DashboardPage() { const [isLoading, setIsLoading] = useState(true); const [projects, setProjects] = useState([]); - const [selectedProjectId, setSelectedProjectId] = useState( - null, - ); - const [projectSummary, setProjectSummary] = useState( - null, - ); + const [selectedProjectId, setSelectedProjectId] = useState(null); + const [projectSummary, setProjectSummary] = useState(null); const [stats, setStats] = useState({ totalDefectedSignboard: 0, totalPothole: 0, @@ -214,9 +208,9 @@ export default function DashboardPage() { setSelectedProjectId(projectsData.items[0].id); } } catch (err) { - console.error("Failed to load projects:", err); - toast.error("Failed to load projects", { - description: "Please check if the backend is running." + console.error('Failed to load projects:', err); + toast.error('Failed to load projects', { + description: 'Please check if the backend is running.', }); } finally { setTimeout(() => { @@ -239,18 +233,12 @@ export default function DashboardPage() { : []; // Extract chainages from selected package - const [selectedPackageId, setSelectedPackageId] = useState( - null, - ); - const [selectedChainageId, setSelectedChainageId] = useState( // Changed 'selectedLocationId' to 'selectedChainageId' - null, - ); + const [selectedPackageId, setSelectedPackageId] = useState(null); + const [selectedChainageId, setSelectedChainageId] = useState(null); // Changed 'selectedLocationId' to 'selectedChainageId' const chainages = - projectSummary && selectedPackageId && selectedPackageId !== "all" - ? Object.keys( - projectSummary.packages[selectedPackageId]?.chainages || {}, - ).map((chnName) => ({ + projectSummary && selectedPackageId && selectedPackageId !== 'all' + ? Object.keys(projectSummary.packages[selectedPackageId]?.chainages || {}).map((chnName) => ({ id: chnName, name: chnName, })) @@ -270,8 +258,8 @@ export default function DashboardPage() { const summary: ProjectSummary = await projectService.getProjectSummary(selectedProjectId); setProjectSummary(summary); } catch (err) { - console.error("Failed to load project summary:", err); - toast.error("Failed to load project summary"); + console.error('Failed to load project summary:', err); + toast.error('Failed to load project summary'); setProjectSummary(null); } finally { setTimeout(() => { @@ -314,16 +302,16 @@ export default function DashboardPage() { let totalRoadCrack = 0; let totalDamagedRoadMarking = 0; let totalGoodSignboard = 0; - const chainageData: DetectionStats["chainageData"] = []; + const chainageData: DetectionStats['chainageData'] = []; const packagesToProcess = - selectedPackageId && selectedPackageId !== "all" + selectedPackageId && selectedPackageId !== 'all' ? { [selectedPackageId]: projectSummary.packages[selectedPackageId] } : projectSummary.packages || {}; for (const [pkgName, pkg] of Object.entries(packagesToProcess)) { const chainagesToProcess = - selectedChainageId && selectedChainageId !== "all" + selectedChainageId && selectedChainageId !== 'all' ? { [selectedChainageId]: pkg.chainages[selectedChainageId] } : pkg.chainages || {}; @@ -338,19 +326,19 @@ export default function DashboardPage() { for (const detection of chn.detections || []) { const type = detection.type.toLowerCase(); - if (type === "defected_sign_board") { + if (type === 'defected_sign_board') { chnDefectedSignboard++; totalDefectedSignboard++; - } else if (type === "pothole") { + } else if (type === 'pothole') { chnPothole++; totalPothole++; - } else if (type === "road_crack") { + } else if (type === 'road_crack') { chnRoadCrack++; totalRoadCrack++; - } else if (type === "damaged_road_marking") { + } else if (type === 'damaged_road_marking') { chnDamagedRoadMarking++; totalDamagedRoadMarking++; - } else if (type === "good_sign_board") { + } else if (type === 'good_sign_board') { chnGoodSignboard++; totalGoodSignboard++; } @@ -363,8 +351,7 @@ export default function DashboardPage() { chnDamagedRoadMarking > 0 || chnGoodSignboard > 0 ) { - const shortName = - chnName.length > 20 ? chnName.substring(0, 20) + "..." : chnName; + const shortName = chnName.length > 20 ? chnName.substring(0, 20) + '...' : chnName; chainageData.push({ name: shortName, defected_sign_board: chnDefectedSignboard, @@ -390,10 +377,7 @@ export default function DashboardPage() { totalDamagedRoadMarking, totalGoodSignboard, totalRoadDamage: - totalDefectedSignboard + - totalPothole + - totalRoadCrack + - totalDamagedRoadMarking, + totalDefectedSignboard + totalPothole + totalRoadCrack + totalDamagedRoadMarking, chainageData, }); }, [projectSummary, selectedPackageId, selectedChainageId]); @@ -425,7 +409,9 @@ export default function DashboardPage() { Filter Analysis -

Refine your view by project, package, or chainage

+

+ Refine your view by project, package, or chainage +

- {isLoading && !projectSummary ? ( ) : ( @@ -532,13 +517,12 @@ export default function DashboardPage() { Severity by Chainage - Detections grouped by road segment + + Detections grouped by road segment + - +
@@ -552,14 +536,14 @@ export default function DashboardPage() { {/* Map - Full Width Below Charts */}
-
-
+ )} diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index 8c0b1dd..295c57d 100644 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -1,106 +1,95 @@ -"use client"; -import * as React from "react"; +'use client'; +import * as React from 'react'; +import { LayoutDashboard, Plus, Layers, Package, MapPin, Milestone } from 'lucide-react'; +import { NavUser } from '@/components/nav-user'; +import { ROUTES } from '@/utils/routes'; import { - LayoutDashboard, - Plus, - Layers, - Package, - MapPin, - Milestone, -} from "lucide-react"; -import { NavUser } from "@/components/nav-user"; -import { ROUTES } from "@/utils/routes"; -import { - Sidebar, - SidebarContent, - SidebarFooter, - SidebarHeader, - SidebarRail, - SidebarMenu, - SidebarMenuItem, - SidebarMenuButton, - SidebarGroup, - SidebarGroupLabel, -} from "@/components/ui/sidebar"; -import Link from "next/link"; -import { usePathname } from "next/navigation"; + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, + SidebarRail, + SidebarMenu, + SidebarMenuItem, + SidebarMenuButton, + SidebarGroup, + SidebarGroupLabel, +} from '@/components/ui/sidebar'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; // This is the navigation data const data = { - user: { - name: "shadcn", - email: "m@example.com", - avatar: "/avatars/shadcn.jpg", + user: { + name: 'Vision Admin', + email: 'admin@visionroad.ai', + avatar: '/avatars/profile.jpg', + }, + navMain: [ + { + title: 'Dashboard', + url: ROUTES.DASHBOARD, + icon: LayoutDashboard, }, - navMain: [ - { - title: "Dashboard", - url: ROUTES.DASHBOARD, - icon: LayoutDashboard, - }, - { - title: "New Analysis", - url: ROUTES.NEW_ANALYSIS, - icon: Plus, - }, - { - title: "Project", - url: ROUTES.PROJECT, - icon: Layers, - }, - { - title: "Package", - url: ROUTES.PACKAGE, - icon: Package, - }, - { - title: "Chainage", - url: ROUTES.CHAINAGE, - icon: Milestone, - }, - ], + { + title: 'New Analysis', + url: ROUTES.NEW_ANALYSIS, + icon: Plus, + }, + { + title: 'Project', + url: ROUTES.PROJECT, + icon: Layers, + }, + { + title: 'Package', + url: ROUTES.PACKAGE, + icon: Package, + }, + { + title: 'Chainage', + url: ROUTES.CHAINAGE, + icon: Milestone, + }, + ], }; export function AppSidebar({ ...props }: React.ComponentProps) { - const pathname = usePathname(); + const pathname = usePathname(); - return ( - - -
-
- -
-
- Vision Road - Analytics Platform -
-
-
- - - - {data.navMain.map((item) => ( - - - - {item.icon && } - {item.title} - - - - ))} - - - - - - - -
- ); + return ( + + +
+
+ +
+
+ Vision Road + Analytics Platform +
+
+
+ + + + {data.navMain.map((item) => ( + + + + {item.icon && } + {item.title} + + + + ))} + + + + + + + +
+ ); } diff --git a/src/components/dashboard/compact-project-selector.tsx b/src/components/dashboard/compact-project-selector.tsx deleted file mode 100644 index 57b8d8d..0000000 --- a/src/components/dashboard/compact-project-selector.tsx +++ /dev/null @@ -1,77 +0,0 @@ -"use client" - -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" -import { Project } from "@/types" - -interface CompactProjectSelectorProps { - projects: Project[] - selectedProjectId: string | null - onProjectChange: (projectId: string) => void - selectedProject: Project | undefined - isLoading?: boolean -} - -export function CompactProjectSelector({ - projects, - selectedProjectId, - onProjectChange, - selectedProject, - isLoading = false -}: CompactProjectSelectorProps) { - return ( -
- {/* Project Dropdown */} -
- Project - -
- - {/* Corridor Badge */} - {selectedProject?.corridor_name && ( - <> -
-
- Corridor - - {selectedProject.corridor_name} - -
- - )} - - {/* State Badge */} - {selectedProject?.state && ( - <> -
-
- State - - {selectedProject.state} - -
- - )} -
- ) -} diff --git a/src/components/dashboard/gradient-stats-card.tsx b/src/components/dashboard/gradient-stats-card.tsx deleted file mode 100644 index 633eba1..0000000 --- a/src/components/dashboard/gradient-stats-card.tsx +++ /dev/null @@ -1,54 +0,0 @@ -"use client" - -import { Card, CardContent } from "@/components/ui/card" -import { LucideIcon } from "lucide-react" -import { cn } from "@/lib/utils" - -interface GradientStatsCardProps { - title: string - subtitle?: string - value: number | string - icon: LucideIcon - gradient?: "green" | "coral" | "blue" | "purple" | "orange" | "indigo" | "emerald" - isLoading?: boolean -} - -export function GradientStatsCard({ - title, - subtitle, - value, - icon: Icon, - isLoading = false -}: GradientStatsCardProps) { - return ( - - -
-

- {title} -

-
- {isLoading ? ( -
- ) : ( - <> -

- {value} -

- {subtitle && ( -

- {subtitle} -

- )} - - )} -
-
- -
- -
- - - ) -} diff --git a/src/components/nav-main.tsx b/src/components/nav-main.tsx deleted file mode 100644 index 1d71af1..0000000 --- a/src/components/nav-main.tsx +++ /dev/null @@ -1,73 +0,0 @@ -"use client" - -import { ChevronRight, type LucideIcon } from "lucide-react" - -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible" -import { - SidebarGroup, - SidebarGroupLabel, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, - SidebarMenuSub, - SidebarMenuSubButton, - SidebarMenuSubItem, -} from "@/components/ui/sidebar" - -export function NavMain({ - items, -}: { - items: { - title: string - url: string - icon?: LucideIcon - isActive?: boolean - items?: { - title: string - url: string - }[] - }[] -}) { - return ( - - Platform - - {items.map((item) => ( - - - - - {item.icon && } - {item.title} - - - - - - {item.items?.map((subItem) => ( - - - - {subItem.title} - - - - ))} - - - - - ))} - - - ) -} diff --git a/src/components/nav-projects.tsx b/src/components/nav-projects.tsx deleted file mode 100644 index f50b20d..0000000 --- a/src/components/nav-projects.tsx +++ /dev/null @@ -1,89 +0,0 @@ -"use client" - -import { - Folder, - Forward, - MoreHorizontal, - Trash2, - type LucideIcon, -} from "lucide-react" - -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" -import { - SidebarGroup, - SidebarGroupLabel, - SidebarMenu, - SidebarMenuAction, - SidebarMenuButton, - SidebarMenuItem, - useSidebar, -} from "@/components/ui/sidebar" - -export function NavProjects({ - projects, -}: { - projects: { - name: string - url: string - icon: LucideIcon - }[] -}) { - const { isMobile } = useSidebar() - - return ( - - Projects - - {projects.map((item) => ( - - - - - {item.name} - - - - - - - More - - - - - - View Project - - - - Share Project - - - - - Delete Project - - - - - ))} - - - - More - - - - - ) -} diff --git a/src/components/team-switcher.tsx b/src/components/team-switcher.tsx deleted file mode 100644 index 2808e0a..0000000 --- a/src/components/team-switcher.tsx +++ /dev/null @@ -1,89 +0,0 @@ -"use client" - -import * as React from "react" -import { ChevronsUpDown, Plus } from "lucide-react" - -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" -import { - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, - useSidebar, -} from "@/components/ui/sidebar" - -export function TeamSwitcher({ - teams, -}: { - teams: { - name: string - logo: React.ElementType - plan: string - }[] -}) { - const { isMobile } = useSidebar() - const [activeTeam, setActiveTeam] = React.useState(teams[0]) - - return ( - - - - - -
- -
-
- - {activeTeam.name} - - {activeTeam.plan} -
- -
-
- - - Teams - - {teams.map((team, index) => ( - setActiveTeam(team)} - className="gap-2 p-2" - > -
- -
- {team.name} - ⌘{index + 1} -
- ))} - - -
- -
-
Add team
-
-
-
-
-
- ) -} diff --git a/src/components/ui/item.tsx b/src/components/ui/item.tsx deleted file mode 100644 index efdf58c..0000000 --- a/src/components/ui/item.tsx +++ /dev/null @@ -1,193 +0,0 @@ -import * as React from 'react' -import { Slot } from '@radix-ui/react-slot' -import { cva, type VariantProps } from 'class-variance-authority' - -import { cn } from '@/lib/utils' -import { Separator } from '@/components/ui/separator' - -function ItemGroup({ className, ...props }: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function ItemSeparator({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -const itemVariants = cva( - 'group/item flex items-center border border-transparent text-sm rounded-md transition-colors [a&]:hover:bg-accent/50 [a&]:transition-colors duration-100 flex-wrap outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]', - { - variants: { - variant: { - default: 'bg-transparent', - outline: 'border-border', - muted: 'bg-muted/50', - }, - size: { - default: 'p-4 gap-4 ', - sm: 'py-3 px-4 gap-2.5', - }, - }, - defaultVariants: { - variant: 'default', - size: 'default', - }, - }, -) - -function Item({ - className, - variant = 'default', - size = 'default', - asChild = false, - ...props -}: React.ComponentProps<'div'> & - VariantProps & { asChild?: boolean }) { - const Comp = asChild ? Slot : 'div' - return ( - - ) -} - -const itemMediaVariants = cva( - 'flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none group-has-[[data-slot=item-description]]/item:translate-y-0.5', - { - variants: { - variant: { - default: 'bg-transparent', - icon: "size-8 border rounded-sm bg-muted [&_svg:not([class*='size-'])]:size-4", - image: - 'size-10 rounded-sm overflow-hidden [&_img]:size-full [&_img]:object-cover', - }, - }, - defaultVariants: { - variant: 'default', - }, - }, -) - -function ItemMedia({ - className, - variant = 'default', - ...props -}: React.ComponentProps<'div'> & VariantProps) { - return ( -
- ) -} - -function ItemContent({ className, ...props }: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function ItemTitle({ className, ...props }: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function ItemDescription({ className, ...props }: React.ComponentProps<'p'>) { - return ( -

a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4', - className, - )} - {...props} - /> - ) -} - -function ItemActions({ className, ...props }: React.ComponentProps<'div'>) { - return ( -

- ) -} - -function ItemHeader({ className, ...props }: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function ItemFooter({ className, ...props }: React.ComponentProps<'div'>) { - return ( -
- ) -} - -export { - Item, - ItemMedia, - ItemContent, - ItemActions, - ItemGroup, - ItemSeparator, - ItemTitle, - ItemDescription, - ItemHeader, - ItemFooter, -} diff --git a/src/components/upload-section.tsx b/src/components/upload-section.tsx deleted file mode 100644 index 0a9d4df..0000000 --- a/src/components/upload-section.tsx +++ /dev/null @@ -1,334 +0,0 @@ -"use client" - -import { useState, useRef } from "react" -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Label } from "@/components/ui/label" -import { Progress } from "@/components/ui/progress" -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" -import { Upload, Loader2, AlertCircle } from "lucide-react" -import type { DetectionData, DetectionType } from "@/types" - -import { videoService } from "@/services/api" -const API_URL = process.env.NEXT_PUBLIC_API_URL -const WS_URL = API_URL?.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://") - -const DETECTION_TYPES = [ - { value: "pothole-detection", label: "Pothole Detection" }, - { value: "sign-board-detection", label: "Signboard Detection" }, - { value: "pot-sign-detection", label: "Pothole & Signboard Detection" }, -] as const - -const DETECTION_METHODS = [ - { value: "yolo", label: "YOLO" }, - { value: "yolo_vl", label: "YOLO with VL" }, - { value: "sam3", label: "SAM 3" }, - { value: "yoloe", label: "YOLOE" }, - { value: "yoloe_trained_vl", label: "YOLOE Trained" }, -] as const - -type UploadSectionProps = { - onDetectionComplete: (data: DetectionData, videoId: string, file: File) => void - onDetectionTypeChange: (type: DetectionType) => void -} - -export function UploadSection({ onDetectionComplete, onDetectionTypeChange }: UploadSectionProps) { - const [file, setFile] = useState(null) - const [jsonFile, setJsonFile] = useState(null) - const [speed, setSpeed] = useState(30) - const [detectionType, setDetectionType] = useState("pothole-detection") - const [selectMethod, setSelectMethod] = useState("yolo_vl") - const [uploading, setUploading] = useState(false) - const [progress, setProgress] = useState(0) - const [statusMessage, setStatusMessage] = useState("") - const [error, setError] = useState(null) - const fileInputRef = useRef(null) - const jsonFileInputRef = useRef(null) - const wsRef = useRef(null) - - const handleDetectionTypeChange = (value: DetectionType) => { - setDetectionType(value) - onDetectionTypeChange(value) - } - - const connectWebSocket = (videoId: string) => { - console.log("[Upload] Connecting WebSocket for video:", videoId) - - const ws = new WebSocket(`${WS_URL}/ws/${videoId}`) - wsRef.current = ws - - ws.onopen = () => { - console.log("[Upload] WebSocket connected") - setError(null) - } - - ws.onmessage = (event) => { - const data = JSON.parse(event.data) - console.log("[Upload] WebSocket message:", data) - - if (data.type === "progress" || data.progress !== undefined) { - const progressValue = data.progress || 0 - setProgress(progressValue) - - let message = data.message || "Processing..." - - // Handle both pothole and signboard progress messages - if (data.unique_potholes !== undefined) { - message += ` | Unique: ${data.unique_potholes} | Total: ${data.total_detections || 0}` - } else if (data.unique_signboards !== undefined) { - message += ` | Unique: ${data.unique_signboards} | Total: ${data.total_detections || 0}` - } - - setStatusMessage(message) - } - - if (data.type === "complete" || data.status === "completed") { - setStatusMessage("Processing completed! Loading results...") - ws.close() - setTimeout(() => loadResults(videoId), 500) - } - - if (data.type === "error") { - setError("Error: " + data.message) - setStatusMessage("") - setUploading(false) - ws.close() - } - } - - ws.onerror = (error) => { - console.error("[Upload] WebSocket error:", error) - setStatusMessage("Connection error. Retrying...") - } - - ws.onclose = () => { - console.log("[Upload] WebSocket closed") - } - } - - const loadResults = async (videoId: string) => { - try { - console.log("[Upload] Loading results for:", videoId) - const detectionData: DetectionData = await videoService.getVideoResults(videoId); - console.log("[Upload] Results loaded:", detectionData) - - setUploading(false) - setProgress(100) - setStatusMessage("✓ Complete!") - setError(null) - - // Pass detection data, video_id, and the original file - if (file) { - onDetectionComplete(detectionData, videoId, file) - } - } catch (error) { - console.error("[Upload] Failed to load results:", error) - setError("Failed to load results. Please try again.") - setStatusMessage("") - setUploading(false) - } - } - - const handleUpload = async () => { - if (!file) { - setError("Please select a video file") - return - } - - const formData = new FormData() - formData.append("file", file) - formData.append("detection_type", detectionType) - formData.append("speed_kmh", speed.toString()) - formData.append("detection_mode", selectMethod) - - // Add JSON file if provided - if (jsonFile) { - formData.append("json_file", jsonFile) - } - - setUploading(true) - setProgress(0) - setStatusMessage("Uploading...") - setError(null) - - try { - const result = await videoService.uploadVideo(formData); - const videoId = result.video_id - - console.log("[Upload] Video uploaded successfully, ID:", videoId) - console.log("[Upload] Response:", result) - setStatusMessage("Uploaded! Starting processing...") - setProgress(10) - - // Connect WebSocket for progress updates - connectWebSocket(videoId) - } catch (error) { - console.error("[Upload] Upload error:", error) - - let errorMessage = "Upload failed" - - if (error instanceof TypeError && error.message === "Failed to fetch") { - errorMessage = "Cannot connect to server. Please check if backend is running." - } else if (error instanceof Error) { - errorMessage = error.message - } - - setError(errorMessage) - setStatusMessage("") - setUploading(false) - setProgress(0) - } - } - - return ( - - - Upload Video - - Select video file, detection type, vehicle speed, and method for analysis - - - -
-
- -
- { - setFile(e.target.files?.[0] || null) - setError(null) - }} - disabled={uploading} - className="flex-1" - /> -
- {file && ( -

- Selected: {file.name} ({(file.size / 1024 / 1024).toFixed(2)} MB) -

- )} -
- -
- -
- { - setJsonFile(e.target.files?.[0] || null) - setError(null) - }} - disabled={uploading} - className="flex-1" - /> -
- {jsonFile && ( -

- Selected: {jsonFile.name} ({(jsonFile.size / 1024).toFixed(2)} KB) -

- )} -
-
- -
-
- - -
- -
- - setSpeed(Number(e.target.value))} - disabled={uploading} - /> -
- -
- - -
-
- - {error && ( -
- -

{error}

-
- )} - - - - {uploading && ( -
- -
- {statusMessage} - {progress}% -
-
- )} -
-
- ) -} \ No newline at end of file