feat(api): restructure api with axios and chainage related changes
This commit is contained in:
@@ -14,7 +14,7 @@ const MapModal = dynamic(() => import("@/components/map-modal"), { ssr: false })
|
||||
import { DetectionData, DetectionType } from "@/types"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL
|
||||
import { projectService } from "@/services/api"
|
||||
|
||||
type VideoPlayerSectionProps = {
|
||||
data: DetectionData
|
||||
@@ -37,7 +37,7 @@ type DetectionLog = {
|
||||
videoTime: string // Video timestamp (MM:SS)
|
||||
}
|
||||
|
||||
type LocationSummaryData = {
|
||||
type ChainageSummaryData = {
|
||||
project: {
|
||||
id: string
|
||||
name: string
|
||||
@@ -48,9 +48,9 @@ type LocationSummaryData = {
|
||||
[packageName: string]: {
|
||||
package_id: string
|
||||
region: string | null
|
||||
locations: {
|
||||
[locationName: string]: {
|
||||
location_id: string
|
||||
chainages: {
|
||||
[chainageName: string]: {
|
||||
chainage_id: string
|
||||
chainage: string | null
|
||||
detection_count: number
|
||||
detections: Array<{
|
||||
@@ -87,7 +87,7 @@ function DetailedSummarySection({
|
||||
show: boolean
|
||||
detectionType: DetectionType
|
||||
}) {
|
||||
const [summaryData, setSummaryData] = useState<LocationSummaryData | null>(null)
|
||||
const [summaryData, setSummaryData] = useState<ChainageSummaryData | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [showMap, setShowMap] = useState(false)
|
||||
|
||||
@@ -97,15 +97,8 @@ function DetailedSummarySection({
|
||||
const fetchSummary = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/summary/projects/${projectId}?video_id=${videoId}`, {
|
||||
headers: { "ngrok-skip-browser-warning": "true" }
|
||||
})
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
setSummaryData(data)
|
||||
} else {
|
||||
console.error(`Failed to fetch summary: ${response.status}`)
|
||||
}
|
||||
const data = await projectService.getProjectSummaryByVideo(projectId, videoId);
|
||||
setSummaryData(data)
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch summary:", err)
|
||||
} finally {
|
||||
@@ -124,14 +117,14 @@ function DetailedSummarySection({
|
||||
// Flatten all detections for the scrollable list
|
||||
const allDetections: Array<{
|
||||
detection: any
|
||||
locationName: string
|
||||
chainageName: string
|
||||
packageName: string
|
||||
}> = []
|
||||
|
||||
Object.entries(summaryData.packages || {}).forEach(([packageName, packageData]) => {
|
||||
Object.entries(packageData?.locations || {}).forEach(([locationName, locationData]) => {
|
||||
locationData?.detections?.forEach(detection => {
|
||||
allDetections.push({ detection, locationName, packageName })
|
||||
Object.entries(packageData?.chainages || {}).forEach(([chainageName, chainageData]) => {
|
||||
chainageData?.detections?.forEach(detection => {
|
||||
allDetections.push({ detection, chainageName, packageName })
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -147,7 +140,7 @@ function DetailedSummarySection({
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle className="text-base font-bold">
|
||||
Locations
|
||||
Chainages
|
||||
</CardTitle>
|
||||
<CardDescription className="text-xs">
|
||||
{isCombined ? "Potholes & Signboards" : isPothole ? "Potholes" : "Signboards"} detected
|
||||
@@ -186,16 +179,16 @@ function DetailedSummarySection({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Packages and Locations */}
|
||||
{/* Packages and Chainages */}
|
||||
{Object.entries(summaryData.packages).map(([packageName, packageData]) => (
|
||||
<div key={packageData.package_id} className="space-y-2">
|
||||
<div className="text-xs font-bold text-muted-foreground truncate">{packageName}</div>
|
||||
<div className="pl-2 space-y-2 border-l-2 border-muted">
|
||||
{Object.entries(packageData.locations).map(([locationName, locationData]) => (
|
||||
<div key={locationData.location_id} className="text-xs p-3 rounded-md bg-muted/50 flex items-center justify-between gap-4">
|
||||
<div className="font-semibold truncate">{locationName}</div>
|
||||
{Object.entries(packageData.chainages).map(([chainageName, chainageData]) => (
|
||||
<div key={chainageData.chainage_id} className="text-xs p-3 rounded-md bg-muted/50 flex items-center justify-between gap-4">
|
||||
<div className="font-semibold truncate">{chainageName}</div>
|
||||
<div className="text-[10px] bg-background px-2 py-0.5 rounded border font-bold">
|
||||
{locationData.detection_count}
|
||||
{chainageData.detection_count}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -226,7 +219,7 @@ function DetailedSummarySection({
|
||||
<CardContent className="flex-1 p-0 overflow-hidden">
|
||||
<ScrollArea className="h-[300px] p-4">
|
||||
<div className="space-y-2">
|
||||
{allDetections.map(({ detection, locationName }, idx) => (
|
||||
{allDetections.map(({ detection, chainageName }, idx) => (
|
||||
<div
|
||||
key={`${detection.id}-${idx}`}
|
||||
className="text-xs p-3 bg-muted/30 border rounded-md hover:bg-muted/50 transition-colors"
|
||||
@@ -240,7 +233,7 @@ function DetailedSummarySection({
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-2 text-[10px] text-muted-foreground">
|
||||
<div className="truncate">Location: <span className="text-foreground font-medium">{locationName}</span></div>
|
||||
<div className="truncate">Chainage: <span className="text-foreground font-medium">{chainageName}</span></div>
|
||||
<div>Confidence: <span className="text-foreground font-medium">{(detection.confidence * 100).toFixed(1)}%</span></div>
|
||||
<div className="col-span-2 font-mono bg-muted/50 p-1 rounded border">
|
||||
GPS: {detection.latitude}, {detection.longitude}
|
||||
@@ -512,7 +505,7 @@ export default function VideoPlayerSection({ data, videoId, videoFile, detection
|
||||
useEffect(() => {
|
||||
const video = videoRef.current
|
||||
if (!video) return
|
||||
const videoUrl = videoFile ? URL.createObjectURL(videoFile) : (videoId ? `${API_URL}/video/${videoId}` : '')
|
||||
const videoUrl = videoFile ? URL.createObjectURL(videoFile) : (videoId ? `${process.env.NEXT_PUBLIC_API_URL}/video/${videoId}` : '')
|
||||
if (videoUrl) {
|
||||
video.src = videoUrl
|
||||
video.onloadeddata = resizeCanvas
|
||||
|
||||
Reference in New Issue
Block a user