From 941f554662393a67677bafe23246869f5bfa055f Mon Sep 17 00:00:00 2001 From: "santasri.pachhal" Date: Fri, 12 Jun 2026 12:28:17 +0530 Subject: [PATCH] chore(chainage): rename chainge to segment --- src/app/(modules)/chainage/page.tsx | 801 +----------------- src/app/(modules)/dashboard/page.tsx | 4 +- src/app/(modules)/package/page.tsx | 4 +- src/app/(modules)/results/[videoId]/page.tsx | 2 +- src/app/(modules)/results/page.tsx | 2 +- src/app/(modules)/segment/page.tsx | 786 +++++++++++++++++ src/app/(modules)/upload/[videoId]/page.tsx | 2 +- src/app/(modules)/upload/page.tsx | 12 +- src/components/app-sidebar.tsx | 2 +- .../dashboard/chainage-bar-chart.tsx | 4 +- src/components/dashboard/filter-selector.tsx | 6 +- src/components/project-selection-section.tsx | 12 +- .../video/detailed-summary-section.tsx | 4 +- src/utils/routes.ts | 2 +- 14 files changed, 817 insertions(+), 826 deletions(-) create mode 100644 src/app/(modules)/segment/page.tsx diff --git a/src/app/(modules)/chainage/page.tsx b/src/app/(modules)/chainage/page.tsx index 8a6443a..6f7d32f 100644 --- a/src/app/(modules)/chainage/page.tsx +++ b/src/app/(modules)/chainage/page.tsx @@ -1,800 +1,5 @@ -'use client'; +import { redirect } from 'next/navigation'; -import { useState, useEffect } 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 { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog'; -import { - Loader2, - CheckCircle2, - MapPin, - Navigation, - Milestone, - ArrowUpCircle, - ArrowDownCircle, -} from 'lucide-react'; -import { DataTable } from '@/components/data-table'; -import { PageHeader } from '@/components/page-header'; -import { PoweredBy } from '@/components/powered-by'; -import { projectService, packageService, chainageService } from '@/services/api'; -import { Project, Package as PackageType, Chainage, ChainageCreate, ChainageUpdate } from '@/types'; -import { ColumnDef } from '@tanstack/react-table'; -import { toast } from 'sonner'; -import { Badge } from '@/components/ui/badge'; -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; - -export default function ChainagePage() { - const [chainages, setChainages] = useState([]); - const [totalItems, setTotalItems] = useState(0); - const [projects, setProjects] = useState([]); - const [packages, setPackages] = useState([]); - const [allPackages, setAllPackages] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [isModalOpen, setIsModalOpen] = useState(false); - const [isSubmitting, setIsSubmitting] = useState(false); - const [error, setError] = useState(null); - const [loadingProjects, setLoadingProjects] = useState(false); - const [loadingPackages, setLoadingPackages] = useState(false); - - // Pagination state - const [skip, setSkip] = useState(0); - const [limit, setLimit] = useState(10); - - // Editing state - const [isEditing, setIsEditing] = useState(false); - const [currentChainage, setCurrentChainage] = useState(null); - - // Form fields - const [selectedProjectId, setSelectedProjectId] = useState(''); - const [selectedPackageId, setSelectedPackageId] = useState(''); - const [segmentName, setSegmentName] = useState(''); - const [chainageStartKm, setChainageStartKm] = useState(''); - const [chainageEndKm, setChainageEndKm] = useState(''); - const [startLat, setStartLat] = useState(''); - const [startLng, setStartLng] = useState(''); - const [endLat, setEndLat] = useState(''); - const [endLng, setEndLng] = useState(''); - const [direction, setDirection] = useState<'UP' | 'DOWN'>('UP'); - - // Load chainages and projects - const loadChainages = async (currentSkip = skip, currentLimit = limit) => { - try { - setIsLoading(true); - setError(null); - const data = await chainageService.getChainages({ skip: currentSkip, limit: currentLimit }); - setChainages(data.items); - setTotalItems(data.totalItems); - } catch (err) { - setError('Failed to load chainages. Please check if the backend is running.'); - } finally { - // Add a small delay for animation stability - setTimeout(() => { - setIsLoading(false); - }, 800); - } - }; - - const loadProjects = async () => { - try { - setLoadingProjects(true); - const data = await projectService.getProjects({ skip: 0, limit: 1000 }); - setProjects(data.items); - } catch (err) { - setError('Failed to load projects.'); - } finally { - setLoadingProjects(false); - } - }; - - const loadAllPackages = async () => { - try { - const data = await packageService.getPackages({ skip: 0, limit: 1000 }); - setAllPackages(data.items); - } catch (err) { - console.error('Failed to load all packages'); - } - }; - - useEffect(() => { - loadChainages(skip, limit); - loadProjects(); - loadAllPackages(); - }, [skip, limit]); - - // Load packages when project changes - useEffect(() => { - if (!selectedProjectId) { - setPackages([]); - if (!isEditing) setSelectedPackageId(''); - return; - } - - const loadPackagesForProject = async () => { - try { - setLoadingPackages(true); - if (!isEditing) setSelectedPackageId(''); - const data = await packageService.getPackagesByProject(selectedProjectId, { - skip: 0, - limit: 1000, - }); - setPackages(data.items); - } catch (err) { - setError('Failed to load packages for the selected project.'); - } finally { - setLoadingPackages(false); - } - }; - loadPackagesForProject(); - }, [selectedProjectId, isEditing]); - - const resetForm = () => { - setSelectedProjectId(''); - setSelectedPackageId(''); - setSegmentName(''); - setChainageStartKm(''); - setChainageEndKm(''); - setStartLat(''); - setStartLng(''); - setEndLat(''); - setEndLng(''); - setDirection('UP'); - setError(null); - setIsEditing(false); - setCurrentChainage(null); - }; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (!selectedPackageId && !isEditing) { - setError('Please select a project and package first'); - return; - } - if (!segmentName.trim()) { - setError('Segment name is required'); - return; - } - if (!startLat || !startLng || !endLat || !endLng) { - setError('All GPS coordinates are required for chainages'); - return; - } - if (!chainageStartKm || !chainageEndKm) { - setError('Chainage start and end values are required'); - return; - } - - setIsSubmitting(true); - setError(null); - - try { - if (isEditing && currentChainage) { - const data: ChainageUpdate = { - segment_name: segmentName.trim(), - chainage_start_km: parseFloat(chainageStartKm), - chainage_end_km: parseFloat(chainageEndKm), - start_lat: parseFloat(startLat), - start_lng: parseFloat(startLng), - end_lat: parseFloat(endLat), - end_lng: parseFloat(endLng), - direction: direction as 'UP' | 'DOWN', - }; - await chainageService.updateChainage(currentChainage.id, data); - toast.success('Chainage Updated', { - description: `${segmentName} has been updated successfully at ${new Date().toLocaleTimeString()}`, - }); - } else { - const data: ChainageCreate = { - package_id: selectedPackageId, - segment_name: segmentName.trim(), - chainage_start_km: parseFloat(chainageStartKm), - chainage_end_km: parseFloat(chainageEndKm), - start_lat: parseFloat(startLat), - start_lng: parseFloat(startLng), - end_lat: parseFloat(endLat), - end_lng: parseFloat(endLng), - direction: direction, - }; - await chainageService.createChainage(data); - toast.success('Chainage Created', { - description: `${segmentName} has been established successfully at ${new Date().toLocaleTimeString()}`, - }); - } - - // Refresh chainages list - await loadChainages(); - - // Close modal and reset form immediately - setIsModalOpen(false); - resetForm(); - } catch (err) { - const message = - err instanceof Error - ? err.message - : `Failed to ${isEditing ? 'update' : 'create'} chainage`; - setError(message); - toast.error('Operation Failed', { - description: message, - }); - } finally { - setIsSubmitting(false); - } - }; - - const handleEdit = (chainage: Chainage) => { - setIsEditing(true); - setCurrentChainage(chainage); - - // Find project for this package - const pkg = allPackages.find((p) => p.id === chainage.package_id); - if (pkg) { - setSelectedProjectId(pkg.project_id); - setSelectedPackageId(chainage.package_id); - } - - setSegmentName(chainage.segment_name || ''); - setChainageStartKm(chainage.chainage_start_km?.toString() || ''); - setChainageEndKm(chainage.chainage_end_km?.toString() || ''); - setStartLat(chainage.start_lat.toString()); - setStartLng(chainage.start_lng.toString()); - setEndLat(chainage.end_lat.toString()); - setEndLng(chainage.end_lng.toString()); - setDirection(chainage.direction); - setIsModalOpen(true); - }; - - const handleDelete = async (chainage: Chainage) => { - if (!confirm(`Are you sure you want to delete chainage "${chainage.segment_name}"?`)) return; - - try { - setIsLoading(true); - await chainageService.deleteChainage(chainage.id); - toast.success('Chainage Deleted', { - description: `${chainage.segment_name} has been removed from the system.`, - }); - await loadChainages(); - } catch (err) { - setError('Failed to delete chainage'); - toast.error('Deletion Failed', { - description: 'The chainage could not be removed. Please try again.', - }); - } finally { - setIsLoading(false); - } - }; - - const getPackageName = (packageId: string) => { - return allPackages.find((p) => p.id === packageId)?.name || packageId; - }; - - const isFormComplete = - selectedPackageId && - segmentName.trim() && - startLat && - startLng && - endLat && - endLng && - chainageStartKm && - chainageEndKm; - - const columns: ColumnDef[] = [ - { - accessorKey: 'segment_name', - header: 'Segment Name', - cell: ({ row }) =>
{row.original.segment_name}
, - }, - { - accessorKey: 'package_id', - header: 'Package', - cell: ({ row }) => getPackageName(row.original.package_id), - }, - { - accessorKey: 'project', - header: 'Project', - cell: ({ row }) => { - const chainage = row.original; - const pkg = allPackages.find((p) => p.id === chainage.package_id); - const project = projects.find((p) => p.id === pkg?.project_id); - return project?.name || '—'; - }, - }, - { - id: 'project_state', - header: 'Project State', - cell: ({ row }) => { - const chainage = row.original; - const pkg = allPackages.find((p) => p.id === chainage.package_id); - const project = projects.find((p) => p.id === pkg?.project_id); - if (!project?.state) return ; - - const states = project.state - .split(',') - .map((s) => s.trim()) - .filter(Boolean); - if (states.length === 0) return ; - - const firstState = states[0]; - const remainingStates = states.slice(1); - - return ( -
- {firstState} - - {remainingStates.length > 0 && ( - - - - - -
-

- Other States -

- {remainingStates.map((item, idx) => ( - - {item} - - ))} -
-
-
- )} -
- ); - }, - }, - { - accessorKey: 'chainage', - header: 'Chainage (km)', - cell: ({ row }) => { - const chainage = row.original; - return ( -
- - - {chainage.chainage_start_km} - {chainage.chainage_end_km} - - - {chainage.direction === 'UP' ? ( - - ) : ( - - )} - {chainage.direction} - -
- ); - }, - }, - { - accessorKey: 'start_gps', - header: 'Start GPS', - cell: ({ row }) => ( - - - {row.original.start_lat.toFixed(4)}, {row.original.start_lng.toFixed(4)} - - ), - }, - { - accessorKey: 'end_gps', - header: 'End GPS', - cell: ({ row }) => ( - - - {row.original.end_lat.toFixed(4)}, {row.original.end_lng.toFixed(4)} - - ), - }, - ]; - - return ( - <> -
- {/* Refined Header */} -
- { - setIsEditing(false); - setIsModalOpen(true); - }} - > - - Add New Chainage - - } - /> -
- - {/* Data Table */} -
- { - setLimit(newLimit); - setSkip(0); // Reset skip when limit changes - }, - }} - /> -
- - -
- - {/* Modal Dialog */} - { - if (!open) { - setIsModalOpen(false); - resetForm(); - } else { - setIsModalOpen(true); - } - }} - > - e.preventDefault()}> - - -
- -
- {isEditing ? 'Edit Chainage Details' : 'Create New Chainage'} -
- - {isEditing - ? 'Update the technical specifications for your road segment chainage.' - : 'Select a project & package, then provide the essential chainage data.'} - -
- -
- {!isEditing && ( -
- {/* Step 1: Select Project */} -
-
-
- 01 -
-

- Select Project -

-
- -
- - {/* Step 2: Select Package */} -
-
-
- 02 -
-

- Select Package -

-
- -
-
- )} - - {/* Step 3: Chainage Details */} -
- {!isEditing && ( -
-
- 03 -
-

- Chainage Information -

-
- )} - - {/* Segment Name & Chainage Row */} -
-
- - setSegmentName(e.target.value)} - placeholder="e.g. Mumbai to Pune" - className="h-11 bg-muted/20 border-border/60" - required - /> -
-
-
- - setChainageStartKm(e.target.value)} - placeholder="0.0" - className="h-11 bg-muted/20 border-border/60 text-sm font-mono" - required - /> -
-
- - setChainageEndKm(e.target.value)} - placeholder="1.0" - className="h-11 bg-muted/20 border-border/60 text-sm font-mono" - required - /> -
-
-
- - {/* Direction Row */} -
- - -
- - {/* GPS Coordinates Grid */} -
- {/* Start Point */} -
-

- START POINT -

-
-
- - setStartLat(e.target.value)} - placeholder="0.0000" - className="h-10 bg-muted/10 border-border/40 text-xs font-mono" - required - /> -
-
- - setStartLng(e.target.value)} - placeholder="0.0000" - className="h-10 bg-muted/10 border-border/40 text-xs font-mono" - required - /> -
-
-
- - {/* End Point */} -
-

- END POINT -

-
-
- - setEndLat(e.target.value)} - placeholder="0.0000" - className="h-10 bg-muted/10 border-border/40 text-xs font-mono" - required - /> -
-
- - setEndLng(e.target.value)} - placeholder="0.0000" - className="h-10 bg-muted/10 border-border/40 text-xs font-mono" - required - /> -
-
-
-
-
- - {/* Submit Button */} -
- - -
-
-
-
- - ); +export default function ChainageRedirectPage() { + redirect('/segment'); } diff --git a/src/app/(modules)/dashboard/page.tsx b/src/app/(modules)/dashboard/page.tsx index 7bac140..1ebc262 100644 --- a/src/app/(modules)/dashboard/page.tsx +++ b/src/app/(modules)/dashboard/page.tsx @@ -484,7 +484,7 @@ export default function DashboardPage() { Filter Analysis

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

@@ -604,7 +604,7 @@ export default function DashboardPage() { - Severity by Chainage + Severity by Segment Detections grouped by road segment diff --git a/src/app/(modules)/package/page.tsx b/src/app/(modules)/package/page.tsx index c065d03..1168e0c 100644 --- a/src/app/(modules)/package/page.tsx +++ b/src/app/(modules)/package/page.tsx @@ -436,7 +436,7 @@ export default function PackagePage() { htmlFor="chainage-start" className="text-[11px] font-bold text-muted-foreground uppercase tracking-wider" > - Chainage Start (km) + Segment Start (km) - Chainage End (km) + Segment End (km)
- Chainage + Segment {session.chainageName} diff --git a/src/app/(modules)/results/page.tsx b/src/app/(modules)/results/page.tsx index e9230a0..6bd8508 100644 --- a/src/app/(modules)/results/page.tsx +++ b/src/app/(modules)/results/page.tsx @@ -118,7 +118,7 @@ export default function ResultsPage() {
- Chainage + Segment {session.chainageName} diff --git a/src/app/(modules)/segment/page.tsx b/src/app/(modules)/segment/page.tsx new file mode 100644 index 0000000..21b3bd0 --- /dev/null +++ b/src/app/(modules)/segment/page.tsx @@ -0,0 +1,786 @@ +'use client'; + +import { useState, useEffect } 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 { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { + Loader2, + CheckCircle2, + MapPin, + Navigation, + Milestone, + ArrowUpCircle, + ArrowDownCircle, +} from 'lucide-react'; +import { DataTable } from '@/components/data-table'; +import { PageHeader } from '@/components/page-header'; +import { PoweredBy } from '@/components/powered-by'; +import { projectService, packageService, chainageService } from '@/services/api'; +import { Project, Package as PackageType, Chainage, ChainageCreate, ChainageUpdate } from '@/types'; +import { ColumnDef } from '@tanstack/react-table'; +import { toast } from 'sonner'; +import { Badge } from '@/components/ui/badge'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; + +export default function ChainagePage() { + const [chainages, setChainages] = useState([]); + const [totalItems, setTotalItems] = useState(0); + const [projects, setProjects] = useState([]); + const [packages, setPackages] = useState([]); + const [allPackages, setAllPackages] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [isModalOpen, setIsModalOpen] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); + const [error, setError] = useState(null); + const [loadingProjects, setLoadingProjects] = useState(false); + const [loadingPackages, setLoadingPackages] = useState(false); + + // Pagination state + const [skip, setSkip] = useState(0); + const [limit, setLimit] = useState(10); + + // Editing state + const [isEditing, setIsEditing] = useState(false); + const [currentChainage, setCurrentChainage] = useState(null); + + // Form fields + const [selectedProjectId, setSelectedProjectId] = useState(''); + const [selectedPackageId, setSelectedPackageId] = useState(''); + const [segmentName, setSegmentName] = useState(''); + const [chainageStartKm, setChainageStartKm] = useState(''); + const [chainageEndKm, setChainageEndKm] = useState(''); + const [startLat, setStartLat] = useState(''); + const [startLng, setStartLng] = useState(''); + const [endLat, setEndLat] = useState(''); + const [endLng, setEndLng] = useState(''); + const [direction, setDirection] = useState<'UP' | 'DOWN'>('UP'); + + // Load chainages and projects + const loadChainages = async (currentSkip = skip, currentLimit = limit) => { + try { + setIsLoading(true); + setError(null); + const data = await chainageService.getChainages({ skip: currentSkip, limit: currentLimit }); + setChainages(data.items); + setTotalItems(data.totalItems); + } catch (err) { + setError('Failed to load segments. Please check if the backend is running.'); + } finally { + // Add a small delay for animation stability + setTimeout(() => { + setIsLoading(false); + }, 800); + } + }; + + const loadProjects = async () => { + try { + setLoadingProjects(true); + const data = await projectService.getProjects({ skip: 0, limit: 1000 }); + setProjects(data.items); + } catch (err) { + setError('Failed to load projects.'); + } finally { + setLoadingProjects(false); + } + }; + + const loadAllPackages = async () => { + try { + const data = await packageService.getPackages({ skip: 0, limit: 1000 }); + setAllPackages(data.items); + } catch (err) { + console.error('Failed to load all packages'); + } + }; + + useEffect(() => { + loadChainages(skip, limit); + loadProjects(); + loadAllPackages(); + }, [skip, limit]); + + // Load packages when project changes + useEffect(() => { + if (!selectedProjectId) { + setPackages([]); + if (!isEditing) setSelectedPackageId(''); + return; + } + + const loadPackagesForProject = async () => { + try { + setLoadingPackages(true); + if (!isEditing) setSelectedPackageId(''); + const data = await packageService.getPackagesByProject(selectedProjectId, { + skip: 0, + limit: 1000, + }); + setPackages(data.items); + } catch (err) { + setError('Failed to load packages for the selected project.'); + } finally { + setLoadingPackages(false); + } + }; + loadPackagesForProject(); + }, [selectedProjectId, isEditing]); + + const resetForm = () => { + setSelectedProjectId(''); + setSelectedPackageId(''); + setSegmentName(''); + setChainageStartKm(''); + setChainageEndKm(''); + setStartLat(''); + setStartLng(''); + setEndLat(''); + setEndLng(''); + setDirection('UP'); + setError(null); + setIsEditing(false); + setCurrentChainage(null); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!selectedPackageId && !isEditing) { + setError('Please select a project and package first'); + return; + } + if (!segmentName.trim()) { + setError('Segment name is required'); + return; + } + if (!chainageStartKm || !chainageEndKm) { + setError('Segment start and end values are required'); + return; + } + + setIsSubmitting(true); + setError(null); + + try { + if (isEditing && currentChainage) { + const data: ChainageUpdate = { + segment_name: segmentName.trim(), + chainage_start_km: parseFloat(chainageStartKm), + chainage_end_km: parseFloat(chainageEndKm), + start_lat: startLat ? parseFloat(startLat) : 0, + start_lng: startLng ? parseFloat(startLng) : 0, + end_lat: endLat ? parseFloat(endLat) : 0, + end_lng: endLng ? parseFloat(endLng) : 0, + direction: direction as 'UP' | 'DOWN', + }; + await chainageService.updateChainage(currentChainage.id, data); + toast.success('Segment Updated', { + description: `${segmentName} has been updated successfully at ${new Date().toLocaleTimeString()}`, + }); + } else { + const data: ChainageCreate = { + package_id: selectedPackageId, + segment_name: segmentName.trim(), + chainage_start_km: parseFloat(chainageStartKm), + chainage_end_km: parseFloat(chainageEndKm), + start_lat: startLat ? parseFloat(startLat) : 0, + start_lng: startLng ? parseFloat(startLng) : 0, + end_lat: endLat ? parseFloat(endLat) : 0, + end_lng: endLng ? parseFloat(endLng) : 0, + direction: direction, + }; + await chainageService.createChainage(data); + toast.success('Segment Created', { + description: `${segmentName} has been established successfully at ${new Date().toLocaleTimeString()}`, + }); + } + + // Refresh chainages list + await loadChainages(); + + // Close modal and reset form immediately + setIsModalOpen(false); + resetForm(); + } catch (err) { + const message = + err instanceof Error + ? err.message + : `Failed to ${isEditing ? 'update' : 'create'} segment`; + setError(message); + toast.error('Operation Failed', { + description: message, + }); + } finally { + setIsSubmitting(false); + } + }; + + const handleEdit = (chainage: Chainage) => { + setIsEditing(true); + setCurrentChainage(chainage); + + // Find project for this package + const pkg = allPackages.find((p) => p.id === chainage.package_id); + if (pkg) { + setSelectedProjectId(pkg.project_id); + setSelectedPackageId(chainage.package_id); + } + + setSegmentName(chainage.segment_name || ''); + setChainageStartKm(chainage.chainage_start_km?.toString() || ''); + setChainageEndKm(chainage.chainage_end_km?.toString() || ''); + setStartLat(chainage.start_lat.toString()); + setStartLng(chainage.start_lng.toString()); + setEndLat(chainage.end_lat.toString()); + setEndLng(chainage.end_lng.toString()); + setDirection(chainage.direction); + setIsModalOpen(true); + }; + + const handleDelete = async (chainage: Chainage) => { + if (!confirm(`Are you sure you want to delete segment "${chainage.segment_name}"?`)) return; + + try { + setIsLoading(true); + await chainageService.deleteChainage(chainage.id); + toast.success('Segment Deleted', { + description: `${chainage.segment_name} has been removed from the system.`, + }); + await loadChainages(); + } catch (err) { + setError('Failed to delete segment'); + toast.error('Deletion Failed', { + description: 'The segment could not be removed. Please try again.', + }); + } finally { + setIsLoading(false); + } + }; + + const getPackageName = (packageId: string) => { + return allPackages.find((p) => p.id === packageId)?.name || packageId; + }; + + const isFormComplete = + selectedPackageId && + segmentName.trim() && + chainageStartKm && + chainageEndKm; + + const columns: ColumnDef[] = [ + { + accessorKey: 'segment_name', + header: 'Segment Name', + cell: ({ row }) =>
{row.original.segment_name}
, + }, + { + accessorKey: 'package_id', + header: 'Package', + cell: ({ row }) => getPackageName(row.original.package_id), + }, + { + accessorKey: 'project', + header: 'Project', + cell: ({ row }) => { + const chainage = row.original; + const pkg = allPackages.find((p) => p.id === chainage.package_id); + const project = projects.find((p) => p.id === pkg?.project_id); + return project?.name || '—'; + }, + }, + { + id: 'project_state', + header: 'Project State', + cell: ({ row }) => { + const chainage = row.original; + const pkg = allPackages.find((p) => p.id === chainage.package_id); + const project = projects.find((p) => p.id === pkg?.project_id); + if (!project?.state) return ; + + const states = project.state + .split(',') + .map((s) => s.trim()) + .filter(Boolean); + if (states.length === 0) return ; + + const firstState = states[0]; + const remainingStates = states.slice(1); + + return ( +
+ {firstState} + + {remainingStates.length > 0 && ( + + + + + +
+

+ Other States +

+ {remainingStates.map((item, idx) => ( + + {item} + + ))} +
+
+
+ )} +
+ ); + }, + }, + { + accessorKey: 'chainage', + header: 'Segment Range (km)', + cell: ({ row }) => { + const chainage = row.original; + return ( +
+ + + {chainage.chainage_start_km} - {chainage.chainage_end_km} + + + {chainage.direction === 'UP' ? ( + + ) : ( + + )} + {chainage.direction} + +
+ ); + }, + }, + { + accessorKey: 'start_gps', + header: 'Start GPS', + cell: ({ row }) => ( + + + {row.original.start_lat.toFixed(4)}, {row.original.start_lng.toFixed(4)} + + ), + }, + { + accessorKey: 'end_gps', + header: 'End GPS', + cell: ({ row }) => ( + + + {row.original.end_lat.toFixed(4)}, {row.original.end_lng.toFixed(4)} + + ), + }, + ]; + + return ( + <> +
+ {/* Refined Header */} +
+ { + setIsEditing(false); + setIsModalOpen(true); + }} + > + + Add Segment + + } + /> +
+ + {/* Data Table */} +
+ { + setLimit(newLimit); + setSkip(0); // Reset skip when limit changes + }, + }} + /> +
+ + +
+ + {/* Modal Dialog */} + { + if (!open) { + setIsModalOpen(false); + resetForm(); + } else { + setIsModalOpen(true); + } + }} + > + e.preventDefault()}> + + +
+ +
+ {isEditing ? 'Edit Segment' : 'Create Segment'} +
+ + {isEditing + ? 'Update the technical specifications for your road segment.' + : 'Select a project & package, then provide the essential segment data.'} + +
+ +
+ {!isEditing && ( +
+ {/* Step 1: Select Project */} +
+
+
+ 01 +
+

+ Select Project +

+
+ +
+ + {/* Step 2: Select Package */} +
+
+
+ 02 +
+

+ Select Package +

+
+ +
+
+ )} + + {/* Step 3: Chainage Details */} +
+ {!isEditing && ( +
+
+ 03 +
+

+ Segment Information +

+
+ )} + + {/* Segment Name & Chainage Row */} +
+
+ + setSegmentName(e.target.value)} + placeholder="e.g. Mumbai to Pune" + className="h-11 bg-muted/20 border-border/60" + required + /> +
+
+
+ + setChainageStartKm(e.target.value)} + placeholder="0.0" + className="h-11 bg-muted/20 border-border/60 text-sm font-mono" + required + /> +
+
+ + setChainageEndKm(e.target.value)} + placeholder="1.0" + className="h-11 bg-muted/20 border-border/60 text-sm font-mono" + required + /> +
+
+
+ + {/* Direction Row */} +
+ + +
+ + {/* GPS Coordinates Grid */} +
+
+

+ START COORDINATES +

+
+
+ + setStartLat(e.target.value)} + placeholder="0.0000" + className="h-10 bg-background/70 border-border/40 text-xs font-mono" + /> +
+
+ + setStartLng(e.target.value)} + placeholder="0.0000" + className="h-10 bg-background/70 border-border/40 text-xs font-mono" + /> +
+
+
+ +
+

+ END COORDINATES +

+
+
+ + setEndLat(e.target.value)} + placeholder="0.0000" + className="h-10 bg-background/70 border-border/40 text-xs font-mono" + /> +
+
+ + setEndLng(e.target.value)} + placeholder="0.0000" + className="h-10 bg-background/70 border-border/40 text-xs font-mono" + /> +
+
+
+
+
+ + {/* Submit Button */} +
+ + +
+
+
+
+ + ); +} diff --git a/src/app/(modules)/upload/[videoId]/page.tsx b/src/app/(modules)/upload/[videoId]/page.tsx index 549e744..a17f250 100644 --- a/src/app/(modules)/upload/[videoId]/page.tsx +++ b/src/app/(modules)/upload/[videoId]/page.tsx @@ -179,7 +179,7 @@ export default function VideoProcessingPage() {
- Chainage + Segment {session.chainageName} diff --git a/src/app/(modules)/upload/page.tsx b/src/app/(modules)/upload/page.tsx index 9c6ec3a..06f6f8f 100644 --- a/src/app/(modules)/upload/page.tsx +++ b/src/app/(modules)/upload/page.tsx @@ -24,14 +24,14 @@ import { Reveal } from '@/components/ui/reveal'; import { cn } from '@/lib/utils'; const DETECTION_METHODS = [ - // { value: 'yolo', label: 'YOLO Detection Model' }, + { value: 'yolo', label: 'Road Defect Detection' }, // { value: 'yolo_vl', label: 'YOLO with Vision-Language Model' }, // { value: 'sam3', label: 'OpenAI SAM 3 Segmentation Model' }, - // { value: 'yoloe', label: 'YOLOE Open-Vocabulary Detection' }, - // { value: 'yoloe_trained_vl', label: 'YOLOE With Vision Language Model' }, + { value: 'yoloe', label: 'YOLOE Open-Vocabulary Detection' }, + { value: 'yoloe_trained_vl', label: 'YOLOE With Vision Language Model' }, { value: 'culvert_detection', label: 'Culvert Detection' }, - { value: 'combined', label: 'Road Defect Detection' }, - { value: 'gemini_video', label: 'Gemini AI Analysis' }, + { value: 'combined', label: 'Road Defect Detection with vl' }, + // { value: 'gemini_video', label: 'Gemini AI Analysis' }, ] as const; export default function UploadPage() { @@ -141,7 +141,7 @@ export default function UploadPage() { 1. Project Details - Select the target project, package, and chainage segment. + Select the target project, package, and segment. diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index 478adc5..93f61f5 100644 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -47,7 +47,7 @@ const data = { icon: Package, }, { - title: 'Chainage', + title: 'Segment', url: ROUTES.CHAINAGE, icon: Milestone, }, diff --git a/src/components/dashboard/chainage-bar-chart.tsx b/src/components/dashboard/chainage-bar-chart.tsx index 8e14ea9..777b775 100644 --- a/src/components/dashboard/chainage-bar-chart.tsx +++ b/src/components/dashboard/chainage-bar-chart.tsx @@ -67,8 +67,8 @@ export function ChainageBarChart({ data, isLoading = false }: ChainageBarChartPr if (data.length === 0) { return (
-

No chainage data available

-

Process videos to see detections by chainage

+

No segment data available

+

Process videos to see detections by segment

); } diff --git a/src/components/dashboard/filter-selector.tsx b/src/components/dashboard/filter-selector.tsx index 0886456..ea621e1 100644 --- a/src/components/dashboard/filter-selector.tsx +++ b/src/components/dashboard/filter-selector.tsx @@ -104,7 +104,7 @@ export function FilterSelector({
- Chainage + Segment
) : ( )} @@ -399,9 +399,9 @@ export function ProjectSelectionSection({
- Select Project Chainage + Select Project Segment - Select Project, Package & Chainage to begin intelligent road analysis. + Select Project, Package & Segment to begin intelligent road analysis.
@@ -409,7 +409,7 @@ export function ProjectSelectionSection({
{[1, 2, 3].map((step, index) => { const status = getStepStatus(step); - const labels = ['Project', 'Package', 'Chainage']; + const labels = ['Project', 'Package', 'Segment']; return (
diff --git a/src/components/video/detailed-summary-section.tsx b/src/components/video/detailed-summary-section.tsx index f2834d9..7628d18 100644 --- a/src/components/video/detailed-summary-section.tsx +++ b/src/components/video/detailed-summary-section.tsx @@ -78,7 +78,7 @@ const DetailedSummarySection = ({
- Chainages + Segments {modeConfig.label} detected
@@ -169,7 +169,7 @@ const DetailedSummarySection = ({
- Chainage: {chainageName} + Segment: {chainageName}
Confidence:{' '} diff --git a/src/utils/routes.ts b/src/utils/routes.ts index 1236629..d2b4188 100644 --- a/src/utils/routes.ts +++ b/src/utils/routes.ts @@ -2,7 +2,7 @@ export const ROUTES = { DASHBOARD: '/dashboard', PROJECT: '/project', PACKAGE: '/package', - CHAINAGE: '/chainage', + CHAINAGE: '/segment', ACCOUNT: '/account', UPLOAD: '/upload', RESULTS: '/results',