mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 04:22:32 +10:00
fix: reverse meta relation and tidy code
This commit is contained in:
@ -1,9 +1,8 @@
|
||||
'use server';
|
||||
|
||||
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-session';
|
||||
import { createDocumentMeta } from '@documenso/lib/server-only/document-meta/create-document-meta';
|
||||
import { upsertDocumentMeta } from '@documenso/lib/server-only/document-meta/upsert-document-meta';
|
||||
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
|
||||
import { updateDocument } from '@documenso/lib/server-only/document/update-document';
|
||||
import { TAddSubjectFormSchema } from '@documenso/ui/primitives/document-flow/add-subject.types';
|
||||
|
||||
export type CompleteDocumentActionInput = TAddSubjectFormSchema & {
|
||||
@ -15,30 +14,15 @@ export const completeDocument = async ({ documentId, email }: CompleteDocumentAc
|
||||
|
||||
const { id: userId } = await getRequiredServerComponentSession();
|
||||
|
||||
if (!email.message && !email.subject) {
|
||||
return await sendDocument({
|
||||
userId,
|
||||
if (email.message || email.subject) {
|
||||
await upsertDocumentMeta({
|
||||
documentId,
|
||||
subject: email.subject,
|
||||
message: email.message,
|
||||
});
|
||||
}
|
||||
|
||||
const createDocumentMetaResponse = await createDocumentMeta({
|
||||
emailBody: email.message,
|
||||
emailSubject: email.subject,
|
||||
});
|
||||
|
||||
await updateDocument({
|
||||
documentId,
|
||||
data: {
|
||||
DocumentMeta: {
|
||||
connect: {
|
||||
id: createDocumentMetaResponse.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await sendDocument({
|
||||
return await sendDocument({
|
||||
userId,
|
||||
documentId,
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Button, Img, Section, Tailwind, Text } from '@react-email/components';
|
||||
import { Button, Column, Img, Row, Section, Tailwind, Text } from '@react-email/components';
|
||||
|
||||
import * as config from '@documenso/tailwind-config';
|
||||
|
||||
@ -29,11 +29,23 @@ export const TemplateDocumentCompleted = ({
|
||||
},
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
<Section>
|
||||
<Row className="table-fixed">
|
||||
<Column />
|
||||
|
||||
<Column>
|
||||
<Img
|
||||
className="h-42 mx-auto"
|
||||
src={getAssetUrl('/static/document.png')}
|
||||
alt="Documenso"
|
||||
/>
|
||||
</Column>
|
||||
|
||||
<Column />
|
||||
</Row>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<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
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Button, Img, Section, Tailwind, Text } from '@react-email/components';
|
||||
import { Button, Column, Img, Row, Section, Tailwind, Text } from '@react-email/components';
|
||||
|
||||
import * as config from '@documenso/tailwind-config';
|
||||
|
||||
@ -30,13 +30,26 @@ export const TemplateDocumentInvite = ({
|
||||
},
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
<Section className="mt-4">
|
||||
<Row className="table-fixed">
|
||||
<Column />
|
||||
|
||||
<Column>
|
||||
<Img
|
||||
className="h-42 mx-auto"
|
||||
src={getAssetUrl('/static/document.png')}
|
||||
alt="Documenso"
|
||||
/>
|
||||
</Column>
|
||||
|
||||
<Column />
|
||||
</Row>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||
{inviterName} has invited you to sign "{documentName}"
|
||||
{inviterName} has invited you to sign
|
||||
<br />"{documentName}"
|
||||
</Text>
|
||||
|
||||
<Text className="my-1 text-center text-base text-slate-400">
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Img, Section, Tailwind, Text } from '@react-email/components';
|
||||
import { Column, Img, Row, Section, Tailwind, Text } from '@react-email/components';
|
||||
|
||||
import * as config from '@documenso/tailwind-config';
|
||||
|
||||
@ -25,11 +25,23 @@ export const TemplateDocumentPending = ({
|
||||
},
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
<Section>
|
||||
<Row className="table-fixed">
|
||||
<Column />
|
||||
|
||||
<Column>
|
||||
<Img
|
||||
className="h-42 mx-auto"
|
||||
src={getAssetUrl('/static/document.png')}
|
||||
alt="Documenso"
|
||||
/>
|
||||
</Column>
|
||||
|
||||
<Column />
|
||||
</Row>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<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
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
'use server';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type CreateDocumentMetaOptions = {
|
||||
emailSubject: string;
|
||||
emailBody: string;
|
||||
};
|
||||
|
||||
export const createDocumentMeta = async ({
|
||||
emailBody,
|
||||
emailSubject,
|
||||
}: CreateDocumentMetaOptions) => {
|
||||
const emailData = {
|
||||
customEmailBody: emailBody,
|
||||
customEmailSubject: emailSubject,
|
||||
};
|
||||
|
||||
const existingDocumentMeta = await prisma.documentMeta.findFirst({
|
||||
where: emailData,
|
||||
});
|
||||
|
||||
if (existingDocumentMeta) {
|
||||
return await prisma.documentMeta.update({
|
||||
where: { id: existingDocumentMeta.id },
|
||||
data: emailData,
|
||||
});
|
||||
} else {
|
||||
return await prisma.documentMeta.create({
|
||||
data: emailData,
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,30 @@
|
||||
'use server';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type CreateDocumentMetaOptions = {
|
||||
documentId: number;
|
||||
subject: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export const upsertDocumentMeta = async ({
|
||||
subject,
|
||||
message,
|
||||
documentId,
|
||||
}: CreateDocumentMetaOptions) => {
|
||||
return await prisma.documentMeta.upsert({
|
||||
where: {
|
||||
documentId,
|
||||
},
|
||||
create: {
|
||||
subject,
|
||||
message,
|
||||
documentId,
|
||||
},
|
||||
update: {
|
||||
subject,
|
||||
message,
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -13,6 +13,7 @@ export const getDocumentById = async ({ id, userId }: GetDocumentByIdOptions) =>
|
||||
},
|
||||
include: {
|
||||
documentData: true,
|
||||
documentMeta: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@ -26,11 +26,11 @@ export const sendDocument = async ({ documentId, userId }: SendDocumentOptions)
|
||||
},
|
||||
include: {
|
||||
Recipient: true,
|
||||
DocumentMeta: true,
|
||||
documentMeta: true,
|
||||
},
|
||||
});
|
||||
|
||||
const customEmail = document?.DocumentMeta;
|
||||
const customEmail = document?.documentMeta;
|
||||
|
||||
if (!document) {
|
||||
throw new Error('Document not found');
|
||||
@ -67,10 +67,7 @@ export const sendDocument = async ({ documentId, userId }: SendDocumentOptions)
|
||||
inviterEmail: user.email,
|
||||
assetBaseUrl,
|
||||
signDocumentLink,
|
||||
customBody: renderCustomEmailTemplate(
|
||||
customEmail?.customEmailBody || '',
|
||||
customEmailTemplate,
|
||||
),
|
||||
customBody: renderCustomEmailTemplate(customEmail?.message || '', customEmailTemplate),
|
||||
});
|
||||
|
||||
await mailer.sendMail({
|
||||
@ -82,8 +79,8 @@ export const sendDocument = async ({ documentId, userId }: SendDocumentOptions)
|
||||
name: process.env.NEXT_PRIVATE_SMTP_FROM_NAME || 'Documenso',
|
||||
address: process.env.NEXT_PRIVATE_SMTP_FROM_ADDRESS || 'noreply@documenso.com',
|
||||
},
|
||||
subject: customEmail?.customEmailSubject
|
||||
? renderCustomEmailTemplate(customEmail.customEmailSubject, customEmailTemplate)
|
||||
subject: customEmail?.subject
|
||||
? renderCustomEmailTemplate(customEmail.subject, customEmailTemplate)
|
||||
: 'Please sign this document',
|
||||
html: render(template),
|
||||
text: render(template, { plainText: true }),
|
||||
|
||||
@ -2,19 +2,11 @@ export const renderCustomEmailTemplate = <T extends Record<string, string>>(
|
||||
template: string,
|
||||
variables: T,
|
||||
): string => {
|
||||
let t = template;
|
||||
|
||||
Object.entries(variables).forEach((entry) => {
|
||||
const [key, value] = entry;
|
||||
|
||||
const placeholder = `{${key}}`;
|
||||
|
||||
const re = new RegExp(placeholder, 'g');
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(variables, key)) {
|
||||
t = t.replace(re, String(value));
|
||||
return template.replace(/\{(\S+)\}/g, (_, key) => {
|
||||
if (key in variables) {
|
||||
return variables[key];
|
||||
}
|
||||
});
|
||||
|
||||
return t;
|
||||
return key;
|
||||
});
|
||||
};
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `documentMetaId` on the `Document` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `customEmailBody` on the `DocumentMeta` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `customEmailSubject` on the `DocumentMeta` table. All the data in the column will be lost.
|
||||
- A unique constraint covering the columns `[documentId]` on the table `DocumentMeta` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `documentId` to the `DocumentMeta` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Document" DROP CONSTRAINT "Document_documentMetaId_fkey";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "Document_documentMetaId_key";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "DocumentMeta"
|
||||
ADD COLUMN "documentId" INTEGER,
|
||||
ADD COLUMN "message" TEXT,
|
||||
ADD COLUMN "subject" TEXT;
|
||||
|
||||
-- Migrate data
|
||||
UPDATE "DocumentMeta" SET "documentId" = (
|
||||
SELECT "id" FROM "Document" WHERE "Document"."documentMetaId" = "DocumentMeta"."id"
|
||||
);
|
||||
|
||||
-- Migrate data
|
||||
UPDATE "DocumentMeta" SET "message" = "customEmailBody";
|
||||
|
||||
-- Migrate data
|
||||
UPDATE "DocumentMeta" SET "subject" = "customEmailSubject";
|
||||
|
||||
-- Prune data
|
||||
DELETE FROM "DocumentMeta" WHERE "documentId" IS NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Document" DROP COLUMN "documentMetaId";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "DocumentMeta"
|
||||
DROP COLUMN "customEmailBody",
|
||||
DROP COLUMN "customEmailSubject";
|
||||
|
||||
-- AlterColumn
|
||||
ALTER TABLE "DocumentMeta" ALTER COLUMN "documentId" SET NOT NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "DocumentMeta_documentId_key" ON "DocumentMeta"("documentId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DocumentMeta" ADD CONSTRAINT "DocumentMeta_documentId_fkey" FOREIGN KEY ("documentId") REFERENCES "Document"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -110,14 +110,11 @@ model Document {
|
||||
Field Field[]
|
||||
documentDataId String
|
||||
documentData DocumentData @relation(fields: [documentDataId], references: [id], onDelete: Cascade)
|
||||
documentMeta DocumentMeta?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
|
||||
documentMetaId String?
|
||||
DocumentMeta DocumentMeta? @relation(fields: [documentMetaId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([documentDataId])
|
||||
@@unique([documentMetaId])
|
||||
}
|
||||
|
||||
enum DocumentDataType {
|
||||
@ -135,10 +132,11 @@ model DocumentData {
|
||||
}
|
||||
|
||||
model DocumentMeta {
|
||||
id String @id @default(cuid())
|
||||
customEmailSubject String?
|
||||
customEmailBody String?
|
||||
Document Document?
|
||||
id String @id @default(cuid())
|
||||
subject String?
|
||||
message String?
|
||||
documentId Int @unique
|
||||
document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
enum ReadStatus {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Document, DocumentData } from '@documenso/prisma/client';
|
||||
import { Document, DocumentData, DocumentMeta } from '@documenso/prisma/client';
|
||||
|
||||
export type DocumentWithData = Document & {
|
||||
documentData?: DocumentData | null;
|
||||
documentMeta?: DocumentMeta | null;
|
||||
};
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { Document, DocumentStatus, Field, Recipient } from '@documenso/prisma/client';
|
||||
import { DocumentStatus, Field, Recipient } from '@documenso/prisma/client';
|
||||
import { DocumentWithData } from '@documenso/prisma/types/document-with-data';
|
||||
import { FormErrorMessage } from '@documenso/ui/primitives/form/form-error-message';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { Label } from '@documenso/ui/primitives/label';
|
||||
@ -21,7 +22,7 @@ export type AddSubjectFormProps = {
|
||||
documentFlow: DocumentFlowStep;
|
||||
recipients: Recipient[];
|
||||
fields: Field[];
|
||||
document: Document;
|
||||
document: DocumentWithData;
|
||||
numberOfSteps: number;
|
||||
onSubmit: (_data: TAddSubjectFormSchema) => void;
|
||||
};
|
||||
@ -41,8 +42,8 @@ export const AddSubjectFormPartial = ({
|
||||
} = useForm<TAddSubjectFormSchema>({
|
||||
defaultValues: {
|
||||
email: {
|
||||
subject: '',
|
||||
message: '',
|
||||
subject: document.documentMeta?.subject ?? '',
|
||||
message: document.documentMeta?.message ?? '',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user