feat: edit recipients when creating document from template (#953)

https://github.com/documenso/documenso/assets/55143799/85a840e3-4fb4-4c02-ba63-b9626f4cea58
This commit is contained in:
Lucas Smith
2024-02-26 12:00:23 +11:00
committed by GitHub
9 changed files with 349 additions and 60 deletions

View File

@ -107,6 +107,8 @@ test('[TEMPLATES]: delete template', async ({ page }) => {
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'Delete' }).click();
await expect(page.getByText('Template deleted').first()).toBeVisible();
await page.waitForTimeout(1000);
}
await unseedTeam(team.url);
@ -187,15 +189,18 @@ test('[TEMPLATES]: use template', async ({ page }) => {
// Use personal template.
await page.getByRole('button', { name: 'Use Template' }).click();
await page.getByRole('button', { name: 'Create Document' }).click();
await page.waitForURL(/documents/);
await page.getByRole('main').getByRole('link', { name: 'Documents' }).click();
await page.waitForURL('/documents');
await expect(page.getByRole('main')).toContainText('Showing 1 result');
await page.goto(`${WEBAPP_BASE_URL}/t/${team.url}/templates`);
await page.waitForTimeout(1000);
// Use team template.
await page.getByRole('button', { name: 'Use Template' }).click();
await page.getByRole('button', { name: 'Create Document' }).click();
await page.waitForURL(/\/t\/.+\/documents/);
await page.getByRole('main').getByRole('link', { name: 'Documents' }).click();
await page.waitForURL(`/t/${team.url}/documents`);

View File

@ -1,14 +1,21 @@
import { nanoid } from '@documenso/lib/universal/id';
import { prisma } from '@documenso/prisma';
import type { TCreateDocumentFromTemplateMutationSchema } from '@documenso/trpc/server/template-router/schema';
import type { RecipientRole } from '@documenso/prisma/client';
export type CreateDocumentFromTemplateOptions = TCreateDocumentFromTemplateMutationSchema & {
export type CreateDocumentFromTemplateOptions = {
templateId: number;
userId: number;
recipients?: {
name?: string;
email: string;
role?: RecipientRole;
}[];
};
export const createDocumentFromTemplate = async ({
templateId,
userId,
recipients,
}: CreateDocumentFromTemplateOptions) => {
const template = await prisma.template.findUnique({
where: {
@ -64,7 +71,11 @@ export const createDocumentFromTemplate = async ({
},
include: {
Recipient: true,
Recipient: {
orderBy: {
id: 'asc',
},
},
},
});
@ -89,5 +100,34 @@ export const createDocumentFromTemplate = async ({
}),
});
if (recipients && recipients.length > 0) {
document.Recipient = await Promise.all(
recipients.map(async (recipient, index) => {
const existingRecipient = document.Recipient.at(index);
return await prisma.recipient.upsert({
where: {
documentId_email: {
documentId: document.id,
email: existingRecipient?.email ?? recipient.email,
},
},
update: {
name: recipient.name,
email: recipient.email,
role: recipient.role,
},
create: {
documentId: document.id,
email: recipient.email,
name: recipient.name,
role: recipient.role,
token: nanoid(),
},
});
}),
);
}
return document;
};

View File

@ -38,6 +38,7 @@ export const findTemplates = async ({
include: {
templateDocumentData: true,
Field: true,
Recipient: true,
},
skip: Math.max(page - 1, 0) * perPage,
orderBy: {

View File

@ -2,7 +2,7 @@ import fs from 'node:fs';
import path from 'node:path';
import { prisma } from '..';
import { DocumentDataType } from '../client';
import { DocumentDataType, ReadStatus, RecipientRole, SendStatus, SigningStatus } from '../client';
const examplePdf = fs
.readFileSync(path.join(__dirname, '../../../assets/example.pdf'))
@ -28,9 +28,36 @@ export const seedTemplate = async (options: SeedTemplateOptions) => {
return await prisma.template.create({
data: {
title,
templateDocumentDataId: documentData.id,
userId: userId,
teamId,
templateDocumentData: {
connect: {
id: documentData.id,
},
},
User: {
connect: {
id: userId,
},
},
Recipient: {
create: {
email: 'recipient.1@documenso.com',
name: 'Recipient 1',
token: Math.random().toString().slice(2, 7),
sendStatus: SendStatus.NOT_SENT,
signingStatus: SigningStatus.NOT_SIGNED,
readStatus: ReadStatus.NOT_OPENED,
role: RecipientRole.SIGNER,
},
},
...(teamId
? {
team: {
connect: {
id: teamId,
},
},
}
: {}),
},
});
};

View File

@ -52,6 +52,7 @@ export const templateRouter = router({
return await createDocumentFromTemplate({
templateId,
userId: ctx.user.id,
recipients: input.recipients,
});
} catch (err) {
throw new TRPCError({

View File

@ -1,5 +1,7 @@
import { z } from 'zod';
import { RecipientRole } from '@documenso/prisma/client';
export const ZCreateTemplateMutationSchema = z.object({
title: z.string().min(1).trim(),
teamId: z.number().optional(),
@ -8,6 +10,15 @@ export const ZCreateTemplateMutationSchema = z.object({
export const ZCreateDocumentFromTemplateMutationSchema = z.object({
templateId: z.number(),
recipients: z
.array(
z.object({
email: z.string().email(),
name: z.string(),
role: z.nativeEnum(RecipientRole),
}),
)
.optional(),
});
export const ZDuplicateTemplateMutationSchema = z.object({