1
0
mirror of https://github.com/XFox111/my-website.git synced 2026-04-22 07:28:01 +03:00

feat: ATS-compliant resume download links

This commit is contained in:
2025-05-11 17:21:53 +00:00
parent 9cf3901307
commit 9a4d6966d0
4 changed files with 35 additions and 13 deletions
+2 -1
View File
@@ -11,7 +11,8 @@ SMTP_TO_EMAIL=email # Email to which emails will be sent
DOMAIN_NAME=example.com # Your domain name DOMAIN_NAME=example.com # Your domain name
RESUME_URL=URL # Location of the resume PDF RESUME_URL=URL # Location of the resume PDF
RESUME_HAS_REFS=false # Appends last page of the resume to a result PDF file ATS_RESUME_URL=URL # Location of the ATS-compatible resume PDF (optional, remove to disable)
RESUME_HAS_REFS=false # Appends last page of the resume to a result PDF file (only appies to non-ATS version)
ALERT_TEXT_URL=URL # URL of a txt file with urgent message to be displayed (see app/_components/AlertMessage.tsx) ALERT_TEXT_URL=URL # URL of a txt file with urgent message to be displayed (see app/_components/AlertMessage.tsx)
CLARITY_ID=string # Clarity Analytics ID (optional, remove to disable) CLARITY_ID=string # Clarity Analytics ID (optional, remove to disable)
CLARITY_CONSENT=1 # 1 if you need to request explicit consent from user, 0 if not (requires CLARITY_ID) CLARITY_CONSENT=1 # 1 if you need to request explicit consent from user, 0 if not (requires CLARITY_ID)
+8 -4
View File
@@ -5,18 +5,22 @@ import { PDFDocument, PDFPage } from "pdf-lib";
export async function GET(req: NextRequest): Promise<Response> export async function GET(req: NextRequest): Promise<Response>
{ {
const type: string | null = req.nextUrl.searchParams.get("type"); const type: string | null = req.nextUrl.searchParams.get("type");
const isAts: boolean = req.nextUrl.searchParams.get("ats") === "true";
const resume: Resume | undefined = findResume(type); const resume: Resume | undefined = findResume(type);
const url: string | undefined = isAts ? process.env.ATS_RESUME_URL : process.env.RESUME_URL;
if (!resume) if (!resume)
return error(400, "'type' parameter is invalid"); return error(400, "'type' parameter is invalid");
if (!process.env.RESUME_URL) const fileName: string = (isAts ? "(ATS) " + resume.fileName : resume.fileName).replaceAll("\"", "'");
if (!url)
return error(500, "Cannot find file location."); return error(500, "Cannot find file location.");
try try
{ {
// Fetch the PDF file from the remote URL using the fetch API // Fetch the PDF file from the remote URL using the fetch API
const response: Response = await fetch(process.env.RESUME_URL as string); const response: Response = await fetch(url);
if (!response.ok) if (!response.ok)
return error(500, "Failed to fetch PDF file"); return error(500, "Failed to fetch PDF file");
@@ -30,7 +34,7 @@ export async function GET(req: NextRequest): Promise<Response>
const [page, refs]: PDFPage[] = await newDoc.copyPages(srcDoc, [resume.pageIndex, srcDoc.getPageCount() - 1]); const [page, refs]: PDFPage[] = await newDoc.copyPages(srcDoc, [resume.pageIndex, srcDoc.getPageCount() - 1]);
newDoc.addPage(page); newDoc.addPage(page);
if (process.env.RESUME_HAS_REFS === "true") if (process.env.RESUME_HAS_REFS === "true" && isAts)
newDoc.addPage(refs); newDoc.addPage(refs);
// Serialize the new PDF document // Serialize the new PDF document
@@ -43,7 +47,7 @@ export async function GET(req: NextRequest): Promise<Response>
// Set response headers for PDF file // Set response headers for PDF file
headers: { headers: {
"Content-Type": "application/pdf", "Content-Type": "application/pdf",
"Content-Disposition": `inline; filename="${resume.fileName.replaceAll("\"", "'")}.pdf"` "Content-Disposition": `inline; filename="${fileName}.pdf"`
} }
} }
); );
+10
View File
@@ -20,6 +20,16 @@
grid-auto-columns: 1fr; grid-auto-columns: 1fr;
gap: $spacingXL; gap: $spacingXL;
.buttonContainer
{
@include flex(column);
}
.atsLink
{
@include body1();
}
.button .button
{ {
flex-flow: column; flex-flow: column;
+8 -1
View File
@@ -21,7 +21,8 @@ const ResumePage: React.FC = () => (
<h1>Who are you looking for?</h1> <h1>Who are you looking for?</h1>
<div className={ cls.resumeButtons }> <div className={ cls.resumeButtons }>
{ resumeList.map(i => { resumeList.map(i =>
<Button key={ i.key } className={ cls.button } <div key={ i.key } className={ cls.buttonContainer }>
<Button className={ cls.button }
href={ `/resume/download?type=${i.key}` } download href={ `/resume/download?type=${i.key}` } download
icon={ icon={
<Image className={ cls.image } src={ i.image.src } priority draggable={ false } <Image className={ cls.image } src={ i.image.src } priority draggable={ false }
@@ -30,6 +31,12 @@ const ResumePage: React.FC = () => (
{ i.label } { i.label }
</Button> </Button>
{ process.env.ATS_RESUME_URL &&
<a className={ cls.atsLink } href={ `/resume/download?type=${i.key}&ats=true` } download>
ATS-compatible version
</a>
}
</div>
) } ) }
</div> </div>