Introduced a files table component for managing file data in the UI. Refactored sub-page components into a separate module for better code organization and maintainability. Adjusted text and links for consistency with language and configuration standards.
202 lines
5.3 KiB
TypeScript
202 lines
5.3 KiB
TypeScript
"use client"
|
|
|
|
import {
|
|
ColumnDef,
|
|
flexRender,
|
|
getCoreRowModel, getPaginationRowModel, getSortedRowModel, SortingState,
|
|
useReactTable
|
|
} from '@tanstack/react-table';
|
|
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "../ui/table"
|
|
import { Button } from '../ui/button';
|
|
import { Badge } from '../ui/badge'
|
|
import { ArrowUpDown, Clock, Download, Trash } from 'lucide-react';
|
|
import { useState } from 'react';
|
|
import Link from 'next/link';
|
|
|
|
// This type is used to define the shape of our data.
|
|
// You can use a Zod schema here if you want.
|
|
export type IFile = {
|
|
uuid: string;
|
|
fileName: string;
|
|
checksum: string;
|
|
extension: string;
|
|
groupId: string | null;
|
|
fileSize: number;
|
|
fileType: string;
|
|
isRestricted: boolean;
|
|
isDocumentation: boolean;
|
|
uploadedAt: string;
|
|
uploadedBy: string;
|
|
}
|
|
|
|
function ContextButtonForFile() {
|
|
return (<div className={"scale-75"}>
|
|
<Button variant={"destructive"}><Trash/></Button>
|
|
</div>)
|
|
}
|
|
|
|
export const filesTableColumns: ColumnDef<IFile>[] = [
|
|
{
|
|
accessorKey: "fileName",
|
|
header: ({ column }) => {
|
|
return (<div className={"flex justify-center items-center"}>
|
|
Nom du fichier
|
|
</div>)
|
|
},
|
|
},
|
|
{
|
|
accessorKey: "uploadedBy",
|
|
header: ({ column }) => {
|
|
return (<div className={"flex justify-center items-center"}>
|
|
Autheur(s)
|
|
</div>)
|
|
},
|
|
},
|
|
{
|
|
accessorKey: "uploadedAt",
|
|
header: ({ column }) => {
|
|
return (
|
|
<Button
|
|
variant="ghost"
|
|
className={"flex w-full"}
|
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
|
>
|
|
Ajouté le
|
|
<ArrowUpDown className="ml-2 h-4 w-4" />
|
|
</Button>
|
|
)
|
|
},
|
|
cell: ({ row }) => {
|
|
const date = new Date(row.getValue("uploadedAt"))
|
|
const formatted = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()} à ${date.getHours()}:${date.getMinutes()}`
|
|
|
|
return (<div className={"flex justify-center items-center"}>
|
|
<Badge
|
|
variant="outline"
|
|
className={"gap-1 flex w-fit items-center"}>
|
|
<Clock className={"w-4 h-4"} />
|
|
<p className={"font-light"}>
|
|
{formatted}
|
|
</p>
|
|
</Badge>
|
|
</div>)
|
|
},
|
|
},
|
|
{
|
|
accessorKey: "extension",
|
|
header: ({ column }) => {
|
|
return (<div className={"flex justify-center items-center"}>
|
|
Extension du fichier
|
|
</div>)
|
|
},
|
|
cell: ({ row }) => {
|
|
const extension = row.getValue("extension") as string;
|
|
|
|
return (<div className={"flex justify-center items-center"}>
|
|
<code className={"bg-gray-300 p-1 px-2 rounded-full"}>{extension}</code>
|
|
</div>)
|
|
},
|
|
},
|
|
{
|
|
id: "actions",
|
|
header: ({ column }) => {
|
|
return (<div className={"flex justify-center items-center"}>
|
|
Actions
|
|
</div>)
|
|
},
|
|
cell: ({ row }) => {
|
|
const file = row.original
|
|
|
|
return (<div className={"flex gap"}>
|
|
<Button variant={"ghost"} asChild>
|
|
<Link
|
|
href={`http://localhost:3333/api/files/${file.uuid}`}
|
|
>
|
|
<Download />
|
|
Télécharger
|
|
</Link>
|
|
</Button>
|
|
<ContextButtonForFile/>
|
|
</div>)
|
|
},
|
|
},
|
|
]
|
|
|
|
interface DataTableProps<TData, TValue> {
|
|
columns: ColumnDef<TData, TValue>[]
|
|
data: TData[]
|
|
}
|
|
|
|
export function FilesDataTable<TData, TValue>({
|
|
columns,
|
|
data,
|
|
}: DataTableProps<TData, TValue>) {
|
|
const [sorting, setSorting] = useState<SortingState>([])
|
|
const table = useReactTable({
|
|
data,
|
|
columns,
|
|
getCoreRowModel: getCoreRowModel(),
|
|
getPaginationRowModel: getPaginationRowModel(),
|
|
onSortingChange: setSorting,
|
|
getSortedRowModel: getSortedRowModel(),
|
|
state: {
|
|
sorting,
|
|
},
|
|
})
|
|
|
|
return (
|
|
<div className="rounded-md border w-full">
|
|
<Table>
|
|
<TableHeader>
|
|
{table.getHeaderGroups().map((headerGroup) => (
|
|
<TableRow key={headerGroup.id}>
|
|
{headerGroup.headers.map((header) => {
|
|
return (
|
|
<TableHead key={header.id}>
|
|
{header.isPlaceholder
|
|
? null
|
|
: flexRender(
|
|
header.column.columnDef.header,
|
|
header.getContext()
|
|
)}
|
|
</TableHead>
|
|
)
|
|
})}
|
|
</TableRow>
|
|
))}
|
|
</TableHeader>
|
|
<TableBody>
|
|
{table.getRowModel().rows?.length ? (
|
|
table.getRowModel().rows.map((row) => (
|
|
<TableRow
|
|
key={row.id}
|
|
data-state={row.getIsSelected() && "selected"}
|
|
>
|
|
{row.getVisibleCells().map((cell) => (
|
|
<TableCell key={cell.id}>
|
|
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
</TableCell>
|
|
))}
|
|
</TableRow>
|
|
))
|
|
) : (
|
|
<TableRow>
|
|
<TableCell colSpan={columns.length} className="h-24 text-center">
|
|
Auccun résultat
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
)
|
|
}
|