From 3891500cf20111617791a09ce4b9a0495e2a0811 Mon Sep 17 00:00:00 2001 From: "santasri.pachhal" Date: Wed, 22 Jul 2026 19:12:52 +0530 Subject: [PATCH] feat(upload): open upload details dialog from table rows --- .../upload/components/UploadActionsMenu.tsx | 85 ----------- .../upload/components/UploadDetailsDialog.tsx | 143 ++++++++++++++++++ .../upload/components/UploadListColumns.tsx | 24 +-- .../upload/components/UploadTable.tsx | 3 + .../upload/components/VideoPreviewDialog.tsx | 41 ----- src/app/(modules)/upload/page.tsx | 17 ++- 6 files changed, 158 insertions(+), 155 deletions(-) delete mode 100644 src/app/(modules)/upload/components/UploadActionsMenu.tsx create mode 100644 src/app/(modules)/upload/components/UploadDetailsDialog.tsx delete mode 100644 src/app/(modules)/upload/components/VideoPreviewDialog.tsx diff --git a/src/app/(modules)/upload/components/UploadActionsMenu.tsx b/src/app/(modules)/upload/components/UploadActionsMenu.tsx deleted file mode 100644 index 7e721c3..0000000 --- a/src/app/(modules)/upload/components/UploadActionsMenu.tsx +++ /dev/null @@ -1,85 +0,0 @@ -'use client'; - -import { useRouter } from 'next/navigation'; -import { - Download, - Eye, - MoreVertical, - PlayCircle, - RotateCcw, - Ticket, - Trash2, -} from 'lucide-react'; - -import { Button } from '@/components/ui/button'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import type { UploadListItem } from '@/types'; - -interface UploadActionsMenuProps { - upload: UploadListItem; - onViewVideo: (upload: UploadListItem) => void; -} - -export function UploadActionsMenu({ - upload, - onViewVideo, -}: UploadActionsMenuProps) { - const router = useRouter(); - - return ( - - - - - - {upload.raw_video_url ? ( - { - event.stopPropagation(); - onViewVideo(upload); - }} - > - - View Video - - ) : null} - - View Details - - - Retry Analysis - - { - event.stopPropagation(); - if (upload.ticket_id) { - router.push(`/ticket/${upload.ticket_id}`); - } - }} - > - Open Ticket - - - - Delete - - - - ); -} diff --git a/src/app/(modules)/upload/components/UploadDetailsDialog.tsx b/src/app/(modules)/upload/components/UploadDetailsDialog.tsx new file mode 100644 index 0000000..9d695c8 --- /dev/null +++ b/src/app/(modules)/upload/components/UploadDetailsDialog.tsx @@ -0,0 +1,143 @@ +'use client'; + +import Link from 'next/link'; +import { ExternalLink, Ticket, UserRound } from 'lucide-react'; + +import { ProtectedVideoPlayer } from '@/components/media/ProtectedVideoPlayer'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { PERMISSIONS } from '@/constants/permissions'; +import { usePermissions } from '@/hooks/usePermissions'; +import { ROUTES } from '@/utils/routes'; +import type { UploadListItem } from '@/types'; +import { formatDate } from '@/utils/date'; + +import { UploadResultCell } from './UploadResultCell'; +import { UploadStatusBadge } from './UploadStatusBadge'; + +interface UploadDetailsDialogProps { + upload: UploadListItem | null; + open: boolean; + onOpenChange: (open: boolean) => void; +} + +export function UploadDetailsDialog({ + upload, + open, + onOpenChange, +}: UploadDetailsDialogProps) { + const { hasPermission } = usePermissions(); + const canOpenTicket = hasPermission(PERMISSIONS.TICKET.READ); + const details = [ + { label: 'Project', value: upload?.project }, + { label: 'Package', value: upload?.package }, + { label: 'Segment', value: upload?.segment }, + { label: 'Chainage', value: upload?.chainage }, + { label: 'Uploaded', value: formatDate(upload?.uploaded_at) }, + ]; + + return ( + + + + Upload Details + + Preview the inspection video and review its processing details. + + + + +
+
+

Video Preview

+ +
+ + +
+
+ + + {upload?.ticket_id && canOpenTicket ? ( + + ) : null} + +
+
+ ); +} diff --git a/src/app/(modules)/upload/components/UploadListColumns.tsx b/src/app/(modules)/upload/components/UploadListColumns.tsx index 8750745..a5371c2 100644 --- a/src/app/(modules)/upload/components/UploadListColumns.tsx +++ b/src/app/(modules)/upload/components/UploadListColumns.tsx @@ -9,7 +9,6 @@ import { Badge } from '@/components/ui/badge'; import type { UploadListItem } from '@/types'; import { formatDate } from '@/utils/date'; -import { UploadActionsMenu } from './UploadActionsMenu'; import { UploadResultCell } from './UploadResultCell'; import { UploadStatusBadge } from './UploadStatusBadge'; @@ -22,9 +21,7 @@ function resolveThumbnailUrl(value: string | null) { return baseUrl ? `${baseUrl}${path}` : path; } -export function useUploadListColumns( - onViewVideo: (upload: UploadListItem) => void, -): ColumnDef[] { +export function useUploadListColumns(): ColumnDef[] { return useMemo( () => [ { @@ -133,24 +130,7 @@ export function useUploadListColumns( meta: { disableTruncate: true }, cell: ({ row }) => , }, - { - id: 'actions', - header: () => Actions, - size: 64, - minSize: 64, - enableSorting: false, - enableHiding: false, - meta: { disableTruncate: true }, - cell: ({ row }) => ( -
- -
- ), - }, ], - [onViewVideo], + [], ); } diff --git a/src/app/(modules)/upload/components/UploadTable.tsx b/src/app/(modules)/upload/components/UploadTable.tsx index 524a62e..428b169 100644 --- a/src/app/(modules)/upload/components/UploadTable.tsx +++ b/src/app/(modules)/upload/components/UploadTable.tsx @@ -12,6 +12,7 @@ interface UploadTableProps { skip: number; limit: number; total: number; + onUploadClick: (upload: UploadListItem) => void; onPageChange: (skip: number) => void; onLimitChange: (limit: number) => void; } @@ -23,6 +24,7 @@ export function UploadTable({ skip, limit, total, + onUploadClick, onPageChange, onLimitChange, }: UploadTableProps) { @@ -33,6 +35,7 @@ export function UploadTable({ isLoading={isLoading} emptyTitle="No uploads found" emptyDescription="Upload your first road inspection video." + onRowClick={onUploadClick} pagination={{ skip, limit, diff --git a/src/app/(modules)/upload/components/VideoPreviewDialog.tsx b/src/app/(modules)/upload/components/VideoPreviewDialog.tsx deleted file mode 100644 index 496fbac..0000000 --- a/src/app/(modules)/upload/components/VideoPreviewDialog.tsx +++ /dev/null @@ -1,41 +0,0 @@ -'use client'; - -import { ProtectedVideoPlayer } from '@/components/media/ProtectedVideoPlayer'; -import { - Dialog, - DialogBody, - DialogContent, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog'; -import type { UploadListItem } from '@/types'; - -interface VideoPreviewDialogProps { - upload: UploadListItem | null; - open: boolean; - onOpenChange: (open: boolean) => void; -} - -export function VideoPreviewDialog({ - upload, - open, - onOpenChange, -}: VideoPreviewDialogProps) { - return ( - - - - Video Preview - - - - - - - - ); -} diff --git a/src/app/(modules)/upload/page.tsx b/src/app/(modules)/upload/page.tsx index d06b9ba..ce4ac57 100644 --- a/src/app/(modules)/upload/page.tsx +++ b/src/app/(modules)/upload/page.tsx @@ -10,7 +10,7 @@ import type { UploadListItem } from '@/types'; import { CreateUploadDialog } from './components/CreateUploadDialog'; import { useUploadListColumns } from './components/UploadListColumns'; import { UploadTable } from './components/UploadTable'; -import { VideoPreviewDialog } from './components/VideoPreviewDialog'; +import { UploadDetailsDialog } from './components/UploadDetailsDialog'; import { useUploadFilters } from './hooks/useUploadFilters'; import { useUploadListEvents } from './hooks/useUploadListEvents'; import { useUploadsQuery } from './hooks/useUploadQueries'; @@ -20,13 +20,15 @@ export default function UploadPage() { const uploadsQuery = useUploadsQuery({ skip, limit }); useUploadListEvents(); const [isCreateOpen, setIsCreateOpen] = useState(false); - const [videoUpload, setVideoUpload] = useState(null); + const [selectedUpload, setSelectedUpload] = useState( + null, + ); const uploads = uploadsQuery.data?.items ?? []; const total = uploadsQuery.data?.total ?? 0; const isLoading = uploadsQuery.isLoading; - const columns = useUploadListColumns(setVideoUpload); + const columns = useUploadListColumns(); return ( <> @@ -50,17 +52,18 @@ export default function UploadPage() { skip={skip} limit={limit} total={total} + onUploadClick={setSelectedUpload} onPageChange={setSkip} onLimitChange={setLimit} /> - { - if (!open) setVideoUpload(null); + if (!open) setSelectedUpload(null); }} />