Add files table and refactor sub-page components

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.
This commit is contained in:
Mathis H (Avnyr) 2024-10-21 14:51:49 +02:00
parent 2d6815efb6
commit 13c77bfc32
Signed by: Mathis
GPG Key ID: DD9E0666A747D126
8 changed files with 301 additions and 55 deletions

View File

@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.

View File

@ -15,7 +15,7 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body className={"h-screen w-screen bg-card flex flex-col justify-between items-center police-ubuntu dark"}>
<body className={"h-screen w-screen bg-card flex flex-col justify-between items-center police-ubuntu"}>
<Header/>
{children}
<Footer/>

View File

@ -1,21 +1,11 @@
"use client"
import { Dispatch, SetStateAction, useState } from 'react';
import { Button } from '../components/ui/button';
import { Home, NotepadTextDashed } from 'lucide-react';
import { NewFileModal } from 'apps/frontend/src/components/new-file-modal';
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup
} from 'apps/frontend/src/components/ui/resizable';
import {
SubHomePage
} from 'apps/frontend/src/components/sub-pages/sub-home-page';
export enum ESubPage {
Home,
Documentation,
}
import { ESubPage, SubPage, SubPageSelector } from '../components/sub-pages';
export default function HomePage() {
const [currentSubPage, setCurrentSubPage] = useState<ESubPage>(0)
@ -43,43 +33,4 @@ export default function HomePage() {
);
}
interface SubPageSelectorProps {
currentSubPage: ESubPage
setCurrentSubPage: Dispatch<SetStateAction<ESubPage>>
}
function SubPageSelector(props: SubPageSelectorProps) {
return (
<div className={"w-full flex flex-col justify-center items-stretch pt-4 p-4 gap-2"}>
<Button
onClick={()=>props.setCurrentSubPage(ESubPage.Home)}
disabled={props.currentSubPage === ESubPage.Home}
className={"gap-1 font-bold"}>
<Home/>
Accueil
</Button>
<NewFileModal/>
<Button
onClick={()=>props.setCurrentSubPage(ESubPage.Documentation)}
disabled={props.currentSubPage === ESubPage.Documentation}>
<NotepadTextDashed />
Documentation
</Button>
</div>
)
}
export interface ISubPageProps {
currentSubPage: ESubPage
}
function SubPage(props: ISubPageProps) {
switch (props.currentSubPage) {
case ESubPage.Home:
return (<SubHomePage/>)
case ESubPage.Documentation:
return (<>Doc</>)
default:
return (<>Default</>)
}
}

View File

@ -23,7 +23,7 @@ export function NewFileModal(props: NewFileModalProps) {
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogTitle>Ajout d'un fichier</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.

View File

@ -0,0 +1,56 @@
import { NewFileModal } from "../new-file-modal";
import { Button } from "../ui/button"
import { Home, NotepadTextDashed } from 'lucide-react';
import {
SubHomePage
} from './sub-home-page';
import { Dispatch, SetStateAction } from 'react';
import {
SubDocPage
} from 'apps/frontend/src/components/sub-pages/sub-doc-page';
export interface SubPageSelectorProps {
currentSubPage: ESubPage
setCurrentSubPage: Dispatch<SetStateAction<ESubPage>>
}
export enum ESubPage {
Home,
Documentation,
}
export function SubPageSelector(props: SubPageSelectorProps) {
return (
<div className={"w-full flex flex-col justify-center items-stretch pt-4 p-4 gap-2"}>
<Button
onClick={()=>props.setCurrentSubPage(ESubPage.Home)}
disabled={props.currentSubPage === ESubPage.Home}
className={"gap-1 font-bold"}>
<Home/>
Accueil
</Button>
<NewFileModal/>
<Button
onClick={()=>props.setCurrentSubPage(ESubPage.Documentation)}
disabled={props.currentSubPage === ESubPage.Documentation}>
<NotepadTextDashed />
Documentation
</Button>
</div>
)
}
export interface ISubPageProps {
currentSubPage: ESubPage
}
export function SubPage(props: ISubPageProps) {
switch (props.currentSubPage) {
case ESubPage.Home:
return (<SubHomePage/>)
case ESubPage.Documentation:
return (<SubDocPage/>)
default:
return (<>Default</>)
}
}

View File

@ -0,0 +1,14 @@
import { useState } from 'react';
export interface SubHomePageProps {
}
export function SubDocPage(props: SubHomePageProps) {
const [isLoaded, setIsLoaded] = useState<boolean>(false);
return (<section className={"w-full h-full rounded bg-card flex flex-col"}>
<h1 className={"text-2xl m-2 font-bold"}>Documentations</h1>
</section>)
}

View File

@ -1,4 +1,8 @@
import { useState } from 'react';
import { HomeIcon } from 'lucide-react';
import {
FilesDataTable, filesTableColumns
} from 'apps/frontend/src/components/tables/files-table';
export interface SubHomePageProps {
@ -8,7 +12,27 @@ export interface SubHomePageProps {
export function SubHomePage(props: SubHomePageProps) {
const [isLoaded, setIsLoaded] = useState<boolean>(false);
return (<section className={"w-full h-full rounded bg-card"}>
return (<section className={"w-full h-full rounded bg-card flex flex-col"}>
<div className={"flex flex-row justify-start items-center gap-2 m-2"}>
<HomeIcon
className={"w-8 h-8 text-secondary"}
/>
<h1 className={"text-2xl font-bold"}>Page principal</h1>
</div>
<div className={"m-1 flex flex-col justify-start items-center w-5/6 self-center h-full"}>
<FilesDataTable columns={filesTableColumns} data={[{
"uuid": "bbc17f8c-244d-4a44-8faf-c5e1ec0786bf",
"fileName": "test",
"checksum": "60d6473dc75edd2e885cc32c098f0379a5dd2d8175de0df1ef7526636b2a03f5",
"extension": "jpeg",
"groupId": null,
"fileSize": 483636,
"fileType": "2c1fb8eb-59b1-4bef-b50d-6bc854f46105",
"isRestricted": false,
"isDocumentation": false,
"uploadedAt": "2024-10-21T11:40:36.350Z",
"uploadedBy": "Avnyr"
}]}/>
</div>
</section>)
}

View File

@ -0,0 +1,201 @@
"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>
)
}