Skip to content

Commit

Permalink
refact: cert
Browse files Browse the repository at this point in the history
  • Loading branch information
Gautam-Hegde committed May 13, 2024
1 parent 847e4a1 commit a6caec7
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Certificate" ADD COLUMN "completedAt" TIMESTAMP(3);
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ model Certificate {
userId String
course Course @relation(fields: [courseId], references: [id])
courseId Int
completedAt DateTime?
@@unique([userId, courseId])
}
Expand Down
Binary file modified public/certificate.pdf
Binary file not shown.
Binary file modified public/certificate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/app/certificate/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const CertificatePage = async () => {
certificateId={cert.id}
course={course}
certificateSlug={cert.slug}
completedAt={cert.completedAt}
userName={user.name!}
key={course.id}
/>
Expand Down
4 changes: 3 additions & 1 deletion src/components/Certificate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useMemo } from 'react'; //used to fix maximum update depth exceeded err
export const CertificateComponent = ({
certificateId,
certificateSlug,
completedAt,
course,
userName,
}: OneCertificate & { userName: string }) => {
Expand All @@ -25,8 +26,9 @@ export const CertificateComponent = ({
course,
userName,
certificateSlug,
completedAt,
}),
[certificateId, course, userName, certificateSlug],
[certificateId, course, userName, certificateSlug, completedAt],
);

const { certificatePdfUrl, certificateImageUrl } = useGenerateCertificate({
Expand Down
5 changes: 5 additions & 0 deletions src/components/CertificateVerify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const CertificateVerify = ({
certificateId: certificate.id,
course: certificate.course,
certificateSlug: certificate.slug,
completedAt: certificate.completedAt as Date,
},
userName: certificate.user.name as string,
});
Expand Down Expand Up @@ -49,6 +50,10 @@ export const CertificateVerify = ({
<CardDescription>
Course Description: {certificate.course.description}
</CardDescription>
<CardDescription>
Course Completed On :{' '}
{certificate.completedAt?.toLocaleDateString()}
</CardDescription>
</CardHeader>
</div>
</Card>
Expand Down
14 changes: 12 additions & 2 deletions src/db/cert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ export const getCertificates = async () => {

const courseWithCert: {
course: Course;
cert: { id: string; courseId: number; userId: string; slug: string };
cert: {
id: string;
courseId: number;
userId: string;
slug: string;
completedAt: Date;
};
user: User;
}[] = [];

Expand All @@ -24,11 +30,14 @@ export const getCertificates = async () => {
where: {
userId_courseId: { courseId: course.id, userId: session?.user.id },
},
update: {},
update: {
completedAt: new Date(),
},
create: {
userId: session?.user.id,
courseId: course.id,
slug: generateUniqueCertId(),
completedAt: new Date(),
},
include: {
user: true,
Expand All @@ -42,6 +51,7 @@ export const getCertificates = async () => {
courseId: certificate.courseId,
userId: certificate.userId,
slug: certificate.slug,
completedAt: certificate.completedAt as Date,
},
user: certificate.user,
});
Expand Down
56 changes: 40 additions & 16 deletions src/hooks/useCertGen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,41 +47,56 @@ export function useGenerateCertificate({
res.arrayBuffer(),
);
const pdfDoc = await PDFDocument.load(existingPdfBytes);
const timesRomanBoldFont = await pdfDoc.embedFont(
StandardFonts.HelveticaBold,
);

const pages = pdfDoc.getPages();
const firstPage = pages[0];
const { width, height } = firstPage.getSize();

const fontSize = 30;
const textWidth = timesRomanBoldFont.widthOfTextAtSize(
const CourierBoldOblique = await pdfDoc.embedFont(
StandardFonts.CourierBoldOblique,
);
const timesRomanBoldFont = await pdfDoc.embedFont(
StandardFonts.TimesRomanBold,
);

const fontSize = 65;
const textWidth = CourierBoldOblique.widthOfTextAtSize(
userName,
fontSize,
);
const xRecipient = (width - textWidth) / 2;
const yRecipient = height * 0.46;
const yRecipient = height * 0.43;
firstPage.drawText(capitalizeFirstLetter(userName), {
x: xRecipient,
y: yRecipient,
size: fontSize,
font: timesRomanBoldFont,
font: CourierBoldOblique,
opacity: 0.85,
color: rgb(0, 0, 0),
});

const certificateNumberFontSize = 28;
firstPage.drawText(
`Certificate No:${certificateDetails.certificateSlug}`,
{
x: width * 0.3,
y: height * 0.12,
x: width * 0.6259,
y: height * 0.1997,
size: certificateNumberFontSize,
font: timesRomanBoldFont,
color: rgb(0, 0, 0),
},
);

const completedAtDateFontSize = 25;
firstPage.drawText(
`${certificateDetails.completedAt.toLocaleDateString('en-IN')}`,
{
x: width * 0.189,
y: height * 0.034,
size: completedAtDateFontSize,
font: timesRomanBoldFont,
color: rgb(0, 0, 0),
},
);
const pdfDataUri = await pdfDoc.saveAsBase64({ dataUri: true });
setCertificatePdfUrl(pdfDataUri);
} catch (error) {
Expand Down Expand Up @@ -112,21 +127,30 @@ export function useGenerateCertificate({
}

ctx.drawImage(certificateImage, 0, 0);

ctx.font = '85px Helvetica';
ctx.font = 'bold italic 65px Courier New';
ctx.fillStyle = 'black';
ctx.globalAlpha = 0.85;
const textWidth = ctx.measureText(recipientName).width;
const xRecipient = (offscreenCanvas.width - textWidth) / 2;
const yRecipient = offscreenCanvas.height * 0.54;
const yRecipient = offscreenCanvas.height * 0.57;
ctx.fillText(recipientName, xRecipient, yRecipient);

const certificateNumberFontSize = 50;
const certificateNumberFontSize = 30;
ctx.font = `bold ${certificateNumberFontSize}px Helvetica`;
const certificateNumberText = `Certificate No: ${certificateDetails.certificateSlug}`;
ctx.fillText(
certificateNumberText,
offscreenCanvas.width * 0.35,
offscreenCanvas.height * 0.88,
offscreenCanvas.width * 0.61,
offscreenCanvas.height * 0.8,
);

const completedAtDateFontSize = 25;
ctx.font = `bold ${completedAtDateFontSize}px Helvetica`;
const completedAtDateText = `${certificateDetails.completedAt.toLocaleDateString('en-IN')}`;
ctx.fillText(
completedAtDateText,
offscreenCanvas.width * 0.19,
offscreenCanvas.height * 0.9675,
);

const dataUrl = offscreenCanvas.toDataURL();
Expand Down
1 change: 1 addition & 0 deletions src/utiles/certificate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import { Course } from '@/store/atoms';
export type OneCertificate = {
certificateId: string;
certificateSlug: string;
completedAt: Date;
course: Course;
};

0 comments on commit a6caec7

Please sign in to comment.