feat: enable resend email menu (#496)

This commit is contained in:
Nafees Nazik
2023-11-16 07:35:45 +05:30
committed by GitHub
parent 34527c1842
commit 51938293f1
27 changed files with 407 additions and 74 deletions

View File

@ -0,0 +1,35 @@
'use server';
import { cache } from 'react';
import { getServerSession as getNextAuthServerSession } from 'next-auth';
import { prisma } from '@documenso/prisma';
import { NEXT_AUTH_OPTIONS } from './auth-options';
export const getServerComponentSession = cache(async () => {
const session = await getNextAuthServerSession(NEXT_AUTH_OPTIONS);
if (!session || !session.user?.email) {
return { user: null, session: null };
}
const user = await prisma.user.findFirstOrThrow({
where: {
email: session.user.email,
},
});
return { user, session };
});
export const getRequiredServerComponentSession = cache(async () => {
const { user, session } = await getServerComponentSession();
if (!user || !session) {
throw new Error('No session found');
}
return { user, session };
});

View File

@ -1,6 +1,6 @@
import { cache } from 'react';
'use server';
import { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next';
import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next';
import { getServerSession as getNextAuthServerSession } from 'next-auth';
@ -28,29 +28,3 @@ export const getServerSession = async ({ req, res }: GetServerSessionOptions) =>
return { user, session };
};
export const getServerComponentSession = cache(async () => {
const session = await getNextAuthServerSession(NEXT_AUTH_OPTIONS);
if (!session || !session.user?.email) {
return { user: null, session: null };
}
const user = await prisma.user.findFirstOrThrow({
where: {
email: session.user.email,
},
});
return { user, session };
});
export const getRequiredServerComponentSession = cache(async () => {
const { user, session } = await getServerComponentSession();
if (!user || !session) {
throw new Error('No session found');
}
return { user, session };
});

View File

@ -0,0 +1,99 @@
import { createElement } from 'react';
import { mailer } from '@documenso/email/mailer';
import { render } from '@documenso/email/render';
import { DocumentInviteEmailTemplate } from '@documenso/email/templates/document-invite';
import { FROM_ADDRESS, FROM_NAME } from '@documenso/lib/constants/email';
import { renderCustomEmailTemplate } from '@documenso/lib/utils/render-custom-email-template';
import { prisma } from '@documenso/prisma';
import { DocumentStatus, SigningStatus } from '@documenso/prisma/client';
export type ResendDocumentOptions = {
documentId: number;
userId: number;
recipients: number[];
};
export const resendDocument = async ({ documentId, userId, recipients }: ResendDocumentOptions) => {
const user = await prisma.user.findFirstOrThrow({
where: {
id: userId,
},
});
const document = await prisma.document.findUnique({
where: {
id: documentId,
userId,
},
include: {
Recipient: {
where: {
id: {
in: recipients,
},
signingStatus: SigningStatus.NOT_SIGNED,
},
},
documentMeta: true,
},
});
const customEmail = document?.documentMeta;
if (!document) {
throw new Error('Document not found');
}
if (document.Recipient.length === 0) {
throw new Error('Document has no recipients');
}
if (document.status === DocumentStatus.DRAFT) {
throw new Error('Can not send draft document');
}
if (document.status === DocumentStatus.COMPLETED) {
throw new Error('Can not send completed document');
}
await Promise.all([
document.Recipient.map(async (recipient) => {
const { email, name } = recipient;
const customEmailTemplate = {
'signer.name': name,
'signer.email': email,
'document.name': document.title,
};
const assetBaseUrl = process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000';
const signDocumentLink = `${process.env.NEXT_PUBLIC_WEBAPP_URL}/sign/${recipient.token}`;
const template = createElement(DocumentInviteEmailTemplate, {
documentName: document.title,
inviterName: user.name || undefined,
inviterEmail: user.email,
assetBaseUrl,
signDocumentLink,
customBody: renderCustomEmailTemplate(customEmail?.message || '', customEmailTemplate),
});
await mailer.sendMail({
to: {
address: email,
name,
},
from: {
name: FROM_NAME,
address: FROM_ADDRESS,
},
subject: customEmail?.subject
? renderCustomEmailTemplate(customEmail.subject, customEmailTemplate)
: 'Please sign this document',
html: render(template),
text: render(template, { plainText: true }),
});
}),
]);
};

View File

@ -10,7 +10,7 @@ import slugify from '@sindresorhus/slugify';
import path from 'node:path';
import { ONE_HOUR, ONE_SECOND } from '../../constants/time';
import { getServerComponentSession } from '../../next-auth/get-server-session';
import { getServerComponentSession } from '../../next-auth/get-server-component-session';
import { alphaid } from '../id';
export const getPresignPostUrl = async (fileName: string, contentType: string) => {