refactor(upload): replace upload card views with list table and addition details in table
This commit is contained in:
153
src/app/(modules)/upload/components/UploadListColumns.tsx
Normal file
153
src/app/(modules)/upload/components/UploadListColumns.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
'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 type { UploadListItem } from '@/types';
|
||||
import { formatDate } from '@/utils/date';
|
||||
|
||||
import { UploadActionsMenu } from './UploadActionsMenu';
|
||||
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(
|
||||
onViewVideo: (upload: UploadListItem) => void,
|
||||
): 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-md border bg-muted bg-cover bg-center"
|
||||
style={
|
||||
thumbnail
|
||||
? { backgroundImage: `url("${thumbnail}")` }
|
||||
: undefined
|
||||
}
|
||||
role={thumbnail ? 'img' : undefined}
|
||||
aria-label={
|
||||
thumbnail
|
||||
? `Thumbnail for ${row.original.video_name}`
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{!thumbnail ? (
|
||||
<Video className="size-5 text-muted-foreground" />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'video_name',
|
||||
header: 'Video Name',
|
||||
size: 150,
|
||||
cell: ({ row }) => (
|
||||
<span className="font-medium">{row.original.video_name}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
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),
|
||||
},
|
||||
{
|
||||
id: 'status',
|
||||
header: '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} />,
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
header: () => <span className="sr-only">Actions</span>,
|
||||
size: 64,
|
||||
minSize: 64,
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
meta: { disableTruncate: true },
|
||||
cell: ({ row }) => (
|
||||
<div className="flex justify-center">
|
||||
<UploadActionsMenu
|
||||
upload={row.original}
|
||||
onViewVideo={onViewVideo}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
],
|
||||
[onViewVideo],
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user