mirror of
https://github.com/documenso/documenso.git
synced 2025-11-17 10:11:35 +10:00
feat: update document table layout (#371)
* feat: update document table layout - Removed dashboard page - Removed redundant ID column - Moved date to first column - Added estimated locales for SSR dates
This commit is contained in:
@ -1,124 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
import { Clock, File, FileCheck } from 'lucide-react';
|
||||
|
||||
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-session';
|
||||
import { findDocuments } from '@documenso/lib/server-only/document/find-documents';
|
||||
import { getStats } from '@documenso/lib/server-only/document/get-stats';
|
||||
import { DocumentStatus as InternalDocumentStatus } from '@documenso/prisma/client';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@documenso/ui/primitives/table';
|
||||
|
||||
import { StackAvatarsWithTooltip } from '~/components/(dashboard)/avatar/stack-avatars-with-tooltip';
|
||||
import { CardMetric } from '~/components/(dashboard)/metric-card/metric-card';
|
||||
import { DocumentStatus } from '~/components/formatter/document-status';
|
||||
import { LocaleDate } from '~/components/formatter/locale-date';
|
||||
|
||||
import { UploadDocument } from './upload-document';
|
||||
|
||||
const CARD_DATA = [
|
||||
{
|
||||
icon: FileCheck,
|
||||
title: 'Completed',
|
||||
status: InternalDocumentStatus.COMPLETED,
|
||||
},
|
||||
{
|
||||
icon: File,
|
||||
title: 'Drafts',
|
||||
status: InternalDocumentStatus.DRAFT,
|
||||
},
|
||||
{
|
||||
icon: Clock,
|
||||
title: 'Pending',
|
||||
status: InternalDocumentStatus.PENDING,
|
||||
},
|
||||
];
|
||||
|
||||
export default async function DashboardPage() {
|
||||
const user = await getRequiredServerComponentSession();
|
||||
|
||||
const [stats, results] = await Promise.all([
|
||||
getStats({
|
||||
user,
|
||||
}),
|
||||
findDocuments({
|
||||
userId: user.id,
|
||||
perPage: 10,
|
||||
}),
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-screen-xl px-4 md:px-8">
|
||||
<h1 className="text-4xl font-semibold">Dashboard</h1>
|
||||
|
||||
<div className="mt-8 grid grid-cols-1 gap-4 md:grid-cols-3">
|
||||
{CARD_DATA.map((card) => (
|
||||
<Link key={card.status} href={`/documents?status=${card.status}`}>
|
||||
<CardMetric icon={card.icon} title={card.title} value={stats[card.status]} />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-12">
|
||||
<UploadDocument />
|
||||
|
||||
<h2 className="mt-8 text-2xl font-semibold">Recent Documents</h2>
|
||||
|
||||
<div className="border-border mt-8 overflow-x-auto rounded-lg border">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">ID</TableHead>
|
||||
<TableHead>Title</TableHead>
|
||||
<TableHead>Reciepient</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead className="text-right">Created</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{results.data.map((document) => {
|
||||
return (
|
||||
<TableRow key={document.id}>
|
||||
<TableCell className="font-medium">{document.id}</TableCell>
|
||||
<TableCell>
|
||||
<Link
|
||||
href={`/documents/${document.id}`}
|
||||
className="focus-visible:ring-ring ring-offset-background rounded-md font-medium hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2"
|
||||
>
|
||||
{document.title}
|
||||
</Link>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<StackAvatarsWithTooltip recipients={document.Recipient} />
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<DocumentStatus status={document.status} />
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<LocaleDate date={document.created} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
{results.data.length === 0 && (
|
||||
<TableRow>
|
||||
<TableCell colSpan={4} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -136,7 +136,7 @@ export const EditDocumentForm = ({
|
||||
duration: 5000,
|
||||
});
|
||||
|
||||
router.push('/dashboard');
|
||||
router.push('/documents');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
|
||||
@ -52,8 +52,9 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => {
|
||||
<DataTable
|
||||
columns={[
|
||||
{
|
||||
header: 'ID',
|
||||
accessorKey: 'id',
|
||||
header: 'Created',
|
||||
accessorKey: 'created',
|
||||
cell: ({ row }) => <LocaleDate date={row.getValue('created')} />,
|
||||
},
|
||||
{
|
||||
header: 'Title',
|
||||
@ -71,11 +72,6 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => {
|
||||
accessorKey: 'status',
|
||||
cell: ({ row }) => <DocumentStatus status={row.getValue('status')} />,
|
||||
},
|
||||
{
|
||||
header: 'Created',
|
||||
accessorKey: 'created',
|
||||
cell: ({ row }) => <LocaleDate date={row.getValue('created')} />,
|
||||
},
|
||||
{
|
||||
header: 'Actions',
|
||||
cell: ({ row }) => (
|
||||
@ -92,7 +88,7 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => {
|
||||
totalPages={results.totalPages}
|
||||
onPaginationChange={onPaginationChange}
|
||||
>
|
||||
{(table) => <DataTablePagination table={table} />}
|
||||
{(table) => <DataTablePagination additionalInformation="VisibleCount" table={table} />}
|
||||
</DataTable>
|
||||
|
||||
{isPending && (
|
||||
|
||||
@ -11,8 +11,8 @@ import { PeriodSelector } from '~/components/(dashboard)/period-selector/period-
|
||||
import { PeriodSelectorValue } from '~/components/(dashboard)/period-selector/types';
|
||||
import { DocumentStatus } from '~/components/formatter/document-status';
|
||||
|
||||
import { UploadDocument } from '../dashboard/upload-document';
|
||||
import { DocumentsDataTable } from './data-table';
|
||||
import { UploadDocument } from './upload-document';
|
||||
|
||||
export type DocumentsPageProps = {
|
||||
searchParams?: {
|
||||
@ -71,35 +71,15 @@ export default async function DocumentsPage({ searchParams = {} }: DocumentsPage
|
||||
<Link href={getTabHref(InternalDocumentStatus.PENDING)}>
|
||||
<DocumentStatus status={InternalDocumentStatus.PENDING} />
|
||||
|
||||
<span className="ml-1 hidden opacity-50 md:inline-block">
|
||||
{Math.min(stats.PENDING, 99)}
|
||||
</span>
|
||||
</Link>
|
||||
</TabsTrigger>
|
||||
|
||||
<TabsTrigger className="min-w-[60px]" value={InternalDocumentStatus.COMPLETED} asChild>
|
||||
<Link href={getTabHref(InternalDocumentStatus.COMPLETED)}>
|
||||
<DocumentStatus status={InternalDocumentStatus.COMPLETED} />
|
||||
|
||||
<span className="ml-1 hidden opacity-50 md:inline-block">
|
||||
{Math.min(stats.COMPLETED, 99)}
|
||||
</span>
|
||||
</Link>
|
||||
</TabsTrigger>
|
||||
|
||||
<TabsTrigger className="min-w-[60px]" value={InternalDocumentStatus.DRAFT} asChild>
|
||||
<Link href={getTabHref(InternalDocumentStatus.DRAFT)}>
|
||||
<DocumentStatus status={InternalDocumentStatus.DRAFT} />
|
||||
|
||||
<span className="ml-1 hidden opacity-50 md:inline-block">
|
||||
{Math.min(stats.DRAFT, 99)}
|
||||
</span>
|
||||
</Link>
|
||||
</TabsTrigger>
|
||||
|
||||
<TabsTrigger className="min-w-[60px]" value="ALL" asChild>
|
||||
<Link href={getTabHref('ALL')}>All</Link>
|
||||
</TabsTrigger>
|
||||
{value !== ExtendedDocumentStatus.ALL && (
|
||||
<span className="ml-1 hidden opacity-50 md:inline-block">
|
||||
{Math.min(stats[value], 99)}
|
||||
{stats[value] > 99 && '+'}
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@ import { Suspense } from 'react';
|
||||
|
||||
import { Caveat, Inter } from 'next/font/google';
|
||||
|
||||
import { LocaleProvider } from '@documenso/lib/client-only/providers/locale';
|
||||
import { getLocale } from '@documenso/lib/server-only/headers/get-locale';
|
||||
import { TrpcProvider } from '@documenso/trpc/react';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Toaster } from '@documenso/ui/primitives/toaster';
|
||||
@ -45,6 +47,8 @@ export const metadata = {
|
||||
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
const flags = await getServerComponentAllFlags();
|
||||
|
||||
const locale = getLocale();
|
||||
|
||||
return (
|
||||
<html
|
||||
lang="en"
|
||||
@ -63,16 +67,18 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
||||
</Suspense>
|
||||
|
||||
<body>
|
||||
<FeatureFlagProvider initialFlags={flags}>
|
||||
<PlausibleProvider>
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||
<TooltipProvider>
|
||||
<TrpcProvider>{children}</TrpcProvider>
|
||||
</TooltipProvider>
|
||||
</ThemeProvider>
|
||||
</PlausibleProvider>
|
||||
<Toaster />
|
||||
</FeatureFlagProvider>
|
||||
<LocaleProvider locale={locale}>
|
||||
<FeatureFlagProvider initialFlags={flags}>
|
||||
<PlausibleProvider>
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||
<TooltipProvider>
|
||||
<TrpcProvider>{children}</TrpcProvider>
|
||||
</TooltipProvider>
|
||||
</ThemeProvider>
|
||||
</PlausibleProvider>
|
||||
<Toaster />
|
||||
</FeatureFlagProvider>
|
||||
</LocaleProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user