feat: update recipient expiry handling

This commit is contained in:
Ephraim Atta-Duncan
2024-11-17 22:57:40 +00:00
parent ba627e22c5
commit 2d7988f484
6 changed files with 90 additions and 5 deletions

View File

@ -101,6 +101,8 @@ export const ResendDocumentActionItem = ({
setIsOpen(false);
} catch (err) {
console.log(err);
toast({
title: _(msg`Something went wrong`),
description: _(msg`This document could not be re-sent at this time. Please try again.`),

View File

@ -41,10 +41,8 @@ export const StackAvatar = ({ first, zIndex, fallbackText = '', type }: StackAva
classes = 'bg-documenso-200 text-documenso-800';
break;
case RecipientStatusType.REJECTED:
classes = 'bg-red-200 text-red-800';
break;
case RecipientStatusType.EXPIRED:
classes = 'bg-gray-200 text-gray-700';
classes = 'bg-red-200 text-red-800';
break;
default:

View File

@ -16,6 +16,7 @@ import type { TRecipientActionAuth } from '../../types/document-auth';
import { getIsRecipientsTurnToSign } from '../recipient/get-is-recipient-turn';
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
import { sendPendingEmail } from './send-pending-email';
import { updateExpiredRecipients } from './update-expired-recipients';
export type CompleteDocumentWithTokenOptions = {
token: string;
@ -61,12 +62,22 @@ export const completeDocumentWithToken = async ({
throw new Error(`Document ${document.id} has no recipient with token ${token}`);
}
await updateExpiredRecipients(documentId);
const [recipient] = document.Recipient;
if (recipient.expired && recipient.expired < new Date()) {
throw new Error(`Recipient ${recipient.id} signature period has expired`);
}
if (recipient.signingStatus === SigningStatus.SIGNED) {
throw new Error(`Recipient ${recipient.id} has already signed`);
}
if (recipient.signingStatus === SigningStatus.EXPIRED) {
throw new Error(`Recipient ${recipient.id} signature period has expired`);
}
if (document.documentMeta?.signingOrder === DocumentSigningOrder.SEQUENTIAL) {
const isRecipientsTurn = await getIsRecipientsTurnToSign({ token: recipient.token });

View File

@ -14,8 +14,8 @@ import type { RequestMetadata } from '@documenso/lib/universal/extract-request-m
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
import { renderCustomEmailTemplate } from '@documenso/lib/utils/render-custom-email-template';
import { prisma } from '@documenso/prisma';
import { DocumentStatus, RecipientRole, SigningStatus } from '@documenso/prisma/client';
import type { Prisma } from '@documenso/prisma/client';
import { DocumentStatus, RecipientRole, SigningStatus } from '@documenso/prisma/client';
import { getI18nInstance } from '../../client-only/providers/i18n.server';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
@ -106,6 +106,23 @@ export const resendDocument = async ({
return;
}
let newExpiryDate: Date | null = null;
if (recipient.expired) {
const durationInMs = recipient.expired.getTime() - document.updatedAt.getTime();
newExpiryDate = new Date(Date.now() + durationInMs);
await prisma.recipient.update({
where: { id: recipient.id },
data: {
expired: newExpiryDate,
signingStatus:
recipient.signingStatus === SigningStatus.EXPIRED
? SigningStatus.NOT_SIGNED
: recipient.signingStatus,
},
});
}
const i18n = await getI18nInstance(document.documentMeta?.language);
const recipientEmailType = RECIPIENT_ROLE_TO_EMAIL_TYPE[recipient.role];

View File

@ -0,0 +1,57 @@
import { prisma } from '@documenso/prisma';
import { SigningStatus } from '@documenso/prisma/client';
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
export const updateExpiredRecipients = async (documentId: number) => {
const now = new Date();
const expiredRecipients = await prisma.recipient.findMany({
where: {
documentId,
expired: {
lt: now,
},
signingStatus: {
not: SigningStatus.EXPIRED,
},
},
});
if (expiredRecipients.length > 0) {
await prisma.recipient.updateMany({
where: {
id: {
in: expiredRecipients.map((recipient) => recipient.id),
},
},
data: {
signingStatus: SigningStatus.EXPIRED,
},
});
await Promise.all(
expiredRecipients.map(async (recipient) =>
prisma.documentAuditLog.create({
data: createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_RECIPIENT_EXPIRED,
documentId,
user: {
name: recipient.name,
email: recipient.email,
},
data: {
recipientEmail: recipient.email,
recipientName: recipient.name,
recipientId: recipient.id,
recipientRole: recipient.role,
},
}),
}),
),
);
}
return expiredRecipients;
};

View File

@ -184,7 +184,7 @@ export function DocumentExpiryDialog({
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[450px]">
<DialogHeader>
<DialogTitle>Set Document Expiry</DialogTitle>
<DialogTitle>Set Recipient Expiry</DialogTitle>
<DialogDescription>
Set the expiry date for the document signing recipient. The recipient will not be able
to sign the document after this date.