mirror of
https://github.com/documenso/documenso.git
synced 2025-11-12 15:53:02 +10:00
feat: add inbox
This commit is contained in:
@ -0,0 +1,71 @@
|
||||
import { Button, Img, Section, Tailwind, Text } from '@react-email/components';
|
||||
|
||||
import * as config from '@documenso/tailwind-config';
|
||||
|
||||
export interface TemplateDocumentCompletedProps {
|
||||
downloadLink: string;
|
||||
reviewLink: string;
|
||||
documentName: string;
|
||||
assetBaseUrl: string;
|
||||
}
|
||||
|
||||
export const TemplateDocumentCompleted = ({
|
||||
downloadLink,
|
||||
reviewLink,
|
||||
documentName,
|
||||
assetBaseUrl,
|
||||
}: TemplateDocumentCompletedProps) => {
|
||||
const getAssetUrl = (path: string) => {
|
||||
return new URL(path, assetBaseUrl).toString();
|
||||
};
|
||||
|
||||
return (
|
||||
<Tailwind
|
||||
config={{
|
||||
theme: {
|
||||
extend: {
|
||||
colors: config.theme.extend.colors,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Section className="flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img className="h-42" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
||||
</div>
|
||||
|
||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-[#7AC455]">
|
||||
<Img src={getAssetUrl('/static/completed.png')} className="-mb-0.5 mr-2 inline h-7 w-7" />
|
||||
Completed
|
||||
</Text>
|
||||
|
||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||
“{documentName}” was signed by all signers
|
||||
</Text>
|
||||
|
||||
<Text className="my-1 text-center text-base text-slate-400">
|
||||
Continue by downloading or reviewing the document.
|
||||
</Text>
|
||||
|
||||
<Section className="mb-6 mt-8 text-center">
|
||||
<Button
|
||||
className="mr-4 inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||
href={reviewLink}
|
||||
>
|
||||
<Img src={getAssetUrl('/static/review.png')} className="-mb-1 mr-2 inline h-5 w-5" />
|
||||
Review
|
||||
</Button>
|
||||
<Button
|
||||
className="inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||
href={downloadLink}
|
||||
>
|
||||
<Img src={getAssetUrl('/static/download.png')} className="-mb-1 mr-2 inline h-5 w-5" />
|
||||
Download
|
||||
</Button>
|
||||
</Section>
|
||||
</Section>
|
||||
</Tailwind>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateDocumentCompleted;
|
||||
@ -0,0 +1,59 @@
|
||||
import { Button, Img, Section, Tailwind, Text } from '@react-email/components';
|
||||
|
||||
import * as config from '@documenso/tailwind-config';
|
||||
|
||||
export interface TemplateDocumentInviteProps {
|
||||
inviterName: string;
|
||||
inviterEmail: string;
|
||||
documentName: string;
|
||||
signDocumentLink: string;
|
||||
assetBaseUrl: string;
|
||||
}
|
||||
|
||||
export const TemplateDocumentInvite = ({
|
||||
inviterName,
|
||||
documentName,
|
||||
signDocumentLink,
|
||||
assetBaseUrl,
|
||||
}: TemplateDocumentInviteProps) => {
|
||||
const getAssetUrl = (path: string) => {
|
||||
return new URL(path, assetBaseUrl).toString();
|
||||
};
|
||||
|
||||
return (
|
||||
<Tailwind
|
||||
config={{
|
||||
theme: {
|
||||
extend: {
|
||||
colors: config.theme.extend.colors,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Section className="mt-4 flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img className="h-42" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
||||
</div>
|
||||
|
||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||
{inviterName} has invited you to sign "{documentName}"
|
||||
</Text>
|
||||
|
||||
<Text className="my-1 text-center text-base text-slate-400">
|
||||
Continue by signing the document.
|
||||
</Text>
|
||||
|
||||
<Section className="mb-6 mt-8 text-center">
|
||||
<Button
|
||||
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
||||
href={signDocumentLink}
|
||||
>
|
||||
Sign Document
|
||||
</Button>
|
||||
</Section>
|
||||
</Section>
|
||||
</Tailwind>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateDocumentInvite;
|
||||
@ -0,0 +1,52 @@
|
||||
import { Img, Section, Tailwind, Text } from '@react-email/components';
|
||||
|
||||
import * as config from '@documenso/tailwind-config';
|
||||
|
||||
export interface TemplateDocumentPendingProps {
|
||||
documentName: string;
|
||||
assetBaseUrl: string;
|
||||
}
|
||||
|
||||
export const TemplateDocumentPending = ({
|
||||
documentName,
|
||||
assetBaseUrl,
|
||||
}: TemplateDocumentPendingProps) => {
|
||||
const getAssetUrl = (path: string) => {
|
||||
return new URL(path, assetBaseUrl).toString();
|
||||
};
|
||||
|
||||
return (
|
||||
<Tailwind
|
||||
config={{
|
||||
theme: {
|
||||
extend: {
|
||||
colors: config.theme.extend.colors,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Section className="flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img className="h-42" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
||||
</div>
|
||||
|
||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-blue-500">
|
||||
<Img src={getAssetUrl('/static/clock.png')} className="-mb-0.5 mr-2 inline h-7 w-7" />
|
||||
Waiting for others
|
||||
</Text>
|
||||
|
||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||
“{documentName}” has been signed
|
||||
</Text>
|
||||
|
||||
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
||||
We're still waiting for other signers to sign this document.
|
||||
<br />
|
||||
We'll notify you as soon as it's ready.
|
||||
</Text>
|
||||
</Section>
|
||||
</Tailwind>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateDocumentPending;
|
||||
22
packages/email/template-components/template-footer.tsx
Normal file
22
packages/email/template-components/template-footer.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { Link, Section, Text } from '@react-email/components';
|
||||
|
||||
export const TemplateFooter = () => {
|
||||
return (
|
||||
<Section>
|
||||
<Text className="my-4 text-base text-slate-400">
|
||||
This document was sent using{' '}
|
||||
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||
Documenso.
|
||||
</Link>
|
||||
</Text>
|
||||
|
||||
<Text className="my-8 text-sm text-slate-400">
|
||||
Documenso
|
||||
<br />
|
||||
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||
</Text>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateFooter;
|
||||
@ -1,25 +1,23 @@
|
||||
import {
|
||||
Body,
|
||||
Button,
|
||||
Container,
|
||||
Head,
|
||||
Html,
|
||||
Img,
|
||||
Link,
|
||||
Preview,
|
||||
Section,
|
||||
Tailwind,
|
||||
Text,
|
||||
} from '@react-email/components';
|
||||
|
||||
import config from '@documenso/tailwind-config';
|
||||
|
||||
interface DocumentCompletedEmailTemplateProps {
|
||||
downloadLink?: string;
|
||||
reviewLink?: string;
|
||||
documentName?: string;
|
||||
assetBaseUrl?: string;
|
||||
}
|
||||
import {
|
||||
TemplateDocumentCompleted,
|
||||
TemplateDocumentCompletedProps,
|
||||
} from '../template-components/template-document-completed';
|
||||
import TemplateFooter from '../template-components/template-footer';
|
||||
|
||||
export type DocumentCompletedEmailTemplateProps = Partial<TemplateDocumentCompletedProps>;
|
||||
|
||||
export const DocumentCompletedEmailTemplate = ({
|
||||
downloadLink = 'https://documenso.com',
|
||||
@ -50,74 +48,23 @@ export const DocumentCompletedEmailTemplate = ({
|
||||
<Section className="bg-white">
|
||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||
<Section className="p-2">
|
||||
<Img src={getAssetUrl('/static/logo.png')} alt="Documenso Logo" className="h-6" />
|
||||
<Img
|
||||
src={getAssetUrl('/static/logo.png')}
|
||||
alt="Documenso Logo"
|
||||
className="mb-4 h-6"
|
||||
/>
|
||||
|
||||
<Section className="mt-4 flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img
|
||||
className="h-42"
|
||||
src={getAssetUrl('/static/document.png')}
|
||||
alt="Documenso"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-[#7AC455]">
|
||||
<Img
|
||||
src={getAssetUrl('/static/completed.png')}
|
||||
className="-mb-0.5 mr-2 inline h-7 w-7"
|
||||
/>
|
||||
Completed
|
||||
</Text>
|
||||
|
||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||
“{documentName}” was signed by all signers
|
||||
</Text>
|
||||
|
||||
<Text className="my-1 text-center text-base text-slate-400">
|
||||
Continue by downloading or reviewing the document.
|
||||
</Text>
|
||||
|
||||
<Section className="mb-6 mt-8 text-center">
|
||||
<Button
|
||||
className="mr-4 inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||
href={reviewLink}
|
||||
>
|
||||
<Img
|
||||
src={getAssetUrl('/static/review.png')}
|
||||
className="-mb-1 mr-2 inline h-5 w-5"
|
||||
/>
|
||||
Review
|
||||
</Button>
|
||||
<Button
|
||||
className="inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||
href={downloadLink}
|
||||
>
|
||||
<Img
|
||||
src={getAssetUrl('/static/download.png')}
|
||||
className="-mb-1 mr-2 inline h-5 w-5"
|
||||
/>
|
||||
Download
|
||||
</Button>
|
||||
</Section>
|
||||
</Section>
|
||||
<TemplateDocumentCompleted
|
||||
downloadLink={downloadLink}
|
||||
reviewLink={reviewLink}
|
||||
documentName={documentName}
|
||||
assetBaseUrl={assetBaseUrl}
|
||||
/>
|
||||
</Section>
|
||||
</Container>
|
||||
|
||||
<Container className="mx-auto max-w-xl">
|
||||
<Section>
|
||||
<Text className="my-4 text-base text-slate-400">
|
||||
This document was sent using{' '}
|
||||
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||
Documenso.
|
||||
</Link>
|
||||
</Text>
|
||||
|
||||
<Text className="my-8 text-sm text-slate-400">
|
||||
Documenso
|
||||
<br />
|
||||
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||
</Text>
|
||||
</Section>
|
||||
<TemplateFooter />
|
||||
</Container>
|
||||
</Section>
|
||||
</Body>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import {
|
||||
Body,
|
||||
Button,
|
||||
Container,
|
||||
Head,
|
||||
Hr,
|
||||
@ -15,13 +14,13 @@ import {
|
||||
|
||||
import config from '@documenso/tailwind-config';
|
||||
|
||||
interface DocumentInviteEmailTemplateProps {
|
||||
inviterName?: string;
|
||||
inviterEmail?: string;
|
||||
documentName?: string;
|
||||
signDocumentLink?: string;
|
||||
assetBaseUrl?: string;
|
||||
}
|
||||
import {
|
||||
TemplateDocumentInvite,
|
||||
TemplateDocumentInviteProps,
|
||||
} from '../template-components/template-document-invite';
|
||||
import TemplateFooter from '../template-components/template-footer';
|
||||
|
||||
export type DocumentInviteEmailTemplateProps = Partial<TemplateDocumentInviteProps>;
|
||||
|
||||
export const DocumentInviteEmailTemplate = ({
|
||||
inviterName = 'Lucas Smith',
|
||||
@ -51,36 +50,21 @@ export const DocumentInviteEmailTemplate = ({
|
||||
>
|
||||
<Body className="mx-auto my-auto bg-white font-sans">
|
||||
<Section>
|
||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||
<Section className="p-2">
|
||||
<Img src={getAssetUrl('/static/logo.png')} alt="Documenso Logo" className="h-6" />
|
||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||
<Section>
|
||||
<Img
|
||||
src={getAssetUrl('/static/logo.png')}
|
||||
alt="Documenso Logo"
|
||||
className="mb-4 h-6"
|
||||
/>
|
||||
|
||||
<Section className="mt-4 flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img
|
||||
className="h-42"
|
||||
src={getAssetUrl('/static/document.png')}
|
||||
alt="Documenso"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||
{inviterName} has invited you to sign "{documentName}"
|
||||
</Text>
|
||||
|
||||
<Text className="my-1 text-center text-base text-slate-400">
|
||||
Continue by signing the document.
|
||||
</Text>
|
||||
|
||||
<Section className="mb-6 mt-8 text-center">
|
||||
<Button
|
||||
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
||||
href={signDocumentLink}
|
||||
>
|
||||
Sign Document
|
||||
</Button>
|
||||
</Section>
|
||||
</Section>
|
||||
<TemplateDocumentInvite
|
||||
inviterName={inviterName}
|
||||
inviterEmail={inviterEmail}
|
||||
documentName={documentName}
|
||||
signDocumentLink={signDocumentLink}
|
||||
assetBaseUrl={assetBaseUrl}
|
||||
/>
|
||||
</Section>
|
||||
</Container>
|
||||
|
||||
@ -102,20 +86,7 @@ export const DocumentInviteEmailTemplate = ({
|
||||
<Hr className="mx-auto mt-12 max-w-xl" />
|
||||
|
||||
<Container className="mx-auto max-w-xl">
|
||||
<Section>
|
||||
<Text className="my-4 text-base text-slate-400">
|
||||
This document was sent using{' '}
|
||||
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||
Documenso.
|
||||
</Link>
|
||||
</Text>
|
||||
|
||||
<Text className="my-8 text-sm text-slate-400">
|
||||
Documenso
|
||||
<br />
|
||||
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||
</Text>
|
||||
</Section>
|
||||
<TemplateFooter />
|
||||
</Container>
|
||||
</Section>
|
||||
</Body>
|
||||
|
||||
@ -4,19 +4,20 @@ import {
|
||||
Head,
|
||||
Html,
|
||||
Img,
|
||||
Link,
|
||||
Preview,
|
||||
Section,
|
||||
Tailwind,
|
||||
Text,
|
||||
} from '@react-email/components';
|
||||
|
||||
import config from '@documenso/tailwind-config';
|
||||
|
||||
interface DocumentPendingEmailTemplateProps {
|
||||
documentName?: string;
|
||||
assetBaseUrl?: string;
|
||||
}
|
||||
import {
|
||||
TemplateDocumentPending,
|
||||
TemplateDocumentPendingProps,
|
||||
} from '../template-components/template-document-pending';
|
||||
import { TemplateFooter } from '../template-components/template-footer';
|
||||
|
||||
export type DocumentPendingEmailTemplateProps = Partial<TemplateDocumentPendingProps>;
|
||||
|
||||
export const DocumentPendingEmailTemplate = ({
|
||||
documentName = 'Open Source Pledge.pdf',
|
||||
@ -43,55 +44,20 @@ export const DocumentPendingEmailTemplate = ({
|
||||
>
|
||||
<Body className="mx-auto my-auto font-sans">
|
||||
<Section className="bg-white">
|
||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||
<Section className="p-2">
|
||||
<Img src={getAssetUrl('/static/logo.png')} alt="Documenso Logo" className="h-6" />
|
||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||
<Section>
|
||||
<Img
|
||||
src={getAssetUrl('/static/logo.png')}
|
||||
alt="Documenso Logo"
|
||||
className="mb-4 h-6"
|
||||
/>
|
||||
|
||||
<Section className="mt-4 flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img
|
||||
className="h-42"
|
||||
src={getAssetUrl('/static/document.png')}
|
||||
alt="Documenso"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-blue-500">
|
||||
<Img
|
||||
src={getAssetUrl('/static/clock.png')}
|
||||
className="-mb-0.5 mr-2 inline h-7 w-7"
|
||||
/>
|
||||
Waiting for others
|
||||
</Text>
|
||||
|
||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||
“{documentName}” has been signed
|
||||
</Text>
|
||||
|
||||
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
||||
We're still waiting for other signers to sign this document.
|
||||
<br />
|
||||
We'll notify you as soon as it's ready.
|
||||
</Text>
|
||||
</Section>
|
||||
<TemplateDocumentPending documentName={documentName} assetBaseUrl={assetBaseUrl} />
|
||||
</Section>
|
||||
</Container>
|
||||
|
||||
<Container className="mx-auto max-w-xl">
|
||||
<Section>
|
||||
<Text className="my-4 text-base text-slate-400">
|
||||
This document was sent using{' '}
|
||||
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||
Documenso.
|
||||
</Link>
|
||||
</Text>
|
||||
|
||||
<Text className="my-8 text-sm text-slate-400">
|
||||
Documenso
|
||||
<br />
|
||||
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||
</Text>
|
||||
</Section>
|
||||
<TemplateFooter />
|
||||
</Container>
|
||||
</Section>
|
||||
</Body>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { Document, DocumentStatus, Prisma } from '@documenso/prisma/client';
|
||||
import { Document, DocumentStatus, Prisma, SigningStatus } from '@documenso/prisma/client';
|
||||
import { DocumentWithRecipientAndSender } from '@documenso/prisma/types/document';
|
||||
import { DocumentWithReciepient } from '@documenso/prisma/types/document-with-recipient';
|
||||
|
||||
import { FindResultSet } from '../../types/find-result-set';
|
||||
@ -68,3 +69,111 @@ export const findDocuments = async ({
|
||||
totalPages: Math.ceil(count / perPage),
|
||||
};
|
||||
};
|
||||
|
||||
export interface FindDocumentsWithRecipientAndSenderOptions {
|
||||
email: string;
|
||||
query?: string;
|
||||
signingStatus?: SigningStatus;
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
orderBy?: {
|
||||
column: keyof Omit<Document, 'document'>;
|
||||
direction: 'asc' | 'desc';
|
||||
};
|
||||
}
|
||||
|
||||
export const findDocumentsWithRecipientAndSender = async ({
|
||||
email,
|
||||
query,
|
||||
signingStatus,
|
||||
page = 1,
|
||||
perPage = 20,
|
||||
orderBy,
|
||||
}: FindDocumentsWithRecipientAndSenderOptions): Promise<
|
||||
FindResultSet<DocumentWithRecipientAndSender>
|
||||
> => {
|
||||
const orderByColumn = orderBy?.column ?? 'created';
|
||||
const orderByDirection = orderBy?.direction ?? 'desc';
|
||||
|
||||
const filters: Prisma.DocumentWhereInput = {
|
||||
Recipient: {
|
||||
some: {
|
||||
email,
|
||||
signingStatus,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (query) {
|
||||
filters.OR = [
|
||||
{
|
||||
User: {
|
||||
email: {
|
||||
contains: query,
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
// Todo: Add filter for `Subject`.
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const [data, count] = await Promise.all([
|
||||
prisma.document.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
created: true,
|
||||
title: true,
|
||||
status: true,
|
||||
userId: true,
|
||||
User: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
Recipient: {
|
||||
where: {
|
||||
email,
|
||||
signingStatus,
|
||||
},
|
||||
},
|
||||
},
|
||||
where: {
|
||||
...filters,
|
||||
},
|
||||
skip: Math.max(page - 1, 0) * perPage,
|
||||
take: perPage,
|
||||
orderBy: {
|
||||
[orderByColumn]: orderByDirection,
|
||||
},
|
||||
}),
|
||||
prisma.document.count({
|
||||
where: {
|
||||
...filters,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
return {
|
||||
data: data.map((item) => {
|
||||
const { User, Recipient, ...rest } = item;
|
||||
|
||||
const subject = undefined; // Todo.
|
||||
const description = undefined; // Todo.
|
||||
|
||||
return {
|
||||
...rest,
|
||||
sender: User,
|
||||
recipient: Recipient[0],
|
||||
subject: subject ?? 'Please sign this document',
|
||||
description: description ?? `${User.name} has invited you to sign "${item.title}"`,
|
||||
};
|
||||
}),
|
||||
count,
|
||||
currentPage: Math.max(page, 1),
|
||||
perPage,
|
||||
totalPages: Math.ceil(count / perPage),
|
||||
};
|
||||
};
|
||||
|
||||
12
packages/prisma/types/document.ts
Normal file
12
packages/prisma/types/document.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Document, Recipient } from '@documenso/prisma/client';
|
||||
|
||||
export type DocumentWithRecipientAndSender = Omit<Document, 'document'> & {
|
||||
recipient: Recipient;
|
||||
sender: {
|
||||
id: number;
|
||||
name: string | null;
|
||||
email: string;
|
||||
};
|
||||
subject: string;
|
||||
description: string;
|
||||
};
|
||||
@ -115,6 +115,11 @@ module.exports = {
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||
},
|
||||
screens: {
|
||||
'3xl': '1920px',
|
||||
'4xl': '2560px',
|
||||
'5xl': '3840px',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')],
|
||||
|
||||
@ -1,17 +1,45 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
|
||||
import { findDocumentsWithRecipientAndSender } from '@documenso/lib/server-only/document/find-documents';
|
||||
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
|
||||
import { setFieldsForDocument } from '@documenso/lib/server-only/field/set-fields-for-document';
|
||||
import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/set-recipients-for-document';
|
||||
|
||||
import { authenticatedProcedure, router } from '../trpc';
|
||||
import {
|
||||
ZSearchInboxDocumentsParamsSchema,
|
||||
ZSendDocumentMutationSchema,
|
||||
ZSetFieldsForDocumentMutationSchema,
|
||||
ZSetRecipientsForDocumentMutationSchema,
|
||||
} from './schema';
|
||||
|
||||
export const documentRouter = router({
|
||||
searchInboxDocuments: authenticatedProcedure
|
||||
.input(ZSearchInboxDocumentsParamsSchema)
|
||||
.query(async ({ input, ctx }) => {
|
||||
try {
|
||||
const { filter, query, cursor: page } = input;
|
||||
|
||||
return await findDocumentsWithRecipientAndSender({
|
||||
email: ctx.session.email,
|
||||
query,
|
||||
signingStatus: filter,
|
||||
orderBy: {
|
||||
column: 'created',
|
||||
direction: 'desc',
|
||||
},
|
||||
page,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: 'Something went wrong. Please try again later.',
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
setRecipientsForDocument: authenticatedProcedure
|
||||
.input(ZSetRecipientsForDocumentMutationSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
|
||||
@ -2,6 +2,19 @@ import { z } from 'zod';
|
||||
|
||||
import { FieldType } from '@documenso/prisma/client';
|
||||
|
||||
export const ZSearchInboxDocumentsParamsSchema = z.object({
|
||||
filter: z
|
||||
.union([z.literal('SIGNED'), z.literal('NOT_SIGNED'), z.undefined()])
|
||||
.catch(() => undefined),
|
||||
cursor: z.number().default(1),
|
||||
query: z
|
||||
.string()
|
||||
.optional()
|
||||
.catch(() => undefined),
|
||||
});
|
||||
|
||||
export type TSearchInboxDocumentsParamsSchema = z.infer<typeof ZSearchInboxDocumentsParamsSchema>;
|
||||
|
||||
export const ZSetRecipientsForDocumentMutationSchema = z.object({
|
||||
documentId: z.number(),
|
||||
recipients: z.array(
|
||||
|
||||
Reference in New Issue
Block a user