Skip to content

Commit

Permalink
feat: improve audit log template (#495)
Browse files Browse the repository at this point in the history
* feat: add to config

* feat: update template

* fix: template
  • Loading branch information
G3root authored Aug 29, 2024
1 parent cad81e4 commit 2e3fdfb
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 16 deletions.
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const nextConfig = {
"pino-pretty",
"pdf-lib",
"@aws-sdk/s3-request-presigner",
"@react-pdf/renderer",
],
},
eslint: {
Expand Down
3 changes: 3 additions & 0 deletions src/jobs/esign-pdf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export type EsignPdfPayloadType = {
audits: {
id: string;
summary: string;
action: string;
occurredAt: Date;
}[];
bucketKey: string;
templateName: string;
Expand Down Expand Up @@ -58,6 +60,7 @@ export class EsignPdfJob extends BaseJob<EsignPdfPayloadType> {
data,
fields,
audits,
templateName,
});
const { fileUrl: _fileUrl, ...bucketData } = await uploadEsignDocuments({
buffer: Buffer.from(modifiedPdfBytes),
Expand Down
141 changes: 127 additions & 14 deletions src/pdf-templates/audit-log-template.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
import { Document, Font, Page, StyleSheet, Text } from "@react-pdf/renderer";
import { dayjsExt } from "@/common/dayjs";
import type { TEsignAuditSchema } from "@/server/audit/schema";
import type { TGetEsignAudits } from "@/server/esign";

import {
Document,
Font,
Page,
Path,
Rect,
StyleSheet,
Svg,
Text,
View,
} from "@react-pdf/renderer";

Font.register({
family: "Oswald",
Expand All @@ -12,31 +26,130 @@ const styles = StyleSheet.create({
paddingHorizontal: 35,
},
title: {
fontSize: 24,
textAlign: "center",
fontFamily: "Oswald",
fontSize: 14,
},
divider: {
width: "100%",
height: 1,
backgroundColor: "#e4e4e7",
margin: "10 0",
},

text: {
margin: 5,
fontSize: 14,
textAlign: "justify",
fontFamily: "Times-Roman",
fontSize: 12,
},
table: {
display: "flex",
width: "auto",
},
tableRow: {
margin: "auto",
flexDirection: "row",
},
tableCol: {
width: "50%",
},
tableCell: {
marginTop: 5,
fontSize: 10,
},
container: {
flexDirection: "row",
width: "100%",
},
column: {
flex: 1,
padding: 10,
},
headerContainer: {
flexDirection: "row",
width: "100%",
alignItems: "center",
},
headerText: {
fontSize: 16,
textAlign: "right",

fontFamily: "Oswald",
},
});
const Logo = () => {
return (
<Svg width="24" height="24" viewBox="0 0 1200 1200" fill="none">
<Rect width="1200" height="1200" rx="24" fill="#18181B" />
<Path
d="M200 599.561C200 387.376 364.852 213.737 573.333 200V414.583C482.872 427.536 413.333 505.419 413.333 599.561C413.333 702.767 496.907 786.434 600 786.434C641.93 786.434 680.63 772.589 711.792 749.225L863.36 900.964C793.003 962.626 700.86 1000 600 1000C379.086 1000 200 820.716 200 599.561Z"
fill="white"
/>
<Path
d="M901.072 863.211C962.672 792.771 1000 700.53 1000 599.561C1000 544.38 988.848 491.806 968.683 443.973L773.611 530.767C782.037 552.058 786.667 575.268 786.667 599.561C786.667 641.535 772.843 680.277 749.504 711.473L901.072 863.211Z"
fill="white"
fill-opacity="0.75"
/>
<Path
d="M626.667 414.583V200C762.219 208.932 879.323 285.46 944.672 396.23L746.885 484.23C717.9 447.286 675.308 421.548 626.667 414.583Z"
fill="white"
fill-opacity="0.5"
/>
</Svg>
);
};

const humanizedStatus: Record<TEsignAuditSchema["action"], string> = {
"document.complete": "Document completed",
"document.email.sent": "Email sent",
"recipient.signed": "Signed",
};

export interface AuditLogTemplateProps {
audits: { id: string; summary: string }[];
audits: TGetEsignAudits;
templateName: string;
}

export function AuditLogTemplate({ audits }: AuditLogTemplateProps) {
export function AuditLogTemplate({
audits,
templateName,
}: AuditLogTemplateProps) {
return (
<Document>
<Page style={styles.body}>
<Text style={styles.title}>eSigning audit logs</Text>
<View style={styles.headerContainer}>
<View style={styles.column}>
<Logo />
</View>
<View style={styles.column}>
<Text style={styles.headerText}>Audit Logs</Text>
</View>
</View>

<View style={styles.divider} />

<View style={styles.table}>
<View style={styles.tableRow}>
<View style={styles.tableCol}>
<Text style={styles.tableCell}>File Name</Text>
</View>
<View style={styles.tableCol}>
<Text style={styles.tableCell}>{templateName}</Text>
</View>
</View>
</View>

<View style={styles.divider} />
<Text style={styles.title}>Document history</Text>
{audits.map((item) => (
<Text key={item.id} style={styles.text}>
{item.summary}
</Text>
<View style={styles.container} key={item.id}>
<View style={styles.column}>
<Text style={styles.text}>
{humanizedStatus?.[
item.action as keyof typeof humanizedStatus
] ?? "unknown action"}
</Text>
</View>
<View style={styles.column}>
<Text style={styles.text}>{item.summary}</Text>
</View>
</View>
))}
</Page>
</Document>
Expand Down
10 changes: 8 additions & 2 deletions src/server/esign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ export async function getEsignAudits({
select: {
id: true,
summary: true,
occurredAt: true,
action: true,
},
});
return audits;
}

type TGetEsignAudits = Awaited<ReturnType<typeof getEsignAudits>>;
export type TGetEsignAudits = Awaited<ReturnType<typeof getEsignAudits>>;

interface getEsignTemplateOptions {
templateId: string;
Expand Down Expand Up @@ -104,13 +106,15 @@ export interface GenerateEsignSignPdfOptionsType {
data: Record<string, string>;
fields: EsignGetTemplateType["fields"];
audits: TGetEsignAudits;
templateName: string;
}

export async function generateEsignPdf({
bucketKey,
data,
fields,
audits,
templateName,
}: GenerateEsignSignPdfOptionsType) {
const docBuffer = await getFileFromS3(bucketKey);
const pdfDoc = await PDFDocument.load(docBuffer);
Expand Down Expand Up @@ -174,7 +178,9 @@ export async function generateEsignPdf({
}

if (audits.length) {
const audit = await renderToBuffer(AuditLogTemplate({ audits }));
const audit = await renderToBuffer(
AuditLogTemplate({ audits, templateName }),
);
const auditPDFDoc = await PDFDocument.load(audit);
const indices = auditPDFDoc.getPageIndices();
const copiedPages = await pdfDoc.copyPages(auditPDFDoc, indices);
Expand Down

0 comments on commit 2e3fdfb

Please sign in to comment.