diff --git a/apps/web/src/app/(dashboard)/dashboard/page.tsx b/apps/web/src/app/(dashboard)/dashboard/page.tsx
index 30ee90ed9..a59daef00 100644
--- a/apps/web/src/app/(dashboard)/dashboard/page.tsx
+++ b/apps/web/src/app/(dashboard)/dashboard/page.tsx
@@ -5,6 +5,7 @@ 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 { Recipient } from '@documenso/prisma/client';
import {
Table,
TableBody,
@@ -14,12 +15,51 @@ import {
TableRow,
} from '@documenso/ui/primitives/table';
+import { StackAvatar } from '~/components/(dashboard)/avatar';
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 renderStackAvatars = (recipients: Recipient[]) => {
+ const zIndex = 50;
+ const itemsToRender = recipients.slice(0, 5);
+ const remainingItems = recipients.length - itemsToRender.length;
+
+ return itemsToRender.map((recipient: Recipient, index: number) => {
+ const first = index === 0 ? true : false;
+ const initials =
+ recipient.name
+ ?.split(' ')
+ .map((name: string) => name.slice(0, 1).toUpperCase())
+ .slice(0, 2)
+ .join('') ?? 'UK';
+
+ const lastItemText =
+ index === itemsToRender.length - 1 && remainingItems > 0
+ ? `+${remainingItems + 1}`
+ : undefined;
+
+ const type =
+ recipient.sendStatus === 'SENT' && recipient.signingStatus === 'SIGNED'
+ ? 'completed'
+ : recipient.sendStatus === 'SENT' && recipient.signingStatus === 'NOT_SIGNED'
+ ? 'waiting'
+ : 'unsigned';
+
+ return (
+
+ );
+ });
+};
+
export default async function DashboardPage() {
const session = await getRequiredServerComponentSession();
@@ -60,6 +100,7 @@ export default async function DashboardPage() {
ID
Title
+ Reciepient
Status
Created
@@ -76,6 +117,11 @@ export default async function DashboardPage() {
{document.title}
+
+
+ {renderStackAvatars(document.Recipient)}
+
+
diff --git a/apps/web/src/components/(dashboard)/avatar/index.tsx b/apps/web/src/components/(dashboard)/avatar/index.tsx
new file mode 100644
index 000000000..a784cbbff
--- /dev/null
+++ b/apps/web/src/components/(dashboard)/avatar/index.tsx
@@ -0,0 +1,36 @@
+import { Avatar, AvatarFallback } from '@documenso/ui/primitives/avatar';
+
+export type StackAvatarProps = {
+ first?: boolean;
+ zIndex?: string;
+ fallbackText?: string;
+ type: 'unsigned' | 'waiting' | 'completed';
+};
+
+export const StackAvatar = ({ first, zIndex, fallbackText, type }: StackAvatarProps) => {
+ let classes = '';
+ switch (type) {
+ case 'unsigned':
+ classes = 'bg-dawn-400 text-dawn-900';
+ break;
+ case 'waiting':
+ classes = 'bg-water text-water-700';
+ break;
+ case 'completed':
+ classes = 'bg-documenso-200 text-documenso-800';
+ break;
+ default:
+ break;
+ }
+
+ return (
+
+ {fallbackText ?? 'UK'}
+
+ );
+};
diff --git a/packages/lib/server-only/document/find-documents.ts b/packages/lib/server-only/document/find-documents.ts
index 627ceee8b..005b6614a 100644
--- a/packages/lib/server-only/document/find-documents.ts
+++ b/packages/lib/server-only/document/find-documents.ts
@@ -1,5 +1,5 @@
import { prisma } from '@documenso/prisma';
-import { Document, DocumentStatus, Prisma } from '@documenso/prisma/client';
+import { Document, DocumentStatus, Prisma, Recipient } from '@documenso/prisma/client';
import { FindResultSet } from '../../types/find-result-set';
@@ -15,6 +15,10 @@ export interface FindDocumentsOptions {
};
}
+export type DocumentWithReciepient = Document & {
+ Recipient: Recipient[];
+};
+
export const findDocuments = async ({
userId,
term,
@@ -22,7 +26,7 @@ export const findDocuments = async ({
page = 1,
perPage = 10,
orderBy,
-}: FindDocumentsOptions): Promise> => {
+}: FindDocumentsOptions): Promise> => {
const orderByColumn = orderBy?.column ?? 'created';
const orderByDirection = orderBy?.direction ?? 'desc';
@@ -48,6 +52,9 @@ export const findDocuments = async ({
orderBy: {
[orderByColumn]: orderByDirection,
},
+ include: {
+ Recipient: true,
+ },
}),
prisma.document.count({
where: {
diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma
index c22c42bf7..65e4e8b63 100644
--- a/packages/prisma/schema.prisma
+++ b/packages/prisma/schema.prisma
@@ -1,6 +1,6 @@
generator client {
- provider = "prisma-client-js"
- previewFeatures = ["extendedWhereUnique", "jsonProtocol"]
+ provider = "prisma-client-js"
+ previewFeatures = ["extendedWhereUnique"]
}
datasource db {
@@ -144,10 +144,10 @@ model Field {
recipientId Int?
type FieldType
page Int
- positionX Decimal @default(0)
- positionY Decimal @default(0)
- width Decimal @default(-1)
- height Decimal @default(-1)
+ positionX Decimal @default(0)
+ positionY Decimal @default(0)
+ width Decimal @default(-1)
+ height Decimal @default(-1)
customText String
inserted Boolean
Document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
diff --git a/packages/tailwind-config/index.cjs b/packages/tailwind-config/index.cjs
index 3f414588d..d841e2711 100644
--- a/packages/tailwind-config/index.cjs
+++ b/packages/tailwind-config/index.cjs
@@ -76,6 +76,20 @@ module.exports = {
900: '#52514a',
950: '#2a2925',
},
+ water: {
+ DEFAULT: '#d7e4f3',
+ 50: '#f3f6fb',
+ 100: '#e3ebf6',
+ 200: '#d7e4f3',
+ 300: '#abc7e5',
+ 400: '#82abd8',
+ 500: '#658ecc',
+ 600: '#5175bf',
+ 700: '#4764ae',
+ 800: '#3e538f',
+ 900: '#364772',
+ 950: '#252d46',
+ },
},
backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',