Files
road-monitoring-ui/src/app/(modules)/upload/components/UploadListColumns.tsx

137 lines
3.8 KiB
TypeScript

'use client';
import { useMemo } from 'react';
import type { ColumnDef } from '@tanstack/react-table';
import { Video } from 'lucide-react';
import { ENV_CONSTANT } from '@/constants/secrect.constant';
import { Badge } from '@/components/ui/badge';
import type { UploadListItem } from '@/types';
import { formatDate } from '@/utils/date';
import { UploadResultCell } from './UploadResultCell';
import { UploadStatusBadge } from './UploadStatusBadge';
function resolveThumbnailUrl(value: string | null) {
if (!value) return null;
if (/^https?:\/\//i.test(value)) return value;
const baseUrl = ENV_CONSTANT.BASE_API_URL?.replace(/\/$/, '');
const path = value.startsWith('/') ? value : `/${value}`;
return baseUrl ? `${baseUrl}${path}` : path;
}
export function useUploadListColumns(): ColumnDef<UploadListItem>[] {
return useMemo(
() => [
{
id: 'thumbnail',
header: 'Thumbnail',
size: 104,
minSize: 96,
enableSorting: false,
meta: { disableTruncate: true },
cell: ({ row }) => {
const thumbnail = resolveThumbnailUrl(row.original.thumbnail);
return (
<div
className="flex aspect-video w-20 items-center justify-center overflow-hidden rounded-lg border bg-muted bg-cover bg-center"
style={
thumbnail
? { backgroundImage: `url("${thumbnail}")` }
: undefined
}
role={thumbnail ? 'img' : undefined}
aria-label={thumbnail ? 'Upload thumbnail' : undefined}
>
{!thumbnail ? (
<Video className="size-5 text-muted-foreground" />
) : null}
</div>
);
},
},
{
id: 'uploaded_by',
header: 'Uploader',
size: 190,
cell: ({ row }) => (
<div>
<p className="font-medium">
{row.original.uploaded_by.name ?? '—'}
</p>
<p className="text-xs text-muted-foreground">
{row.original.uploaded_by.email ?? '—'}
</p>
</div>
),
},
{
accessorKey: 'project',
header: 'Project',
size: 165,
cell: ({ row }) => row.original.project ?? '—',
},
{
accessorKey: 'package',
header: 'Package',
size: 110,
cell: ({ row }) => row.original.package ?? '—',
},
{
accessorKey: 'segment',
header: 'Segment',
size: 140,
cell: ({ row }) => row.original.segment ?? '—',
},
{
accessorKey: 'chainage',
header: 'Chainage',
size: 155,
cell: ({ row }) => row.original.chainage ?? '—',
},
{
accessorKey: 'uploaded_at',
header: 'Uploaded At',
size: 175,
cell: ({ row }) => formatDate(row.original.uploaded_at),
},
{
accessorKey: 'is_uploaded',
header: 'Upload Status',
size: 125,
meta: { disableTruncate: true },
cell: ({ row }) =>
row.original.is_uploaded ? (
<Badge className="bg-emerald-500/15 text-emerald-600 dark:text-emerald-400">
Uploaded
</Badge>
) : (
<span className="text-muted-foreground"></span>
),
},
{
id: 'status',
header: 'Analysis Status',
size: 145,
meta: { disableTruncate: true },
cell: ({ row }) => (
<UploadStatusBadge
status={row.original.status}
progress={row.original.progress}
/>
),
},
{
id: 'result',
header: 'Result',
size: 170,
meta: { disableTruncate: true },
cell: ({ row }) => <UploadResultCell item={row.original} />,
},
],
[],
);
}