scan/[scanID]/page.tsx
"use client";
import Navbar from "@/components/navbar";
import { Button } from "@/components/ui/button";
import { Check } from "lucide-react";
import React, { useEffect, useState } from "react";
import { findScanById, generatePDF, uploadPDF } from "../actions";
import { redirect } from "next/navigation";
import { handleDownload } from "@/utils/handleDownload";
import { createClerkSupabaseClient } from "@/utils/supabase/client";
const ScanDetails = ({ params }: { params: { scanId: string } }) => {
const [pdfBlob, setPdfBlob] = useState<Blob | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchPDF = async () => {
try {
const scan = await findScanById(params.scanId);
console.log({ scan });
if (scan.length === 0) {
redirect("/dashboard");
return;
}
const supabase = createClerkSupabaseClient();
let { data: old, error } = await supabase.storage
.from("resumes")
.download(`scans/${params.scanId}.pdf`);
if (!old) {
const pdfBuffer = await generatePDF({
htmlContent: scan[0].ai_output,
});
console.log("Trying to upload pdf:", pdfBuffer);
await uploadPDF(params.scanId, pdfBuffer);
({ data: old, error } = await supabase.storage
.from("resumes")
.download(`scans/${params.scanId}.pdf`));
}
setPdfBlob(old);
setLoading(false);
} catch (error) {
console.error("Failed to fetch or generate PDF:", error);
}
};
fetchPDF();
}, [params.scanId]);
return (
<div className="min-h-screen flex flex-col">
<Navbar />
<div className="w-full flex-1 flex items-center px-8">
<div className="w-full flex gap-24">
<div className="bg-white w-[30%] py-10 justify-between h-[40rem] rounded-xl flex flex-col items-center">
<div className="text-center flex flex-col items-center">
<div className="rounded-full w-20 h-20 bg-green-400 flex justify-center items-center">
<Check className="text-white" size={24} />
</div>
<h1 className="text-3xl pt-8">
Your resume is <br /> now tailored.
</h1>
</div>
<Button onClick={() => handleDownload(pdfBlob)} disabled={loading}>
Download Resume
</Button>
</div>
<div
id="resume-content"
className="w-[70%] h-[40rem] rounded-xl border-2 border-gray-700 bg-white overflow-y-auto"
></div>
</div>
</div>
</div>
);
};
export default ScanDetails;
scan/actions.ts
"use server";
import { createClerkSupabaseClient } from "@/utils/supabase/server";
import puppeteer from "puppeteer";
export const findScanById = async (id: string) => {
const supabase = await createClerkSupabaseClient();
const { data, error } = await supabase.from("Tailors").select().eq("id", id);
if (error) {
throw error;
}
return data;
};
export const generatePDF = async ({ htmlContent }: { htmlContent: string }) => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(htmlContent, { waitUntil: "domcontentloaded" });
await page.emulateMediaType("screen");
const pdfBuffer = await page.pdf({
margin: { top: 0, right: 0, bottom: 0, left: 0 },
printBackground: true,
format: "A4",
});
await browser.close();
return pdfBuffer;
};
export const uploadPDF = async (scanId: string, pdfBuffer: Buffer) => {
const supabase = await createClerkSupabaseClient();
const { data, error } = await supabase.storage
.from("resumes")
.upload(`scans/${scanId}.pdf`, pdfBuffer, {
cacheControl: "3600",
upsert: true,
contentType: "application/pdf",
});
if (error) throw new Error(`Failed to upload PDF: ${error.message}`);
return data;
};
utils/handleDownload.ts
export const handleDownload = (pdfBlob: Blob | null) => {
if (pdfBlob) {
const url = URL.createObjectURL(pdfBlob);
const a = document.createElement("a");
a.href = url;
a.download = "resume.pdf"; // The filename you want the file to have
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
// Release the object URL after download
URL.revokeObjectURL(url);
}
};
I am making an app that allows users to tailor their resumes to a job description, when they upload their job description and resume, an AI will tailor the resume and send back to html form, which then i use to create a PDF document using Puppeteer
, after the AI sends back the response i direct the users to a scan page where they can download the new resume. It works by uploading the resume to Supabase storage first and then downloading it and serving it to the user, my issue is that when the file is downloaded, the PDF does not seem to work and it has no preview, why is that? Even when i go on Supabase dashboard and check the resume myself, it is uploded but the PDF is buggy and does not open.
RakibulB is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.