'use client'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { X } from 'lucide-react'; import { MultiSelectPopover } from '@/components/form/MultiSelectPopover'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { useDetectionCoordinatesQuery, useTicketDetectionsQuery, } from '../../../hooks/useTicketQueries'; import { formatCompactRangeCoordinate, formatRangeCoordinate, type AssignmentRangePoint, } from './assignmentRange'; import { AssignmentIssuesMap } from './AssignmentIssuesMap'; import { useIssueColumns } from './IssueColumns'; import { IssueTable } from './IssueTable'; const DEFAULT_PAGE_SIZE = 10; const MAP_PAGE_SIZE = 50; interface IssueTypeOption { class_name: string; display_name: string; count: number; } interface ChooseIssuesSectionProps { videoId?: string; issueTypes: IssueTypeOption[]; selectedIssueTypes: string[]; startPoint: AssignmentRangePoint | null; endPoint: AssignmentRangePoint | null; onSelectedIssueTypesChange: (values: string[]) => void; onStartPointChange: (point: AssignmentRangePoint | null) => void; onEndPointChange: (point: AssignmentRangePoint | null) => void; } export function ChooseIssuesSection({ videoId, issueTypes, selectedIssueTypes, startPoint, endPoint, onSelectedIssueTypesChange, onStartPointChange, onEndPointChange, }: ChooseIssuesSectionProps) { const [skip, setSkip] = useState(0); const [limit, setLimit] = useState(DEFAULT_PAGE_SIZE); const handleSetStart = useCallback( (point: AssignmentRangePoint) => { onStartPointChange(point); onEndPointChange(null); }, [onEndPointChange, onStartPointChange], ); const handleSetEnd = useCallback( (point: AssignmentRangePoint) => { if (point.detectionId === startPoint?.detectionId) return; onEndPointChange(point); }, [onEndPointChange, startPoint?.detectionId], ); const columns = useIssueColumns({ startPoint, endPoint, onSetStart: handleSetStart, onSetEnd: handleSetEnd, }); const issueTypeOptions = useMemo( () => issueTypes.map((issue) => ({ value: issue.class_name, label: issue.display_name, })), [issueTypes], ); const handleIssueTypesChange = useCallback( (values: string[]) => { onSelectedIssueTypesChange(values); onStartPointChange(null); onEndPointChange(null); }, [onEndPointChange, onSelectedIssueTypesChange, onStartPointChange], ); useEffect(() => { setSkip(0); }, [selectedIssueTypes]); const queryParams = useMemo( () => ({ skip, limit, class_name: selectedIssueTypes.length > 0 ? selectedIssueTypes : undefined, sort: 'timestamp_asc', }), [limit, selectedIssueTypes, skip], ); const detectionsQuery = useTicketDetectionsQuery(videoId, queryParams); const mapQueryParams = useMemo( () => ({ limit: MAP_PAGE_SIZE, class_name: selectedIssueTypes.length > 0 ? selectedIssueTypes : undefined, assignment_status: 'unassigned' as const, }), [selectedIssueTypes], ); const coordinatesQuery = useDetectionCoordinatesQuery( videoId, mapQueryParams, ); const result = detectionsQuery.data; const mapData = useMemo(() => { const pages = coordinatesQuery.data?.pages; if (!pages?.length) return undefined; const latestPage = pages[pages.length - 1]; return { ...latestPage, items: pages.flatMap((page) => page.items), truncated: Boolean(coordinatesQuery.hasNextPage), }; }, [coordinatesQuery.data?.pages, coordinatesQuery.hasNextPage]); return (