"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 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 */}
) }